(外链:以下是一整套Activiti7 的内容,有兴趣的可以看看)
- (一)Activiti7 之工作流介绍:https://blog.csdn.net/qq_23845083/article/details/131292415
- (二)Activiti7 之BPMN:https://blog.csdn.net/qq_23845083/article/details/131292515
- (三)Activiti7 之新手入门:https://blog.csdn.net/qq_23845083/article/details/131292627
- (四)Activiti7 之实战应用:https://blog.csdn.net/qq_23845083/article/details/131292700
1 基本流程
1.1 流程图
此处每个 userTask 均需设置执行人
1.2 BPMN 文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.activiti.org/testm1625990337688" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="m1625990337688" name="" targetNamespace="http://www.activiti.org/testm1625990337688">
<process id="zhanleai_approve_base" name="测试出差申请流程" processType="None" isClosed="false" isExecutable="true">
<documentation />
<startEvent id="_2" name="StartEvent" />
<userTask id="_3" name="创建出差申请" activiti:assignee="张三" activiti:exclusive="true">
<documentation />
<extensionElements>
<activiti:taskListener event="create" class="com.gh.maintenance.controller.activiti_example.ActivitiApproveListener" />
</extensionElements>
</userTask>
<userTask id="_4" name="经理审批" activiti:assignee="李四" activiti:exclusive="true">
<documentation />
<extensionElements />
</userTask>
<userTask id="_5" name="总经理审批" activiti:assignee="老马" activiti:exclusive="true">
<documentation />
<extensionElements />
</userTask>
<userTask id="_6" name="财务审批" activiti:assignee="小王" activiti:exclusive="true" />
<endEvent id="_7" name="EndEvent" />
<sequenceFlow id="_8" sourceRef="_2" targetRef="_3" />
<sequenceFlow id="_9" sourceRef="_4" targetRef="_5" />
<sequenceFlow id="_10" sourceRef="_5" targetRef="_6" />
<sequenceFlow id="_11" sourceRef="_6" targetRef="_7" />
<sequenceFlow id="_12" sourceRef="_3" targetRef="_4" />
</process>
<bpmndi:BPMNDiagram id="Diagram-_1" name="New Diagram" documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0">
<bpmndi:BPMNPlane bpmnElement="zhanleai_approve_base">
<bpmndi:BPMNEdge id="BPMNEdge__12" bpmnElement="_12" sourceElement="_3" targetElement="_4">
<di:waypoint x="650" y="13" />
<di:waypoint x="700" y="13" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__11" bpmnElement="_11" sourceElement="_6" targetElement="_7">
<di:waypoint x="1110" y="13" />
<di:waypoint x="1162" y="13" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__10" bpmnElement="_10" sourceElement="_5" targetElement="_6">
<di:waypoint x="960" y="13" />
<di:waypoint x="1010" y="13" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__9" bpmnElement="_9" sourceElement="_4" targetElement="_5">
<di:waypoint x="800" y="13" />
<di:waypoint x="860" y="13" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__8" bpmnElement="_8" sourceElement="_2" targetElement="_3">
<di:waypoint x="501" y="13" />
<di:waypoint x="550" y="13" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Shape-_2" bpmnElement="_2">
<dc:Bounds x="465" y="-5" width="32" height="32" />
<bpmndi:BPMNLabel>
<dc:Bounds x="393" y="6" width="53" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_3" bpmnElement="_3">
<dc:Bounds x="550" y="-27" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_4" bpmnElement="_4">
<dc:Bounds x="700" y="-27" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_5" bpmnElement="_5">
<dc:Bounds x="860" y="-27" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_6" bpmnElement="_6">
<dc:Bounds x="1010" y="-27" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_7" bpmnElement="_7">
<dc:Bounds x="1162" y="-5" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="1215" y="6" width="49" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
1.3 启动流程实例
/**
* 启动流程实例
* `act_hi_actinst` 流程实例执行历史信息
* `act_hi_identitylink` 流程参与用户的历史信息
* `act_hi_procinst` 流程实例的历史信息
* `act_hi_taskinst` 流程任务的历史信息
* `act_ru_execution` 流程执行信息
* `act_ru_identitylink` 流程的正在参与用户信息
* `act_ru_task` 流程当前任务信息
*/
@RequestMapping("/startProcess")
public String startProcess(String key) {
// 1、根据流程定义的id启动流程
ProcessInstance instance = runtimeService.startProcessInstanceByKey(key);
// 2、输出内容
log.info("流程定义ID:" + instance.getProcessDefinitionId());
log.info("流程实例ID:" + instance.getId());
log.info("当前活动的ID:" + instance.getActivityId());
return "出差申请流程启动成功!";
}
1.4 查询个人待执行任务
/**
* 查询个人待执行的任务
*/
@RequestMapping("/getUnfinishTaskList")
public List<Map<String,String>> getUnfinishTaskList(String key, String taskAssignee) {
// 1、根据流程key 和 任务的负责人 查询任务
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(key) //流程Key
.taskAssignee(taskAssignee) //要查询的负责人
.list();
List<Map<String,String>> taskMapList = new ArrayList<>();
// 2、输出
for (Task task : taskList) {
Map<String,String> taskMap = new HashMap<>();
taskMap.put("processInstanceId",task.getProcessInstanceId()); //流程实例
taskMap.put("id",task.getId()); //任务Id
taskMap.put("assignee",task.getAssignee()); //任务负责人
taskMap.put("name",task.getName()); //任务名称
//取流程中设置的变量值(基本类型)
// taskMap.put("taskAssignee", Objects.nonNull(taskService.getVariable(task.getId(),"出差申请人"))?taskService.getVariable(task.getId(),"出差申请人").toString():""); //出差申请人
// taskMap.put("days", Objects.nonNull(taskService.getVariable(task.getId(),"请假天数"))?taskService.getVariable(task.getId(),"请假天数").toString():""); //出差天数
// taskMap.put("evaluateFee", Objects.nonNull(taskService.getVariable(task.getId(),"出差预计费用"))?taskService.getVariable(task.getId(),"出差预计费用").toString():""); //出差预计费用
// taskMap.put("startDate", Objects.nonNull(taskService.getVariable(task.getId(),"出差开始日期"))?taskService.getVariable(task.getId(),"出差开始日期").toString():""); //出差开始日期
//取流程中设置的变量值(bean类型)
taskMap.put("approveInfo",Objects.nonNull(taskService.getVariable(task.getId(),"出差信息"))?JSONObject.toJSONString(taskService.getVariable(task.getId(),"出差信息")):"");
taskMapList.add(taskMap);
}
return taskMapList;
}
1.5 完成个人任务
/**
* (以张三创建出差申请为例)
* 完成个人任务 : 创建出差申请
* `act_ru_task` 这里的 '创建出差申请' 会变为 '经理审批'
* 也就是也是下一个任务: 经理审批
* `act_hi_taskinst` 这里的'创建出差申请'这条记录会有开始时间和结束时间
* 然后还会增加一条记录 '经理审批'
*/
@RequestMapping("/completeTask")
public String completeTask(String key,String taskAssignee,String days,String evaluateFee, String startDate) {
// 查找该负责人下所有的任务
Task task = taskService.createTaskQuery()
.processDefinitionKey(key)
.taskAssignee(taskAssignee)
.singleResult();
//设置流程变量(基本类型),前提是该流程实例必须未执行完成 —— 存在 act_ru_variable 表中,对应取值即可
// taskService.setVariable(task.getId(), "请假人", taskAssignee);
// taskService.setVariable(task.getId(), "出差天数",days);
// taskService.setVariable(task.getId(), "出差预计费用", evaluateFee);
// taskService.setVariable(task.getId(), "出差开始日期", startDate);
//设置流程变量(JavaBean类型),前提是该流程实例必须未执行完成 —— 存在 act_ru_variable 表中,但是实际值存在 act_ge_bytearray 表中
ApproveInfo approveInfo = ApproveInfo.builder()
.taskAssignee(taskAssignee)
.days(days)
.evaluateFee(evaluateFee)
.startDate(startDate)
.build();
taskService.setVariable(task.getId(),"出差信息",approveInfo);
//执行流程
taskService.complete(task.getId());
return "当前," + task.getAssignee() + "已完成任务:" + task.getName() ;
}
1.6 根据任务ID完成任务
/**
* 根据任务ID来完成任务
*/
@RequestMapping("/completeTaskByTaskId")
public String completeTaskByTaskId(String taskId) {
Task task = taskService.createTaskQuery().taskId(taskId).singleResult();
taskService.complete(taskId);
return "当前已完成任务:" + task.getName() ;
}
2 排他网关
部分代码跟前面简单流程的有重复,我这部分就只贴流程图、bpmn文件和核心代码了
2.1 流程图
排他网关需要配置出口的表达式,然后通过 activiti 参数传值的形式会自动识别到该值,自动进行程序流转。
2.2 BPMN 文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.activiti.org/testm1625990337688" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="m1625990337688" name="" targetNamespace="http://www.activiti.org/testm1625990337688">
<process id="zhanleai_approve_reject" name="测试出差申请流程" processType="None" isClosed="false" isExecutable="true">
<documentation />
<startEvent id="_1" name="流程开始">
<documentation />
<extensionElements />
<outgoing>Flow_11ejhh5</outgoing>
</startEvent>
<userTask id="_2" name="创建出差申请" activiti:assignee="张三" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_08ru13p</incoming>
<incoming>Flow_11ejhh5</incoming>
<outgoing>Flow_1b2032e</outgoing>
</userTask>
<userTask id="_4" name="经理审批" activiti:assignee="李四" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_1fc8hv7</incoming>
<outgoing>Flow_13ro4z7</outgoing>
</userTask>
<userTask id="_5" name="总经理审批" activiti:assignee="老马" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_13ro4z7</incoming>
<outgoing>Flow_1jpug20</outgoing>
</userTask>
<userTask id="_7" name="财务审批" activiti:assignee="小王" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_09owxd3</incoming>
<outgoing>Flow_1m3z2le</outgoing>
</userTask>
<sequenceFlow id="_11" sourceRef="_7" targetRef="_9" />
<userTask id="_8" name="大老板审批" activiti:assignee="老赵" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_0p8i7yo</incoming>
<outgoing>Flow_149ikim</outgoing>
<outgoing>Flow_1h2q7h5</outgoing>
</userTask>
<sequenceFlow id="Flow_149ikim" sourceRef="_8" targetRef="_9" />
<exclusiveGateway id="_6">
<documentation />
<incoming>Flow_1jpug20</incoming>
<outgoing>Flow_09owxd3</outgoing>
<outgoing>Flow_08ru13p</outgoing>
</exclusiveGateway>
<sequenceFlow id="Flow_1jpug20" sourceRef="_5" targetRef="_6" />
<sequenceFlow id="Flow_09owxd3" name="同意审批" sourceRef="_6" targetRef="_7">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_08ru13p" name="驳回申请" sourceRef="_6" targetRef="_2">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==0}</conditionExpression>
</sequenceFlow>
<exclusiveGateway id="_3" name="">
<documentation />
<incoming>Flow_1b2032e</incoming>
<outgoing>Flow_1fc8hv7</outgoing>
<outgoing>Flow_0p8i7yo</outgoing>
</exclusiveGateway>
<sequenceFlow id="Flow_11ejhh5" sourceRef="_1" targetRef="_2" />
<sequenceFlow id="Flow_1b2032e" sourceRef="_2" targetRef="_3">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_1fc8hv7" name="非特殊情况" sourceRef="_3" targetRef="_4">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==0}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_0p8i7yo" name="特殊情况" sourceRef="_3" targetRef="_8">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_1h2q7h5" sourceRef="_8" targetRef="_9">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_1m3z2le" sourceRef="_7" targetRef="_9" />
<sequenceFlow id="Flow_13ro4z7" sourceRef="_4" targetRef="_5" />
<endEvent id="_9" name="EndEvent">
<documentation />
<incoming>Flow_1h2q7h5</incoming>
<incoming>Flow_1m3z2le</incoming>
<terminateEventDefinition id="TerminateEventDefinition_1q47fr4" />
</endEvent>
</process>
<bpmndi:BPMNDiagram id="Diagram-_1" name="New Diagram" documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0">
<bpmndi:BPMNPlane bpmnElement="zhanleai_approve_reject">
<bpmndi:BPMNEdge id="Flow_13ro4z7_di" bpmnElement="Flow_13ro4z7">
<di:waypoint x="485" y="310" />
<di:waypoint x="485" y="340" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1m3z2le_di" bpmnElement="Flow_1m3z2le">
<di:waypoint x="485" y="640" />
<di:waypoint x="485" y="750" />
<di:waypoint x="622" y="750" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1h2q7h5_di" bpmnElement="Flow_1h2q7h5">
<di:waypoint x="800" y="330" />
<di:waypoint x="800" y="750" />
<di:waypoint x="658" y="750" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0p8i7yo_di" bpmnElement="Flow_0p8i7yo">
<di:waypoint x="640" y="125" />
<di:waypoint x="640" y="190" />
<di:waypoint x="800" y="190" />
<di:waypoint x="800" y="250" />
<bpmndi:BPMNLabel>
<dc:Bounds x="698" y="165" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1fc8hv7_di" bpmnElement="Flow_1fc8hv7">
<di:waypoint x="640" y="125" />
<di:waypoint x="640" y="190" />
<di:waypoint x="485" y="190" />
<di:waypoint x="485" y="230" />
<bpmndi:BPMNLabel>
<dc:Bounds x="535" y="165" width="55" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1b2032e_di" bpmnElement="Flow_1b2032e">
<di:waypoint x="640" y="30" />
<di:waypoint x="640" y="75" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_11ejhh5_di" bpmnElement="Flow_11ejhh5">
<di:waypoint x="640" y="-82" />
<di:waypoint x="640" y="-50" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_08ru13p_di" bpmnElement="Flow_08ru13p">
<di:waypoint x="460" y="480" />
<di:waypoint x="360" y="480" />
<di:waypoint x="360" y="-10" />
<di:waypoint x="590" y="-10" />
<bpmndi:BPMNLabel>
<dc:Bounds x="353" y="225" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_09owxd3_di" bpmnElement="Flow_09owxd3">
<di:waypoint x="485" y="505" />
<di:waypoint x="485" y="560" />
<bpmndi:BPMNLabel>
<dc:Bounds x="478" y="523" width="45" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jpug20_di" bpmnElement="Flow_1jpug20">
<di:waypoint x="485" y="420" />
<di:waypoint x="485" y="455" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Shape-_2" bpmnElement="_1">
<dc:Bounds x="622" y="-118" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="618" y="-147" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_3" bpmnElement="_2">
<dc:Bounds x="590" y="-50" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_4" bpmnElement="_4">
<dc:Bounds x="435" y="230" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_5" bpmnElement="_5">
<dc:Bounds x="435" y="340" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_6" bpmnElement="_7">
<dc:Bounds x="435" y="560" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_19lsvak_di" bpmnElement="_8">
<dc:Bounds x="750" y="250" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_06brwuq_di" bpmnElement="_6" isMarkerVisible="true">
<dc:Bounds x="460" y="455" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_1izdxic_di" bpmnElement="_3" isMarkerVisible="true">
<dc:Bounds x="615" y="75" width="50" height="50" />
<bpmndi:BPMNLabel>
<dc:Bounds x="607" y="125" width="66" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1y7rj7q_di" bpmnElement="_9">
<dc:Bounds x="622" y="732" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="616" y="775" width="49" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
2.3 排他网关核心代码
其实也就是流程图配置参数,然后调用的时候从前端传进来,后端代码需要将这个放到 variableMap 对象中,activiti 会自动根据 status 的值来判断,从而自动流转。
3 指定任意节点
流程图和 bpmn 复用排他网关
3.1 核心流程点
用户在前端页面的操作如下:
- 查询已执行的任务节点信息【前端】
- 选择节点信息【前端】
- 改变节点信息【前端】
3.2 根据流程实例ID查询已执行的任务节点信息
/**
* 根据流程实例ID查询已执行的任务节点信息
*
* act_hi_taskinst:历史流程任务表
*
* @Date 2023/6/14 15:03
* @Param [processInstanceId]
* @return
**/
@RequestMapping("/getRunNodesByProcInstId")
public Map<String,String> getRunNodesByProcInstId(String processInstanceId) {
Map<String,String> map = new LinkedHashMap();
// 获取流程历史中已执行节点,并按照节点在流程中执行先后顺序排序
List<HistoricActivityInstance> historicActivityInstanceList = historyService.createHistoricActivityInstanceQuery()
.processInstanceId(processInstanceId)
.activityType("userTask") //用户任务
.finished() //已经执行的任务节点
.orderByHistoricActivityInstanceEndTime()
.asc()
.list();
// 已执行的节点ID集合
if(Objects.nonNull(historicActivityInstanceList) && historicActivityInstanceList.size()>0){
for (HistoricActivityInstance historicActivityInstance:historicActivityInstanceList){
if(!map.containsKey(historicActivityInstance.getActivityId())){
map.put(historicActivityInstance.getActivityId(),historicActivityInstance.getActivityName());
}
}
}
return map;
}
3.3 改变节点到指定节点
/**
* 改变节点到指定节点
* @param rejectNodeId 指定节点ID
* @param processInstanceId 流程实例ID
* @param assignee 负责人
* @return
*/
@RequestMapping("/changeRunNode")
public String changeRunNode(String rejectNodeId, String processInstanceId, String assignee) {
// 查找该负责人下所有的任务
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.singleResult();
//如果当前节点处理人不是该用户,就无法进行改变节点操作
if (!assignee.equals(task.getAssignee())) {
return "当前用户无法改变流程节点";
}
//获取当前节点
String currActivityId = task.getTaskDefinitionKey();
String processDefinitionId = task.getProcessDefinitionId();
BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
FlowNode currFlow = (FlowNode) bpmnModel.getMainProcess().getFlowElement(currActivityId);
if (null == currFlow) {
List<SubProcess> subProcessList = bpmnModel.getMainProcess().findFlowElementsOfType(SubProcess.class, true);
for (SubProcess subProcess : subProcessList) {
FlowElement flowElement = subProcess.getFlowElement(currActivityId);
if (flowElement != null) {
currFlow = (FlowNode) flowElement;
break;
}
}
}
//获取目标节点
FlowNode targetFlow = (FlowNode) bpmnModel.getFlowElement(rejectNodeId);
//如果不是同一个流程(子流程)不能进行改变节点操作
if (!(currFlow.getParentContainer().equals(targetFlow.getParentContainer()))) {
return "不是同一个流程,无法进行改变节点操作";
}
//记录原活动方向
List<SequenceFlow> oriSequenceFlows = Lists.newArrayList();
oriSequenceFlows.addAll(currFlow.getOutgoingFlows());
//清理活动方向
currFlow.getOutgoingFlows().clear();
//建立新的方向
List<SequenceFlow> newSequenceFlows = Lists.newArrayList();
SequenceFlow newSequenceFlow = new SequenceFlow();
String uuid = UUID.randomUUID().toString().replace("-", "");
newSequenceFlow.setId(uuid);
newSequenceFlow.setSourceFlowElement(currFlow); //原节点
newSequenceFlow.setTargetFlowElement(targetFlow); //目标节点
newSequenceFlows.add(newSequenceFlow);
currFlow.setOutgoingFlows(newSequenceFlows);
//审批意见叠加
//variables 审批意见 act_ru_variable 变量表
Map<String, Object> variables = task.getProcessVariables();
variables.put("status","2");
variables.put("msg","资料填写有误,请重新填写!");
//完成节点任务
taskService.complete(task.getId(), variables);
//恢复原方向
currFlow.setOutgoingFlows(oriSequenceFlows);
return "改变流程到指定节点,已完成!";
}
4 并行网关
4.1 流程图
4.2 BPMN 文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.activiti.org/testm1625990337688" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="m1625990337688" name="" targetNamespace="http://www.activiti.org/testm1625990337688">
<process id="zhanleai_approve_parallel" name="测试出差申请流程" processType="None" isClosed="false" isExecutable="true">
<documentation />
<startEvent id="_1" name="流程开始">
<documentation />
<extensionElements />
<outgoing>Flow_11ejhh5</outgoing>
</startEvent>
<userTask id="_2" name="创建出差申请" activiti:assignee="张三" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_08ru13p</incoming>
<incoming>Flow_11ejhh5</incoming>
<outgoing>Flow_1b2032e</outgoing>
</userTask>
<userTask id="_4" name="经理审批" activiti:assignee="李四" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_1fc8hv7</incoming>
<outgoing>Flow_13ro4z7</outgoing>
</userTask>
<userTask id="_5" name="总经理审批" activiti:assignee="老马" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_13ro4z7</incoming>
<outgoing>Flow_1jpug20</outgoing>
</userTask>
<userTask id="_7" name="财务审批" activiti:assignee="小王" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_09owxd3</incoming>
<outgoing>Flow_1m3z2le</outgoing>
</userTask>
<sequenceFlow id="_11" sourceRef="_7" targetRef="_9" />
<userTask id="_8" name="大老板审批" activiti:assignee="老赵" activiti:exclusive="true">
<documentation />
<extensionElements />
<incoming>Flow_0p8i7yo</incoming>
<outgoing>Flow_149ikim</outgoing>
<outgoing>Flow_1h2q7h5</outgoing>
</userTask>
<sequenceFlow id="Flow_149ikim" sourceRef="_8" targetRef="_9" />
<exclusiveGateway id="_6">
<documentation />
<incoming>Flow_1jpug20</incoming>
<outgoing>Flow_09owxd3</outgoing>
<outgoing>Flow_08ru13p</outgoing>
</exclusiveGateway>
<sequenceFlow id="Flow_1jpug20" sourceRef="_5" targetRef="_6" />
<sequenceFlow id="Flow_09owxd3" name="同意审批" sourceRef="_6" targetRef="_7">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==1}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_08ru13p" name="驳回申请" sourceRef="_6" targetRef="_2">
<documentation />
<conditionExpression xsi:type="tFormalExpression">${status==0}</conditionExpression>
</sequenceFlow>
<sequenceFlow id="Flow_11ejhh5" sourceRef="_1" targetRef="_2" />
<sequenceFlow id="Flow_1b2032e" sourceRef="_2" targetRef="_3">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_1fc8hv7" name="" sourceRef="_3" targetRef="_4">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_0p8i7yo" name="" sourceRef="_3" targetRef="_8">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_1h2q7h5" sourceRef="_8" targetRef="_9">
<documentation />
</sequenceFlow>
<sequenceFlow id="Flow_1m3z2le" sourceRef="_7" targetRef="_9" />
<sequenceFlow id="Flow_13ro4z7" sourceRef="_4" targetRef="_5" />
<parallelGateway id="_3" name="">
<documentation />
<incoming>Flow_1b2032e</incoming>
<outgoing>Flow_1fc8hv7</outgoing>
<outgoing>Flow_0p8i7yo</outgoing>
</parallelGateway>
<endEvent id="_9" name="结束任务">
<documentation />
<incoming>Flow_1h2q7h5</incoming>
<incoming>Flow_1m3z2le</incoming>
<terminateEventDefinition id="TerminateEventDefinition_1gxwlzk" />
</endEvent>
</process>
<bpmndi:BPMNDiagram id="Diagram-_1" name="New Diagram" documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0">
<bpmndi:BPMNPlane bpmnElement="zhanleai_approve_parallel">
<bpmndi:BPMNEdge id="Flow_13ro4z7_di" bpmnElement="Flow_13ro4z7">
<di:waypoint x="485" y="310" />
<di:waypoint x="485" y="340" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1m3z2le_di" bpmnElement="Flow_1m3z2le">
<di:waypoint x="485" y="640" />
<di:waypoint x="485" y="750" />
<di:waypoint x="622" y="750" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1h2q7h5_di" bpmnElement="Flow_1h2q7h5">
<di:waypoint x="840" y="350" />
<di:waypoint x="840" y="750" />
<di:waypoint x="658" y="750" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_0p8i7yo_di" bpmnElement="Flow_0p8i7yo">
<di:waypoint x="640" y="125" />
<di:waypoint x="640" y="190" />
<di:waypoint x="840" y="190" />
<di:waypoint x="840" y="270" />
<bpmndi:BPMNLabel>
<dc:Bounds x="718" y="165" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1fc8hv7_di" bpmnElement="Flow_1fc8hv7">
<di:waypoint x="640" y="125" />
<di:waypoint x="640" y="190" />
<di:waypoint x="485" y="190" />
<di:waypoint x="485" y="230" />
<bpmndi:BPMNLabel>
<dc:Bounds x="535" y="165" width="55" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1b2032e_di" bpmnElement="Flow_1b2032e">
<di:waypoint x="640" y="30" />
<di:waypoint x="640" y="75" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_11ejhh5_di" bpmnElement="Flow_11ejhh5">
<di:waypoint x="640" y="-82" />
<di:waypoint x="640" y="-50" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_08ru13p_di" bpmnElement="Flow_08ru13p">
<di:waypoint x="460" y="480" />
<di:waypoint x="360" y="480" />
<di:waypoint x="360" y="-10" />
<di:waypoint x="590" y="-10" />
<bpmndi:BPMNLabel>
<dc:Bounds x="353" y="225" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_09owxd3_di" bpmnElement="Flow_09owxd3">
<di:waypoint x="485" y="505" />
<di:waypoint x="485" y="560" />
<bpmndi:BPMNLabel>
<dc:Bounds x="478" y="523" width="45" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="Flow_1jpug20_di" bpmnElement="Flow_1jpug20">
<di:waypoint x="485" y="420" />
<di:waypoint x="485" y="455" />
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Shape-_2" bpmnElement="_1">
<dc:Bounds x="622" y="-118" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="618" y="-147" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_3" bpmnElement="_2">
<dc:Bounds x="590" y="-50" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_4" bpmnElement="_4">
<dc:Bounds x="435" y="230" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_5" bpmnElement="_5">
<dc:Bounds x="435" y="340" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_6" bpmnElement="_7">
<dc:Bounds x="435" y="560" width="100" height="80" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Activity_19lsvak_di" bpmnElement="_8">
<dc:Bounds x="790" y="270" width="100" height="80" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_06brwuq_di" bpmnElement="_6" isMarkerVisible="true">
<dc:Bounds x="460" y="455" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Gateway_02haxla_di" bpmnElement="_3">
<dc:Bounds x="615" y="75" width="50" height="50" />
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Event_1mmhxvi_di" bpmnElement="_9">
<dc:Bounds x="622" y="732" width="36" height="36" />
<bpmndi:BPMNLabel>
<dc:Bounds x="619" y="775" width="44" height="14" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
4.3 核心动作
并行网关没有什么特别的设置,直接画流程图,正常流转就能结束。但是需要注意一点,必须将结束事件设置为:Terminate End Event,不然会出现整个流程无法结束的情况。
5 任务监听器
- create:任务创建后触发
- Assignment:任务分配后触发
- Delete:任务完成后触发
- All:所有任务都触发
5.1 流程图
针对某个 userTask 设置监听器,选择“创建后”,java类设置全路径为:com.gh.maintenance.controller.activiti_example.ActivitiApproveListener
5.2 BPMN 文件
<?xml version="1.0" encoding="UTF-8"?>
<definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="http://www.omg.org/spec/DD/20100524/DI" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:tns="http://www.activiti.org/testm1625990337688" xmlns:xsd="http://www.w3.org/2001/XMLSchema" id="m1625990337688" name="" targetNamespace="http://www.activiti.org/testm1625990337688">
<process id="zhanleai_approve_listener" name="测试出差申请流程" processType="None" isClosed="false" isExecutable="true">
<documentation />
<startEvent id="_2" name="StartEvent" />
<userTask id="_3" name="创建出差申请" activiti:assignee="张三" activiti:exclusive="true">
<documentation />
<extensionElements>
<activiti:taskListener event="create" class="com.gh.maintenance.controller.activiti_example.ActivitiApproveListener" />
</extensionElements>
</userTask>
<userTask id="_4" name="经理审批" activiti:assignee="李四" activiti:exclusive="true">
<documentation />
<extensionElements />
</userTask>
<userTask id="_5" name="总经理审批" activiti:assignee="老马" activiti:exclusive="true">
<documentation></documentation>
<extensionElements />
</userTask>
<userTask id="_6" name="财务审批" activiti:assignee="小王" activiti:exclusive="true">
<documentation></documentation>
<extensionElements />
</userTask>
<endEvent id="_7" name="EndEvent" />
<sequenceFlow id="_8" sourceRef="_2" targetRef="_3" />
<sequenceFlow id="_9" sourceRef="_4" targetRef="_5" />
<sequenceFlow id="_10" sourceRef="_5" targetRef="_6" />
<sequenceFlow id="_11" sourceRef="_6" targetRef="_7" />
<sequenceFlow id="_12" sourceRef="_3" targetRef="_4" />
</process>
<bpmndi:BPMNDiagram id="Diagram-_1" name="New Diagram" documentation="background=#3C3F41;count=1;horizontalcount=1;orientation=0;width=842.4;height=1195.2;imageableWidth=832.4;imageableHeight=1185.2;imageableX=5.0;imageableY=5.0">
<bpmndi:BPMNPlane bpmnElement="zhanleai_approve_listener">
<bpmndi:BPMNEdge id="BPMNEdge__12" bpmnElement="_12" sourceElement="_3" targetElement="_4">
<di:waypoint x="477.5" y="160" />
<di:waypoint x="477.5" y="195" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__11" bpmnElement="_11" sourceElement="_6" targetElement="_7">
<di:waypoint x="481" y="440" />
<di:waypoint x="481" y="510" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__10" bpmnElement="_10" sourceElement="_5" targetElement="_6">
<di:waypoint x="480" y="340" />
<di:waypoint x="480" y="385" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__9" bpmnElement="_9" sourceElement="_4" targetElement="_5">
<di:waypoint x="477.5" y="250" />
<di:waypoint x="477.5" y="285" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge id="BPMNEdge__8" bpmnElement="_8" sourceElement="_2" targetElement="_3">
<di:waypoint x="481" y="27" />
<di:waypoint x="481" y="105" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="0" height="0" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNEdge>
<bpmndi:BPMNShape id="Shape-_2" bpmnElement="_2">
<dc:Bounds x="465" y="-5" width="32" height="32" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="32" height="32" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_3" bpmnElement="_3">
<dc:Bounds x="435" y="105" width="85" height="55" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_4" bpmnElement="_4">
<dc:Bounds x="435" y="195" width="85" height="55" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_5" bpmnElement="_5">
<dc:Bounds x="435" y="285" width="85" height="55" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_6" bpmnElement="_6">
<dc:Bounds x="440" y="385" width="85" height="55" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="85" height="55" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape id="Shape-_7" bpmnElement="_7">
<dc:Bounds x="465" y="510" width="32" height="32" />
<bpmndi:BPMNLabel>
<dc:Bounds x="0" y="0" width="32" height="32" />
</bpmndi:BPMNLabel>
</bpmndi:BPMNShape>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
5.3 任务监听器核心代码
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.delegate.DelegateTask;
import org.activiti.engine.delegate.TaskListener;
/**
* @Description: 监听器 【create-任务创建后触发 Assignment-任务分配后触发 Delete-任务完成后触发 All-所有任务都触发】
*
* @Author: zhanleai
* @Date:2023/6/16 11:37
*/
@Slf4j
public class ActivitiApproveListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>此监听器触发机制为:"+delegateTask.getEventName());
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>触发监听任务ID值为:"+delegateTask.getId());
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>负责人为:"+delegateTask.getAssignee());
log.info(">>>>>>>>>>>>>>>>>>>>>>>>>任务名称"+delegateTask.getName());
}
}
(外链:以下是一整套Activiti7 的内容,有兴趣的可以看看)
- Activiti7 之工作流介绍(一):https://blog.csdn.net/qq_23845083/article/details/131292415
- Activiti7 之BPMN(二):https://mp.csdn.net/mp_blog/creation/success/131292515
- Activiti7 之新手入门(三):https://blog.csdn.net/qq_23845083/article/details/131292627
- Activiti7 之实战应用(四):https://blog.csdn.net/qq_23845083/article/details/131292700