Skip to content

Commit 7eefb07

Browse files
committed
add error trigger
1 parent 9314673 commit 7eefb07

9 files changed

Lines changed: 388 additions & 25 deletions

File tree

flow-engine-framework/src/main/java/com/codingapi/flow/exception/FlowConfigException.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -129,4 +129,13 @@ public static FlowConfigException routerNodeScriptNull() {
129129
public static FlowConfigException repositoryNotRegistered() {
130130
return new FlowConfigException("config.repository.notRegistered", "Flow repository components not registered");
131131
}
132+
133+
/**
134+
* Error throw cannot be null
135+
*
136+
* @return exception
137+
*/
138+
public static FlowConfigException errorThrowNotNull() {
139+
return new FlowConfigException("config.errorThrow.required", "Error throw cannot be null");
140+
}
132141
}

flow-engine-framework/src/main/java/com/codingapi/flow/manager/NodeStrategyManager.java

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import com.codingapi.flow.action.IFlowAction;
44
import com.codingapi.flow.action.actions.PassAction;
5+
import com.codingapi.flow.error.ErrorThrow;
56
import com.codingapi.flow.exception.FlowConfigException;
67
import com.codingapi.flow.exception.FlowValidationException;
78
import com.codingapi.flow.form.FormMeta;
@@ -192,4 +193,19 @@ public <T extends INodeStrategy> T getStrategy(Class<T> clazz) {
192193
}
193194
return null;
194195
}
196+
197+
/**
198+
* 错误触发(没有匹配到人时执行的逻辑)
199+
* @param session 触发会话
200+
* @return 错误触发
201+
*/
202+
public ErrorThrow errorTrigger(FlowSession session) {
203+
List<INodeStrategy> strategies = this.strategies;
204+
for (INodeStrategy strategy : strategies) {
205+
if (strategy instanceof ErrorTriggerStrategy) {
206+
return ((ErrorTriggerStrategy) strategy).errorTrigger(session);
207+
}
208+
}
209+
return null;
210+
}
195211
}

flow-engine-framework/src/main/java/com/codingapi/flow/manager/OperatorManager.java

Lines changed: 16 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,9 @@
33
import com.codingapi.flow.operator.IFlowOperator;
44
import lombok.Getter;
55

6+
import java.util.ArrayList;
67
import java.util.List;
8+
import java.util.Objects;
79

