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.manager.FlowableManager;
import com.lanyuanxiaoyao.flowable.core.repository.FlowableRepository; import com.lanyuanxiaoyao.flowable.core.repository.FlowableRepository;
import java.util.UUID; import java.util.UUID;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.ApplicationContext;
import org.springframework.stereotype.Service; import org.springframework.stereotype.Service;
/** /**
* @author lanyuanxiaoyao * @author lanyuanxiaoyao
* @version 20241231 * @version 20241231
*/ */
@Slf4j
@Service @Service
public class SpringFlowableManager extends FlowableManager { public class SpringFlowableManager extends FlowableManager {
public SpringFlowableManager(FlowableRepository flowableRepository) { private final ApplicationContext applicationContext;
public SpringFlowableManager(FlowableRepository flowableRepository, ApplicationContext applicationContext) {
super(flowableRepository, () -> UUID.randomUUID().toString()); 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) @Column(nullable = false)
private String name; private String name;
private String description; private String description;
@Enumerated(EnumType.STRING) @Enumerated(EnumType.STRING)
@Column(nullable = false) @Column(nullable = false)
private FlowableNode.Type type; private FlowableNode.Type type;
private String automaticAction;
@ElementCollection(fetch = javax.persistence.FetchType.EAGER) @ElementCollection(fetch = javax.persistence.FetchType.EAGER)
@MapKeyColumn(name = "action") @MapKeyColumn(name = "action")
@Column(name = "nodeId") @Column(name = "nodeId")
@CollectionTable(foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT)) @CollectionTable(name = "flowable_node_manual_actions", foreignKey = @ForeignKey(ConstraintMode.NO_CONSTRAINT))
private Map<FlowableAction, String> nextNodes; private Map<FlowableAction, String> manualActions;
@CreatedDate @CreatedDate
private LocalDateTime createdTime; private LocalDateTime createdTime;
@LastModifiedDate @LastModifiedDate
@@ -61,11 +64,12 @@ public class JpaFlowableNode {
this.name = node.getName(); this.name = node.getName();
this.description = node.getDescription(); this.description = node.getDescription();
this.type = node.getType(); this.type = node.getType();
this.nextNodes = node.getNextNodes(); this.automaticAction = node.getAutomaticAction();
this.manualActions = node.getManualActions();
} }
public FlowableNode toFlowableNode() { 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); node.setUpdatedTime(updateTime);
return node; 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; package com.lanyuanxiaoyao.flowable.jpa;
import com.lanyuanxiaoyao.flowable.core.SimpleAutoAction;
import org.springframework.boot.SpringApplication; import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Bean;
import org.springframework.data.jpa.repository.config.EnableJpaAuditing; import org.springframework.data.jpa.repository.config.EnableJpaAuditing;
/** /**
@@ -14,4 +16,9 @@ public class SpringFlowableApplication {
public static void main(String[] args) { public static void main(String[] args) {
SpringApplication.run(SpringFlowableApplication.class, 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); flowableRepository.saveInstance(instance);
if (FlowableNode.Type.AUTOMATIC.equals(node.getType())) { if (FlowableNode.Type.AUTOMATIC.equals(node.getType())) {
action(instance, node, FlowableAction.APPROVE, "系统审批通过", MapHelper.empty()); autoAction(instance, node, MapHelper.empty());
} }
return instance.getInstanceId(); return instance.getInstanceId();
} }
@@ -103,6 +103,15 @@ public abstract class FlowableManager {
action(instanceId, action, comment, MapHelper.empty()); 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) { private void action(String instanceId, FlowableAction action, String comment, Map<String, Object> metadata) {
FlowableInstance instance = flowableRepository.getInstance(instanceId); FlowableInstance instance = flowableRepository.getInstance(instanceId);
FlowableNode node = flowableRepository.getNode(instance.getCurrentNodeId()); FlowableNode node = flowableRepository.getNode(instance.getCurrentNodeId());
@@ -117,19 +126,19 @@ public abstract class FlowableManager {
saveInstance(instance, FlowableInstance.Status.ERROR, metadata, action, comment); saveInstance(instance, FlowableInstance.Status.ERROR, metadata, action, comment);
return; return;
} }
if (Objects.isNull(node.getNextNodes()) if (Objects.isNull(node.getManualActions())
|| !node.getNextNodes().containsKey(action) || !node.getManualActions().containsKey(action)
|| StringHelper.isBlank(node.getNextNodes().get(action))) { || StringHelper.isBlank(node.getManualActions().get(action))) {
saveInstance(instance, FlowableInstance.Status.COMPLETED, metadata, action, comment); saveInstance(instance, FlowableInstance.Status.COMPLETED, metadata, action, comment);
return; return;
} }
String nextNodeId = node.getNextNodes().get(action); String nextNodeId = node.getManualActions().get(action);
FlowableNode nextNode = flowableRepository.getNode(nextNodeId); FlowableNode nextNode = flowableRepository.getNode(nextNodeId);
instance.setCurrentNodeId(nextNode.getNodeId()); instance.setCurrentNodeId(nextNode.getNodeId());
saveInstance(instance, FlowableInstance.Status.RUNNING, metadata, action, comment); saveInstance(instance, FlowableInstance.Status.RUNNING, metadata, action, comment);
if (FlowableNode.Type.AUTOMATIC.equals(nextNode.getType())) { 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 { public interface IdGenerator {
String createId(); String createId();
} }

View File

@@ -17,23 +17,27 @@ public class FlowableNode {
private final String nodeId; private final String nodeId;
private final String name; private final String name;
private final String description; private final String description;
private final Type type; private final Type type;
private final Map<FlowableAction, String> nextNodes; private final String automaticAction;
private final List<Class<? extends FlowableListener>> listeners; private final Map<FlowableAction, String> manualActions;
private final List<String> listeners;
private final LocalDateTime createdTime; private final LocalDateTime createdTime;
private LocalDateTime updatedTime = LocalDateTime.now(); private LocalDateTime updatedTime = LocalDateTime.now();
public FlowableNode(String nodeId, String name, String description, Type type, Map<FlowableAction, String> nextNodes) { public FlowableNode(String nodeId, String name, String description, Type type, String automaticAction, Map<FlowableAction, String> manualActions) {
this(nodeId, name, description, type, nextNodes, ListHelper.empty(), LocalDateTime.now()); 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.nodeId = nodeId;
this.name = name; this.name = name;
this.description = description; this.description = description;
this.type = type; this.type = type;
this.nextNodes = nextNodes; this.automaticAction = automaticAction;
this.manualActions = manualActions;
this.listeners = listeners; this.listeners = listeners;
this.createdTime = createdTime; this.createdTime = createdTime;
} }
@@ -42,4 +46,8 @@ public class FlowableNode {
AUTOMATIC, AUTOMATIC,
MANUAL, 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(),
UUID.randomUUID().toString(), UUID.randomUUID().toString(),
FlowableNode.Type.MANUAL, FlowableNode.Type.MANUAL,
null,
nextNodes nextNodes
); );
} }
@@ -120,4 +121,20 @@ public abstract class TestFlowableManager {
Assertions.assertThrows(IllegalArgumentException.class, () -> manager.approve(instanceId)); 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 com.lanyuanxiaoyao.flowable.core.manager.FlowableManager;
import java.util.UUID; import java.util.UUID;
import lombok.SneakyThrows;
/** /**
* @author lanyuanxiaoyao * @author lanyuanxiaoyao
@@ -11,4 +12,10 @@ public class SimpleFlowableManager extends FlowableManager {
public SimpleFlowableManager() { public SimpleFlowableManager() {
super(new InMemoryFlowableRepository(), () -> UUID.randomUUID().toString()); super(new InMemoryFlowableRepository(), () -> UUID.randomUUID().toString());
} }
@SneakyThrows
@Override
protected <T> T createBean(String classpath) {
return (T) Class.forName(classpath).newInstance();
}
} }