1
0

完成spring jpa的存储适配

This commit is contained in:
2025-01-02 16:05:15 +08:00
parent 13b9366346
commit 422e024b7b
30 changed files with 1271 additions and 14 deletions

View File

@@ -0,0 +1,17 @@
package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import com.lanyuanxiaoyao.flowable.core.repository.FlowableRepository;
import java.util.UUID;
import org.springframework.stereotype.Service;
/**
* @author lanyuanxiaoyao
* @version 20241231
*/
@Service
public class SpringFlowableManager extends FlowableManager {
public SpringFlowableManager(FlowableRepository flowableRepository) {
super(flowableRepository, () -> UUID.randomUUID().toString());
}
}

View File

@@ -0,0 +1,109 @@
package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.model.FlowableHistory;
import com.lanyuanxiaoyao.flowable.core.model.FlowableInstance;
import com.lanyuanxiaoyao.flowable.core.model.FlowableNode;
import com.lanyuanxiaoyao.flowable.core.repository.FlowableRepository;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableHistory;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableInstance;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableNode;
import com.lanyuanxiaoyao.flowable.jpa.repository.JpaFlowableHistoryRepository;
import com.lanyuanxiaoyao.flowable.jpa.repository.JpaFlowableInstanceRepository;
import com.lanyuanxiaoyao.flowable.jpa.repository.JpaFlowableNodeRepository;
import java.util.List;
import java.util.stream.Collectors;
import javax.transaction.Transactional;
import org.springframework.stereotype.Service;
/**
* @author lanyuanxiaoyao
* @version 20241231
*/
@Service
public class SpringJpaFlowableRepository implements FlowableRepository {
private final JpaFlowableNodeRepository jpaFlowableNodeRepository;
private final JpaFlowableInstanceRepository jpaFlowableInstanceRepository;
private final JpaFlowableHistoryRepository jpaFlowableHistoryRepository;
public SpringJpaFlowableRepository(JpaFlowableNodeRepository jpaFlowableNodeRepository, JpaFlowableInstanceRepository jpaFlowableInstanceRepository, JpaFlowableHistoryRepository jpaFlowableHistoryRepository) {
this.jpaFlowableNodeRepository = jpaFlowableNodeRepository;
this.jpaFlowableInstanceRepository = jpaFlowableInstanceRepository;
this.jpaFlowableHistoryRepository = jpaFlowableHistoryRepository;
}
@Transactional(rollbackOn = Exception.class)
@Override
public void saveNode(FlowableNode node) {
jpaFlowableNodeRepository.save(new JpaFlowableNode(node));
}
@Transactional(rollbackOn = Exception.class)
@Override
public void saveNode(List<FlowableNode> nodes) {
jpaFlowableNodeRepository.saveAll(nodes.stream().map(JpaFlowableNode::new).collect(Collectors.toList()));
}
@Override
public FlowableNode getNode(String nodeId) {
return jpaFlowableNodeRepository.findById(nodeId)
.map(JpaFlowableNode::toFlowableNode)
.orElse(null);
}
@Override
public List<FlowableNode> listNodes() {
return jpaFlowableNodeRepository.findAll()
.stream()
.map(JpaFlowableNode::toFlowableNode)
.collect(Collectors.toList());
}
@Transactional(rollbackOn = Exception.class)
@Override
public void saveInstance(FlowableInstance instance) {
jpaFlowableInstanceRepository.save(new JpaFlowableInstance(instance));
}
@Override
public FlowableInstance getInstance(String instantId) {
return jpaFlowableInstanceRepository.findById(instantId)
.map(JpaFlowableInstance::toFlowableInstance)
.orElse(null);
}
@Override
public List<FlowableInstance> listInstances() {
return jpaFlowableInstanceRepository.findAll()
.stream()
.map(JpaFlowableInstance::toFlowableInstance)
.collect(Collectors.toList());
}
@Transactional(rollbackOn = Exception.class)
@Override
public void saveHistory(FlowableHistory history) {
jpaFlowableHistoryRepository.save(new JpaFlowableHistory(history));
}
@Override
public FlowableHistory getHistory(String historyId) {
return jpaFlowableHistoryRepository.findById(historyId)
.map(JpaFlowableHistory::toFlowableHistory)
.orElse(null);
}
@Override
public List<FlowableHistory> listHistories(String instanceId) {
return jpaFlowableHistoryRepository.findAllByInstanceId(instanceId)
.stream()
.map(JpaFlowableHistory::toFlowableHistory)
.collect(Collectors.toList());
}
@Transactional(rollbackOn = Exception.class)
@Override
public void saveInstanceAndHistory(FlowableInstance instance, FlowableHistory history) {
saveInstance(instance);
saveHistory(history);
}
}

