首先是环境搭建可参考之前的博客,而且有具体demo提供下载 https://download.csdn.net/download/qq_33333654/11790823
demo中仅涵盖了排他网关的实例。
接下来准备绘制流程图:
具体的xml代码如下:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <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:tns="http://www.activiti.org/testm1539766523202" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" expressionLanguage="http://www.w3.org/1999/XPath" id="m1539766523202" name="" targetNamespace="http://www.activiti.org/testm1539766523202" typeLanguage="http://www.w3.org/2001/XMLSchema"> <process id="bingxingleveal" isClosed="false" isExecutable="true" processType="None"> <startEvent id="_2" name="StartEvent"/> <userTask activiti:exclusive="true" id="shenqing" name="提交申请"/> <parallelGateway gatewayDirection="Unspecified" id="_4" name="ParallelGateway"/> <userTask activiti:exclusive="true" id="shenpiA" name="审批A"/> <userTask activiti:exclusive="true" id="shenpiB" name="审批B"/> <userTask activiti:exclusive="true" id="shenpiC" name="审批C"/> <exclusiveGateway gatewayDirection="Unspecified" id="_8" name="ExclusiveGateway"/> <parallelGateway gatewayDirection="Unspecified" id="_9" name="ParallelGateway"/> <userTask activiti:exclusive="true" id="_10" name="最终审批"/> <endEvent id="_11" name="EndEvent"/> <sequenceFlow id="_12" sourceRef="_2" targetRef="shenqing"/> <sequenceFlow id="_13" sourceRef="shenqing" targetRef="_4"/> <sequenceFlow id="_14" sourceRef="_4" targetRef="shenpiB"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.submit==true}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="_15" sourceRef="_4" targetRef="shenpiA"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.submit==true}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="_16" sourceRef="shenpiB" targetRef="_9"/> <sequenceFlow id="_18" sourceRef="shenpiC" targetRef="_8"/> <sequenceFlow id="_19" name="驳回" sourceRef="_8" targetRef="shenpiA"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree3==false}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="_20" name="同意" sourceRef="_8" targetRef="_9"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree3==true}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="_21" sourceRef="_9" targetRef="_10"/> <sequenceFlow id="_22" sourceRef="_10" targetRef="_11"/> <sequenceFlow id="_3" sourceRef="shenpiA" targetRef="shenpiC"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${bingxing.agree1==true}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram 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" id="Diagram-_1" name="New Diagram"> <bpmndi:BPMNPlane bpmnElement="bingxingleveal"> <bpmndi:BPMNShape bpmnElement="_2" id="Shape-_2"> <dc:Bounds height="32.0" width="32.0" x="10.0" y="190.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="shenqing" id="Shape-shenqing"> <dc:Bounds height="55.0" width="85.0" x="125.0" y="180.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_4" id="Shape-_4"> <dc:Bounds height="32.0" width="32.0" x="275.0" y="190.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="shenpiA" id="Shape-shenpiA"> <dc:Bounds height="55.0" width="85.0" x="400.0" y="80.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="shenpiB" id="Shape-shenpiB"> <dc:Bounds height="55.0" width="85.0" x="385.0" y="310.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="shenpiC" id="Shape-shenpiC"> <dc:Bounds height="55.0" width="85.0" x="550.0" y="85.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_8" id="Shape-_8" isMarkerVisible="false"> <dc:Bounds height="32.0" width="32.0" x="735.0" y="110.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_9" id="Shape-_9"> <dc:Bounds height="32.0" width="32.0" x="745.0" y="205.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_10" id="Shape-_10"> <dc:Bounds height="55.0" width="85.0" x="900.0" y="210.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="55.0" width="85.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="_11" id="Shape-_11"> <dc:Bounds height="32.0" width="32.0" x="1105.0" y="230.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="32.0" width="32.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13" sourceElement="shenqing" targetElement="_4"> <di:waypoint x="210.0" y="207.5"/> <di:waypoint x="275.0" y="206.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12" sourceElement="_2" targetElement="shenqing"> <di:waypoint x="42.0" y="206.0"/> <di:waypoint x="125.0" y="207.5"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_15" id="BPMNEdge__15" sourceElement="_4" targetElement="_5"> <di:waypoint x="290.0" y="191.0"/> <di:waypoint x="290.0" y="110.0"/> <di:waypoint x="400.0" y="110.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_14" id="BPMNEdge__14" sourceElement="_4" targetElement="_6"> <di:waypoint x="290.0" y="221.0"/> <di:waypoint x="290.0" y="305.0"/> <di:waypoint x="385.0" y="337.5"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_16" id="BPMNEdge__16" sourceElement="_6" targetElement="_9"> <di:waypoint x="470.0" y="335.0"/> <di:waypoint x="760.0" y="335.0"/> <di:waypoint x="760.0" y="236.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_19" id="BPMNEdge__19" sourceElement="_8" targetElement="_5"> <di:waypoint x="751.0" y="110.0"/> <di:waypoint x="630.0" y="40.0"/> <di:waypoint x="442.5" y="80.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_18" id="BPMNEdge__18" sourceElement="_7" targetElement="_8"> <di:waypoint x="635.0" y="112.5"/> <di:waypoint x="735.0" y="126.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_3" id="BPMNEdge__3" sourceElement="_5" targetElement="_7"> <di:waypoint x="500.0" y="107.5"/> <di:waypoint x="550.0" y="112.5"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_20" id="BPMNEdge__20" sourceElement="_8" targetElement="_9"> <di:waypoint x="756.0" y="137.0"/> <di:waypoint x="756.0" y="210.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_22" id="BPMNEdge__22" sourceElement="_10" targetElement="_11"> <di:waypoint x="985.0" y="237.5"/> <di:waypoint x="1105.0" y="246.0"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="_21" id="BPMNEdge__21" sourceElement="_9" targetElement="_10"> <di:waypoint x="777.0" y="221.0"/> <di:waypoint x="900.0" y="237.5"/> <bpmndi:BPMNLabel> <dc:Bounds height="0.0" width="0.0" x="0.0" y="0.0"/> </bpmndi:BPMNLabel> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
该实例图中有排他网关和并行网关,避免理解错误。菱形中间带X的是排他网关,带+号的是并行网关。
所谓并行其实就是java的&&。图片中只有上下两条路全部通过并行网关才会放行到最终审批,否则任意一条不通过,都会处于等待状态。例如:审批B通过了,但是审批C驳回了,那么并行网关是不会通过的。
接下来上具体操作代码:
准备下工具类和连线的限制条件所需的实体bean,实体bean会存放到act数据的全局变量中(act_ru_variable),可以通过这个变量操作流程。
工具类:
package com.example.demo.utils; import org.activiti.bpmn.model.*; import org.activiti.bpmn.model.Process; import org.activiti.engine.ProcessEngine; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.history.HistoricProcessInstance; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.history.HistoricVariableInstance; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import java.util.*; /** * @ProjectName: demo * @Package: com.example.demo.utils * @ClassName: ActivitiUtil * @Author: MC * @Description: ${description} * @Date: 2019/9/19 0019 18:17 * @Version: 1.0 */ @Service public class ActivitiUtil { @Autowired private ProcessEngine processEngine; @Autowired private RuntimeService runtimeService ; @Autowired private TaskService taskService ; @Autowired private RepositoryService repositoryService; /** * @Method 部署流程 * @Author MC * @Return * @Date 2019/9/19 0019 18:34 */ public void deploy(String filePath){ if(!StringUtils.isEmpty(filePath)){ repositoryService.createDeployment() .addClasspathResource(filePath) .deploy(); } } /** * @Method 启动流程 * @Author MC * @Return * @Date 2019/9/19 0019 18:35 */ public Map<String,Object> start(Map<String,Object> map ,String processId){ ProcessInstance leave1 = runtimeService.startProcessInstanceByKey(processId, map); String processDefinitionId = leave1.getProcessDefinitionId(); System.out.print("============processDefinitionId:" + processDefinitionId);//流程定义的ID System.out.print("============processInstanceId:" + leave1.getId());//流程实例的ID Map<String, Object> resultMap = new HashMap<>(); resultMap.put("result",leave1); resultMap.put("processDefinitionId",processDefinitionId); resultMap.put("processInstanceId",leave1.getId()); return resultMap; } /** * @Method 根据流程实例ID和用户ID查询任务ID * @Author MC 用户ID必须设置为Assignee * @Return * @Date 2019/9/19 0019 19:01 */ public String getTaskIdByAssignee( String processInstanceId, String userId){ TaskService taskService = processEngine.getTaskService();//获取任务的Service,设置和获取流程变量 //查询当前办理人的任务ID Task task = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskAssignee(userId)//任务办理人 .singleResult(); return task.getId(); } /** * @Method 根据流程实例ID和userTask标签体设置的ID获取当前任务对象 * @Author MC * @Return * @Date 2019/9/24 0024 9:54 */ public String getTaskIdByDefinitionKey( String processInstanceId, String defKey){ TaskService taskService = processEngine.getTaskService();//获取任务的Service,设置和获取流程变量 //查询当前办理人的任务ID Task task = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey(defKey)//userTask标签体的id .singleResult(); return task.getId(); } /** * @Method 获取流程实例列表 * @Author MC * @Return * @Date 2019/9/19 0019 18:32 */ public List<ProcessInstance> queryProcessInstanceAllList(String processDefinitionKey){ return runtimeService .createProcessInstanceQuery().processDefinitionKey(processDefinitionKey) .list(); } /** * @Method 根据assignee来查询用户 * @Author MC * @Return * @Date 2019/9/19 0019 18:29 */ public Task queryTask(String assignee) { //startProcessInstance(); // taskService.createTaskQuery().taskCandidateGroup("sales").singleResult(); Task task= taskService.createTaskQuery().taskAssignee(assignee).singleResult(); if(task == null){ return null; } System.out.println("审批人为【"+assignee+"】的任务有:任务编号为【" + task.getId() + "】"+ task.getTaskDefinitionKey()); return task; } public Task queryTask(String assignee, String processInstanceId) { Task task= taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskAssignee(assignee)//任务办理人 .singleResult(); if(task == null){ return null; } System.out.println("审批人为【"+assignee+"】的任务有:任务编号为【" + task.getId() + "】"+ task.getTaskDefinitionKey()); return task; } /** * * @param queryType 查询类型1 根据 assignee 查询 2 根据candidateuser查询 * @param str */ public String getNextNodeId(int queryType,String str) { Task task = null; if(queryType==1) { task = taskService.createTaskQuery().taskAssignee(str).singleResult(); }else if(queryType==2){ task = taskService.createTaskQuery().taskCandidateUser(str).singleResult(); }else if(queryType==3){ task = taskService.createTaskQuery().taskCandidateGroup(str).singleResult(); } // List<FlowElement> list = getNextNode(task.getId()); if(task==null) { return null; } // for(FlowElement e :list) { // //((org.activiti.bpmn.model.UserTask) e) // } return task.getId(); } /** * 获取流程的下一个节点 且要经过规则引擎判断后的节点 * @param taskId * @return */ private List<FlowElement> getNextNode(String taskId) { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); if(task==null) { return null; } List<FlowElement> list = new ArrayList<FlowElement>(); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(task.getProcessInstanceId()).singleResult(); //当前活动节点 String activitiId = processInstance.getActivityId(); System.out.println("当前节点是【"+activitiId+"】"); //pmmnModel 遍历节点需要它 BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId()); List<Process> processList = bpmnModel.getProcesses(); //循环多个物理流程 for(Process process:processList) { //返回该流程的所有任务,事件 Collection<FlowElement> cColl = process.getFlowElements(); //遍历节点 for(FlowElement f :cColl) { //如果改节点是当前节点 者 输出该节点的下一个节点 if(f.getId().equals(activitiId)) { List<SequenceFlow> sequenceFlowList = new ArrayList<SequenceFlow>(); //通过反射来判断是哪种类型 if(f instanceof org.activiti.bpmn.model.StartEvent) { //开始事件的输出路由 sequenceFlowList = ((org.activiti.bpmn.model.StartEvent) f).getOutgoingFlows(); }else if(f instanceof org.activiti.bpmn.model.UserTask) { sequenceFlowList = ((org.activiti.bpmn.model.UserTask) f).getOutgoingFlows(); for(SequenceFlow sf :sequenceFlowList) { String targetRef = sf.getTargetRef(); FlowElement ref = process.getFlowElement(targetRef); // nextActivitiIdList.add(ref.getId()); list.add(ref); } }else if(f instanceof org.activiti.bpmn.model.SequenceFlow) { }else if(f instanceof org.activiti.bpmn.model.EndEvent) { sequenceFlowList = ((org.activiti.bpmn.model.EndEvent) f).getOutgoingFlows(); } break; } } } return list; } /** * @Method 流程流转到下一步 * @Author MC 根据 assignee 查询出任务,如果存在则设置当前任务的 assignee 为 nextUser * @Return 不存在下一个节点返回false; * @Date 2019/9/19 0019 18:23 */ public boolean completeByAssignee(String assignee,String nextUser) throws Exception { HashMap<String,Object> map = new HashMap<String,Object>(); map.put("nextUser", nextUser); Task task = taskService.createTaskQuery().taskAssignee(assignee).singleResult(); if(task == null){ System.out.println("下一节点不存在"); return false; } taskService.complete(task.getId(),map); System.out.println("完成任务 编号为【" + task.getId() + "】,名称为【"+task.getName()+"】的任务"); return true; } /** * 设置某个节点的审批人员 * @param taskId * @param user */ public void setApproveUser(String taskId,String user) { Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); task.setAssignee(user); taskService.saveTask(task); } /** * 取下一个节点的审批人 * @param taskId * @return */ public List<String> getNextTaskUserByTaskId(String taskId) { List<String> list = new ArrayList<String>(); List<FlowElement> fList = getNextNode(taskId); for(FlowElement u:fList){ String str = ((org.activiti.bpmn.model.UserTask) u).getAssignee(); list.add(str); } return list ; } /** * 找当前节点的候选审批人 供流程实例start后调用 * @param taskId * @return */ public List<String> getThisTaskUser(String taskId) { List<String> list = new ArrayList<String>(); Task task = taskService.createTaskQuery().taskId(taskId).singleResult(); String taskUser = task.getAssignee(); //*****************************根据taskUser的配置到自己的表里面去找数据 list.add(taskUser); return list ; } /** * @Method 任务是否完结 * @Author MC * @Return * @Date 2019/9/20 0020 11:20 */ public boolean isOverTask(String processInstanceId){ ProcessInstance pi= runtimeService.createProcessInstanceQuery() // 创建流程实例查询 .processInstanceId(processInstanceId) // 用流程实例id查询 .singleResult(); if(pi!=null){ System.out.println("流程正在执行!"); return false; }else{ System.out.println("流程已经执行结束!"); } return true; } /** * @Method 历史流程实例查询 * @Author MC * @Return * @Date 2019/9/20 0020 11:22 */ public List<HistoricProcessInstance> queryHisProInstance(String processDefinitionKey){ List<HistoricProcessInstance> historicProcessInstanceList = processEngine.getHistoryService().createHistoricProcessInstanceQuery() .processDefinitionKey(processDefinitionKey) .orderByProcessInstanceEndTime() .desc() .list(); /*for(HistoricProcessInstance historicProcessInstance:historicProcessInstanceList){ System.out.println("历史流程实例id: "+historicProcessInstance.getId()); System.out.println("历史流程实例的完成时间: "+historicProcessInstance.getEndTime()); }*/ return historicProcessInstanceList; } /** * 查询历史流程变量 */ public List<HistoricVariableInstance> queryHisProVariable(String processInstanceId){ List<HistoricVariableInstance> historicVariableInstanceList = processEngine.getHistoryService() .createHistoricVariableInstanceQuery() .processInstanceId(processInstanceId).list(); /*for(HistoricVariableInstance historicVariableInstance: historicVariableInstanceList){ System.out.println("历史流程变量id: "+historicVariableInstance.getId()); System.out.println("历史流程变量名称: "+historicVariableInstance.getVariableName()); System.out.println("历史流程变量值: "+historicVariableInstance.getValue()); System.out.println("=================================================="); }*/ return historicVariableInstanceList; } /** * 根据办理人查询历史任务实例 */ public List<HistoricTaskInstance> queryHisTaskInstanceByAssignee(String processDefinitionKey,String taskAssignee){ List<HistoricTaskInstance> historicTaskInstanceList = processEngine.getHistoryService().createHistoricTaskInstanceQuery() .processDefinitionKey(processDefinitionKey) .taskAssignee(taskAssignee).list(); /*for(HistoricTaskInstance historicTaskInstance:historicTaskInstanceList){ System.out.println("历史任务id: "+historicTaskInstance.getId()); System.out.println("历史任务名称: "+historicTaskInstance.getName()); System.out.println("历史任务结束时间: "+historicTaskInstance.getEndTime()); System.out.println("办理人: "+historicTaskInstance.getAssignee()); System.out.println("=================================================="); }*/ return historicTaskInstanceList; } /** * 历史任务查询 * type: 0:未完成 1:已完成 "":all */ public List<HistoricTaskInstance> historyTaskList(String processInstanceId,String type){ List<HistoricTaskInstance> list=null; if(StringUtils.isEmpty(type)){ list = processEngine.getHistoryService() // 历史相关Service .createHistoricTaskInstanceQuery() // 创建历史任务实例查询 .processInstanceId(processInstanceId) // 用流程实例id查询 .list(); }else if("0".equals(type)){ list = processEngine.getHistoryService() // 历史相关Service .createHistoricTaskInstanceQuery() // 创建历史任务实例查询 .processInstanceId(processInstanceId) // 用流程实例id查询 .unfinished() .list(); }else if("1".equals(type)){ processEngine.getHistoryService() // 历史相关Service .createHistoricTaskInstanceQuery() // 创建历史任务实例查询 .processInstanceId(processInstanceId) // 用流程实例id查询 .finished() // 查询已经完成的任务 .list(); } /* for(HistoricTaskInstance hti:list){ System.out.println("任务ID:"+hti.getId()); System.out.println("流程实例ID:"+hti.getProcessInstanceId()); System.out.println("任务名称:"+hti.getName()); System.out.println("办理人:"+hti.getAssignee()); System.out.println("开始时间:"+hti.getStartTime()); System.out.println("结束时间:"+hti.getEndTime()); System.out.println("================================="); }*/ return list; } /** * 已完成的历史活动查询 */ public List<HistoricActivityInstance> historyActInstanceList(String processInstanceId){ List<HistoricActivityInstance> list=processEngine.getHistoryService() // 历史相关Service .createHistoricActivityInstanceQuery() // 创建历史活动实例查询 .processInstanceId(processInstanceId) // 执行流程实例id .finished() .list(); /* for(HistoricActivityInstance hai:list){ System.out.println("活动ID:"+hai.getId()); System.out.println("流程实例ID:"+hai.getProcessInstanceId()); System.out.println("活动名称:"+hai.getActivityName()); System.out.println("办理人:"+hai.getAssignee()); System.out.println("开始时间:"+hai.getStartTime()); System.out.println("结束时间:"+hai.getEndTime()); System.out.println("================================="); }*/ return list; } }
act全局变量所需的实体对象leave:
package com.example.demo.model; import lombok.Data; import java.io.Serializable; import java.util.Date; /** * @ProjectName: demo * @Package: com.example.demo.service.model * @ClassName: Leave * @Author: MC * @Description: ${description} * @Date: 2019/9/19 0019 13:14 * @Version: 1.0 */ @Data public class Leave implements Serializable { private static final long serialVersionUID = 2248469053125414262L; private String userId; private Boolean submit; private Date startDate; private Date endDate; private float totalDay; private String desc; private String taskId; private String taskName; private String approver1; private Boolean agree1; private String approveDesc1; private String approver2; private Boolean agree2; private String approveDesc2; private Boolean agree3; private String approveDesc3; }
具体操作的代码:
package com.example.demo.web; import com.example.demo.model.Leave; import com.example.demo.utils.ActivitiUtil; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.task.Task; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.bind.annotation.RestController; import java.util.HashMap; import java.util.Map; /** * @ProjectName: demo * @Package: com.example.demo.web * @ClassName: BingxingController * @Author: MC * @Description: ${description} * @Date: 2019/9/23 0023 14:41 * @Version: 1.0 */ @RestController @RequestMapping("/bingxing") public class BingxingController { @Autowired private ActivitiUtil activitiUtil; @Autowired private RuntimeService runtimeService; @Autowired private TaskService taskService ; //---------------------------- // 注意:bingxing.bpmn没有设置userTask标签的 activiti:assignee 属性,所以获取task需要根据ID获取 // 另外,连接线的限制条件获取的是全局变量的bingxing,我之前写错了,写成获取全局变量的leave了 // ----------------------------- @RequestMapping(value = "/start") public String start (){ activitiUtil.deploy("processes/bingxing.bpmn"); Map<String,Object> map = new HashMap<>();//流程变量对象 Leave leave = new Leave(); leave.setUserId("shenqing"); map.put("bingxing",leave);//其所存act_ru_variable表name属性值对应其map的Key Map<String, Object> startMap = activitiUtil.start(map, "bingxingleveal"); String processInstanceId = startMap.get("processInstanceId").toString(); return processInstanceId; } @RequestMapping(value = "/approve") public void approve(@RequestParam String processInstanceId){ Task task = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey("shenqing")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法 .singleResult(); String taskId = task.getId(); activitiUtil.setApproveUser(taskId, "shenqing"); // Task task = activitiUtil.queryTask("shenqing",processInstanceId); Map<String,Object> map = new HashMap<>(); // 获取流程参数 对应启动流程时,入参的参数leave Leave variable = (Leave)taskService.getVariable(taskId, "bingxing"); // 从入参的表单对象中取值,设置流程参数对象的值 variable.setSubmit(true); map.put("bingxing",variable); taskService.complete(taskId,map); } @RequestMapping(value = "/approve2") public void approve2(@RequestParam String processInstanceId){ /* Task shenpiBtask = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey("shenpiB")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法 .singleResult(); String shenpiBtaskId = shenpiBtask.getId(); taskService.complete(shenpiBtaskId);*/ Task shenpiAtask = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey("shenpiA")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法 .singleResult(); String shenpiAtaskId = shenpiAtask.getId(); // Task task = activitiUtil.queryTask("shenqing",processInstanceId); Map<String,Object> map = new HashMap<>(); // 获取流程参数 对应启动流程时,入参的参数leave Leave variable = (Leave)taskService.getVariable(shenpiAtaskId, "bingxing"); // 从入参的表单对象中取值,设置流程参数对象的值 variable.setAgree1(true); // map.put("bingxing",variable); map.put("leave",variable);//原来画图画错了,连接线的条件设置成了leave了。。。。。。 taskService.complete(shenpiAtaskId,map); } @RequestMapping(value = "/approve3") public void approve3(@RequestParam String processInstanceId){ Task shenpiAtask = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey("shenpiC")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法 .singleResult(); String shenpiAtaskId = shenpiAtask.getId(); // Task task = activitiUtil.queryTask("shenqing",processInstanceId); Map<String,Object> map = new HashMap<>(); // 获取流程参数 对应启动流程时,入参的参数leave Leave variable = (Leave)taskService.getVariable(shenpiAtaskId, "leave"); // 从入参的表单对象中取值,设置流程参数对象的值 variable.setAgree3(true); // map.put("bingxing",variable); map.put("leave",variable);//原来画图画错了,连接线的条件设置成了leave了。。。。。。 taskService.complete(shenpiAtaskId,map); } @RequestMapping(value = "/approve4") public void approve4(@RequestParam String processInstanceId){ Task shenpiAtask = taskService.createTaskQuery() .processInstanceId(processInstanceId)//使用流程实例ID .taskDefinitionKey("_10")//注意:这里是因为xml文件中的userTask标签没有设置activiti:assignee属性时获取的方法 .singleResult(); String shenpiAtaskId = shenpiAtask.getId(); taskService.complete(shenpiAtaskId); } }
如果你看过上一篇博客排他网关,你会发现,排他网关的xml中userTask标签体设置了activiti:assignee而并行的xml中没有设置,在启动流程后,可以观察act_ru_task表中的assignee字段值为空,但是def_key字段值对应xml中userTask标签体的ID属性。
仔细看下approve2方法,我注释了一块代码,这一块可以单独写一个方法进行观察ru_task表数据,shenpiB和shenpiA会在task表中出现两条任务数据。
具体按照代码走一遍,最好自己上手敲,才会慢慢理解。