810
/**
911
* 节点操作者管理
@@ -15,8 +17,20 @@ public class OperatorManager {
1517
private final List<Long> operatorIds;
1618

1719
public OperatorManager(List<IFlowOperator> operators) {
18-
this.operators = operators;
19-
this.operatorIds = operators.stream().map(IFlowOperator::getUserId).toList();
20+
if(operators!=null && !operators.isEmpty()) {
21+
this.operators = operators.stream().filter(Objects::nonNull).toList();
22+
}else {
23+
this.operators = new ArrayList<>();
24+
}
25+
if(!this.operators.isEmpty()) {
26+
this.operatorIds = this.operators.stream().map(IFlowOperator::getUserId).toList();
27+
}else {
28+
this.operatorIds = new ArrayList<>();
29+
}
30+
}
31+
32+
public boolean isEmpty() {
33+
return operators.isEmpty();
2034
}
2135

2236
public boolean match(IFlowOperator operator) {

flow-engine-framework/src/main/java/com/codingapi/flow/node/BaseAuditNode.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.codingapi.flow.node;
22

33
import com.codingapi.flow.action.IFlowAction;
4+
import com.codingapi.flow.error.ErrorThrow;
45
import com.codingapi.flow.exception.FlowConfigException;
56
import com.codingapi.flow.form.FormMeta;
67
import com.codingapi.flow.manager.NodeStrategyManager;
@@ -116,6 +117,20 @@ public List<FlowRecord> generateCurrentRecords(FlowSession session) {
116117
List<FlowRecord> records = new ArrayList<>();
117118
NodeStrategyManager nodeStrategyManager = this.strategyManager();
118119
OperatorManager operatorManager = nodeStrategyManager.loadOperators(session);
120+
// 执行异常节点配置
121+
if(operatorManager.isEmpty()){
122+
ErrorThrow errorThrow = nodeStrategyManager.errorTrigger(session);
123+
if(errorThrow==null){
124+
throw FlowConfigException.errorThrowNotNull();
125+
}
126+
if(errorThrow.isNode()){
127+
IFlowNode errorNode = errorThrow.getNode();
128+
FlowSession errorSession = session.updateSession(errorNode);
129+
return errorNode.generateCurrentRecords(errorSession);
130+
}else {
131+
operatorManager = new OperatorManager(errorThrow.getOperators());
132+
}
133+
}
119134
List<IFlowOperator> operators = operatorManager.getOperators();
120135
for (int order = 0; order < operators.size(); order++) {
121136
IFlowOperator operator = operators.get(order);

flow-engine-framework/src/main/java/com/codingapi/flow/script/node/ErrorTriggerScript.java

Lines changed: 3 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,21 +13,9 @@
1313
public class ErrorTriggerScript {
1414

1515

16-
public static final String SCRIPT_NODE_DEFAULT = """
17-
def run(request){
18-
return com.codingapi.flow.error.ErrorThrow.builder()
19-
.node(request.getStartNode())
20-
.build();
21-
}
22-
""";
23-
24-
public static final String SCRIPT_OPERATOR_DEFAULT = """
25-
def run(request){
26-
return com.codingapi.flow.error.ErrorThrow.builder()
27-
.operators(request.getCreatedOperator())
28-
.build();
29-
}
30-
""";
16+
public static final String SCRIPT_NODE_DEFAULT = "def run(request){ return $bind.createErrorThrow(request.getStartNode()); }";
17+
18+
public static final String SCRIPT_OPERATOR_DEFAULT = "def run(request){ return $bind.createErrorThrow(request.getCreatedOperator()); }";
3119

3220
@Getter
3321
private final String script;

flow-engine-framework/src/main/java/com/codingapi/flow/script/runtime/FlowScriptContext.java

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
11
package com.codingapi.flow.script.runtime;
22

3+
import com.codingapi.flow.error.ErrorThrow;
4+
import com.codingapi.flow.node.IFlowNode;
35
import com.codingapi.flow.operator.IFlowOperator;
46
import com.codingapi.flow.record.FlowRecord;
57
import lombok.Getter;
68
import lombok.Setter;
79

10+
import java.util.Arrays;
811
import java.util.List;
912

1013
public class FlowScriptContext {
@@ -20,6 +23,37 @@ private FlowScriptContext() {
2023
@Setter
2124
private IBeanFactory beanFactory;
2225

26+
27+
public ErrorThrow createErrorThrow(IFlowNode node) {
28+
return ErrorThrow.builder()
29+
.node(node)
30+
.build();
31+
}
32+
33+
public ErrorThrow createErrorThrow(IFlowOperator... operators) {
34+
return ErrorThrow.builder()
35+
.operators(List.of(operators))
36+
.build();
37+
}
38+
39+
public ErrorThrow createErrorThrow(IFlowOperator operator) {
40+
return ErrorThrow.builder()
41+
.operators(List.of(operator))
42+
.build();
43+
}
44+
45+
public ErrorThrow createErrorThrow(List<Long> userIds) {
46+
List<IFlowOperator> operators = beanFactory.findOperatorsByIds(userIds);
47+
return ErrorThrow.builder()
48+
.operators(operators)
49+
.build();
50+
}
51+
52+
public ErrorThrow createErrorThrow(long... userIds) {
53+
List<Long> userIdList = Arrays.stream(userIds).boxed().toList();
54+
return this.createErrorThrow(userIdList);
55+
}
56+
2357
public <T> T getBean(Class<T> clazz) {
2458
return beanFactory.getBean(clazz);
2559
}

flow-engine-framework/src/main/java/com/codingapi/flow/strategy/node/ErrorTriggerStrategy.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,10 @@ public class ErrorTriggerStrategy extends BaseStrategy {
1616

1717
private ErrorTriggerScript errorTriggerScript;
1818

19+
public ErrorTriggerStrategy(String script) {
20+
this.errorTriggerScript = new ErrorTriggerScript(script);
21+
}
22+
1923
public void setErrorTriggerScript(String script) {
2024
this.errorTriggerScript = new ErrorTriggerScript(script);
2125
}

flow-engine-framework/src/test/java/com/codingapi/flow/service/FlowServiceTest.java

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
import com.codingapi.flow.repository.*;
2222
import com.codingapi.flow.script.runtime.FlowScriptContext;
2323
import com.codingapi.flow.script.runtime.IBeanFactory;
24+
import com.codingapi.flow.strategy.node.ErrorTriggerStrategy;
2425
import com.codingapi.flow.strategy.node.FormFieldPermissionStrategy;
2526
import com.codingapi.flow.strategy.node.OperatorLoadStrategy;
2627
import com.codingapi.flow.user.User;
@@ -2655,4 +2656,111 @@ void forwardOperator() {
26552656

26562657
}
26572658

2659+
2660+
/**
2661+
* 节点异常测试
2662+
*/
2663+
@Test
2664+
void errorTest() {
2665+
2666+
User user = new User(1, "user");
2667+
User boss = new User(2, "boss");
2668+
User lorne = new User(3, "lorne");
2669+
2670+
userGateway.save(user);
2671+
userGateway.save(boss);
2672+
userGateway.save(lorne);
2673+
2674+
GatewayContext.getInstance().setFlowOperatorGateway(userGateway);
2675+
2676+
FormMeta form = FormMetaBuilder.builder()
2677+
.name("请假流程")
2678+
.code("leave")
2679+
.addField("请假人", "name", "string")
2680+
.addField("请假天数", "days", "int")
2681+
.addField("请假事由", "reason", "string")
2682+
.build();
2683+
2684+
StartNode startNode = StartNode
2685+
.builder()
2686+
.strategies(NodeStrategyBuilder.builder()
2687+
.addStrategy(new FormFieldPermissionStrategy(FormFieldPermissionsBuilder.builder()
2688+
.addPermission("leave", "name", PermissionType.WRITE)
2689+
.addPermission("leave", "days", PermissionType.WRITE)
2690+
.addPermission("leave", "reason", PermissionType.WRITE)
2691+
.build()))
2692+
.build())
2693+
.actions(ActionBuilder.builder()
2694+
.addAction(new CustomAction())
2695+
.build())
2696+
.build();
2697+
2698+
ApprovalNode bossNode = ApprovalNode.builder()
2699+
.name("经理审批")
2700+
.strategies(NodeStrategyBuilder.builder()
2701+
.addStrategy(new FormFieldPermissionStrategy(FormFieldPermissionsBuilder.builder()
2702+
.addPermission("leave", "name", PermissionType.WRITE)
2703+
.addPermission("leave", "days", PermissionType.WRITE)
2704+
.addPermission("leave", "reason", PermissionType.WRITE)
2705+
.build()))
2706+
.addStrategy(new OperatorLoadStrategy("def run(request){return [$bind.getOperatorById(-1)]}"))
2707+
.addStrategy(new ErrorTriggerStrategy("def run(request){ return $bind.createErrorThrow(3); }"))
2708+
.build()
2709+
)
2710+
.build();
2711+
2712+
EndNode endNode = EndNode.builder().build();
2713+
Workflow workflow = WorkflowBuilder.builder()
2714+
.title("请假流程")
2715+
.code("leave")
2716+
.createdOperator(user)
2717+
.form(form)
2718+
.addNode(startNode)
2719+
.addNode(bossNode)
2720+
.addNode(endNode)
2721+
.addEdge(new FlowEdge(startNode.getId(), bossNode.getId()))
2722+
.addEdge(new FlowEdge(bossNode.getId(), endNode.getId()))
2723+
.build();
2724+
2725+
workflowRepository.save(workflow);
2726+
2727+
Map<String, Object> data = Map.of("name", "lorne", "days", 1, "reason", "leave");
2728+
2729+
List<IFlowAction> startActions = startNode.actionManager().getActions();
2730+
FlowCreateRequest userCreateRequest = new FlowCreateRequest();
2731+
userCreateRequest.setWorkId(workflow.getId());
2732+
userCreateRequest.setFormData(data);
2733+
userCreateRequest.setActionId(startActions.get(0).id());
2734+
userCreateRequest.setOperatorId(user.getUserId());
2735+
flowService.create(userCreateRequest);
2736+
2737+
List<FlowRecord> userRecordList = flowRecordRepository.findTodoByOperator(user.getUserId());
2738+
assertEquals(1, userRecordList.size());
2739+
2740+
FlowActionRequest userRequest = new FlowActionRequest();
2741+
userRequest.setFormData(data);
2742+
userRequest.setRecordId(userRecordList.get(0).getId());
2743+
userRequest.setAdvice(new FlowAdviceBody(startActions.get(0).id(), "同意", user.getUserId()));
2744+
flowService.action(userRequest);
2745+
2746+
List<FlowRecord> bossRecordList = flowRecordRepository.findTodoByOperator(boss.getUserId());
2747+
assertEquals(0, bossRecordList.size());
2748+
2749+
List<FlowRecord> lorneRecordList = flowRecordRepository.findTodoByOperator(lorne.getUserId());
2750+
assertEquals(1, lorneRecordList.size());
2751+
2752+
2753+
List<IFlowAction> bossActions = bossNode.actionManager().getActions();
2754+
2755+
FlowActionRequest bossRequest = new FlowActionRequest();
2756+
bossRequest.setFormData(data);
2757+
bossRequest.setRecordId(lorneRecordList.get(0).getId());
2758+
bossRequest.setAdvice(new FlowAdviceBody(bossActions.get(0).id(), "同意", lorne.getUserId()));
2759+
flowService.action(bossRequest);
2760+
2761+
List<FlowRecord> records = flowRecordRepository.findProcessRecords(lorneRecordList.get(0).getProcessId());
2762+
assertEquals(3, records.size());
2763+
assertEquals(3, records.stream().filter(FlowRecord::isFinish).toList().size());
2764+
2765+
}
26582766
}

0 commit comments

Comments
 (0)