springboot+flowable⼯作流
背景:项⽬涉及到审批,⽤⼯作流会合适⼀点。由于之前未接触过,因此选⽤在activiti基础上开发的flowable进⾏需求:在springboot中引⼊flowable并封装操作(初次使⽤,仅供参考)
⽅法:
⼀、引⼊依赖
<dependency>
<groupId>org.flowable</groupId>
<artifactId>flowable-spring-boot-starter</artifactId>
<version>6.4.2</version>
</dependency>
⼆、封装操作⼯具(FlowableUtil)
1import com.hztech.framework.util.SpringBeanUtil;
2import ption.CustomException;
3import ine.ProcessEngine;
4import ine.RuntimeService;
5import ine.TaskService;
6import ine.runtime.ProcessInstance;
7import org.flowable.task.api.Task;
8import org.jetbrains.annotations.NotNull;
9
10import java.util.ArrayList;
11import java.util.HashMap;
12import java.util.List;
13
14/**
15 * @ClassName FlowableUtil
16 * @Description ⼯作流⼯具
17 * @Author 包海鹏
18 * @Date 2020/4/27 14:45
19 * @Version 1.0
20 **/
21public class FlowableUtil {
22
23/**
24 * 流程运⾏控制服务
25*/
26private RuntimeService runtimeService;
27
28/**
29 * 任务管理服务
30*/
31private TaskService taskService;
32
33/**
34 * 流程引擎
35*/
36private ProcessEngine processEngine;
37
38/**
39 * 初始化获取实例
40*/
41public FlowableUtil() {
42 runtimeService = Bean(RuntimeService.class);
43 taskService = Bean(TaskService.class);
44 processEngine = Bean(ProcessEngine.class);
45 }
46
47
48/**
49 * 启动流程
50 *
51 * @param processKey 流程定义key(流程图ID)
52 * @param businessKey 业务key
53 * @param map 参数键值对
54 * @return流程实例ID
55 * @Author 包海鹏
56*/
57public String start(String processKey, String businessKey, HashMap<String, Object> map) {
58
59 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processKey, businessKey, map);
Id();
61 }
62
63/**
64 * 终⽌流程
65 *
66 * @param processInstanceId 流程实例ID
67 * @param reason 终⽌理由
68 * @Author 包海鹏
69*/
70public void stop(String processInstanceId, String reason) {
71
72 runtimeService.deleteProcessInstance(processInstanceId, reason);
73 }
74
75
76/**
77 * 获取指定⽤户的任务列表(创建时间倒序)
78 *
79 * @param userId ⽤户ID
81 * @Author 包海鹏
82*/
83public List<Task> getListByUserId(String userId) {
84
85 List<Task> tasks = ateTaskQuery().taskAssignee(userId).orderByTaskCreateTime().desc().list();
86for (Task task : tasks) {
87 System.out.String());
88 }
89return tasks;
90 }
91
92/**
93 * 获取指定⽤户组的任务列表
94 *
95 * @param group ⽤户组
96 * @return任务列表
97 * @Author 包海鹏
98*/
99public List<Task> getListByGroup(String group) {
100
101 List<Task> tasks = ateTaskQuery().taskCandidateGroup(group).orderByTaskCreateTime().desc().list();
102for (Task task : tasks) {
103 System.out.String());
104 }
105return tasks;
106 }
107
108
109/**
110 * 完成指定任务
111 *
112 * @param taskId 任务ID
113 * @param map 变量键值对
114 * @Author 包海鹏
115*/
116public void complete(String taskId, HashMap<String, Object> map) {
117
118 Task task = ateTaskQuery().taskId(taskId).singleResult();
119if (task == null) {
120throw new CustomException("流程不存在");
121 }
122 taskServiceplete(taskId, map);
123 }
124
125/**
126 * 获取指定任务列表中的特定任务
127 *
128 * @param list 任务列表
129 * @param businessKey 业务key
130 * @return任务
131 * @Author 包海鹏
132*/
133public Task getOneByBusinessKey(@NotNull List<Task> list, String businessKey) {
134
135 Task task = null;
136for (Task t : list) {
137// 通过任务对象获取流程实例
138 ProcessInstance pi = ateProcessInstanceQuery().ProcessInstanceId()).singleResult();
139if (businessKey.BusinessKey())) {
140 task = t;
141 }
142 }
143return task;
144 }
145
146/**
147 * 创建流程并完成第⼀个任务
148 *
149 * @param processKey 流程定义key(流程图ID)
150 * @param businessKey 业务key
151 * @param map 变量键值对
152 * @Author 包海鹏
153*/
154public void startAndComplete(String processKey, String businessKey, HashMap<String, Object> map) {
155
156 String processInstanceId = start(processKey, businessKey, map);
157 Task task = TaskService().createTaskQuery().processInstanceId(processInstanceId).singleResult();
158 Id(), map);
159
160 }
161
162/**
163 * 退回到指定任务节点
164 *
165 * @param currentTaskId 当前任务ID
166 * @param targetTaskKey ⽬标任务节点key
167 * @Author 包海鹏
168*/
169public void backToStep(String currentTaskId, String targetTaskKey) {
170
171 Task currentTask = ateTaskQuery().taskId(currentTaskId).singleResult();
172if (currentTask == null) {
173throw new CustomException("当前任务节点不存在");
174 }
175 List<String> currentTaskKeys = new ArrayList<>();
176 currentTaskKeys.TaskDefinitionKey());
177 ateChangeActivityStateBuilder().ProcessInstanceId()).moveActivityIdsToSingleActivityId(currentTaskKeys, targetTaskKey); 178 }
179 }
⼆、封装业务⼯具(ExitUtil、PlanUtil)
1import com.hztech.mscm.util.FlowableUtil;
2import org.flowable.task.api.Task;
3
4import java.util.HashMap;
5import java.util.List;
6
7/**
8 * @ClassName PlanUtil
9 * @Description 出库模块⼯作流⼯具
10 * @Author 包海鹏
11 * @Date 2020/3/11 15:37
12 * @Version 1.0
13 **/
15
16private static final String EXIT_PROCESS_KEY = "exit";
17
18
19/**
20 * 提交
21 *
22 * @param inputUserId 申请⼈ID
23 * @param audiUserId 审核⼈ID
24 * @param exitId 出库单ID
25*/
26public static void submit(String inputUserId, String audiUserId, String exitId) {
27
28if (inputUserId.isEmpty() || audiUserId.isEmpty() || exitId.isEmpty()) {
29throw new RuntimeException("【saveAndSubmit】参数缺失!");
30 }
31
32 HashMap<String, Object> map = new HashMap<>();
33 map.put("inputUserId", inputUserId);
spring启动流程面试回答34 map.put("audiUserId", audiUserId);
35 FlowableUtil util = new FlowableUtil();
36 util.startAndComplete(EXIT_PROCESS_KEY, exitId, map);
37 }
38
39/**
40 * 通过-审核
41 *
42 * @param userId 审核操作⼈ID
43 * @param exitId 出库单ID
44*/
45public static void successApplyDepartment(String userId, String exitId) {
46
47 HashMap<String, Object> map = new HashMap<>();
48 map.put("outcome", "YES");
49 apply(userId, exitId, map);
50 }
51
52/**
53 * 拒绝-审核
54 *
55 * @param userId 审核操作⼈ID
56 * @param exitId 采购计划ID
57*/
58public static void failApplyDepartment(String userId, String exitId) {
59
60 HashMap<String, Object> map = new HashMap<>();
61 map.put("outcome", "NO");
62 apply(userId, exitId, map);
63 }
64
65
66/**
67 * 申请处理⽅法
68 *
69 * @param userId 申请操作⼈ID
70 * @param exitId 出库单ID
71 * @param map 变量组
72*/
73private static void apply(String userId, String exitId, HashMap<String, Object> map) {
74
75 FlowableUtil util = new FlowableUtil();
76 List<Task> list = TaskList(userId);
77 Task task = OneTask(list, exitId);
78if (null != task) {
79 Id(), map);
80 }
81
82 }
83 }
1import com.hztech.mscm.util.FlowableUtil;
2import org.flowable.task.api.Task;
3
4import java.util.HashMap;
5import java.util.List;
6
7/**
8 * @ClassName PlanUtil
9 * @Description 采购模块⼯作流⼯具
10 * @Author 包海鹏
11 * @Date 2020/3/11 15:37
12 * @Version 1.0
13 **/
14public class PlanUtil {
15
16private static final String PLAN_PROCESS_KEY = "plan";
17
18
19/**
20 * 提交
21 *
22 * @param inputUserId 采购申请⼈ID
23 * @param departmentUserId 部门审核⼈ID
24 * @param planId 采购计划ID
25*/
26public static void submit(String inputUserId, String departmentUserId, String planId) {
27
28if (inputUserId.isEmpty() || departmentUserId.isEmpty() || planId.isEmpty()) {
29throw new RuntimeException("【saveAndSubmit】参数缺失!");
30 }
31
32 HashMap<String, Object> map = new HashMap<>();
33 map.put("inputUserId", inputUserId);
34 map.put("departmentUserId", departmentUserId);
35 FlowableUtil util = new FlowableUtil();
36 util.startAndComplete(PLAN_PROCESS_KEY, planId, map);
37 }
38
39/**
40 * 通过-部门审核
41 *
42 * @param userId 审核操作⼈ID
43 * @param companyUserId 公司审批⼈ID
44 * @param planId 采购计划ID
45*/
46public static void successApplyDepartment(String userId, String companyUserId, String planId) { 47
48 HashMap<String, Object> map = new HashMap<>();
49 map.put("companyUserId", companyUserId);
50 map.put("outcome", "YES");
51 apply(userId, planId, map);
52 }
53
54/**
55 * 拒绝-部门审核
56 *
57 * @param userId 审核操作⼈ID
58 * @param planId 采购计划ID
59*/
60public static void failApplyDepartment(String userId, String planId) {
61
62 HashMap<String, Object> map = new HashMap<>();
63 map.put("outcome", "NO");
64 apply(userId, planId, map);
65 }
66
67/**
68 * 通过-公司审批
69 *
70 * @param userId 审批操作⼈ID
71 * @param planId 采购计划ID
72*/
73public static void successApplyCompany(String userId, String planId) {
74
75 HashMap<String, Object> map = new HashMap<>();
76 map.put("outcome", "YES");
77 apply(userId, planId, map);
78 }
79
80/**
81 * 拒绝-公司审批
82 *
83 * @param userId 审批操作⼈ID
84 * @param planId 采购计划ID
85*/
86public static void failApplyCompany(String userId, String planId) {
87
88 HashMap<String, Object> map = new HashMap<>();
89 map.put("outcome", "NO");
90 apply(userId, planId, map);
91 }
92
93/**
94 * 申请处理⽅法
95 *
96 * @param userId 申请操作⼈ID
97 * @param planId 采购计划ID
98 * @param map 变量组
99*/
100private static void apply(String userId, String planId, HashMap<String, Object> map) {
101
102 FlowableUtil util = new FlowableUtil();
103 List<Task> list = TaskList(userId);
104 Task task = OneTask(list, planId);
105if (null != task) {
106 Id(), map);
107 }
108
109 }
110 }
三、放置流程图
1<?xml version="1.0" encoding="UTF-8"?>
2<definitions xmlns="/spec/BPMN/20100524/MODEL" xmlns:xsi="/2001/XMLSchema-instance" xmlns:xsd="/2001/XMLSchema" xmlns:flowable="/bpmn" xmlns:bpmndi 3<process id="exit" name="出库" isExecutable="true">
4<startEvent id="startEvent1"></startEvent>
5<userTask id="sid-84B1745B-2537-454B-BA36-2C857AAA1970" name="创建出库单" flowable:assignee="${inputUserId}">
6<extensionElements>
7<modeler:initiator-can-complete xmlns:modeler="/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
8</extensionElements>
9</userTask>
10<sequenceFlow id="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" sourceRef="startEvent1" targetRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970"></sequenceFlow>
11<userTask id="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" name="审核" flowable:assignee="${audiUserId}">
12<extensionElements>
13<modeler:initiator-can-complete xmlns:modeler="/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
14</extensionElements>
15</userTask>
16<sequenceFlow id="sid-51E82709-526B-49A3-95D1-483934328025" sourceRef="sid-84B1745B-2537-454B-BA36-2C857AAA1970" targetRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E"></sequenceFlow>
17<endEvent id="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44"></endEvent>
18<sequenceFlow id="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
19<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="NO"}]]></conditionExpression>
20</sequenceFlow>
21<sequenceFlow id="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" sourceRef="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" targetRef="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
22<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome="YES"}]]></conditionExpression>
23</sequenceFlow>
24</process>
25<bpmndi:BPMNDiagram id="BPMNDiagram_exit">
26<bpmndi:BPMNPlane bpmnElement="exit" id="BPMNPlane_exit">
27<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
28<omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
29</bpmndi:BPMNShape>
30<bpmndi:BPMNShape bpmnElement="sid-84B1745B-2537-454B-BA36-2C857AAA1970" id="BPMNShape_sid-84B1745B-2537-454B-BA36-2C857AAA1970">
31<omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
32</bpmndi:BPMNShape>
33<bpmndi:BPMNShape bpmnElement="sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E" id="BPMNShape_sid-446F98D6-E3CB-4D90-8A09-304B3DEB817E">
34<omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
35</bpmndi:BPMNShape>
36<bpmndi:BPMNShape bpmnElement="sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44" id="BPM
NShape_sid-410DC542-F32C-4B96-ADC7-A1E8E4F48B44">
37<omgdc:Bounds height="28.0" width="28.0" x="540.0" y="164.0"></omgdc:Bounds>
38</bpmndi:BPMNShape>
39<bpmndi:BPMNEdge bpmnElement="sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7" id="BPMNEdge_sid-BDADDC89-3FBD-4375-95C0-47019F7BE1D7">
40<omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint>
41<omgdi:waypoint x="370.0" y="273.0"></omgdi:waypoint>
42<omgdi:waypoint x="554.0" y="273.0"></omgdi:waypoint>
43<omgdi:waypoint x="554.0" y="191.94993609491092"></omgdi:waypoint>
44</bpmndi:BPMNEdge>
45<bpmndi:BPMNEdge bpmnElement="sid-51E82709-526B-49A3-95D1-483934328025" id="BPMNEdge_sid-51E82709-526B-49A3-95D1-483934328025">
46<omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint>
47<omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint>
48</bpmndi:BPMNEdge>
49<bpmndi:BPMNEdge bpmnElement="sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C" id="BPMNEdge_sid-DD3C2B4A-2CA4-48CB-A76C-5CFCB95EB24C">
50<omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
51<omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
52</bpmndi:BPMNEdge>
53<bpmndi:BPMNEdge bpmnElement="sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2" id="BPMNEdge_sid-891CEBB3-C9FA-4A75-8225-B4B879A6BEB2">
54<omgdi:waypoint x="419.9499999999156" y="178.0"></omgdi:waypoint>
55<omgdi:waypoint x="540.0" y="178.0"></omgdi:waypoint>
56</bpmndi:BPMNEdge>
57</bpmndi:BPMNPlane>
58</bpmndi:BPMNDiagram>
59</definitions>
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="/spec/BPMN/20100524/MODEL" xmlns:xsi="/2001/XMLSchema-instance" xmlns:xsd="/2001/XMLSchema" xmlns:flowable="/bpmn" xmlns:bpmndi <process id="plan" name="采购" isExecutable="true">
<documentation>采购流程</documentation>
<startEvent id="startEvent1"></startEvent>
<userTask id="makePlan" name="编写采购单" flowable:assignee="${inputUserId}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" sourceRef="startEvent1" targetRef="makePlan"></sequenceFlow>
<userTask id="department" name="部门审核" flowable:assignee="${departmentUserId}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<userTask id="company" name="公司审批" flowable:assignee="${companyUserId}">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="/modeler"><![CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<endEvent id="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" name="结束"></endEvent>
<sequenceFlow id="f1" sourceRef="makePlan" targetRef="department"></sequenceFlow>
<sequenceFlow id="departmentYes" name="通过" sourceRef="department" targetRef="company">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="companyYes" name="通过" sourceRef="company" targetRef="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="YES"}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="departmentNo" name="拒绝" sourceRef="department" targetRef="makePlan">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="companyNo" name="拒绝" sourceRef="company" targetRef="makePlan">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${outcome=="NO"}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_plan">
<bpmndi:BPMNPlane bpmnElement="plan" id="BPMNPlane_plan">
<bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1">
<omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="makePlan" id="BPMNShape_makePlan">
<omgdc:Bounds height="80.0" width="100.0" x="175.0" y="138.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="department" id="BPMNShape_department">
<omgdc:Bounds height="80.0" width="100.0" x="320.0" y="138.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="company" id="BPMNShape_company">
<omgdc:Bounds height="80.0" width="100.0" x="465.0" y="138.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5" id="BPMNShape_sid-D7B9B979-C32C-4959-A4F7-129C0691D8E5">
<omgdc:Bounds height="28.0" width="28.0" x="610.0" y="164.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="companyYes" id="BPMNEdge_companyYes">
<omgdi:waypoint x="564.95" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="610.0" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="companyNo" id="BPMNEdge_companyNo">
<omgdi:waypoint x="515.0" y="138.0"></omgdi:waypoint>
<omgdi:waypoint x="515.0" y="56.0"></omgdi:waypoint>
<omgdi:waypoint x="225.0" y="56.0"></omgdi:waypoint>
<omgdi:waypoint x="225.0" y="138.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB" id="BPMNEdge_sid-C443333F-D5FF-41E4-9F84-AA4B33BC57AB">
<omgdi:waypoint x="129.9499984899576" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="174.9999999999917" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="departmentYes" id="BPMNEdge_departmentYes">
<omgdi:waypoint x="419.94999999999067" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="464.9999999999807" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="departmentNo" id="BPMNEdge_departmentNo">
<omgdi:waypoint x="370.0" y="217.95000000000002"></omgdi:waypoint>
<omgdi:waypoint x="370.0" y="296.0"></omgdi:waypoint>
<omgdi:waypoint x="225.0" y="296.0"></omgdi:waypoint>
<omgdi:waypoint x="225.0" y="217.95000000000002"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="f1" id="BPMNEdge_f1">
<omgdi:waypoint x="274.9499999999907" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="319.9999999999807" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论