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小时内删除。