With the activiti framework, you first need to create a bpmn flowchart. There are two choices: one is the plug-in that comes with the ide (eclipse is good, not to mention it; the other is the plug-in that is really hard to use and has not been updated for several years); the other is the tool that activiti officially provides. activiti-app (Version 6.0, which we only use to draw), put activiti-app.war on tomcat to run.
## 1, Drawing flowchart
- Access address: http://localhost:8080/activiti-app
- Account: admin
- Password:test
Create a process first
Create a leave process
The flowchart is as follows:
Key attributes:
- Each rectangle box is a userTask, with the most critical property: Assignments Task Specifier
Since the identity section of activiti is not used, I choose to dynamically pass in a parameter (dynamic variable names cannot be repeated): - Each connector is a sequenceFlow, and the key properties are: Flow conditional sequential Flow condition; conditional expression can be set; variable names of branches must be consistent here, such as ${audit==1"} if an audit passes ${audit==1"} and ${audit==1"}
2. Import Flowchart
Download the drawn flowchart locally, create a new file (leave.bpmn20.xml) in the processes directory, and copy the flowchart into the XML with the text open:
<?xml version="1.0" encoding="UTF-8"?> <definitions xmlns="http://www.omg.org/spec/BPMN/20100524/MODEL" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:activiti="http://activiti.org/bpmn" xmlns:bpmndi="http://www.omg.org/spec/BPMN/20100524/DI" xmlns:omgdc="http://www.omg.org/spec/DD/20100524/DC" xmlns:omgdi="http://www.omg.org/spec/DD/20100524/DI" typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath" targetNamespace="http://www.activiti.org/processdef"> <process id="leave" name="Leave process" isExecutable="true"> <startEvent id="startEvent1" name="start"></startEvent> <userTask id="sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA" name="Fill in the application" activiti:assignee="${user}"><!--activiti:assignee Task Designator--> <extensionElements> <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete> </extensionElements> </userTask> <sequenceFlow id="sid-782B5EB0-C3E4-4EA8-B47C-001493E8CFAA" sourceRef="startEvent1" targetRef="sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA"></sequenceFlow> <userTask id="sid-F30892E7-AD40-44CE-8FE1-911564290536" name="Leader approval" activiti:assignee="${approve}"> <extensionElements> <modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><![CDATA[false]]></modeler:initiator-can-complete> </extensionElements> </userTask> <sequenceFlow id="sid-9BAB7E50-7E04-4C87-8448-ECDF79CB4405" sourceRef="sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA" targetRef="sid-F30892E7-AD40-44CE-8FE1-911564290536"></sequenceFlow> <exclusiveGateway id="sid-C7396408-A226-4385-9E87-C63DA1295BEE"></exclusiveGateway> <sequenceFlow id="sid-4570FB2C-F000-4EB9-961B-795DFD3CD037" sourceRef="sid-F30892E7-AD40-44CE-8FE1-911564290536" targetRef="sid-C7396408-A226-4385-9E87-C63DA1295BEE"></sequenceFlow> <endEvent id="sid-E8EA0FBB-EAE1-4316-BAAE-1465DD35D4EA" name="End"></endEvent> <!--sequenceFlow Process Branch--> <sequenceFlow id="sid-715DC950-61C4-4AA8-9662-A6FD71611EAA" name="Audit Failed" sourceRef="sid-C7396408-A226-4385-9E87-C63DA1295BEE" targetRef="sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${audit==0}]]></conditionExpression> </sequenceFlow> <sequenceFlow id="sid-EA1D4887-5497-43DE-9D57-A03D3B719681" name="Approval Passed" sourceRef="sid-C7396408-A226-4385-9E87-C63DA1295BEE" targetRef="sid-E8EA0FBB-EAE1-4316-BAAE-1465DD35D4EA"> <conditionExpression xsi:type="tFormalExpression"><![CDATA[${audit==1}]]></conditionExpression> </sequenceFlow> </process> <bpmndi:BPMNDiagram id="BPMNDiagram_leave"> <bpmndi:BPMNPlane bpmnElement="leave" id="BPMNPlane_leave"> <bpmndi:BPMNShape bpmnElement="startEvent1" id="BPMNShape_startEvent1"> <omgdc:Bounds height="30.0" width="30.0" x="90.0" y="150.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA" id="BPMNShape_sid-E9DA7720-703C-4AA1-9233-5B4977C4D7FA"> <omgdc:Bounds height="80.0" width="100.0" x="165.0" y="125.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-F30892E7-AD40-44CE-8FE1-911564290536" id="BPMNShape_sid-F30892E7-AD40-44CE-8FE1-911564290536"> <omgdc:Bounds height="80.0" width="100.0" x="300.0" y="125.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-C7396408-A226-4385-9E87-C63DA1295BEE" id="BPMNShape_sid-C7396408-A226-4385-9E87-C63DA1295BEE"> <omgdc:Bounds height="40.0" width="40.0" x="450.0" y="145.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNShape bpmnElement="sid-E8EA0FBB-EAE1-4316-BAAE-1465DD35D4EA" id="BPMNShape_sid-E8EA0FBB-EAE1-4316-BAAE-1465DD35D4EA"> <omgdc:Bounds height="28.0" width="28.0" x="540.0" y="151.0"></omgdc:Bounds> </bpmndi:BPMNShape> <bpmndi:BPMNEdge bpmnElement="sid-782B5EB0-C3E4-4EA8-B47C-001493E8CFAA" id="BPMNEdge_sid-782B5EB0-C3E4-4EA8-B47C-001493E8CFAA"> <omgdi:waypoint x="120.0" y="165.0"></omgdi:waypoint> <omgdi:waypoint x="165.0" y="165.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-9BAB7E50-7E04-4C87-8448-ECDF79CB4405" id="BPMNEdge_sid-9BAB7E50-7E04-4C87-8448-ECDF79CB4405"> <omgdi:waypoint x="265.0" y="165.0"></omgdi:waypoint> <omgdi:waypoint x="300.0" y="165.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-4570FB2C-F000-4EB9-961B-795DFD3CD037" id="BPMNEdge_sid-4570FB2C-F000-4EB9-961B-795DFD3CD037"> <omgdi:waypoint x="400.0" y="165.20746887966806"></omgdi:waypoint> <omgdi:waypoint x="450.4166666666667" y="165.41666666666666"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-715DC950-61C4-4AA8-9662-A6FD71611EAA" id="BPMNEdge_sid-715DC950-61C4-4AA8-9662-A6FD71611EAA"> <omgdi:waypoint x="470.5" y="145.5"></omgdi:waypoint> <omgdi:waypoint x="470.5" y="26.0"></omgdi:waypoint> <omgdi:waypoint x="215.0" y="26.0"></omgdi:waypoint> <omgdi:waypoint x="215.0" y="125.0"></omgdi:waypoint> </bpmndi:BPMNEdge> <bpmndi:BPMNEdge bpmnElement="sid-EA1D4887-5497-43DE-9D57-A03D3B719681" id="BPMNEdge_sid-EA1D4887-5497-43DE-9D57-A03D3B719681"> <omgdi:waypoint x="489.6144578313253" y="165.3855421686747"></omgdi:waypoint> <omgdi:waypoint x="540.0002509882663" y="165.0838308324056"></omgdi:waypoint> </bpmndi:BPMNEdge> </bpmndi:BPMNPlane> </bpmndi:BPMNDiagram> </definitions>
3. Configure application.yml
spring: datasource: #Data Source Basic Configuration username: root password: root url: jdbc:mysql://localhost/activiti?serverTimezone=Asia/Shanghai&characterEncoding=UTF-8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false driver-class-name: com.mysql.cj.jdbc.Driver activiti: # Open History Library db-history-used: true history-level: audit
The level of historical information can be configured as follows (activiti7 feels like none by default):
none: Ignore all historical archives.This is the best performance state for the process to execute, but no historical information is available.
Activity: Save all process instance information and activity instance information.At the end of the process instance, the latest variable value from the last process instance is assigned to the historical variable.Details of the process will not be saved.
audit: It holds all process instance information, activity information, and ensures that all variables and submitted form properties are synchronized so that all user interaction information is traceable and can be used for auditing.
full: This is the highest-level archive of historical information and also the slowest.This level stores information that occurs during auditing and all other details, mainly updating process variables.
4. Start a task
/** * Start a leave process * @param user User key * @param processDefinitionKey Flowchart key Each process has a corresponding key This is fixed within a process written in bpmn */ void startLeaveProcess(String user,String processDefinitionKey){ System.out.println(user+"Start a leave process:"+ processDefinitionKey); HashMap<String, Object> variables=new HashMap<>(); variables.put("user", user);//userKey is specified in the process variable above ProcessInstance instance = runtimeService .startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("Process Instances ID:"+instance.getId()); System.out.println("Process Definition ID:"+instance.getProcessDefinitionId()); System.out.println("=================================================================="); }
Run result:
Zhang San starts a leave process: Process Instance ID:34f2f038-0d07-11ea-b319-9c5c8e7034f6 Process Definition ID:leave:1:32f7bc77-0d07-11ea-b319-9c5c8e7034f6 ==================================================================
Notice the changes in the database:
mysql> select ID_,REV_,PROC_INST_ID_,NAME_,ASSIGNEE_ from act_ru_task; +--------------------------------------+------+--------------------------------------+----------+-----------+ | ID_ | REV_ | PROC_INST_ID_ | NAME_ | ASSIGNEE_ | +--------------------------------------+------+--------------------------------------+----------+-----------+ | 34f8958d-0d07-11ea-b319-9c5c8e7034f6 | 1 | 34f2f038-0d07-11ea-b319-9c5c8e7034f6 | Fill in the application | Zhang San | +--------------------------------------+------+--------------------------------------+----------+-----------+ 1 row in set
5. Query the current process according to the executor
/** * Query current task process */ void queryLeaveProcessING(String assignee){ System.out.println(assignee+"Query your current process:"); List<Task> list = taskService.createTaskQuery()//Create Task Query Object .taskAssignee(assignee)//Specify Personal Task Query .list(); if(list!=null && list.size()>0){ for(Task task:list){ System.out.println("task ID:"+task.getId()); System.out.println("Task Name:"+task.getName()); System.out.println("Task creation time:"+task.getCreateTime()); System.out.println("Task Manager:"+task.getAssignee()); System.out.println("Process Instances ID: "+task.getProcessInstanceId()); System.out.println("target of execution ID:"+task.getExecutionId()); System.out.println("Process Definition ID:"+task.getProcessDefinitionId()); Map<String, Object> map = task.getProcessVariables(); for (Map.Entry<String, Object> m : map.entrySet()) { System.out.println("key:" + m.getKey() + " value:" + m.getValue()); } for (Map.Entry<String, Object> m : task.getTaskLocalVariables().entrySet()) { System.out.println("key:" + m.getKey() + " value:" + m.getValue()); } } } System.out.println("=================================================================="); }
Run result:
Zhang San queries his current process: Task ID:34f8958d-0d07-11ea-b319-9c5c8e7034f6 Task Name: Fill in the application Task creation time: Fri Nov 22 17:05:19 CST 2019 Managing the task: Zhang San Process Instance ID: 34f2f038-0d07-11ea-b319-9c5c8e7034f6 Execution object ID:34f3b38a-0d07-11ea-b319-9c5c8e7034f6 Process Definition ID:leave:1:32f7bc77-0d07-11ea-b319-9c5c8e7034f6 ==================================================================
6. Submit to Leader for Review
void completeTask(String approve,String taskId){ System.out.println(approve+": Submit your own process:"+taskId); //Task ID HashMap<String, Object> variables=new HashMap<>(); variables.put("approve", approve);//userKey is specified in the process variable above taskService.complete(taskId,variables); System.out.println("Complete Task: Task ID: "+taskId); System.out.println("=================================================================="); }
Run result:
Leader Li Si: Submit own process: 34f8958d-0d07-11ea-b319-9c5c8e7034f6 Complete Task: Task ID: 34f8958d-0d07-11ea-b319-9c5c8e7034f6 ==================================================================
Database:
mysql> select ID_,REV_,PROC_INST_ID_,NAME_,ASSIGNEE_ from act_ru_task; +--------------------------------------+------+--------------------------------------+----------+-----------+ | ID_ | REV_ | PROC_INST_ID_ | NAME_ | ASSIGNEE_ | +--------------------------------------+------+--------------------------------------+----------+-----------+ | e60702be-0d08-11ea-8a0a-9c5c8e7034f6 | 1 | 34f2f038-0d07-11ea-b319-9c5c8e7034f6 | Leader approval | Leader Li Si | +--------------------------------------+------+--------------------------------------+----------+-----------+ 1 row in set
7. Leadership review and approval
void completeTask(String user,String taskId,int audit){ System.out.println(user+": Submit your own process:"+taskId+" ;Pass or not:"+audit); //Task ID HashMap<String, Object> variables=new HashMap<>(); variables.put("audit", audit);//userKey is specified in the process variable above taskService.complete(taskId,variables); System.out.println("Complete Task: Task ID: "+taskId); System.out.println("=================================================================="); }
Run result:
Leader Li 4: Submit your own process: e60702be-0d08-11ea-8a0a-9c5c8e7034f6; Pass or not:1 Complete Task: Task ID: e60702be-0d08-11ea-8a0a-9c5c8e7034f6 ==================================================================
Database:
mysql> select ID_,REV_,PROC_INST_ID_,NAME_,ASSIGNEE_ from act_ru_task; Empty set
8. Query historical data
Query according to process ID:
List<HistoricTaskInstance> list=historyService // History-related Service s .createHistoricTaskInstanceQuery() // Create Historical Activity Instance Query .processInstanceId("34f2f038-0d07-11ea-b319-9c5c8e7034f6") // Execution process instance id .orderByTaskCreateTime() .asc() .list(); for(HistoricTaskInstance hai:list){ System.out.println("activity ID:"+hai.getId()); System.out.println("Process Instances ID:"+hai.getProcessInstanceId()); System.out.println("Activity name:"+hai.getName()); System.out.println("Handler:"+hai.getAssignee()); System.out.println("Start time:"+hai.getStartTime()); System.out.println("End time:"+hai.getEndTime()); System.out.println("=================================================================="); }
Run result:
Activity ID:34f8958d-0d07-11ea-b319-9c5c8e7034f6 Process Instance ID:34f2f038-0d07-11ea-b319-9c5c8e7034f6 Activity Name: Fill in Application Handler: Zhang San Start time: Fri Nov 22 17:05:19 CST 2019 End time: Fri Nov 22 17:17:25 CST 2019 ================================================================== Activity ID:e60702be-0d08-11ea-8a0a-9c5c8e7034f6 Process Instance ID:34f2f038-0d07-11ea-b319-9c5c8e7034f6 Activity Name: Leader Approval Manager: Leader Li Si Start time: Fri Nov 22 17:17:25 CST 2019 End time: Fri Nov 22 17:31:03 CST 2019 ==================================================================
Query personal history:
List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery().taskAssignee("Zhang San").orderByTaskCreateTime().asc().list(); for(HistoricTaskInstance hai:list){ System.out.println("activity ID:"+hai.getId()); System.out.println("Process Instances ID:"+hai.getProcessInstanceId()); System.out.println("Activity name:"+hai.getName()); System.out.println("Handler:"+hai.getAssignee()); System.out.println("Start time:"+hai.getStartTime()); System.out.println("End time:"+hai.getEndTime()); System.out.println("=================================================================="); }
Run result:
Activity ID:34f8958d-0d07-11ea-b319-9c5c8e7034f6 Process Instance ID:34f2f038-0d07-11ea-b319-9c5c8e7034f6 Activity Name: Fill in Application Handler: Zhang San Start time: Fri Nov 22 17:05:19 CST 2019 End time: Fri Nov 22 17:17:25 CST 2019 ==================================================================
Database:
mysql> select ID_,PROC_INST_ID_,NAME_,ASSIGNEE_ from act_hi_taskinst; +--------------------------------------+--------------------------------------+----------+-----------+ | ID_ | PROC_INST_ID_ | NAME_ | ASSIGNEE_ | +--------------------------------------+--------------------------------------+----------+-----------+ | 34f8958d-0d07-11ea-b319-9c5c8e7034f6 | 34f2f038-0d07-11ea-b319-9c5c8e7034f6 | Fill in the application | Zhang San | | e60702be-0d08-11ea-8a0a-9c5c8e7034f6 | 34f2f038-0d07-11ea-b319-9c5c8e7034f6 | Leader approval | Leader Li Si | +--------------------------------------+--------------------------------------+----------+-----------+ 2 rows in set
9. Complete test class code
package com.example.activitidemo2; import org.activiti.engine.HistoryService; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricTaskInstance; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Task; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import javax.annotation.Resource; import java.util.HashMap; import java.util.List; import java.util.Map; @SpringBootTest class ActivitiDemo2ApplicationTests { @Resource RepositoryService repositoryService; @Resource RuntimeService runtimeService; @Resource TaskService taskService; @Resource HistoryService historyService; @Test void contextLoads() { System.out.println("Number of process definitions : " + repositoryService.createProcessDefinitionQuery().count()); System.out.println("Number of tasks : " + taskService.createTaskQuery().count()); runtimeService.startProcessInstanceByKey("oneTaskProcess"); System.out.println("Number of tasks after process start: " + taskService.createTaskQuery().count()); } @Test void testProcess(){ //Zhang San starts a vacation process String user = "Zhang San"; String approve = "Leader Li Si"; // startLeaveProcess(user,"leave"); //Zhang Sanquery his own process // queryLeaveProcessING(user); // Submitted to Leader Li Si for Review // String taskId = "34f8958d-0d07-11ea-b319-9c5c8e7034f6"; // completeTask(approve,taskId); //Leader Li Si inquires about his own process // queryLeaveProcessING(approve); //Li Si submits his own process completeTask(approve,"e60702be-0d08-11ea-8a0a-9c5c8e7034f6",1); //Zhang San Queries His Historical Process // queryHistoryTask(userKey); } /** * Start a leave process * @param user User key * @param processDefinitionKey Flowchart key Each process has a corresponding key This is fixed within a process written in bpmn */ void startLeaveProcess(String user,String processDefinitionKey){ System.out.println(user+"Start a leave process:"+ processDefinitionKey); HashMap<String, Object> variables=new HashMap<>(); variables.put("user", user);//userKey is specified in the process variable above ProcessInstance instance = runtimeService .startProcessInstanceByKey(processDefinitionKey,variables); System.out.println("Process Instances ID:"+instance.getId()); System.out.println("Process Definition ID:"+instance.getProcessDefinitionId()); System.out.println("=================================================================="); } /** * Query current task process */ void queryLeaveProcessING(String assignee){ System.out.println(assignee+"Query your current process:"); List<Task> list = taskService.createTaskQuery()//Create Task Query Object .taskAssignee(assignee)//Specify Personal Task Query .list(); if(list!=null && list.size()>0){ for(Task task:list){ System.out.println("task ID:"+task.getId()); System.out.println("Task Name:"+task.getName()); System.out.println("Task creation time:"+task.getCreateTime()); System.out.println("Task Manager:"+task.getAssignee()); System.out.println("Process Instances ID: "+task.getProcessInstanceId()); System.out.println("target of execution ID:"+task.getExecutionId()); System.out.println("Process Definition ID:"+task.getProcessDefinitionId()); Map<String, Object> map = task.getProcessVariables(); for (Map.Entry<String, Object> m : map.entrySet()) { System.out.println("key:" + m.getKey() + " value:" + m.getValue()); } for (Map.Entry<String, Object> m : task.getTaskLocalVariables().entrySet()) { System.out.println("key:" + m.getKey() + " value:" + m.getValue()); } } } System.out.println("=================================================================="); } @Test void completeTask(String approve,String taskId){ System.out.println(approve+": Submit your own process:"+taskId); //Task ID HashMap<String, Object> variables=new HashMap<>(); variables.put("approve", approve);//userKey is specified in the process variable above taskService.complete(taskId,variables); System.out.println("Complete Task: Task ID: "+taskId); System.out.println("=================================================================="); } @Test void completeTask(String user,String taskId,int audit){ System.out.println(user+": Submit your own process:"+taskId+" ;Pass or not:"+audit); //Task ID HashMap<String, Object> variables=new HashMap<>(); variables.put("audit", audit);//userKey is specified in the process variable above taskService.complete(taskId,variables); System.out.println("Complete Task: Task ID: "+taskId); System.out.println("=================================================================="); } @Test void queryHistoryTask(){ List<HistoricTaskInstance> list=historyService // History-related Service s .createHistoricTaskInstanceQuery() // Create Historical Activity Instance Query .processInstanceId("34f2f038-0d07-11ea-b319-9c5c8e7034f6") // Execution process instance id .orderByTaskCreateTime() .asc() .list(); for(HistoricTaskInstance hai:list){ System.out.println("activity ID:"+hai.getId()); System.out.println("Process Instances ID:"+hai.getProcessInstanceId()); System.out.println("Activity name:"+hai.getName()); System.out.println("Handler:"+hai.getAssignee()); System.out.println("Start time:"+hai.getStartTime()); System.out.println("End time:"+hai.getEndTime()); System.out.println("=================================================================="); } // List<HistoricTaskInstance> list = historyService.createHistoricTaskInstanceQuery(). taskAssignee("Zhang San"). orderByTaskCreateTime().asc().list(); // for(HistoricTaskInstance hai:list){ // System.out.println("Activity ID:"+hai.getId())); // System.out.println("Process Instance ID:"+hai.getProcessInstanceId())); // System.out.println("Activity name:"+hai.getName())); // System.out.println("Administrator:"+hai.getAssignee())); // System.out.println("Start time:"+hai.getStartTime())); // System.out.println("End time:"+hai.getEndTime())); // System.out.println("=================================================================="); // } } }