View File

@@ -0,0 +1,54 @@
package com.lanyuanxiaoyao.flowable.jpa.entity;
import com.lanyuanxiaoyao.flowable.core.model.FlowableAction;
import com.lanyuanxiaoyao.flowable.core.model.FlowableHistory;
import java.time.LocalDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@NoArgsConstructor
@ToString
@Getter
@Setter
@Entity
@Table(name = "flowable_history")
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
public class JpaFlowableHistory {
@Id
private String historyId;
@Column(nullable = false)
private String instanceId;
@Enumerated(EnumType.STRING)
private FlowableAction action;
private String comment;
@CreatedDate
private LocalDateTime createdTime;
public JpaFlowableHistory(FlowableHistory history) {
this.historyId = history.getHistoryId();
this.instanceId = history.getInstanceId();
this.action = history.getAction();
this.comment = history.getComment();
}
public FlowableHistory toFlowableHistory() {
return new FlowableHistory(historyId, instanceId, action, comment, createdTime);
}
}

View File

@@ -0,0 +1,94 @@
package com.lanyuanxiaoyao.flowable.jpa.entity;
import com.lanyuanxiaoyao.flowable.core.model.FlowableInstance;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.time.LocalDateTime;
import java.util.Map;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import javax.persistence.Lob;
import javax.persistence.Table;
import lombok.Cleanup;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.SneakyThrows;
import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@NoArgsConstructor
@ToString
@Getter
@Setter
@Entity
@Table(name = "flowable_instance")
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
public class JpaFlowableInstance {
@Id
private String instanceId;
@Lob
private byte[] metadata;
@Column(nullable = false)
private String currentNodeId;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private FlowableInstance.Status status = FlowableInstance.Status.RUNNING;
@CreatedDate
private LocalDateTime createdTime;
@LastModifiedDate
private LocalDateTime updatedTime;
@SneakyThrows
public JpaFlowableInstance(FlowableInstance instance) {
this.instanceId = instance.getInstanceId();
this.metadata = objectToBytes(instance.getMetadata());
this.currentNodeId = instance.getCurrentNodeId();
this.status = instance.getStatus();
}
private static byte[] objectToBytes(Object object) throws IOException {
@Cleanup
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
@Cleanup
ObjectOutputStream objectOutputStream = new ObjectOutputStream(byteArrayOutputStream);
objectOutputStream.writeObject(object);
return byteArrayOutputStream.toByteArray();
}
private static Object bytesToObject(byte[] bytes) throws IOException, ClassNotFoundException {
@Cleanup
java.io.ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes);
@Cleanup
java.io.ObjectInputStream objectInputStream = new ObjectInputStream(byteArrayInputStream);
return objectInputStream.readObject();
}
@SneakyThrows
public FlowableInstance toFlowableInstance() {
return new FlowableInstance(
instanceId,
currentNodeId,
(Map<String, Object>) bytesToObject(this.metadata),
status,
createdTime,
updatedTime
);
}
}

View File

