增加Junit测试
This commit is contained in:
6
pom.xml
6
pom.xml
@@ -20,6 +20,12 @@
|
||||
<artifactId>lombok</artifactId>
|
||||
<version>1.18.34</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.junit.jupiter</groupId>
|
||||
<artifactId>junit-jupiter</artifactId>
|
||||
<version>5.11.4</version>
|
||||
<scope>test</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -1,30 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowInstance;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowStatus;
|
||||
|
||||
/**
|
||||
* 流程断言工具类
|
||||
* 用于验证流程执行状态是否符合预期
|
||||
*/
|
||||
public class FlowAssert {
|
||||
|
||||
public static void assertEquals(String message, Object expected, Object actual) {
|
||||
if (!expected.equals(actual)) {
|
||||
throw new AssertionError(String.format("%s: 期望值=%s, 实际值=%s", message, expected, actual));
|
||||
}
|
||||
}
|
||||
|
||||
public static void assertStatus(String message, FlowStatus expectedStatus, FlowInstance instance) {
|
||||
assertEquals(message + " - 状态检查", expectedStatus, instance.getStatus());
|
||||
}
|
||||
|
||||
public static void assertNode(String message, String expectedNode, FlowInstance instance) {
|
||||
assertEquals(message + " - 节点检查", expectedNode, instance.getCurrentNode());
|
||||
}
|
||||
|
||||
public static void assertVariable(String message, Object expectedValue, String key, FlowInstance instance) {
|
||||
Object actualValue = instance.getContextVariables().get(key);
|
||||
assertEquals(message + " - <20><><EFBFBD>量[" + key + "]检查", expectedValue, actualValue);
|
||||
}
|
||||
}
|
||||
@@ -1,241 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.example.node.LeaveRequestNode;
|
||||
import com.lanyuanxiaoyao.flowable.example.node.ManagerApprovalNode;
|
||||
import com.lanyuanxiaoyao.flowable.example.node.SimpleFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.example.node.LeaveSystemCheckNode;
|
||||
import com.lanyuanxiaoyao.flowable.model.Flow;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowInstance;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowInstanceRepository;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowRepository;
|
||||
import com.lanyuanxiaoyao.flowable.repository.memory.MemoryFlowInstanceRepository;
|
||||
import com.lanyuanxiaoyao.flowable.repository.memory.MemoryFlowRepository;
|
||||
import com.lanyuanxiaoyao.flowable.service.FlowService;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowStatus;
|
||||
|
||||
public class FlowExample {
|
||||
public static void main(String[] args) {
|
||||
// 1. 初始化仓储和服务
|
||||
FlowRepository flowRepository = new MemoryFlowRepository();
|
||||
FlowInstanceRepository instanceRepository = new MemoryFlowInstanceRepository();
|
||||
FlowService flowService = new FlowService(flowRepository, instanceRepository);
|
||||
|
||||
// 2. 创建请假审批流程
|
||||
Flow leaveFlow = createLeaveFlow(flowService);
|
||||
System.out.println("创建请假流程:" + leaveFlow.getName());
|
||||
System.out.println("审批节点:" + leaveFlow.getNodes());
|
||||
|
||||
// 3. 创建报销审批流程
|
||||
Flow expenseFlow = createExpenseFlow(flowService);
|
||||
System.out.println("\n创建报销流程:" + expenseFlow.getName());
|
||||
System.out.println("审批节点:" + expenseFlow.getNodes());
|
||||
|
||||
// 4. 演示请假审批流程
|
||||
demonstrateLeaveFlow(flowService, leaveFlow.getId());
|
||||
|
||||
// 5. 演示报销审批流程(带拒绝场景)
|
||||
demonstrateExpenseFlow(flowService, expenseFlow.getId());
|
||||
|
||||
// 演示带有自定义节点操作的请假流程
|
||||
demonstrateLeaveFlowWithCustomNodes(flowService);
|
||||
|
||||
// 演示系统节点审批流程
|
||||
demonstrateSystemNodeFlow(flowService);
|
||||
}
|
||||
|
||||
private static Flow createLeaveFlow(FlowService flowService) {
|
||||
Flow flow = new Flow();
|
||||
flow.setName("员工请假审批流程");
|
||||
flow.setDescription("处理员工请假申请的标准流程");
|
||||
flow.addNode(new SimpleFlowNode("直属主管审批"));
|
||||
flow.addNode(new SimpleFlowNode("部门经理审批"));
|
||||
flow.addNode(new SimpleFlowNode("人力资源审批"));
|
||||
return flowService.createFlow(flow);
|
||||
}
|
||||
|
||||
private static Flow createExpenseFlow(FlowService flowService) {
|
||||
Flow flow = new Flow();
|
||||
flow.setName("费用报销审批流程");
|
||||
flow.setDescription("处理员工报销申请的标准流程");
|
||||
flow.addNode(new SimpleFlowNode("财务初审"));
|
||||
flow.addNode(new SimpleFlowNode("部门经理审批"));
|
||||
flow.addNode(new SimpleFlowNode("财务总监审批"));
|
||||
flow.addNode(new SimpleFlowNode("出纳打款"));
|
||||
return flowService.createFlow(flow);
|
||||
}
|
||||
|
||||
private static void demonstrateLeaveFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 开始请假审批流程演示 ===");
|
||||
|
||||
// 启动流程实例
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 直属主管审批
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("直属主管审批通过,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 部门经理审批
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("部门经理审批通过,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 人力资源审批
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("人力资源审批通过,流程状态:" + instance.getStatus());
|
||||
}
|
||||
|
||||
private static void demonstrateExpenseFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 开始报销审批流程演示(带拒绝场景)===");
|
||||
|
||||
// 启动流程实例
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 财务初审通过
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("财务初审通过,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 部门经理拒绝
|
||||
instance = flowService.reject(instance.getId());
|
||||
System.out.println("部门经理拒绝,流程状态:" + instance.getStatus());
|
||||
|
||||
try {
|
||||
// 尝试继续审批(应该会失败)
|
||||
flowService.approve(instance.getId());
|
||||
} catch (IllegalStateException e) {
|
||||
System.out.println("尝试继续审批被拒绝:" + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private static void demonstrateLeaveFlowWithCustomNodes(FlowService flowService) {
|
||||
System.out.println("\n=== 开始自定义节点请假流程演示 ===");
|
||||
|
||||
// 创建流程定义
|
||||
Flow flow = new Flow();
|
||||
flow.setName("带自定义操作的请假流程");
|
||||
flow.setDescription("包含节点操作的请假流程示例");
|
||||
|
||||
// 添加自定义节点
|
||||
flow.addNode(new LeaveRequestNode());
|
||||
flow.addNode(new ManagerApprovalNode());
|
||||
|
||||
Flow savedFlow = flowService.createFlow(flow);
|
||||
System.out.println("创建流程:" + savedFlow.getName());
|
||||
|
||||
// 演示通过流程
|
||||
demonstrateApproveFlow(flowService, savedFlow.getId());
|
||||
|
||||
// 演示拒绝流程
|
||||
demonstrateRejectFlow(flowService, savedFlow.getId());
|
||||
}
|
||||
|
||||
private static void demonstrateApproveFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 演示通过流程 ===");
|
||||
|
||||
// 启动流程实例
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("\n启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 请假申请通过
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n请假申请通过,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 经理审批通过
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n经理审批通过,流程状态:" + instance.getStatus());
|
||||
}
|
||||
|
||||
private static void demonstrateRejectFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 演示拒绝流程 ===");
|
||||
|
||||
// 启动新的流程实例
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("\n启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 请假申请通过
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n请假申请通过,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 经理审批拒绝
|
||||
instance = flowService.reject(instance.getId());
|
||||
System.out.println("\n经理审批拒绝,流程状态:" + instance.getStatus());
|
||||
}
|
||||
|
||||
private static void demonstrateSystemNodeFlow(FlowService flowService) {
|
||||
System.out.println("\n=== 开始系统节点审批流程演示 ===");
|
||||
|
||||
// 创建流程定义
|
||||
Flow flow = new Flow();
|
||||
flow.setName("带系统审核的请假流程");
|
||||
flow.setDescription("包含系统自动审核的请假流程示例");
|
||||
|
||||
// 添加节点
|
||||
flow.addNode(new LeaveRequestNode()); // 请假申请
|
||||
flow.addNode(new LeaveSystemCheckNode(5)); // 系统审核(允许5天内自动通过)
|
||||
flow.addNode(new ManagerApprovalNode()); // 经理审批
|
||||
|
||||
Flow savedFlow = flowService.createFlow(flow);
|
||||
System.out.println("创建流程:" + savedFlow.getName());
|
||||
|
||||
// 演示自动通过的情况(3天请假)
|
||||
demonstrateSystemApproveFlow(flowService, savedFlow.getId());
|
||||
|
||||
// 演示自动拒绝的情况(7天请假)
|
||||
demonstrateSystemRejectFlow(flowService, savedFlow.getId());
|
||||
}
|
||||
|
||||
private static void demonstrateSystemApproveFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 演示系统自动通过流程 ===");
|
||||
|
||||
// 启动流程实例(LeaveRequestNode设置3天请假)
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("\n启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 验证初始状态
|
||||
FlowAssert.assertStatus("流程启动", FlowStatus.PENDING, instance);
|
||||
FlowAssert.assertNode("流程启动", "请假申请", instance);
|
||||
FlowAssert.assertVariable("流程启动", 3, "days", instance);
|
||||
FlowAssert.assertVariable("流程启动", "年假", "reason", instance);
|
||||
|
||||
// 请假申请通过后会自动执行系统审核
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n请假申请通过后,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 验证系统审核通过
|
||||
FlowAssert.assertStatus("系统审核", FlowStatus.PENDING, instance);
|
||||
FlowAssert.assertNode("系统审核", "经理审批", instance);
|
||||
FlowAssert.assertVariable("系统审核", "系统自动通过", "systemComment", instance);
|
||||
|
||||
// 经理最终审批
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n经理审批通过,流程状态:" + instance.getStatus());
|
||||
|
||||
// 验证流程完成
|
||||
FlowAssert.assertStatus("流程完成", FlowStatus.APPROVED, instance);
|
||||
FlowAssert.assertVariable("流程完成", "同意", "managerComment", instance);
|
||||
}
|
||||
|
||||
private static void demonstrateSystemRejectFlow(FlowService flowService, String flowId) {
|
||||
System.out.println("\n=== 演示系统自动拒绝流程 ===");
|
||||
|
||||
// 修改LeaveRequestNode中的请假天数为7天
|
||||
LeaveRequestNode.setTestDays(7);
|
||||
|
||||
// 启动流程实例
|
||||
FlowInstance instance = flowService.startFlow(flowId);
|
||||
System.out.println("\n启动流程实例,当前节点:" + instance.getCurrentNode());
|
||||
|
||||
// 验证初始状态
|
||||
FlowAssert.assertStatus("流程启动", FlowStatus.PENDING, instance);
|
||||
FlowAssert.assertNode("流程启动", "请假申请", instance);
|
||||
FlowAssert.assertVariable("流程启动", 7, "days", instance);
|
||||
|
||||
// 请假申请通过后系统会自动拒绝
|
||||
instance = flowService.approve(instance.getId());
|
||||
System.out.println("\n请假申请后,流程状态:" + instance.getStatus());
|
||||
|
||||
// 验证系统拒绝
|
||||
FlowAssert.assertStatus("系统拒绝", FlowStatus.REJECTED, instance);
|
||||
FlowAssert.assertVariable("系统拒绝", "请假天数(7)超过系统限制(5),需要额外审批", "systemComment", instance);
|
||||
}
|
||||
}
|
||||
@@ -1,41 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.node.AbstractFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class LeaveRequestNode extends AbstractFlowNode {
|
||||
// 用于测试的请假天数
|
||||
private static int testDays = 3;
|
||||
|
||||
public LeaveRequestNode() {
|
||||
super("请假申请");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
// 模拟设置请假信息,使用testDays而不是硬编码的值
|
||||
context.setVariable("days", testDays);
|
||||
context.setVariable("reason", "年假");
|
||||
context.setVariable("requestTime", LocalDateTime.now());
|
||||
System.out.println("执行请假申请节点:设置请假天数为" + testDays + "天,请假理由为年假");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
System.out.println("请假申请提交成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
System.out.println("请假申请被撤销");
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置测试用的请假天数
|
||||
* @param days 请假天数
|
||||
*/
|
||||
public static void setTestDays(int days) {
|
||||
testDays = days;
|
||||
}
|
||||
}
|
||||
@@ -1,61 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.node.SystemFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 请假系统自动审核节点
|
||||
* 根据请假天数自动判断是否通过
|
||||
*/
|
||||
public class LeaveSystemCheckNode extends SystemFlowNode {
|
||||
private final int maxDays; // 最大允许请假天数
|
||||
|
||||
public LeaveSystemCheckNode(int maxDays) {
|
||||
super("系统审核");
|
||||
this.maxDays = maxDays;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoApprove(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
return days != null && days <= maxDays;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRejectionReason(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
return String.format("请假天数(%d)超过系统限制(%d),需要额外审批", days, maxDays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
|
||||
System.out.println("执行系统审核节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 系统限制:" + maxDays + "天");
|
||||
|
||||
context.setVariable("systemComment", "系统自动通过");
|
||||
context.setVariable("systemCheckTime", LocalDateTime.now());
|
||||
System.out.println("系统自动审核通过");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
|
||||
System.out.println("执行系统审核节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 系统限制:" + maxDays + "天");
|
||||
|
||||
String rejectionReason = getRejectionReason(context);
|
||||
context.setVariable("systemComment", rejectionReason);
|
||||
context.setVariable("systemCheckTime", LocalDateTime.now());
|
||||
System.out.println("系统自动审核拒绝:" + rejectionReason);
|
||||
}
|
||||
}
|
||||
@@ -1,39 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.node.AbstractFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class ManagerApprovalNode extends AbstractFlowNode {
|
||||
public ManagerApprovalNode() {
|
||||
super("经理审批");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
LocalDateTime requestTime = context.getVariable("requestTime", LocalDateTime.class);
|
||||
|
||||
System.out.println("执行经理审批节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 申请时间:" + requestTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
context.setVariable("approvalTime", LocalDateTime.now());
|
||||
context.setVariable("managerComment", "同意");
|
||||
System.out.println("经理已批准请假申请");
|
||||
System.out.println("- 审批意见:同意");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
context.setVariable("approvalTime", LocalDateTime.now());
|
||||
context.setVariable("managerComment", "请假天数过长,建议调整后重新提交");
|
||||
System.out.println("经理已拒绝请假申请");
|
||||
System.out.println("- 拒绝原因:请假天数过长,建议调整后重新提交");
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.example.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.node.AbstractFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
|
||||
public class SimpleFlowNode extends AbstractFlowNode {
|
||||
public SimpleFlowNode(String nodeId) {
|
||||
super(nodeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
System.out.println("执行节点:" + getNodeId());
|
||||
}
|
||||
}
|
||||
@@ -1,57 +1,165 @@
|
||||
package com.lanyuanxiaoyao.flowable.model;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.node.FlowNode;
|
||||
import lombok.Data;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程定义类
|
||||
* 用于定义一个完整的审批流程,包含流程的基本信息和所有审批节点
|
||||
* 流程实例类
|
||||
* 包含流程定义和执行状态
|
||||
*/
|
||||
@Data
|
||||
public class Flow {
|
||||
/**
|
||||
* 流程定义ID
|
||||
*/
|
||||
private String id;
|
||||
/**
|
||||
* 流程实例ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
private String name;
|
||||
/**
|
||||
* 流程名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 流程描述
|
||||
*/
|
||||
private String description;
|
||||
/**
|
||||
* 流程描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 流程节点列表
|
||||
* 按照列表顺序依次执行,每个节点都是一个可执行的审批操作
|
||||
*/
|
||||
private List<FlowNode> nodes;
|
||||
/**
|
||||
* 流程节点列表
|
||||
* 按照列表顺序依次执行,每个节点都是一个可执行的审批操作
|
||||
*/
|
||||
private List<FlowNode> nodes;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
/**
|
||||
* 当前执行到的节点ID
|
||||
*/
|
||||
private String currentNode;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
/**
|
||||
* 当前流程状态
|
||||
*/
|
||||
private FlowStatus status;
|
||||
|
||||
public Flow() {
|
||||
this.nodes = new ArrayList<>();
|
||||
/**
|
||||
* 流程上下文变量
|
||||
* 用于存储流程执行过程中的数据,实现节点间的数据传递
|
||||
*/
|
||||
private Map<String, Object> contextVariables;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
public Flow() {
|
||||
this.nodes = new ArrayList<>();
|
||||
this.contextVariables = new HashMap<>();
|
||||
this.status = FlowStatus.PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个新的流程节点
|
||||
*
|
||||
* @param node 要添加的流程节点
|
||||
*/
|
||||
public void addNode(FlowNode node) {
|
||||
nodes.add(node);
|
||||
if (currentNode == null && !nodes.isEmpty()) {
|
||||
currentNode = nodes.get(0).getNodeId();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 添加一个新的流程节点
|
||||
* @param node 要添加的流程节点
|
||||
*/
|
||||
public void addNode(FlowNode node) {
|
||||
nodes.add(node);
|
||||
/**
|
||||
* 获取当前节点
|
||||
*
|
||||
* @return 当前节点对象
|
||||
*/
|
||||
public FlowNode getCurrentNodeObject() {
|
||||
return nodes.stream()
|
||||
.filter(node -> node.getNodeId().equals(currentNode))
|
||||
.findFirst()
|
||||
.orElseThrow(() -> new IllegalStateException("找不到当前节点"));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取下一个节点
|
||||
*
|
||||
* @return 下一个节点对象,如果已经是最后一个节点则返回null
|
||||
*/
|
||||
public FlowNode getNextNode() {
|
||||
for (int i = 0; i < nodes.size() - 1; i++) {
|
||||
if (nodes.get(i).getNodeId().equals(currentNode)) {
|
||||
return nodes.get(i + 1);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断当前是否是最后一个节点
|
||||
*
|
||||
* @return true表示是最后一个节点
|
||||
*/
|
||||
public boolean isLastNode() {
|
||||
return nodes.get(nodes.size() - 1).getNodeId().equals(currentNode);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移动到下一个节点
|
||||
*
|
||||
* @throws IllegalStateException 如果已经是最后一个节点
|
||||
*/
|
||||
public void moveToNextNode() {
|
||||
FlowNode nextNode = getNextNode();
|
||||
if (nextNode == null) {
|
||||
throw new IllegalStateException("已经是最后一个节点");
|
||||
}
|
||||
currentNode = nextNode.getNodeId();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建流程上下文
|
||||
*/
|
||||
public FlowContext createContext() {
|
||||
FlowContext context = new FlowContext();
|
||||
context.setFlowId(id);
|
||||
context.getVariables().putAll(contextVariables);
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* 保存上下文变量
|
||||
*/
|
||||
public void saveContext(FlowContext context) {
|
||||
contextVariables.clear();
|
||||
contextVariables.putAll(context.getVariables());
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建流程实例的副本
|
||||
* 用于从流程定义创建新的流程实例
|
||||
*/
|
||||
public Flow createInstance() {
|
||||
Flow instance = new Flow();
|
||||
instance.setName(name);
|
||||
instance.setDescription(description);
|
||||
instance.setNodes(new ArrayList<>(nodes));
|
||||
instance.setContextVariables(new HashMap<>(contextVariables));
|
||||
instance.setCreateTime(LocalDateTime.now());
|
||||
instance.setUpdateTime(LocalDateTime.now());
|
||||
if (!nodes.isEmpty()) {
|
||||
instance.setCurrentNode(nodes.get(0).getNodeId());
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -1,63 +1,44 @@
|
||||
package com.lanyuanxiaoyao.flowable.model;
|
||||
|
||||
import lombok.Data;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程上下文类
|
||||
* 用于在流程节点执行过程中传递和存储数据
|
||||
* 流程上下文
|
||||
* 用于在节点间传递数据
|
||||
*/
|
||||
@Data
|
||||
public class FlowContext {
|
||||
/**
|
||||
* 对应的流程定义ID
|
||||
*/
|
||||
private String flowId;
|
||||
/**
|
||||
* 流程ID
|
||||
*/
|
||||
private String flowId;
|
||||
|
||||
/**
|
||||
* 对应的流程实例ID
|
||||
*/
|
||||
private String instanceId;
|
||||
/**
|
||||
* 上下文变量
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
|
||||
/**
|
||||
* 上下文变量存储
|
||||
* 用于在节点间传递数据
|
||||
*/
|
||||
private Map<String, Object> variables;
|
||||
public FlowContext() {
|
||||
this.variables = new HashMap<>();
|
||||
}
|
||||
|
||||
public FlowContext() {
|
||||
this.variables = new HashMap<>();
|
||||
/**
|
||||
* 获取指定类型的变量值
|
||||
*/
|
||||
public <T> T getVariable(String key, Class<T> type) {
|
||||
Object value = variables.get(key);
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
return type.cast(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上下文变量
|
||||
* @param key 变量名
|
||||
* @param value 变量值
|
||||
*/
|
||||
public void setVariable(String key, Object value) {
|
||||
variables.put(key, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上下文变量
|
||||
* @param key 变量名
|
||||
* @return 变量值
|
||||
*/
|
||||
public Object getVariable(String key) {
|
||||
return variables.get(key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定类型的上下文变量
|
||||
* @param key 变量名
|
||||
* @param type 期望的变量类型
|
||||
* @param <T> 变量类型
|
||||
* @return 转换为指定类型的变量值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
public <T> T getVariable(String key, Class<T> type) {
|
||||
Object value = variables.get(key);
|
||||
return value == null ? null : (T) value;
|
||||
}
|
||||
/**
|
||||
* 设置变量值
|
||||
*/
|
||||
public void setVariable(String key, Object value) {
|
||||
variables.put(key, value);
|
||||
}
|
||||
}
|
||||
@@ -1,54 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.model;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* 流程实例类
|
||||
* 代表一个正在执行的具体流程,记录了当前的执行状态和上下文数据
|
||||
*/
|
||||
@Data
|
||||
public class FlowInstance {
|
||||
/**
|
||||
* 实例ID
|
||||
*/
|
||||
private String id;
|
||||
|
||||
/**
|
||||
* 对应的流程定义ID
|
||||
*/
|
||||
private String flowId;
|
||||
|
||||
/**
|
||||
* 当前执行到的节点ID
|
||||
*/
|
||||
private String currentNode;
|
||||
|
||||
/**
|
||||
* 当前流程状态
|
||||
* @see FlowStatus
|
||||
*/
|
||||
private FlowStatus status;
|
||||
|
||||
/**
|
||||
* 创建时间
|
||||
*/
|
||||
private LocalDateTime createTime;
|
||||
|
||||
/**
|
||||
* 最后更新时间
|
||||
*/
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
/**
|
||||
* 流程上下文变量
|
||||
* 用于存储流程执行过程中的数据,实现节点间的数据传递
|
||||
*/
|
||||
private Map<String, Object> contextVariables;
|
||||
|
||||
public FlowInstance() {
|
||||
this.contextVariables = new HashMap<>();
|
||||
}
|
||||
}
|
||||
@@ -5,31 +5,31 @@ package com.lanyuanxiaoyao.flowable.model;
|
||||
* 用于表示流程实例的当前状态
|
||||
*/
|
||||
public enum FlowStatus {
|
||||
/**
|
||||
* 进行中:流程正在执行中
|
||||
*/
|
||||
PENDING("进行中"),
|
||||
/**
|
||||
* 进行中:流程正在执行中
|
||||
*/
|
||||
PENDING("进行中"),
|
||||
|
||||
/**
|
||||
* 已通过:流程已经完成并通过
|
||||
*/
|
||||
APPROVED("已通过"),
|
||||
/**
|
||||
* 已通过:流程已经完成并通过
|
||||
*/
|
||||
APPROVED("已通过"),
|
||||
|
||||
/**
|
||||
* 已拒绝:流程被拒绝
|
||||
*/
|
||||
REJECTED("已拒绝");
|
||||
/**
|
||||
* 已拒绝:流程被拒绝
|
||||
*/
|
||||
REJECTED("已拒绝");
|
||||
|
||||
/**
|
||||
* 状态的中文描述
|
||||
*/
|
||||
private final String description;
|
||||
/**
|
||||
* 状态的中文描述
|
||||
*/
|
||||
private final String description;
|
||||
|
||||
FlowStatus(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
FlowStatus(String description) {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
public String getDescription() {
|
||||
return description;
|
||||
}
|
||||
}
|
||||
@@ -6,21 +6,21 @@ import lombok.RequiredArgsConstructor;
|
||||
|
||||
@RequiredArgsConstructor
|
||||
public abstract class AbstractFlowNode implements FlowNode {
|
||||
@Getter
|
||||
private final String nodeId;
|
||||
@Getter
|
||||
private final String nodeId;
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
// 默认实现为空
|
||||
}
|
||||
}
|
||||
@@ -7,23 +7,23 @@ import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
* 定义节点的基本操作
|
||||
*/
|
||||
public interface FlowNode {
|
||||
/**
|
||||
* 获取节点ID
|
||||
*/
|
||||
String getNodeId();
|
||||
/**
|
||||
* 获取节点ID
|
||||
*/
|
||||
String getNodeId();
|
||||
|
||||
/**
|
||||
* 节点初始化时执行的操作
|
||||
*/
|
||||
void execute(FlowContext context);
|
||||
/**
|
||||
* 节点初始化时执行的操作
|
||||
*/
|
||||
void execute(FlowContext context);
|
||||
|
||||
/**
|
||||
* 节点通过时执行的操作
|
||||
*/
|
||||
void onApprove(FlowContext context);
|
||||
/**
|
||||
* 节点通过时执行的操作
|
||||
*/
|
||||
void onApprove(FlowContext context);
|
||||
|
||||
/**
|
||||
* 节点拒绝时执行的操作
|
||||
*/
|
||||
void onReject(FlowContext context);
|
||||
/**
|
||||
* 节点拒绝时执行的操作
|
||||
*/
|
||||
void onReject(FlowContext context);
|
||||
}
|
||||
@@ -7,21 +7,23 @@ import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
* 根据预设规则自动执行审批操作
|
||||
*/
|
||||
public abstract class SystemFlowNode extends AbstractFlowNode {
|
||||
public SystemFlowNode(String nodeId) {
|
||||
super(nodeId);
|
||||
}
|
||||
public SystemFlowNode(String nodeId) {
|
||||
super(nodeId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 系统自动判断是否通过
|
||||
* @param context 流程上下文
|
||||
* @return true表示通过,false表示拒绝
|
||||
*/
|
||||
public abstract boolean autoApprove(FlowContext context);
|
||||
/**
|
||||
* 系统自动判断是否通过
|
||||
*
|
||||
* @param context 流程上下文
|
||||
* @return true表示通过,false表示拒绝
|
||||
*/
|
||||
public abstract boolean autoApprove(FlowContext context);
|
||||
|
||||
/**
|
||||
* 获取拒绝原因
|
||||
* @param context 流程上下文
|
||||
* @return 拒绝原因
|
||||
*/
|
||||
protected abstract String getRejectionReason(FlowContext context);
|
||||
/**
|
||||
* 获取拒绝原因
|
||||
*
|
||||
* @param context 流程上下文
|
||||
* @return 拒绝原因
|
||||
*/
|
||||
protected abstract String getRejectionReason(FlowContext context);
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.repository;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowInstance;
|
||||
import java.util.List;
|
||||
|
||||
public interface FlowInstanceRepository {
|
||||
FlowInstance save(FlowInstance instance);
|
||||
FlowInstance findById(String id);
|
||||
List<FlowInstance> findAll();
|
||||
List<FlowInstance> findByFlowId(String flowId);
|
||||
void deleteById(String id);
|
||||
FlowInstance update(FlowInstance instance);
|
||||
}
|
||||
@@ -1,12 +1,11 @@
|
||||
package com.lanyuanxiaoyao.flowable.repository;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.Flow;
|
||||
import java.util.List;
|
||||
|
||||
public interface FlowRepository {
|
||||
Flow save(Flow flow);
|
||||
Flow findById(String id);
|
||||
List<Flow> findAll();
|
||||
void deleteById(String id);
|
||||
Flow update(Flow flow);
|
||||
Flow save(Flow flow);
|
||||
|
||||
Flow update(Flow flow);
|
||||
|
||||
Flow findById(String id);
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package com.lanyuanxiaoyao.flowable.repository.memory;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowInstance;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowInstanceRepository;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class MemoryFlowInstanceRepository implements FlowInstanceRepository {
|
||||
private final Map<String, FlowInstance> storage = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public FlowInstance save(FlowInstance instance) {
|
||||
String id = UUID.randomUUID().toString();
|
||||
instance.setId(id);
|
||||
storage.put(id, instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowInstance findById(String id) {
|
||||
return storage.get(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowInstance> findAll() {
|
||||
return new ArrayList<>(storage.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FlowInstance> findByFlowId(String flowId) {
|
||||
return storage.values().stream()
|
||||
.filter(instance -> instance.getFlowId().equals(flowId))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String id) {
|
||||
storage.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public FlowInstance update(FlowInstance instance) {
|
||||
if (instance.getId() == null) {
|
||||
throw new IllegalArgumentException("Instance id cannot be null when updating");
|
||||
}
|
||||
storage.put(instance.getId(), instance);
|
||||
return instance;
|
||||
}
|
||||
}
|
||||
@@ -2,44 +2,33 @@ package com.lanyuanxiaoyao.flowable.repository.memory;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.Flow;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowRepository;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class MemoryFlowRepository implements FlowRepository {
|
||||
private final Map<String, Flow> storage = new ConcurrentHashMap<>();
|
||||
private final Map<String, Flow> flows = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public Flow save(Flow flow) {
|
||||
String id = UUID.randomUUID().toString();
|
||||
flow.setId(id);
|
||||
storage.put(id, flow);
|
||||
return flow;
|
||||
@Override
|
||||
public Flow save(Flow flow) {
|
||||
if (flow.getId() == null) {
|
||||
flow.setId(UUID.randomUUID().toString());
|
||||
}
|
||||
flows.put(flow.getId(), flow);
|
||||
return flow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flow findById(String id) {
|
||||
return storage.get(id);
|
||||
@Override
|
||||
public Flow update(Flow flow) {
|
||||
if (flow.getId() == null || !flows.containsKey(flow.getId())) {
|
||||
throw new IllegalArgumentException("找不到对应的流程实例");
|
||||
}
|
||||
flows.put(flow.getId(), flow);
|
||||
return flow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<Flow> findAll() {
|
||||
return new ArrayList<>(storage.values());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void deleteById(String id) {
|
||||
storage.remove(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Flow update(Flow flow) {
|
||||
if (flow.getId() == null) {
|
||||
throw new IllegalArgumentException("Flow id cannot be null when updating");
|
||||
}
|
||||
storage.put(flow.getId(), flow);
|
||||
return flow;
|
||||
}
|
||||
@Override
|
||||
public Flow findById(String id) {
|
||||
return flows.get(id);
|
||||
}
|
||||
}
|
||||
@@ -1,236 +1,153 @@
|
||||
package com.lanyuanxiaoyao.flowable.service;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.Flow;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowInstance;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowRepository;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowInstanceRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.List;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowStatus;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowStatus;
|
||||
import com.lanyuanxiaoyao.flowable.node.FlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.node.SystemFlowNode;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowRepository;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.RequiredArgsConstructor;
|
||||
|
||||
/**
|
||||
* 流程服务类
|
||||
* 提供流程的创建、启动、审批等核心功能
|
||||
*/
|
||||
@RequiredArgsConstructor
|
||||
public class FlowService {
|
||||
private final FlowRepository flowRepository;
|
||||
private final FlowInstanceRepository instanceRepository;
|
||||
private final FlowRepository flowRepository;
|
||||
|
||||
/**
|
||||
* 创建新的流程定义
|
||||
*/
|
||||
public Flow createFlow(Flow flow) {
|
||||
if (flow.getNodes() == null || flow.getNodes().isEmpty()) {
|
||||
throw new IllegalArgumentException("流程节点不能为空");
|
||||
}
|
||||
flow.setCreateTime(LocalDateTime.now());
|
||||
flow.setUpdateTime(LocalDateTime.now());
|
||||
return flowRepository.save(flow);
|
||||
}
|
||||
|
||||
/**
|
||||
* 启动一个新的流程实例
|
||||
*/
|
||||
public FlowInstance startFlow(String flowId) {
|
||||
Flow flow = flowRepository.findById(flowId);
|
||||
if (flow == null) {
|
||||
throw new IllegalArgumentException("找不到对应的流程定义");
|
||||
/**
|
||||
* 创建新的流程定义
|
||||
*/
|
||||
public Flow createFlow(Flow flow) {
|
||||
validateFlowNodes(flow);
|
||||
initializeFlow(flow);
|
||||
return flowRepository.save(flow);
|
||||
}
|
||||
|
||||
FlowInstance instance = new FlowInstance();
|
||||
instance.setFlowId(flowId);
|
||||
instance.setCurrentNode(flow.getNodes().get(0).getNodeId());
|
||||
instance.setStatus(FlowStatus.PENDING);
|
||||
instance.setCreateTime(LocalDateTime.now());
|
||||
instance.setUpdateTime(LocalDateTime.now());
|
||||
|
||||
// 保存实例
|
||||
instance = instanceRepository.save(instance);
|
||||
|
||||
// 创建上下文
|
||||
FlowContext context = createContext(instance);
|
||||
|
||||
// 执行第一个节点
|
||||
FlowNode firstNode = flow.getNodes().get(0);
|
||||
firstNode.execute(context);
|
||||
|
||||
// 如果是系统节点,自动执行审批
|
||||
if (firstNode instanceof SystemFlowNode) {
|
||||
instance = handleSystemNode(instance, firstNode, context);
|
||||
}
|
||||
|
||||
// 保存上下文变量
|
||||
saveContext(instance, context);
|
||||
return instanceRepository.update(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 审批通过当前节点
|
||||
*/
|
||||
public FlowInstance approve(String instanceId) {
|
||||
FlowInstance instance = getAndValidateInstance(instanceId);
|
||||
if (FlowStatus.APPROVED.equals(instance.getStatus()) ||
|
||||
FlowStatus.REJECTED.equals(instance.getStatus())) {
|
||||
throw new IllegalStateException("当前流程已经结束");
|
||||
/**
|
||||
* 启动一个新的流程实例
|
||||
*/
|
||||
public Flow startFlow(String flowId) {
|
||||
Flow flowDefinition = findFlowById(flowId);
|
||||
Flow instance = flowDefinition.createInstance();
|
||||
instance = flowRepository.save(instance);
|
||||
return executeNode(instance);
|
||||
}
|
||||
|
||||
Flow flow = flowRepository.findById(instance.getFlowId());
|
||||
List<FlowNode> nodes = flow.getNodes();
|
||||
int currentIndex = -1;
|
||||
|
||||
// 查找当前节点
|
||||
for (int i = 0; i < nodes.size(); i++) {
|
||||
if (nodes.get(i).getNodeId().equals(instance.getCurrentNode())) {
|
||||
currentIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
/**
|
||||
* 审批通过当前节点
|
||||
*/
|
||||
public Flow approve(String flowId) {
|
||||
Flow flow = findFlowById(flowId);
|
||||
validateFlowNotCompleted(flow);
|
||||
|
||||
// 创建上下文并加载已有变量
|
||||
FlowContext context = createContext(instance);
|
||||
FlowContext context = flow.createContext();
|
||||
FlowNode currentNode = flow.getCurrentNodeObject();
|
||||
currentNode.onApprove(context);
|
||||
|
||||
// 执行当前节点的通过操作
|
||||
FlowNode currentNode = nodes.get(currentIndex);
|
||||
currentNode.onApprove(context);
|
||||
|
||||
// 判断是否是最后一个节点
|
||||
if (currentIndex == nodes.size() - 1) {
|
||||
instance.setStatus(FlowStatus.APPROVED);
|
||||
} else {
|
||||
// 移动到下一个节点并执行
|
||||
FlowNode nextNode = nodes.get(currentIndex + 1);
|
||||
instance.setCurrentNode(nextNode.getNodeId());
|
||||
nextNode.execute(context);
|
||||
|
||||
// 如果下一个是系统节点,自动执行审批
|
||||
if (nextNode instanceof SystemFlowNode) {
|
||||
instance = handleSystemNode(instance, nextNode, context);
|
||||
}
|
||||
}
|
||||
|
||||
// 保存上下文变量
|
||||
saveContext(instance, context);
|
||||
instance.setUpdateTime(LocalDateTime.now());
|
||||
return instanceRepository.update(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝当前节点,结束流程
|
||||
*/
|
||||
public FlowInstance reject(String instanceId) {
|
||||
FlowInstance instance = getAndValidateInstance(instanceId);
|
||||
if (FlowStatus.APPROVED.equals(instance.getStatus()) ||
|
||||
FlowStatus.REJECTED.equals(instance.getStatus())) {
|
||||
throw new IllegalStateException("当前流程已经结束");
|
||||
}
|
||||
|
||||
// 创建上下文并加载已有变量
|
||||
FlowContext context = createContext(instance);
|
||||
|
||||
// 执行当前节点的拒绝操作
|
||||
Flow flow = flowRepository.findById(instance.getFlowId());
|
||||
for (FlowNode node : flow.getNodes()) {
|
||||
if (node.getNodeId().equals(instance.getCurrentNode())) {
|
||||
node.onReject(context);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
instance.setStatus(FlowStatus.REJECTED);
|
||||
|
||||
// 保存上下文变量
|
||||
saveContext(instance, context);
|
||||
instance.setUpdateTime(LocalDateTime.now());
|
||||
return instanceRepository.update(instance);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程实例当前状态
|
||||
*/
|
||||
public FlowInstance getFlowInstance(String instanceId) {
|
||||
return getAndValidateInstance(instanceId);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程定义的所有节点
|
||||
*/
|
||||
public List<FlowNode> getFlowNodes(String flowId) {
|
||||
Flow flow = flowRepository.findById(flowId);
|
||||
if (flow == null) {
|
||||
throw new IllegalArgumentException("找不到对应的流程定义");
|
||||
}
|
||||
return flow.getNodes();
|
||||
}
|
||||
|
||||
private FlowInstance getAndValidateInstance(String instanceId) {
|
||||
FlowInstance instance = instanceRepository.findById(instanceId);
|
||||
if (instance == null) {
|
||||
throw new IllegalArgumentException("找不到对应的流程实例");
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private FlowContext createContext(FlowInstance instance) {
|
||||
FlowContext context = new FlowContext();
|
||||
context.setFlowId(instance.getFlowId());
|
||||
context.setInstanceId(instance.getId());
|
||||
// 从实例中加载已保存的变量
|
||||
if (instance.getContextVariables() != null) {
|
||||
context.getVariables().putAll(instance.getContextVariables());
|
||||
}
|
||||
return context;
|
||||
}
|
||||
|
||||
private void saveContext(FlowInstance instance, FlowContext context) {
|
||||
// 将上下文变量保存到实例中
|
||||
instance.getContextVariables().clear();
|
||||
instance.getContextVariables().putAll(context.getVariables());
|
||||
}
|
||||
|
||||
/**
|
||||
* 处理系统节点的自动审批
|
||||
*/
|
||||
private FlowInstance handleSystemNode(FlowInstance instance, FlowNode node, FlowContext context) {
|
||||
SystemFlowNode systemNode = (SystemFlowNode) node;
|
||||
if (systemNode.autoApprove(context)) {
|
||||
// 自动通过
|
||||
systemNode.onApprove(context);
|
||||
// 如果<E5A682><E69E9C>最后一个节点,标记为完成
|
||||
if (isLastNode(instance.getFlowId(), node.getNodeId())) {
|
||||
instance.setStatus(FlowStatus.APPROVED);
|
||||
if (flow.isLastNode()) {
|
||||
flow.setStatus(FlowStatus.APPROVED);
|
||||
return updateFlow(flow, context);
|
||||
} else {
|
||||
// 否则移动到下一个节点
|
||||
FlowNode nextNode = getNextNode(instance.getFlowId(), node.getNodeId());
|
||||
instance.setCurrentNode(nextNode.getNodeId());
|
||||
nextNode.execute(context);
|
||||
// 如果下一个还是系统节点,继续自动处理
|
||||
if (nextNode instanceof SystemFlowNode) {
|
||||
instance = handleSystemNode(instance, nextNode, context);
|
||||
flow = updateFlow(flow, context); // 先保存当前节点的状态
|
||||
flow.moveToNextNode();
|
||||
return executeNode(flow); // 执行下一个节点(可能是系统节点)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 拒绝当前节点,结束流程
|
||||
*/
|
||||
public Flow reject(String flowId) {
|
||||
Flow flow = findFlowById(flowId);
|
||||
validateFlowNotCompleted(flow);
|
||||
|
||||
FlowContext context = flow.createContext();
|
||||
flow.getCurrentNodeObject().onReject(context);
|
||||
flow.saveContext(context); // 保存拒绝操作的上下文变量
|
||||
flow.setStatus(FlowStatus.REJECTED);
|
||||
|
||||
return updateFlow(flow, context);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取流程实例
|
||||
*/
|
||||
public Flow getFlow(String flowId) {
|
||||
return findFlowById(flowId);
|
||||
}
|
||||
|
||||
// 私有辅助方法
|
||||
|
||||
private void validateFlowNodes(Flow flow) {
|
||||
if (flow.getNodes() == null || flow.getNodes().isEmpty()) {
|
||||
throw new IllegalArgumentException("流程节点不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeFlow(Flow flow) {
|
||||
flow.setCreateTime(LocalDateTime.now());
|
||||
flow.setUpdateTime(LocalDateTime.now());
|
||||
}
|
||||
|
||||
private Flow findFlowById(String flowId) {
|
||||
Flow flow = flowRepository.findById(flowId);
|
||||
if (flow == null) {
|
||||
throw new IllegalArgumentException("找不到对应的流程");
|
||||
}
|
||||
return flow;
|
||||
}
|
||||
|
||||
private void validateFlowNotCompleted(Flow flow) {
|
||||
if (FlowStatus.APPROVED.equals(flow.getStatus()) ||
|
||||
FlowStatus.REJECTED.equals(flow.getStatus())) {
|
||||
throw new IllegalStateException("当前流程已经结束");
|
||||
}
|
||||
}
|
||||
|
||||
private Flow executeNode(Flow flow) {
|
||||
FlowContext context = flow.createContext();
|
||||
FlowNode currentNode = flow.getCurrentNodeObject();
|
||||
|
||||
// 执行当前节点
|
||||
currentNode.execute(context);
|
||||
|
||||
// 如果是系统节点,自动执行审批
|
||||
if (currentNode instanceof SystemFlowNode) {
|
||||
return handleSystemNode(flow, currentNode, context);
|
||||
}
|
||||
|
||||
return updateFlow(flow, context);
|
||||
}
|
||||
|
||||
private Flow handleSystemNode(Flow flow, FlowNode node, FlowContext context) {
|
||||
SystemFlowNode systemNode = (SystemFlowNode) node;
|
||||
|
||||
if (systemNode.autoApprove(context)) {
|
||||
// 自动通过
|
||||
systemNode.onApprove(context);
|
||||
flow = updateFlow(flow, context); // 先保存当前状态
|
||||
|
||||
if (!flow.isLastNode()) {
|
||||
flow.moveToNextNode();
|
||||
return executeNode(flow); // 执行下一个节点
|
||||
} else {
|
||||
flow.setStatus(FlowStatus.APPROVED);
|
||||
return updateFlow(flow, context);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// 自动拒绝
|
||||
systemNode.onReject(context);
|
||||
instance.setStatus(FlowStatus.REJECTED);
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private boolean isLastNode(String flowId, String nodeId) {
|
||||
Flow flow = flowRepository.findById(flowId);
|
||||
List<FlowNode> nodes = flow.getNodes();
|
||||
return nodes.get(nodes.size() - 1).getNodeId().equals(nodeId);
|
||||
}
|
||||
|
||||
private FlowNode getNextNode(String flowId, String currentNodeId) {
|
||||
Flow flow = flowRepository.findById(flowId);
|
||||
List<FlowNode> nodes = flow.getNodes();
|
||||
for (int i = 0; i < nodes.size() - 1; i++) {
|
||||
if (nodes.get(i).getNodeId().equals(currentNodeId)) {
|
||||
return nodes.get(i + 1);
|
||||
} else {
|
||||
// 自动<E887AA><E58AA8>绝
|
||||
systemNode.onReject(context);
|
||||
flow.setStatus(FlowStatus.REJECTED);
|
||||
return updateFlow(flow, context);
|
||||
}
|
||||
}
|
||||
throw new IllegalStateException("找不到下一个节点");
|
||||
}
|
||||
}
|
||||
|
||||
private Flow updateFlow(Flow flow, FlowContext context) {
|
||||
flow.saveContext(context);
|
||||
flow.setUpdateTime(LocalDateTime.now());
|
||||
return flowRepository.update(flow);
|
||||
}
|
||||
}
|
||||
213
src/test/java/com/lanyuanxiaoyao/flowable/FlowServiceTest.java
Normal file
213
src/test/java/com/lanyuanxiaoyao/flowable/FlowServiceTest.java
Normal file
@@ -0,0 +1,213 @@
|
||||
package com.lanyuanxiaoyao.flowable;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.Flow;
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowStatus;
|
||||
import com.lanyuanxiaoyao.flowable.node.LeaveRequestNode;
|
||||
import com.lanyuanxiaoyao.flowable.node.LeaveSystemCheckNode;
|
||||
import com.lanyuanxiaoyao.flowable.node.ManagerApprovalNode;
|
||||
import com.lanyuanxiaoyao.flowable.repository.FlowRepository;
|
||||
import com.lanyuanxiaoyao.flowable.repository.memory.MemoryFlowRepository;
|
||||
import com.lanyuanxiaoyao.flowable.service.FlowService;
|
||||
import org.junit.jupiter.api.BeforeEach;
|
||||
import org.junit.jupiter.api.DisplayName;
|
||||
import org.junit.jupiter.api.Nested;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
|
||||
@DisplayName("流程服务测试")
|
||||
class FlowServiceTest {
|
||||
private FlowService flowService;
|
||||
private Flow leaveFlow;
|
||||
|
||||
@BeforeEach
|
||||
void setUp() {
|
||||
FlowRepository flowRepository = new MemoryFlowRepository();
|
||||
flowService = new FlowService(flowRepository);
|
||||
|
||||
// 创建请假流程定义
|
||||
leaveFlow = new Flow();
|
||||
leaveFlow.setName("带系统审核的请假流程");
|
||||
leaveFlow.setDescription("包含系统自动审核的请假流程示例");
|
||||
leaveFlow.addNode(new LeaveRequestNode());
|
||||
leaveFlow.addNode(new LeaveSystemCheckNode(5));
|
||||
leaveFlow.addNode(new ManagerApprovalNode());
|
||||
|
||||
leaveFlow = flowService.createFlow(leaveFlow);
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("流程创建和启动测试")
|
||||
class FlowCreationTest {
|
||||
@Test
|
||||
@DisplayName("创建流程时节点列表为空应抛出异常")
|
||||
void shouldThrowExceptionWhenNodesEmpty() {
|
||||
Flow invalidFlow = new Flow();
|
||||
invalidFlow.setName("无效流程");
|
||||
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> flowService.createFlow(invalidFlow)
|
||||
);
|
||||
|
||||
assertEquals("流程节点不能为空", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("找不到流程定义时启动流程应抛出异常")
|
||||
void shouldThrowExceptionWhenFlowNotFound() {
|
||||
IllegalArgumentException exception = assertThrows(
|
||||
IllegalArgumentException.class,
|
||||
() -> flowService.startFlow("non-existent-id")
|
||||
);
|
||||
|
||||
assertEquals("找不到对应的流程", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("启动流程时应正确初始化状态")
|
||||
void shouldInitializeStateWhenStartFlow() {
|
||||
Flow flow = flowService.startFlow(leaveFlow.getId());
|
||||
|
||||
assertNotNull(flow.getId(), "流程ID不应为空");
|
||||
assertEquals(FlowStatus.PENDING, flow.getStatus(), "初始状态应为PENDING");
|
||||
assertEquals("请假申请", flow.getCurrentNode(), "应从第一个节点开始");
|
||||
assertNotNull(flow.getCreateTime(), "创建时间不应为空");
|
||||
assertNotNull(flow.getUpdateTime(), "更新时间不应为空");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("系统节点审批流程测试")
|
||||
class SystemNodeFlowTest {
|
||||
@Test
|
||||
@DisplayName("请假天数在限制内时应自动通过系统审核")
|
||||
void shouldAutoApproveWhenLeaveDaysWithinLimit() {
|
||||
LeaveRequestNode.setTestDays(3);
|
||||
Flow flow = flowService.startFlow(leaveFlow.getId());
|
||||
|
||||
// 验证初始状态
|
||||
assertEquals(FlowStatus.PENDING, flow.getStatus());
|
||||
assertEquals("请假申请", flow.getCurrentNode());
|
||||
assertEquals(3, flow.getContextVariables().get("days"));
|
||||
assertEquals("年假", flow.getContextVariables().get("reason"));
|
||||
|
||||
// 提交请假申请
|
||||
flow = flowService.approve(flow.getId());
|
||||
|
||||
// 验证系统审核通过
|
||||
assertEquals(FlowStatus.PENDING, flow.getStatus());
|
||||
assertEquals("经理审批", flow.getCurrentNode());
|
||||
assertEquals("系统自动通过", flow.getContextVariables().get("systemComment"));
|
||||
|
||||
// 经理审批
|
||||
flow = flowService.approve(flow.getId());
|
||||
|
||||
// 验证流程完成
|
||||
assertEquals(FlowStatus.APPROVED, flow.getStatus());
|
||||
assertEquals("同意", flow.getContextVariables().get("managerComment"));
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("请假天数超出限制时应被系统自动拒绝")
|
||||
void shouldAutoRejectWhenLeaveDaysExceedLimit() {
|
||||
LeaveRequestNode.setTestDays(7);
|
||||
Flow flow = flowService.startFlow(leaveFlow.getId());
|
||||
|
||||
// 验证初始状态
|
||||
assertEquals(FlowStatus.PENDING, flow.getStatus());
|
||||
assertEquals("请假申请", flow.getCurrentNode());
|
||||
assertEquals(7, flow.getContextVariables().get("days"));
|
||||
|
||||
// 提交请假申请
|
||||
flow = flowService.approve(flow.getId());
|
||||
|
||||
// 验证系统拒绝
|
||||
assertEquals(FlowStatus.REJECTED, flow.getStatus());
|
||||
assertEquals("请假天数(7)超过系统限制(5),需要额外审批",
|
||||
flow.getContextVariables().get("systemComment"));
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("人工审批流程测试")
|
||||
class ManualApprovalTest {
|
||||
@Test
|
||||
@DisplayName("经理应能直接拒绝请假申请")
|
||||
void shouldAllowManagerToReject() {
|
||||
LeaveRequestNode.setTestDays(3);
|
||||
Flow flow = flowService.startFlow(leaveFlow.getId());
|
||||
|
||||
// 通过请假申请和系统审核
|
||||
flow = flowService.approve(flow.getId());
|
||||
|
||||
// 经理拒绝
|
||||
flow = flowService.reject(flow.getId());
|
||||
|
||||
assertEquals(FlowStatus.REJECTED, flow.getStatus());
|
||||
assertEquals("经理审批", flow.getCurrentNode());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("已完成的流程不能再次审批")
|
||||
void shouldNotAllowApproveCompletedFlow() {
|
||||
LeaveRequestNode.setTestDays(3);
|
||||
// 完成整个流程
|
||||
Flow completedFlow = flowService.startFlow(leaveFlow.getId());
|
||||
completedFlow = flowService.approve(completedFlow.getId());
|
||||
final Flow finalFlow = flowService.approve(completedFlow.getId());
|
||||
|
||||
// 尝试再次审批
|
||||
IllegalStateException exception = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> flowService.approve(finalFlow.getId())
|
||||
);
|
||||
|
||||
assertEquals("当前流程已经结束", exception.getMessage());
|
||||
}
|
||||
|
||||
@Test
|
||||
@DisplayName("已拒绝的流程不能再次审批")
|
||||
void shouldNotAllowApproveRejectedFlow() {
|
||||
LeaveRequestNode.setTestDays(3);
|
||||
// 拒绝流程
|
||||
Flow rejectedFlow = flowService.startFlow(leaveFlow.getId());
|
||||
final Flow finalFlow = flowService.reject(rejectedFlow.getId());
|
||||
|
||||
// 尝试继续审批
|
||||
IllegalStateException exception = assertThrows(
|
||||
IllegalStateException.class,
|
||||
() -> flowService.approve(finalFlow.getId())
|
||||
);
|
||||
|
||||
assertEquals("当前流程已经结束", exception.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
@DisplayName("流程变量测试")
|
||||
class FlowVariableTest {
|
||||
@Test
|
||||
@DisplayName("流程变量应在节点间正确传递")
|
||||
void shouldPassVariablesBetweenNodes() {
|
||||
LeaveRequestNode.setTestDays(3);
|
||||
Flow flow = flowService.startFlow(leaveFlow.getId());
|
||||
|
||||
// 验证请假申请节点设置的变量
|
||||
assertEquals(3, flow.getContextVariables().get("days"));
|
||||
assertEquals("年假", flow.getContextVariables().get("reason"));
|
||||
|
||||
// 提交请假申请,验证系统审核节点的变量
|
||||
flow = flowService.approve(flow.getId());
|
||||
assertEquals("系统自动通过", flow.getContextVariables().get("systemComment"));
|
||||
assertNotNull(flow.getContextVariables().get("systemCheckTime"));
|
||||
|
||||
// 经理审批,验证所有变量都被保留
|
||||
flow = flowService.approve(flow.getId());
|
||||
assertEquals(3, flow.getContextVariables().get("days"));
|
||||
assertEquals("年假", flow.getContextVariables().get("reason"));
|
||||
assertEquals("系统自动通过", flow.getContextVariables().get("systemComment"));
|
||||
assertEquals("同意", flow.getContextVariables().get("managerComment"));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.lanyuanxiaoyao.flowable.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
import lombok.Setter;
|
||||
|
||||
public class LeaveRequestNode extends AbstractFlowNode {
|
||||
// 用于测试的请假天数
|
||||
@Setter
|
||||
private static int testDays = 3;
|
||||
|
||||
public LeaveRequestNode() {
|
||||
super("请假申请");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
// 模拟设置请假信息,使用testDays而不是硬编码的值
|
||||
context.setVariable("days", testDays);
|
||||
context.setVariable("reason", "年假");
|
||||
context.setVariable("requestTime", LocalDateTime.now());
|
||||
System.out.println("执行请假申请节点:设置请假天数为" + testDays + "天,请假理由为年假");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
System.out.println("请假申请提交成功");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
System.out.println("请假申请被撤销");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package com.lanyuanxiaoyao.flowable.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* 请假系统自动审核节点
|
||||
* 根据请假天数自动判断是否通过
|
||||
*/
|
||||
public class LeaveSystemCheckNode extends SystemFlowNode {
|
||||
private final int maxDays; // 最大允许请假天数
|
||||
|
||||
public LeaveSystemCheckNode(int maxDays) {
|
||||
super("系统审核");
|
||||
this.maxDays = maxDays;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean autoApprove(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
return days != null && days <= maxDays;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getRejectionReason(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
return String.format("请假天数(%d)超过系统限制(%d),需要额外审批", days, maxDays);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
|
||||
System.out.println("执行系统审核节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 系统限制:" + maxDays + "天");
|
||||
|
||||
context.setVariable("systemComment", "系统自动通过");
|
||||
context.setVariable("systemCheckTime", LocalDateTime.now());
|
||||
System.out.println("系统自动审核通过");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
|
||||
System.out.println("执行系统审核节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 系统限制:" + maxDays + "天");
|
||||
|
||||
String rejectionReason = getRejectionReason(context);
|
||||
context.setVariable("systemComment", rejectionReason);
|
||||
context.setVariable("systemCheckTime", LocalDateTime.now());
|
||||
System.out.println("系统自动审核拒绝:" + rejectionReason);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package com.lanyuanxiaoyao.flowable.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
public class ManagerApprovalNode extends AbstractFlowNode {
|
||||
public ManagerApprovalNode() {
|
||||
super("经理审批");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
Integer days = context.getVariable("days", Integer.class);
|
||||
String reason = context.getVariable("reason", String.class);
|
||||
LocalDateTime requestTime = context.getVariable("requestTime", LocalDateTime.class);
|
||||
|
||||
System.out.println("执行经理审批节点:");
|
||||
System.out.println("- 请假天数:" + days);
|
||||
System.out.println("- 请假理由:" + reason);
|
||||
System.out.println("- 申请时间:" + requestTime);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
context.setVariable("approvalTime", LocalDateTime.now());
|
||||
context.setVariable("managerComment", "同意");
|
||||
System.out.println("经理已批准请假申请");
|
||||
System.out.println("- 审批意见:同意");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
context.setVariable("approvalTime", LocalDateTime.now());
|
||||
context.setVariable("managerComment", "请假天数过长,建议调整后重新提交");
|
||||
System.out.println("经理已拒绝请假申请");
|
||||
System.out.println("- 拒绝原因:请假天数过长,建议调整后重新提交");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package com.lanyuanxiaoyao.flowable.node;
|
||||
|
||||
import com.lanyuanxiaoyao.flowable.model.FlowContext;
|
||||
|
||||
/**
|
||||
* 简单流程节点
|
||||
* 仅用于演示基本的审批流程
|
||||
*/
|
||||
public class SimpleFlowNode extends AbstractFlowNode {
|
||||
public SimpleFlowNode(String nodeId) {
|
||||
super(nodeId);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void execute(FlowContext context) {
|
||||
System.out.println("执行节点:" + getNodeId());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onApprove(FlowContext context) {
|
||||
System.out.println("节点[" + getNodeId() + "]通过");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReject(FlowContext context) {
|
||||
System.out.println("节点[" + getNodeId() + "]拒绝");
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user