1
0

新增自动节点

This commit is contained in:
2025-01-02 17:43:40 +08:00
parent 7d88674c66
commit c3ca027f72
9 changed files with 138 additions and 17 deletions

View File

@@ -3,15 +3,40 @@ package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import com.lanyuanxiaoyao.flowable.core.repository.FlowableRepository;
import java.util.UUID;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service;
/**
* @author lanyuanxiaoyao
* @version 20241231
*/
@Slf4j
@Service
public class SpringFlowableManager extends FlowableManager {
public SpringFlowableManager(FlowableRepository flowableRepository) {
private final ApplicationContext applicationContext;
public SpringFlowableManager(FlowableRepository flowableRepository, ApplicationContext applicationContext) {
super(flowableRepository, () -> UUID.randomUUID().toString());
this.applicationContext = applicationContext;
}
@SneakyThrows
@Override
protected <T> T createBean(String classpath) {
Class<?> clazz = Class.forName(classpath);
T targetObject = null;
try {
targetObject = (T) applicationContext.getBean(clazz);
} catch (Exception springException) {
log.warn("{} not found in spring context", springException);
try {
targetObject = (T) clazz.newInstance();
} catch (Exception javaException) {
throw new IllegalArgumentException(javaException);
}
}
return targetObject;
}
}

View File

@@ -43,14 +43,17 @@ public class JpaFlowableNode {
@Column(nullable = false)
private String name;
private String description;
@Enumerated(EnumType.STRING)
@Column(nullable = false)
private FlowableNode.Type type;
private String automaticAction;
@ElementCollection(fetch = javax.persistence.FetchType.EAGER)
@MapKeyColumn(name = "action")
@Column(name = "nodeId")
@CollectionTable(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Map<FlowableAction, String> nextNodes;
@CollectionTable(name = "flowable_node_manual_actions", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Map<FlowableAction, String> manualActions;
@CreatedDate
private LocalDateTime createdTime;
@LastModifiedDate
@@ -61,11 +64,12 @@ public class JpaFlowableNode {
this.name = node.getName();
this.description = node.getDescription();
this.type = node.getType();
this.nextNodes = node.getNextNodes();
this.automaticAction = node.getAutomaticAction();
this.manualActions = node.getManualActions();
}
public FlowableNode toFlowableNode() {
FlowableNode node = new FlowableNode(nodeId, name, description, type, nextNodes, null, createdTime);
FlowableNode node = new FlowableNode(nodeId, name, description, type, automaticAction, manualActions, null, createdTime);
node.setUpdatedTime(updateTime);
return node;
}

View File

@@ -0,0 +1,25 @@
package com.lanyuanxiaoyao.flowable.core;
import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import com.lanyuanxiaoyao.flowable.core.model.FlowableAction;
import com.lanyuanxiaoyao.flowable.core.model.FlowableInstance;
import com.lanyuanxiaoyao.flowable.core.model.FlowableNode;
import java.util.Map;
import javax.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
@Slf4j
public class SimpleAutoAction implements FlowableNode.AutoAction {
@Resource
private FlowableManager flowableManager;
@Override
public FlowableAction action(FlowableInstance instance, FlowableNode node, Map<String, Object> metadata) {
log.info("Initial with spring: {}", flowableManager.listNodes());
return FlowableAction.APPROVE;
}
}

View File

@@ -1,7 +1,9 @@
package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.SimpleAutoAction;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
/**
@@ -14,4 +16,9 @@ public class SpringFlowableApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFlowableApplication.class, args);
}
@Bean
public SimpleAutoAction simpleAutoAction() {
return new SimpleAutoAction();
}
}

View File

@@ -70,7 +70,7 @@ public abstract class FlowableManager {
flowableRepository.saveInstance(instance);
if (FlowableNode.Type.AUTOMATIC.equals(node.getType())) {
action(instance, node, FlowableAction.APPROVE, "系统审批通过", MapHelper.empty());
autoAction(instance, node, MapHelper.empty());
}
return instance.getInstanceId();
}
@@ -103,6 +103,15 @@ public abstract class FlowableManager {
action(instanceId, action, comment, MapHelper.empty());
}
private void autoAction(FlowableInstance instance, FlowableNode node, Map<String, Object> metadata) {
String actionClass = node.getAutomaticAction();
if (StringHelper.isBlank(actionClass)) {
throw new IllegalArgumentException("自动节点执行器为空");
}
FlowableNode.AutoAction autoAction = createBean(actionClass);
action(instance, node, autoAction.action(instance, node, metadata), "系统自动执行", metadata);
}
private void action(String instanceId, FlowableAction action, String comment, Map<String, Object> metadata) {
FlowableInstance instance = flowableRepository.getInstance(instanceId);
FlowableNode node = flowableRepository.getNode(instance.getCurrentNodeId());
@@ -117,19 +126,19 @@ public abstract class FlowableManager {
saveInstance(instance, FlowableInstance.Status.ERROR, metadata, action, comment);
return;
}
if (Objects.isNull(node.getNextNodes())
|| !node.getNextNodes().containsKey(action)
|| StringHelper.isBlank(node.getNextNodes().get(action))) {
if (Objects.isNull(node.getManualActions())
|| !node.getManualActions().containsKey(action)
|| StringHelper.isBlank(node.getManualActions().get(action))) {
saveInstance(instance, FlowableInstance.Status.COMPLETED, metadata, action, comment);
return;
}
String nextNodeId = node.getNextNodes().get(action);
String nextNodeId = node.getManualActions().get(action);
FlowableNode nextNode = flowableRepository.getNode(nextNodeId);
instance.setCurrentNodeId(nextNode.getNodeId());
saveInstance(instance, FlowableInstance.Status.RUNNING, metadata, action, comment);
if (FlowableNode.Type.AUTOMATIC.equals(nextNode.getType())) {
action(instance, node, FlowableAction.APPROVE, "系统审批通过", metadata);
autoAction(instance, node, metadata);
}
}
@@ -150,6 +159,8 @@ public abstract class FlowableManager {
}
}
protected abstract <T> T createBean(String classpath);
public interface IdGenerator {
String createId();
}

View File

@@ -17,23 +17,27 @@ public class FlowableNode {
private final String nodeId;
private final String name;
private final String description;
private final Type type;
private final Map<FlowableAction, String> nextNodes;
private final List<Class<? extends FlowableListener>> listeners;
private final String automaticAction;
private final Map<FlowableAction, String> manualActions;
private final List<String> listeners;
private final LocalDateTime createdTime;
private LocalDateTime updatedTime = LocalDateTime.now();
public FlowableNode(String nodeId, String name, String description, Type type, Map<FlowableAction, String> nextNodes) {
this(nodeId, name, description, type, nextNodes, ListHelper.empty(), LocalDateTime.now());
public FlowableNode(String nodeId, String name, String description, Type type, String automaticAction, Map<FlowableAction, String> manualActions) {
this(nodeId, name, description, type, automaticAction, manualActions, ListHelper.empty(), LocalDateTime.now());
}
public FlowableNode(String nodeId, String name, String description, Type type, Map<FlowableAction, String> nextNodes, List<Class<? extends FlowableListener>> listeners, LocalDateTime createdTime) {
public FlowableNode(String nodeId, String name, String description, Type type, String automaticAction, Map<FlowableAction, String> manualActions, List<String> listeners, LocalDateTime createdTime) {
this.nodeId = nodeId;
this.name = name;
this.description = description;
this.type = type;
this.nextNodes = nextNodes;
this.automaticAction = automaticAction;
this.manualActions = manualActions;
this.listeners = listeners;
this.createdTime = createdTime;
}
@@ -42,4 +46,8 @@ public class FlowableNode {
AUTOMATIC,
MANUAL,
}
public interface AutoAction {
FlowableAction action(FlowableInstance instance, FlowableNode node, Map<String, Object> metadata);
}
}

View File

@@ -35,6 +35,7 @@ public abstract class TestFlowableManager {
UUID.randomUUID().toString(),
UUID.randomUUID().toString(),
FlowableNode.Type.MANUAL,
null,
nextNodes
);
}
@@ -120,4 +121,20 @@ public abstract class TestFlowableManager {
Assertions.assertThrows(IllegalArgumentException.class, () -> manager.approve(instanceId));
}
@Test
public void testAutomaticNode() {
FlowableManager manager = flowableManager();
FlowableNode node = new FlowableNode(
"2733d930-7a4b-491e-b1ca-4d5811435e9f",
"自动节点",
"自动节点",
FlowableNode.Type.AUTOMATIC,
"com.lanyuanxiaoyao.flowable.core.SimpleAutoAction",
null
);
manager.create(node);
String instanceId = manager.start(node.getNodeId());
Assertions.assertEquals(FlowableInstance.Status.COMPLETED, manager.getInstance(instanceId).getStatus());
}
}

View File

@@ -0,0 +1,17 @@
package com.lanyuanxiaoyao.flowable.core;
import com.lanyuanxiaoyao.flowable.core.model.FlowableAction;
import com.lanyuanxiaoyao.flowable.core.model.FlowableInstance;
import com.lanyuanxiaoyao.flowable.core.model.FlowableNode;
import java.util.Map;
/**
* @author lanyuanxiaoyao
* @version 20250102
*/
public class SimpleAutoAction implements FlowableNode.AutoAction {
@Override
public FlowableAction action(FlowableInstance instance, FlowableNode node, Map<String, Object> metadata) {
return FlowableAction.APPROVE;
}
}

View File

@@ -2,6 +2,7 @@ package com.lanyuanxiaoyao.flowable.core;
import com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import java.util.UUID;
import lombok.SneakyThrows;
/**
* @author lanyuanxiaoyao
@@ -11,4 +12,10 @@ public class SimpleFlowableManager extends FlowableManager {
public SimpleFlowableManager() {
super(new InMemoryFlowableRepository(), () -> UUID.randomUUID().toString());
}
@SneakyThrows
@Override
protected <T> T createBean(String classpath) {
return (T) Class.forName(classpath).newInstance();
}
}