diff --git a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableManager.java b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableManager.java index 7a46a06..f9ccb78 100644 --- a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableManager.java +++ b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableManager.java @@ -22,6 +22,18 @@ public class SpringFlowableManager extends FlowableManager { this.applicationContext = applicationContext; } + public List listNodes(Specification specification) { + return repository.listNodes(specification); + } + + public List listInstances(Specification specification) { + return repository.listInstances(specification); + } + + public List listHistories(String instanceId, Specification specification) { + return repository.listHistories(instanceId, specification); + } + @SneakyThrows @Override protected T createBean(String classpath) { diff --git a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableRepository.java b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableRepository.java index 9086108..09927a3 100644 --- a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableRepository.java +++ b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/SpringFlowableRepository.java @@ -9,7 +9,11 @@ import com.lanyuanxiaoyao.flowable.jpa.repository.FlowableInstanceRepository; import com.lanyuanxiaoyao.flowable.jpa.repository.FlowableNodeRepository; import java.util.List; import java.util.stream.Collectors; +import java.util.stream.StreamSupport; import javax.transaction.Transactional; +import org.springframework.data.domain.Pageable; +import org.springframework.data.domain.Sort; +import org.springframework.data.jpa.domain.Specification; /** * @author lanyuanxiaoyao @@ -26,6 +30,11 @@ public class SpringFlowableRepository implements FlowableRepository { this.flowableHistoryRepository = flowableHistoryRepository; } + @Override + public boolean existsNode(String nodeId) { + return flowableNodeRepository.existsById(nodeId); + } + @Transactional(rollbackOn = Exception.class) @Override public void saveNode(com.lanyuanxiaoyao.flowable.core.model.FlowableNode node) { @@ -45,14 +54,34 @@ public class SpringFlowableRepository implements FlowableRepository { .orElse(null); } - @Override - public List listNodes() { - return flowableNodeRepository.findAll() - .stream() + private List toNodes(Iterable nodes) { + return StreamSupport.stream(nodes.spliterator(), false) .map(FlowableNode::toFlowableNode) .collect(Collectors.toList()); } + @Override + public List listNodes() { + return toNodes(flowableNodeRepository.findAll()); + } + + public List listNodes(Specification specification) { + return toNodes(flowableNodeRepository.findAll(specification)); + } + + public List listNodes(Specification specification, Sort sort) { + return toNodes(flowableNodeRepository.findAll(specification, sort)); + } + + public List listNodes(Specification specification, Pageable pageable) { + return toNodes(flowableNodeRepository.findAll(specification, pageable)); + } + + @Override + public boolean existsInstance(String instanceId) { + return flowableInstanceRepository.existsById(instanceId); + } + @Transactional(rollbackOn = Exception.class) @Override public void saveInstance(com.lanyuanxiaoyao.flowable.core.model.FlowableInstance instance) { @@ -66,14 +95,34 @@ public class SpringFlowableRepository implements FlowableRepository { .orElse(null); } - @Override - public List listInstances() { - return flowableInstanceRepository.findAll() - .stream() + private List toInstances(Iterable instances) { + return StreamSupport.stream(instances.spliterator(), false) .map(FlowableInstance::toFlowableInstance) .collect(Collectors.toList()); } + @Override + public List listInstances() { + return toInstances(flowableInstanceRepository.findAll()); + } + + public List listInstances(Specification specification) { + return toInstances(flowableInstanceRepository.findAll(specification)); + } + + public List listInstances(Specification specification, Sort sort) { + return toInstances(flowableInstanceRepository.findAll(specification, sort)); + } + + public List listInstances(Specification specification, Pageable pageable) { + return toInstances(flowableInstanceRepository.findAll(specification, pageable)); + } + + @Override + public boolean existsHistory(String historyId) { + return flowableHistoryRepository.existsById(historyId); + } + @Transactional(rollbackOn = Exception.class) @Override public void saveHistory(com.lanyuanxiaoyao.flowable.core.model.FlowableHistory history) { @@ -87,14 +136,52 @@ public class SpringFlowableRepository implements FlowableRepository { .orElse(null); } - @Override - public List listHistories(String instanceId) { - return flowableHistoryRepository.findAllByInstanceId(instanceId) - .stream() + private List toHistories(Iterable histories) { + return StreamSupport.stream(histories.spliterator(), false) .map(FlowableHistory::toFlowableHistory) .collect(Collectors.toList()); } + @Override + public List listHistories(String instanceId) { + return toHistories(flowableHistoryRepository.findAllByInstanceId(instanceId)); + } + + public List listHistories(String instanceId, Specification specification) { + return toHistories( + flowableHistoryRepository.findAll( + (root, query, builder) -> builder.and( + builder.equal(root.get("instanceId"), instanceId), + specification.toPredicate(root, query, builder) + ) + ) + ); + } + + public List listHistories(String instanceId, Specification specification, Sort sort) { + return toHistories( + flowableHistoryRepository.findAll( + (root, query, builder) -> builder.and( + builder.equal(root.get("instanceId"), instanceId), + specification.toPredicate(root, query, builder) + ), + sort + ) + ); + } + + public List listHistories(String instanceId, Specification specification, Pageable pageable) { + return toHistories( + flowableHistoryRepository.findAll( + (root, query, builder) -> builder.and( + builder.equal(root.get("instanceId"), instanceId), + specification.toPredicate(root, query, builder) + ), + pageable + ) + ); + } + @Transactional(rollbackOn = Exception.class) @Override public void saveInstanceAndHistory(com.lanyuanxiaoyao.flowable.core.model.FlowableInstance instance, com.lanyuanxiaoyao.flowable.core.model.FlowableHistory history) { diff --git a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableHistoryRepository.java b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableHistoryRepository.java index 00f98bc..ddd8277 100644 --- a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableHistoryRepository.java +++ b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableHistoryRepository.java @@ -3,6 +3,8 @@ package com.lanyuanxiaoyao.flowable.jpa.repository; import com.lanyuanxiaoyao.flowable.jpa.entity.FlowableHistory; import java.util.List; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.stereotype.Repository; /** @@ -10,6 +12,6 @@ import org.springframework.stereotype.Repository; * @version 20250102 */ @Repository -public interface FlowableHistoryRepository extends JpaRepository { +public interface FlowableHistoryRepository extends JpaRepository, JpaSpecificationExecutor, QueryByExampleExecutor { List findAllByInstanceId(String instanceId); } diff --git a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableInstanceRepository.java b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableInstanceRepository.java index 365f963..eecbb46 100644 --- a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableInstanceRepository.java +++ b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableInstanceRepository.java @@ -2,6 +2,8 @@ package com.lanyuanxiaoyao.flowable.jpa.repository; import com.lanyuanxiaoyao.flowable.jpa.entity.FlowableInstance; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.stereotype.Repository; /** @@ -9,5 +11,5 @@ import org.springframework.stereotype.Repository; * @version 20250102 */ @Repository -public interface FlowableInstanceRepository extends JpaRepository { +public interface FlowableInstanceRepository extends JpaRepository, JpaSpecificationExecutor, QueryByExampleExecutor { } diff --git a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableNodeRepository.java b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableNodeRepository.java index 27bed89..5557f2f 100644 --- a/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableNodeRepository.java +++ b/adapter/flowable-spring-boot-jpa-starter/src/main/java/com/lanyuanxiaoyao/flowable/jpa/repository/FlowableNodeRepository.java @@ -2,6 +2,8 @@ package com.lanyuanxiaoyao.flowable.jpa.repository; import com.lanyuanxiaoyao.flowable.jpa.entity.FlowableNode; import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.data.jpa.repository.JpaSpecificationExecutor; +import org.springframework.data.repository.query.QueryByExampleExecutor; import org.springframework.stereotype.Repository; /** @@ -9,5 +11,5 @@ import org.springframework.stereotype.Repository; * @version 20250102 */ @Repository -public interface FlowableNodeRepository extends JpaRepository { +public interface FlowableNodeRepository extends JpaRepository, JpaSpecificationExecutor, QueryByExampleExecutor { } diff --git a/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/manager/FlowableManager.java b/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/manager/FlowableManager.java index 00501a9..56f84b6 100644 --- a/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/manager/FlowableManager.java +++ b/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/manager/FlowableManager.java @@ -36,6 +36,10 @@ public abstract class FlowableManager { this.repository = repository; } + public boolean existsNode(String nodeId) { + return repository.existsNode(nodeId); + } + public List listNodes() { return repository.listNodes(); } @@ -44,6 +48,10 @@ public abstract class FlowableManager { return repository.getNode(nodeId); } + public boolean existsInstance(String instanceId) { + return repository.existsInstance(instanceId); + } + public List listInstances() { return repository.listInstances(); } @@ -52,6 +60,10 @@ public abstract class FlowableManager { return repository.getInstance(instantId); } + public boolean existsHistory(String historyId) { + return repository.existsHistory(historyId); + } + public List listHistories(String instanceId) { return repository.listHistories(instanceId); } diff --git a/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/repository/FlowableRepository.java b/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/repository/FlowableRepository.java index be394f6..6f97770 100644 --- a/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/repository/FlowableRepository.java +++ b/flowable-core/src/main/java/com/lanyuanxiaoyao/flowable/core/repository/FlowableRepository.java @@ -12,6 +12,8 @@ import java.util.List; * @version 20241231 */ public interface FlowableRepository { + boolean existsNode(String nodeId); + void saveNode(FlowableNode node); void saveNode(List nodes); @@ -20,12 +22,16 @@ public interface FlowableRepository { List listNodes(); + boolean existsInstance(String instanceId); + void saveInstance(FlowableInstance instance); FlowableInstance getInstance(String instantId); List listInstances(); + boolean existsHistory(String historyId); + void saveHistory(FlowableHistory history); FlowableHistory getHistory(String historyId); diff --git a/flowable-example/src/main/java/com/lanyuanxiaoyao/flowable/test/TestFlowableManager.java b/flowable-example/src/main/java/com/lanyuanxiaoyao/flowable/test/TestFlowableManager.java index 0fdc689..3764117 100644 --- a/flowable-example/src/main/java/com/lanyuanxiaoyao/flowable/test/TestFlowableManager.java +++ b/flowable-example/src/main/java/com/lanyuanxiaoyao/flowable/test/TestFlowableManager.java @@ -1,10 +1,12 @@ package com.lanyuanxiaoyao.flowable.test; +import com.lanyuanxiaoyao.flowable.core.helper.ListHelper; import com.lanyuanxiaoyao.flowable.core.helper.MapHelper; import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager; import com.lanyuanxiaoyao.flowable.core.model.FlowableAction; import com.lanyuanxiaoyao.flowable.core.model.FlowableHandler; import com.lanyuanxiaoyao.flowable.core.model.FlowableInstance; +import com.lanyuanxiaoyao.flowable.core.model.FlowableListener; import com.lanyuanxiaoyao.flowable.core.model.FlowableNode; import com.lanyuanxiaoyao.flowable.test.accessor.RoleCheckAccessor; import com.lanyuanxiaoyao.flowable.test.handler.TwoApproveHandler; @@ -12,7 +14,10 @@ import java.util.Map; import java.util.UUID; import lombok.extern.slf4j.Slf4j; import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; /** * 集成测试 @@ -21,6 +26,7 @@ import org.junit.jupiter.api.Test; * @version 20241231 */ @Slf4j +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) public abstract class TestFlowableManager { protected abstract FlowableManager flowableManager(); @@ -41,10 +47,23 @@ public abstract class TestFlowableManager { .build(); } + @Test + @Order(1) + public void testRepository() { + FlowableManager manager = flowableManager(); + FlowableNode node1 = createManualNode(); + Assertions.assertFalse(manager.existsNode(node1.getNodeId())); + manager.create(node1); + Assertions.assertTrue(manager.existsNode(node1.getNodeId())); + Assertions.assertNotNull(manager.getNode(node1.getNodeId())); + Assertions.assertEquals(1, manager.listNodes().size()); + } + /** * 单节点审批 */ @Test + @Order(2) public void testSingleNode() { FlowableManager manager = flowableManager(); FlowableNode node1 = createManualNode(); @@ -69,6 +88,7 @@ public abstract class TestFlowableManager { } @Test + @Order(3) public void testMultiNode() { FlowableManager manager = flowableManager(); FlowableNode node1 = createManualNode( @@ -105,6 +125,7 @@ public abstract class TestFlowableManager { } @Test + @Order(4) public void testTerminal() { FlowableManager manager = flowableManager(); FlowableNode node1 = createManualNode(); @@ -115,7 +136,7 @@ public abstract class TestFlowableManager { Assertions.assertEquals(FlowableInstance.Status.RUNNING, manager.getInstance(instanceId).getStatus()); manager.terminal(instanceId, "d896b642-a1d8-499c-92e7-bed63581f2f8"); - Assertions.assertEquals(FlowableInstance.Status.ERROR, manager.getInstance(instanceId).getStatus()); + Assertions.assertEquals(FlowableInstance.Status.TERMINAL, manager.getInstance(instanceId).getStatus()); Assertions.assertEquals(1, manager.listHistories(instanceId).size()); Assertions.assertEquals(FlowableAction.TERMINAL, manager.listHistories(instanceId).get(0).getAction()); Assertions.assertEquals("d896b642-a1d8-499c-92e7-bed63581f2f8", manager.listHistories(instanceId).get(0).getComment()); @@ -124,6 +145,7 @@ public abstract class TestFlowableManager { } @Test + @Order(5) public void testSuspend() { FlowableManager manager = flowableManager(); FlowableNode node = FlowableNode.builder() @@ -142,9 +164,10 @@ public abstract class TestFlowableManager { Assertions.assertEquals(FlowableInstance.Status.COMPLETED, manager.getInstance(instanceId).getStatus()); } - protected abstract Class getAutomaticNodeClass(); + protected abstract Class getHandler(); @Test + @Order(6) public void testAutomaticNode() { FlowableManager manager = flowableManager(); FlowableNode node = FlowableNode.builder() @@ -152,7 +175,7 @@ public abstract class TestFlowableManager { .name("5d60dab0-7691-4543-b753-af7ac02cb7ec") .description("5d60dab0-7691-4543-b753-af7ac02cb7ec") .type(FlowableNode.Type.AUTOMATIC) - .handler(getAutomaticNodeClass().getName()) + .handler(getHandler().getName()) .build(); manager.create(node); String instanceId = manager.start(node.getNodeId()); @@ -160,6 +183,7 @@ public abstract class TestFlowableManager { } @Test + @Order(7) public void testNodeContext() { FlowableManager manager = flowableManager(); FlowableNode node1 = createManualNode( @@ -182,6 +206,7 @@ public abstract class TestFlowableManager { } @Test + @Order(8) public void testAccessor() { FlowableManager manager = flowableManager(); FlowableNode node = FlowableNode.builder() diff --git a/flowable-example/src/test/java/com/lanyuanxiaoyao/flowable/test/InMemoryFlowableRepository.java b/flowable-example/src/test/java/com/lanyuanxiaoyao/flowable/test/InMemoryFlowableRepository.java index c515f9c..e0f7018 100644 --- a/flowable-example/src/test/java/com/lanyuanxiaoyao/flowable/test/InMemoryFlowableRepository.java +++ b/flowable-example/src/test/java/com/lanyuanxiaoyao/flowable/test/InMemoryFlowableRepository.java @@ -22,6 +22,11 @@ public class InMemoryFlowableRepository implements FlowableRepository { private static final Map instances = new HashMap<>(); private static final Map> histories = new HashMap<>(); + @Override + public boolean existsNode(String nodeId) { + return nodes.containsKey(nodeId); + } + @Override public void saveNode(FlowableNode node) { nodes.put(node.getNodeId(), node); @@ -44,6 +49,11 @@ public class InMemoryFlowableRepository implements FlowableRepository { return new ArrayList<>(nodes.values()); } + @Override + public boolean existsInstance(String instanceId) { + return instances.containsKey(instanceId); + } + @Override public void saveInstance(FlowableInstance instance) { instances.put(instance.getInstanceId(), instance); @@ -59,6 +69,11 @@ public class InMemoryFlowableRepository implements FlowableRepository { return new ArrayList<>(instances.values()); } + @Override + public boolean existsHistory(String historyId) { + return histories.containsKey(historyId); + } + @Override public void saveHistory(FlowableHistory history) { String instanceId = history.getInstanceId();