@@ -0,0 +1,72 @@
package com.lanyuanxiaoyao.flowable.jpa.entity;
import com.lanyuanxiaoyao.flowable.core.model.FlowableAction;
import com.lanyuanxiaoyao.flowable.core.model.FlowableNode;
import java.time.LocalDateTime;
import java.util.Map;
import javax.persistence.CollectionTable;
import javax.persistence.Column;
import javax.persistence.ConstraintMode;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.EntityListeners;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.ForeignKey;
import javax.persistence.Id;
import javax.persistence.MapKeyColumn;
import javax.persistence.Table;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.ToString;
import org.hibernate.annotations.DynamicUpdate;
import org.springframework.data.annotation.CreatedDate;
import org.springframework.data.annotation.LastModifiedDate;
import org.springframework.data.jpa.domain.support.AuditingEntityListener;
/**
* @author lanyuanxiaoyao
* @version 20241231
*/
@NoArgsConstructor
@ToString
@Getter
@Setter
@Entity
@Table(name = "flowable_node")
@DynamicUpdate
@EntityListeners(AuditingEntityListener.class)
public class JpaFlowableNode {
@Id
private String nodeId;
@Column(nullable = false)
private String name;
private String description;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private FlowableNode.RunType runType;
@ElementCollection(fetch = javax.persistence.FetchType.EAGER)
@MapKeyColumn(name = "action")
@Column(name = "nodeId")
@CollectionTable(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Map<FlowableAction, String> nextNodes;
@CreatedDate
private LocalDateTime createdTime;
@LastModifiedDate
private LocalDateTime updateTime;
public JpaFlowableNode(FlowableNode node) {
this.nodeId = node.getNodeId();
this.name = node.getName();
this.description = node.getDescription();
this.runType = node.getRunType();
this.nextNodes = node.getNextNodes();
}
public FlowableNode toFlowableNode() {
FlowableNode node = new FlowableNode(nodeId, name, description, runType, nextNodes, null, createdTime);
node.setUpdatedTime(updateTime);
return node;
}
}

View File

@@ -0,0 +1,15 @@
package com.lanyuanxiaoyao.flowable.jpa.repository;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableHistory;
import java.util.List;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@Repository
public interface JpaFlowableHistoryRepository extends JpaRepository<JpaFlowableHistory, String> {
List<JpaFlowableHistory> findAllByInstanceId(String instanceId);
}

View File

@@ -0,0 +1,13 @@
package com.lanyuanxiaoyao.flowable.jpa.repository;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableInstance;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@Repository
public interface JpaFlowableInstanceRepository extends JpaRepository<JpaFlowableInstance, String> {
}

View File

@@ -0,0 +1,13 @@
package com.lanyuanxiaoyao.flowable.jpa.repository;
import com.lanyuanxiaoyao.flowable.jpa.entity.JpaFlowableNode;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@Repository
public interface JpaFlowableNodeRepository extends JpaRepository<JpaFlowableNode, String> {
}

View File

@@ -0,0 +1,17 @@
package com.lanyuanxiaoyao.flowable.jpa;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@SpringBootApplication
@EnableJpaAuditing
public class SpringFlowableApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFlowableApplication.class, args);
}
}

View File

@@ -0,0 +1,21 @@
package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import com.lanyuanxiaoyao.flowable.core.test.TestFlowableManager;
import javax.annotation.Resource;
import org.springframework.boot.test.context.SpringBootTest;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@SpringBootTest
public class TestSpringFlowableManager extends TestFlowableManager {
@Resource
private SpringFlowableManager flowableManager;
@Override
protected FlowableManager flowableManager() {
return flowableManager;
}
}

View File

@@ -0,0 +1,18 @@
spring:
datasource:
url: jdbc:h2:mem:testdb
username: flowable
password: flowable
driver-class-name: org.h2.Driver
jpa:
show-sql: true
hibernate:
ddl-auto: create
logging:
level:
root: info
org:
hibernate:
orm:
jdbc:
bind: trace