I had read a lot of books about Activiti in the library before, but I didn’t know what it was. I only knew that it was just the same word as Activity in Android, and I naivedly thought that it would not be used in the future. However, I was asked to learn Activiti on the first day of my internship. So take note, and I’ll show you two small cases to get in the door.
Introduction of Activiti
Activiti is a lightweight Java-centric open source BPMN engine that publishes designed process definitions and schedules processes through apis to meet real-world process automation needs.
BPMN is a common and standard language for process modeling. It is used to draw business flow diagrams to better understand business processes and relationships between departments, and to facilitate communication and understanding of business processes.
For Java developers, Activiti’s lead architect Tom Baeyens mentioned that the first goal of Activiti is to get developers on board. Activiti can also be used as a standalone server. Activiti also provides many advanced BPM tools, including the development of collaboration tools. This enables developers, business people, and operation and maintenance personnel to work together better.
Here’s an overview of Activiti’s various services:
- RepositoryService: Definition files, deployment files, and supporting data (such as BPMN2.0 XML files, form definition files, process definition image files, and so on) are required for each different version of the business process definition in Activiti. These files are stored in Activiti’s built-in Repository. The Repository Service provides access to a Repository.
- RuntimeService: In Activiti, each time a process definition is started, an instance of the corresponding process object is generated. The Runtime Service provides the functions of starting processes, querying process instances, and setting and obtaining process instance variables. It also provides access services for process deployment, process definition, and process instances.
- TaskService: In Activiti, each execution node in a business process definition is called a Task. Data access, state changes, and other operations in the process are performed in the Task. The Task Service provides operations on user tasks and forms. It provides run-time task query, fetch, complete, delete and variable setting functions.
- IdentityService: Activiti provides built-in user and group management. Users and groups must be used to retrieve tasks. Identity Service provides the ability to manage users and groups in Activiti systems.
- ManagementService: ManagementService provides the Management and maintenance functions of the Activiti process engine. These functions are not used in workflow-driven applications and are mainly used for routine maintenance of the Activiti system.
- HistoryService: HistoryService is used to get information about running or completed process instances. Unlike process information obtained in Runtime Service, History information contains persistent information that has been persisted and optimized for queries.
- FormService: Processes and status tasks in Activiti can be associated with business-related data. Using Form Services, you can access the Form data needed to start and complete tasks and render the Form as needed.
(Workflows are always in the form of tasks that drive people to process a business or that drive a business system to automate a job.)
BPMN process definition
You can use one of the official tools to design the BMPN workflow flow chart. After downloading it, put it under tomcat webapps, and then start Tomcat. The login interface is shown below, with user name admin and password test respectively.
Once you go in, select the first one, and then Create Process.
Next, let’s do a simple process. Now let’s assume that Xiao Ming does his homework first and then plays games when he gets home in the evening. Let’s write a program according to this process.
Once we’ve drawn it, we download it as an XML file. We won’t tell you how to download it, but we put it in the Resources/Processes path. The activiti-app tool is actually used to generate the following data.
Activiti-test.bpmn20.xml reads as follows:
<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="activiti-test" name="activiti-test" isExecutable="true">
<documentation>activiti-test</documentation>
<startEvent id="start" name="Start"></startEvent>
<endEvent id="end" name="The end"></endEvent>
<userTask id="user_task1" name="Do your homework" activiti:assignee="${user}"></userTask>
<userTask id="user_task2" name="Play video games" activiti:assignee="${user}"></userTask>
<sequenceFlow id="sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C" sourceRef="start" targetRef="user_task1"></sequenceFlow>
<sequenceFlow id="sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B" sourceRef="user_task1" targetRef="user_task2"></sequenceFlow>
<sequenceFlow id="sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0" sourceRef="user_task2" targetRef="end"></sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_activiti-test">
<bpmndi:BPMNPlane bpmnElement="activiti-test" id="BPMNPlane_activiti-test">
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
<omgdc:Bounds height="30.0" width="30.0" x="100.0" y="163.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
<omgdc:Bounds height="28.0" width="28.0" x="662.5" y="164.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="user_task1" id="BPMNShape_user_task1">
<omgdc:Bounds height="80.0" width="100.0" x="236.5" y="138.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="user_task2" id="BPMNShape_user_task2">
<omgdc:Bounds height="80.0" width="100.0" x="435.0" y="138.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0" id="BPMNEdge_sid-9CC4C5EC-9D5E-47F3-BEF4-94D268E004E0">
<omgdi:waypoint x="535.0" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="662.5" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B" id="BPMNEdge_sid-5E51BC0F-5775-4727-8DD4-5325575BAC7B">
<omgdi:waypoint x="336.5" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="435.0" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C" id="BPMNEdge_sid-50EF2A93-83CE-44ED-AA41-F1A8F7ADE00C">
<omgdi:waypoint x="130.0" y="178.0"></omgdi:waypoint>
<omgdi:waypoint x="236.5" y="178.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
Copy the code
Introduction to Basic Concepts
A business process consists of the following parts:
- Events
Events are used to indicate what happened during the life cycle of a process. Events are always drawn in a circle, and there are two main categories of events in BPMN 2.0:
- Catching events. When the process executes to this event, it interrupts execution and waits to be fired
- Throwing) events. When the process executes to the event, a result is thrown
The representative graph is as follows:
- Gateways
Gateway is a process definition element in the BPMN2 specification, which can be called “Gateway”, “decision” or “judgment” in Chinese. Gateways are used to control the flow of execution, generating tokens when paths are split and consuming tokens when paths are merged. Common gateways can be divided into exclusive gateway (XOR), parallel gateway (AND) AND inclusive gateway (OR), representing the following graph:
- Activities
Activities are the core elements of business process definition, which can be called “Activities”, “nodes” or “steps” in Chinese. An activity can be a basic processing unit (such as human task, service task) or a composite unit (such as external subprocess, nested subprocess) in a process, representing the following graph:
Rely on
There may be another dependency in other articles called Activiti-spring-boot-starter-basic. I don’t know the difference, but I’ve tested both and can use either.
Not adding security here will cause an error, and the @SpringBootApplication annotation of the startup class will also exclude two classes.
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0. M6</version>
</dependency>
<dependency>
Copy the code
@SpringBootApplication(exclude = {SecurityAutoConfiguration.class, ManagementWebSecurityAutoConfiguration.class})
public class SpringBootDemoApplication {
public static void main(String[] args) { SpringApplication.run(SpringBootDemoApplication.class, args); }}Copy the code
Configuring the Database
Since the data is also stored in the database, you also need to configure the database information and activiti information under Application.properties.
spring.datasource.url=jdbc:mysql://localhost:3306/test? useUnicode=true&characterEncoding=utf-8&serverTimezone=GMT%2B8&autoReconnect=true spring.datasource.driver-class-name=com.mysql.jdbc.Driver spring.datasource.username=root spring.datasource.password=h spring.activiti.database-schema-update=true spring.activiti.process-definition-location-prefix=classpath:/processes/ spring.activiti.db-history-used=true spring.activiti.check-process-definitions=true spring.activiti.history-level=auditCopy the code
When started, many tables are generated in the database
The controller
package com.hxl.springbootdemo.activiti;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class ActivitiController {
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
/** * Start the process instance *@param userName
* @return* /
@GetMapping("start")
public String start(@RequestParam String userName){
Map<String, Object> map = new HashMap<>();
map.put("user", userName);
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activiti-test", map);
return "OK";
}
/** * Get task *@param userName
* @return* /
@GetMapping("tasks")
public String tasks(@RequestParam String userName){
List<Task> list = taskService.createTaskQuery().taskAssignee(userName).list();
return list.toString();
}
/** * Complete the task *@paramId Task ID *@return* /
@GetMapping("completetask")
public String completeTask(@RequestParam String id) {
taskService.complete(id);
return "Complete this task."; }}Copy the code
Tests & Results
Xiao Ming http://localhost:8081/start?userName=
Start the process
OK
Copy the code
Xiao Ming http://localhost:8081/tasks?userName=
Access to task
[Task[id= b56be675-45B0-11EB-92B2-0242151ab6eb, name= Task]]Copy the code
http://localhost:8081/completetask?id=b56be675-45b0-11eb-92b2-0242151ab6eb
To complete the task
Complete this taskCopy the code
Xiao Ming http://localhost:8081/tasks?userName=
Retrieve task
[Task[id= CC3296b9-45B0-11EB-92B2-0242151ab6eb, name= game]]Copy the code
Leave process design
In this figure, the first step is for the user to submit the leave information, and then judge the leave duration. If it is greater than or equal to 3 days, the leave duration will be approved by the dean; if it is less than 3 days, the approval will be approved by the class manager. Conditional judgment is used here. To add a condition, you can click on the pointing line in the UI and add it in the Flow Condition column.
<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="activiti-leave" name="activiti-leave" isExecutable="true">
<documentation>activiti-leave</documentation>
<startEvent id="start" name="Start"></startEvent>
<userTask id="user_task1" name="Submit leave" activiti:assignee="#{user}">
<extensionElements>
<activiti:formProperty id="new_property_1" name="userName" type="string"></activiti:formProperty>
<activiti:formProperty id="new_property_2" name="day" type="long"></activiti:formProperty>
<activiti:formProperty id="new_property_3" name="tel" type="string"></activiti:formProperty>
<activiti:formProperty id="new_property_4" name="content" type="string"></activiti:formProperty>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><! [CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-055C2D31-C86C-4788-B373-D378575B98DC" sourceRef="start" targetRef="user_task1"></sequenceFlow>
<userTask id="task_2" name="Head teacher Audit" activiti:assignee="banren">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><! [CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<exclusiveGateway id="sid-7230A3CF-B4DC-416F-AC22-21117F684115"></exclusiveGateway>
<endEvent id="end" name="The end"></endEvent>
<userTask id="task_3" name="Dean" activiti:assignee="yuanzhang">
<extensionElements>
<modeler:initiator-can-complete xmlns:modeler="http://activiti.com/modeler"><! [CDATA[false]]></modeler:initiator-can-complete>
</extensionElements>
</userTask>
<sequenceFlow id="sid-31E21674-09F8-4AB8-8672-CF08043EDD21" sourceRef="user_task1" targetRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115"></sequenceFlow>
<sequenceFlow id="sid-D7DD5340-DE9B-4436-8F94-748A8933AC81" sourceRef="task_3" targetRef="end"></sequenceFlow>
<sequenceFlow id="sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB" sourceRef="task_2" targetRef="end"></sequenceFlow>
<sequenceFlow id="sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3" sourceRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115" targetRef="task_3">
<conditionExpression xsi:type="tFormalExpression"><! [CDATA[${day>=3}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0" sourceRef="sid-7230A3CF-B4DC-416F-AC22-21117F684115" targetRef="task_2">
<conditionExpression xsi:type="tFormalExpression"><! [CDATA[${day<3}]]></conditionExpression>
</sequenceFlow>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_activiti-leave">
<bpmndi:BPMNPlane bpmnElement="activiti-leave" id="BPMNPlane_activiti-leave">
<bpmndi:BPMNShape bpmnElement="start" id="BPMNShape_start">
<omgdc:Bounds height="30.0" width="30.0" x="75.0" y="115.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="user_task1" id="BPMNShape_user_task1">
<omgdc:Bounds height="80.0" width="100.0" x="171.5" y="90.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_2" id="BPMNShape_task_2">
<omgdc:Bounds height="80.0" width="100.0" x="480.0" y="180.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="sid-7230A3CF-B4DC-416F-AC22-21117F684115" id="BPMNShape_sid-7230A3CF-B4DC-416F-AC22-21117F684115">
<omgdc:Bounds height="40.0" width="40.0" x="345.0" y="110.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="end" id="BPMNShape_end">
<omgdc:Bounds height="28.0" width="28.0" x="660.0" y="116.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="task_3" id="BPMNShape_task_3">
<omgdc:Bounds height="80.0" width="100.0" x="480.0" y="15.0"></omgdc:Bounds>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="sid-31E21674-09F8-4AB8-8672-CF08043EDD21" id="BPMNEdge_sid-31E21674-09F8-4AB8-8672-CF08043EDD21">
<omgdi:waypoint x="271.5" y="130.0"></omgdi:waypoint>
<omgdi:waypoint x="345.0" y="130.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB" id="BPMNEdge_sid-45E0E489-E181-4EEC-B162-DE7F6747F5DB">
<omgdi:waypoint x="580.0" y="188.75"></omgdi:waypoint>
<omgdi:waypoint x="662.1280237439288" y="137.41998516004452"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3" id="BPMNEdge_sid-DDE1F19E-DC48-4797-8CDA-22261EF293D3">
<omgdi:waypoint x="379.2083333333333" y="124.20833333333333"></omgdi:waypoint>
<omgdi:waypoint x="480.0" y="77.9483282674772"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-055C2D31-C86C-4788-B373-D378575B98DC" id="BPMNEdge_sid-055C2D31-C86C-4788-B373-D378575B98DC">
<omgdi:waypoint x="105.0" y="130.0"></omgdi:waypoint>
<omgdi:waypoint x="171.5" y="130.0"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0" id="BPMNEdge_sid-D5171CDD-8C96-45F2-9E7B-34FF2683CEF0">
<omgdi:waypoint x="377.8051181102362" y="137.1948818897638"></omgdi:waypoint>
<omgdi:waypoint x="480.0" y="192.7963525835866"></omgdi:waypoint>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="sid-D7DD5340-DE9B-4436-8F94-748A8933AC81" id="BPMNEdge_sid-D7DD5340-DE9B-4436-8F94-748A8933AC81">
<omgdi:waypoint x="580.0" y="81.04166666666667"></omgdi:waypoint>
<omgdi:waypoint x="661.5832028216623" y="123.53291813628245"></omgdi:waypoint>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
Copy the code
The controller
package com.hxl.springbootdemo.activiti;
import org.activiti.engine.HistoryService;
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.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@RestController
public class ActivitiLeaveController {
private Map<String,String> map =new HashMap<>();
@Autowired
private TaskService taskService;
@Autowired
private RuntimeService runtimeService;
@Autowired
private HistoryService historyService;
/** * Historical tasks *@param userName
* @return* /
@GetMapping("history")
private List<HistoricTaskInstance> history(@RequestParam String userName){
List<HistoricTaskInstance> list1 = historyService.createHistoricTaskInstanceQuery().taskAssignee(userName).list();
return list1;
}
/** * Complete the task *@paramId Task ID *@return* /
@GetMapping("completetask")
public String completeTask(@RequestParam String id) {
taskService.complete(id);
return "Complete this task.";
}
/** * Get task *@param userName
* @return* /
@GetMapping("tasks")
public List<Map<String,Object>> tasks(@RequestParam String userName){
List<Map<String,Object>> result =new ArrayList<>();
List<Task> list = taskService.createTaskQuery().taskAssignee(userName).list();
for (Task task : list) {
Map<String,Object> map =new HashMap<>();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(task.getProcessInstanceId())
.singleResult();
Map<String, Object> variables = runtimeService.getVariables(processInstance.getId());
map.put("Days off",variables.get("day"));
map.put("Leave person",variables.get("user"));
map.put("Mobile phone Number",variables.get("tel"));
map.put("Content",variables.get("content"));
map.put("taskInfo",task.toString());
result.add(map);
}
return result;
}
@PostMapping("leave")
public String leave(@RequestParam String userName,
@RequestParam int day,
@RequestParam String tel,
@RequestParam String content) {
Map<String, Object> objectObjectHashMap = new HashMap<>();
objectObjectHashMap.put("user", userName);
objectObjectHashMap.put("day", day);
objectObjectHashMap.put("content",content);
objectObjectHashMap.put("tel",tel);
/** * Create a process instance */
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("activiti-leave", objectObjectHashMap);
runtimeService.setVariables(processInstance.getId(),objectObjectHashMap);
Task task = taskService.createTaskQuery().processInstanceId(processInstance.getId())
.singleResult();
map.put(userName,processInstance.getId());
System.out.println(task);
taskService.complete(task.getId(),objectObjectHashMap);
return "Commit successfully id="+ task.getId(); }}Copy the code
Tests & Results
1. Submit information at http://localhost:8081/leave
Here I submit two, one xiao Ming asking for a leave of 1 day and one Xiao Zhang asking for a leave of 10 days.
Id = 7EC509E1-45C8-11EB-8238-0242151 AB6EBCopy the code
2.http://localhost:8081/tasks? UserName =banren Displays the task of the class
Xiao Ming asked for a day’s leave, so it was reviewed by the head teacher
[{" cell phone number ": "15048879423", "taskInfo": "Task[id= 7ed42519-45C8-11EB-8238-0242159AB6EB, name= 7ed42519-45C8-11EB-8238-0242159AB6EB, "content ": "A "," days of leave ": 1}]Copy the code
3.http://localhost:8081/completetask? Id = 7ED42519-45C8-11EB-8238-0242151 AB6EB Shift manager has completed the approval
Complete this taskCopy the code
4.http://localhost:8081/tasks? UserName =yuanzhang View dean task
[{" phone number ": "150XXXXXXXX ", "taskInfo": "Task[id= f2CF9CD0-45C8-11EB-8238-02421515AB6EB, name= dean]"," leave person ": "xiaozhang "," content ": "Take a wife "," leave days ": 10}]Copy the code
5.http://localhost:8081/completetask? Id = F2CF9CD0-45C8-11EB-8238-0242151 Ab6EB dean completes approval
Complete this taskCopy the code
Xiao Ming http://localhost:8081/history?userName=
See the history
[ { "id": "7ec509e1-45c8-11eb-8238-0242151ab6eb", "processInstanceId": "7ec298d9-45c8-11eb-8238-0242151ab6eb", "processDefinitionId": "Activiti - leave: 1-0 d8b4a47-45 c8-11 eb - 8238-0242151 ab6eb", "startTime" : "the 2020-12-24 T09:14:58. 755 + 00:00", "endTime" : "2020-12-24T09:14:58.845+00:00", "durationInMillis": 90, "executionId": "7EC30E0E-45C8-11EB-8238-0242151 AB6EB ", "name": "Submitted leave ", "assignee":" xiaoming ", "taskDefinitionKey": "user_task1", "priority": 50, "tenantId": "", "time": "The 2020-12-24 T09:14:58. 755 + 00:00", "createTime" : "the 2020-12-24 T09:14:58. 755 + 00:00", "persistentState" : { "taskDefinitionKey": "user_task1", "processDefinitionId": "Activiti-leave: 1:0D8B4A47-45C8-11EB-8238-0242151 AB6EB ", "durationInMillis": 90, "name":" submitted leave ", "assignee": "EndTime ": "2020-12-24T09:14:58.845+00:00", "priority": 50}, "processVariables": {}, "taskLocalVariables": {}, "deleted": false, "inserted": false, "updated": false } ]Copy the code