环境:Springboot2.3.12.RELEASE + Activiti7.1.0.M6
本篇主要演示复杂的审批流程的应用:排他网关路由的使用(Exclusive Gateway)
流程设计
审批说明:当员工请假天数小于等于3天时,部门经理审批,当部门经理同意flag==1流程结束,不同意flag==0流程返回到"员工请假"节点;当请假天数大于3天时,先由部门经理审批,再由总经理审批,当总经理同意flag==1流程结束,不同意flag==0流程返回到"员工请假"节点。
<?xml version= "1.0" encoding= "UTF-8" ?> <definitions xmlns= "http://HdhCmsTestomg.org/spec/BPMN/20100524/MODEL" xmlns:xsi= "http://HdhCmsTestw3.org/2001/XMLSchema-instance" xmlns:xsd= "http://HdhCmsTestw3.org/2001/XMLSchema" xmlns:activiti= "http://activiti.org/bpmn" xmlns:bpmndi= "http://HdhCmsTestomg.org/spec/BPMN/20100524/DI" xmlns:omgdc= "http://HdhCmsTestomg.org/spec/DD/20100524/DC" xmlns:omgdi= "http://HdhCmsTestomg.org/spec/DD/20100524/DI" typeLanguage= "http://HdhCmsTestw3.org/2001/XMLSchema" expressionLanguage= "http://HdhCmsTestw3.org/1999/XPath" targetNamespace= "http://HdhCmsTestxg测试数据" > <process id= "holiday3" name = "holiday3" isExecutable= "true" > <startEvent id= "startevent1" name = "Start" ></startEvent> <userTask id= "usertask1" name = "员工请假" activiti:assignee= "${userId}" ></userTask> <exclusiveGateway id= "exclusivegateway1" name = "Exclusive Gateway" ></exclusiveGateway> <sequenceFlow id= "flow1" sourceRef= "startevent1" targetRef= "usertask1" ></sequenceFlow> <sequenceFlow id= "flow2" sourceRef= "usertask1" targetRef= "exclusivegateway1" ></sequenceFlow> <userTask id= "usertask2" name = "部门经理审批" activiti:assignee= "${d_mgr}" ></userTask> <sequenceFlow id= "flow3" name = "${days <=3}" sourceRef= "exclusivegateway1" targetRef= "usertask2" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${days <=3}]]></conditionExpression> </sequenceFlow> <userTask id= "usertask3" name = "部门经理审批" activiti:assignee= "${d_mgr}" ></userTask> <userTask id= "usertask4" name = "总经理审批" activiti:assignee= "${g_mgr}" ></userTask> <sequenceFlow id= "flow4" name = "${days > 3}" sourceRef= "exclusivegateway1" targetRef= "usertask3" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${days > 3}]]></conditionExpression> </sequenceFlow> <sequenceFlow id= "flow5" sourceRef= "usertask3" targetRef= "usertask4" ></sequenceFlow> <endEvent id= "endevent1" name = "End" ></endEvent> <sequenceFlow id= "flow6" name = "${flag==1}" sourceRef= "usertask2" targetRef= "endevent1" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${flag==1}]]></conditionExpression> </sequenceFlow> <sequenceFlow id= "flow7" name = "${flag==1}" sourceRef= "usertask4" targetRef= "endevent1" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${flag==1}]]></conditionExpression> </sequenceFlow> <sequenceFlow id= "flow8" name = "${flag==0}" sourceRef= "usertask2" targetRef= "usertask1" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${flag==0}]]></conditionExpression> </sequenceFlow> <sequenceFlow id= "flow9" name = "${flag==0}" sourceRef= "usertask4" targetRef= "usertask1" > <conditionExpression xsi:type= "tFormalExpression" ><![CDATA[${flag==0}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id= "BPMNDiagram_holiday3" > <bpmndi:BPMNPlane bpmnElement= "holiday3" id= "BPMNPlane_holiday3" > <bpmndi:BPMNShape bpmnElement= "startevent1" id= "BPMNShape_startevent1" > <omgdc:Bounds height= "35.0" width= "35.0" x= "470.0" y= "40.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "usertask1" id= "BPMNShape_usertask1" > <omgdc:Bounds height= "55.0" width= "105.0" x= "435.0" y= "120.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "exclusivegateway1" id= "BPMNShape_exclusivegateway1" > <omgdc:Bounds height= "40.0" width= "40.0" x= "467.0" y= "260.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "usertask2" id= "BPMNShape_usertask2" > <omgdc:Bounds height= "55.0" width= "105.0" x= "220.0" y= "253.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "usertask3" id= "BPMNShape_usertask3" > <omgdc:Bounds height= "55.0" width= "105.0" x= "640.0" y= "253.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "usertask4" id= "BPMNShape_usertask4" > <omgdc:Bounds height= "55.0" width= "105.0" x= "880.0" y= "253.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement= "endevent1" id= "BPMNShape_endevent1" > <omgdc:Bounds height= "35.0" width= "35.0" x= "470.0" y= "430.0" ></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement= "flow1" id= "BPMNEdge_flow1" > <omgdi:waypoint x= "487.0" y= "75.0" ></omgdi:waypoint> <omgdi:waypoint x= "487.0" y= "120.0" ></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow2" id= "BPMNEdge_flow2" > <omgdi:waypoint x= "487.0" y= "175.0" ></omgdi:waypoint> <omgdi:waypoint x= "487.0" y= "260.0" ></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow3" id= "BPMNEdge_flow3" > <omgdi:waypoint x= "467.0" y= "280.0" ></omgdi:waypoint> <omgdi:waypoint x= "325.0" y= "280.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "361.0" y= "280.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow4" id= "BPMNEdge_flow4" > <omgdi:waypoint x= "507.0" y= "280.0" ></omgdi:waypoint> <omgdi:waypoint x= "640.0" y= "280.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "538.0" y= "280.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow5" id= "BPMNEdge_flow5" > <omgdi:waypoint x= "745.0" y= "280.0" ></omgdi:waypoint> <omgdi:waypoint x= "880.0" y= "280.0" ></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow6" id= "BPMNEdge_flow6" > <omgdi:waypoint x= "272.0" y= "308.0" ></omgdi:waypoint> <omgdi:waypoint x= "272.0" y= "447.0" ></omgdi:waypoint> <omgdi:waypoint x= "470.0" y= "447.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "300.0" y= "429.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow7" id= "BPMNEdge_flow7" > <omgdi:waypoint x= "932.0" y= "308.0" ></omgdi:waypoint> <omgdi:waypoint x= "932.0" y= "447.0" ></omgdi:waypoint> <omgdi:waypoint x= "505.0" y= "447.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "800.0" y= "429.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow8" id= "BPMNEdge_flow8" > <omgdi:waypoint x= "272.0" y= "253.0" ></omgdi:waypoint> <omgdi:waypoint x= "272.0" y= "147.0" ></omgdi:waypoint> <omgdi:waypoint x= "435.0" y= "147.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "290.0" y= "151.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement= "flow9" id= "BPMNEdge_flow9" > <omgdi:waypoint x= "932.0" y= "253.0" ></omgdi:waypoint> <omgdi:waypoint x= "932.0" y= "147.0" ></omgdi:waypoint> <omgdi:waypoint x= "540.0" y= "147.0" ></omgdi:waypoint> <bpmndi:BPMNLabel> <omgdc:Bounds height= "14.0" width= "100.0" x= "790.0" y= "151.0" ></omgdc:Bounds> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>到此流程设计完成。
Service接口
@Service public class HolidayService { private static final Logger logger = LoggerFactory.getLogger(HolidayService2.class); @Resource private RuntimeService runtimeService ; @Resource private TaskService taskService ; /** * <p> * 设置assignee的取值,用户可以在界面上设置流程的执行人 * </p> * <p>时间:2021年1月22日-下午8:30:39</p> * @author 爷爷 * @param processDefinitionId * @ return ProcessInstance */ public ProcessInstance startProcessInstanceAssignVariables(String processDefinitionId, Map<String, Object> variables) { Authentication.setAuthenticatedUserId((String)variables.get( "assignee" )) ; ProcessInstance processInstance = runtimeService.startProcessInstanceById(processDefinitionId, variables); logger.info( "流程定义ID: {}" , processInstance.getProcessDefinitionId()); logger.info( "流程实例ID: {}" , processInstance.getId()); logger.info( "BussinessKey: {}" , processInstance.getBusinessKey()) ; return processInstance ; } /** * <p>执行任务</p> * <p>时间:2021年1月24日-上午10:40:39</p> * @author 爷爷 * @param variables * @param instanceId * @ return void */ public void executionTask(Map<String, Object> variables, String instanceId) { Task task = taskService.createTaskQuery().processInstanceId(instanceId).singleResult() ; if (task == null ) { logger.error( "任务【{}】不存在" , instanceId) ; throw new RuntimeException( "任务【" + instanceId + "】不存在" ) ; } // 注意这里一定要设置变量,否则流程中设置的表达式无法获取,如下图 taskService.setVariables(task.getId(), variables); taskService测试数据plete(task.getId(), variables) ; } }方法的含义已经在代码中说明了。
Controller接口
package com.pack.controller; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.stream.Collectors; import javax.annotation.Resource; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.apache测试数据mons.lang3.StringUtils; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import com.pack.dto.ProcessDefinitionDTO; import com.pack.dto.ProcessInstanceDTO; import com.pack.dto.R; import com.pack.task.HolidayService2; @RestController @RequestMapping( "/holidays2" ) public class HolidayController2 { @Resource private HolidayService holidayService ; /** * <p>启动请假审批流程</p> * <p>时间:2021年1月23日-上午10:32:55</p> * @author 爷爷 * @param userId * @param processDefinitionId 流程定义Id * @ return R */ @GetMapping( "/start" ) public R startProcess(String userId, String processDefinitionId) { Map<String, Object> variables = new HashMap<>() ; variables.put( "userId" , userId) ; ProcessInstance instance = holidayService.startProcessInstanceAssignVariables(processDefinitionId, variables) ; ProcessInstanceDTO dto = new ProcessInstanceDTO() ; dto.setInstanceId(instance.getId()) ; return R.success(dto) ; } /** * <p> * 填写审批单 * </p> * <p>时间:2021年1月23日-上午11:57:30</p> * @author 爷爷 * @param Map取值如下 * @param days 请假天数 * @param explain 审批单说明 * @param instanceId 流程实例ID * @param assignee 指定下一个流程执行人 * @ return R */ @GetMapping( "/apply" ) public R fillApply(@RequestParam Map<String, Object> variables) { String instanceId = (String) variables.remove( "instanceId" ) ; if (StringUtils.isEmpty(instanceId)) { return R.failure( "未知任务" ) ; } holidayService.executionTask(variables, instanceId); return R.success() ; } }测试
启动流程
请假人处理
d_mgr:部门经理ID
days:3 (小于3天)
部门经理处理
flag:0 (不同意,驳回到员工申请)
查看act_hi_actinst表数据:
流程又进入到了[员工申请]节点
再次重复上面的流程,当走到部门经理时,将flag=1。
到此流程结束,当请求天数大于3天的处理过程与上面基本相同。
原文链接:https://HdhCmsTesttoutiao测试数据/a7038841229978747422/
查看更多关于Springboot整合工作流引擎Activiti之网关路由的详细内容...
声明:本文来自网络,不代表【好得很程序员自学网】立场,转载请注明出处:http://haodehen.cn/did211879