preface

Creating an Activiti workflow consists of the following steps:

1, define the process, according to the SPECIFICATION of BPMN, use the process definition tool, use the process symbol to describe the whole process

2. Deploy the process, load the drawn process definition file into the database, and generate the data of the table

3. Start the process and use Java code to manipulate the contents of the database table

1. Create a flow chart

Last time we set up the basic framework, this time we will do it:

By default, Activiti processes files are stored in the Processes folder of the Resource directory.

1. Create a processes folder

2. Draw flow charts

Because we used the STS development tool and installed the Activiti Designer plug-in, we could then draw the flowchart.

Right-click above the Processes folder and create the Activiti Designer process Designer.

Go to the next step, and when you’re done it will pop up this canvas, flow Designer, and we can draw our flow chart.

Once we have drawn our flow chart, we need to set the KEY (ID) for the flow. This is important:

With the ID and name set, we need to set the owner of each task node:

The same is true for the other two nodes. We set the manager approval as Li Si, and the chairman approval as Wang Wu. Just hit Save and we’ve generated the BPMN file. Now we’re going to regenerate it into a PNG file. Just hit Export PNG and copy it to processes.

Create leave application: Zhang SAN Manager approval: Li Si Chairman approval: Wang Wu

3. Complete XML files


      
<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/test">
  <process id="myProcess" name="Leave Approval Process" isExecutable="true">
    <startEvent id="startevent1" name="Start"></startEvent>
    <userTask id="usertask1" name="Application for Leave" activiti:assignee="Zhang"></userTask>
    <sequenceFlow id="flow1" sourceRef="startevent1" targetRef="usertask1"></sequenceFlow>
    <userTask id="usertask2" name="Manager approval" activiti:assignee="Bill"></userTask>
    <sequenceFlow id="flow2" sourceRef="usertask1" targetRef="usertask2"></sequenceFlow>
    <userTask id="usertask3" name="Chairman's Approval" activiti:assignee="Fifty"></userTask>
    <sequenceFlow id="flow3" sourceRef="usertask2" targetRef="usertask3"></sequenceFlow>
    <endEvent id="endevent1" name="End"></endEvent>
    <sequenceFlow id="flow4" sourceRef="usertask3" targetRef="endevent1"></sequenceFlow>
  </process>
  <bpmndi:BPMNDiagram id="BPMNDiagram_myProcess">
    <bpmndi:BPMNPlane bpmnElement="myProcess" id="BPMNPlane_myProcess">
      <bpmndi:BPMNShape bpmnElement="startevent1" id="BPMNShape_startevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="260.0" y="240.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask1" id="BPMNShape_usertask1">
        <omgdc:Bounds height="55.0" width="105.0" x="340.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask2" id="BPMNShape_usertask2">
        <omgdc:Bounds height="55.0" width="105.0" x="490.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="usertask3" id="BPMNShape_usertask3">
        <omgdc:Bounds height="55.0" width="105.0" x="640.0" y="230.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNShape bpmnElement="endevent1" id="BPMNShape_endevent1">
        <omgdc:Bounds height="35.0" width="35.0" x="790.0" y="240.0"></omgdc:Bounds>
      </bpmndi:BPMNShape>
      <bpmndi:BPMNEdge bpmnElement="flow1" id="BPMNEdge_flow1">
        <omgdi:waypoint x="295.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="340.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow2" id="BPMNEdge_flow2">
        <omgdi:waypoint x="445.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="490.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow3" id="BPMNEdge_flow3">
        <omgdi:waypoint x="595.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="640.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
      <bpmndi:BPMNEdge bpmnElement="flow4" id="BPMNEdge_flow4">
        <omgdi:waypoint x="745.0" y="257.0"></omgdi:waypoint>
        <omgdi:waypoint x="790.0" y="257.0"></omgdi:waypoint>
      </bpmndi:BPMNEdge>
    </bpmndi:BPMNPlane>
  </bpmndi:BPMNDiagram>
</definitions>
Copy the code

The second Service overview

The name of the service The service function
RepositoryService Activiti’s resource management class
RuntimeService Activiti’s process run management class
TaskService Activiti’s task management class
HistoryService Activiti’s history management class
ManagerService Activiti’s engine management class

Brief introduction:

RepositoryService

Activiti resource Management class provides management and control of process distribution packages and process-defined operations. A business flowchart designed using a workflow modeling tool requires the service to deploy the contents of the process definition file to a computer.

RuntimeService

Activiti’s process run management class. You can get a lot of information about process execution from this service class

TaskService

Activiti’s task management class. You can get information about tasks from this class.

HistoryService

Activiti’s history management class allows you to query historical information. When a process is executed, the engine stores a lot of data (depending on the configuration), such as when the process instance started, who participated in the task, when the task was completed, the execution path of each process instance, and so on. The service obtains this data mainly through the query function.

ManagementService

Activiti’s Engine Management class provides management and maintenance capabilities for the Activiti process engine, which are not used in workflow-driven applications and are primarily used for routine maintenance of the Activiti system.

3. Deployment process


@Autowired  
private RepositoryService repositoryService; 
@Autowired  
private RuntimeService runtimeService;  
@Autowired  
private TaskService taskService;

/** * Deployment process (deploy BPMN and PNG files to the database) *@return* /
@GetMapping("deployment")
public Map<String, Object> deployment(a) { 
Deployment deployment = repositoryService.createDeployment()
		.name("Deployment Leave Application Process")
		.addClasspathResource("processes/MyProcess.bpmn")
		.addClasspathResource("processes/MyProcess.png")
		.deploy();

Map<String, Object> map = new HashMap<>();
map.put("msg"."->>> Application for leave deployment successful!");
map.put("Deployment Process ID:", deployment.getId());
map.put("Deployment Process Name :", deployment.getName());
map.put("Deployment time :", deployment.getDeploymentTime());
return map;
}
Copy the code

1. Involved table

Classification table The name of the table explain
General data
[act_ge_bytearray] Common process definitions and process resources
[act_ge_property] System related Attributes
Process definition table
[act_re_deployment] Deployment Unit Information
[act_re_procdef] Deployed process definitions
## 2. Deployment analysis

Act_re_deployment: Process deployment table, with one record added for each deployment.

There is a one-to-many relationship between act_RE_Deployment table and ACT_RE_procdef table. In act_RE_procdef table, there are multiple information, such as Zhang SAN’s leave application or Li SAN’s leave application. Each record corresponds to the definition information of a process.

Fourth, query process definition

Core: Query the act_re_procdef table information based on the deployment process ID

@GetMapping("getSingle")
public Map<String, Object> getSingle(a) {
	// Get the process definition
	String deploymentId = "1";
	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
	Map<String, Object> map = new HashMap<>();
	map.put("id", processDefinition.getId());
	map.put("name", processDefinition.getName());
	map.put("key", processDefinition.getKey());
	map.put("des", processDefinition.getDescription());
	map.put("version", processDefinition.getVersion());
	map.put("deploymentId", processDefinition.getDeploymentId());
	map.put("resourceName", processDefinition.getResourceName());
	return map;
}
Copy the code

5. Start the process instance

//1. Start the process definition and return the process instance
ProcessInstance pi = runtimeService.startProcessInstanceById(processDefinition.getId());
// start with the process instance Key
runtimeService.startProcessInstanceByKey(processDefinition.getKey());
Copy the code

Start the process instance according to the ID or KEY defined by the process.

/** * Start the process instance *@return* /
@PostMapping("startProcess")
public Map<String, Object> startProcess(a) {
// Get the process instance ID
String deploymentId = "1";
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().deploymentId(deploymentId).singleResult();
String processId = processDefinition.getId();
//1. Start the process definition and return the process instance
ProcessInstance pi = runtimeService.startProcessInstanceById(processId);
Map<String, Object> map = new HashMap<>();
map.put("Process created successfully, current process instance ID:", pi.getId());
return map;
}
Copy the code

1. Involved table

Classification table The name of the table explain
General data
[act_ge_property] System related Attributes
Process history
[act_hi_actinst] Historical process instances
[act_hi_identitylink] History of user relationships during process runs
[act_hi_procinst] Historical process instances
[act_hi_taskinst] Historical task instances
Run instance table
[act_ru_execution] Runtime process execution instance
[act_ru_identitylink] Runtime user relationship information, which stores information about task nodes and participants
[act_ru_task] Runtime task

2. Start process analysis

For this process, starting a process means launching a new application for leave, which is equivalent to the relationship between Java class and Java object. After the class is defined, it is necessary to create a new object to use, of course, multiple objects can be new. For the application process of asking for leave, if Zhang SAN initiates a request for leave, it is necessary to start a process instance. Request for Leave Initiating a request for leave also requires starting a process instance.

6. Task query

Here taskService provides a number of query methods:

/** * query my to-do list *@param name
 * @return* /
@GetMapping("myTask")
public Map<String, Object> myTask(String id) {
	//1. Query tasks based on task IDS
	Task task = taskService.createTaskQuery().taskId(id).singleResult();
	
    Map<String, Object> map = new HashMap<>();
	map.put("Process instance ID:", task.getProcessInstanceId());
	map.put("The task ID.", task.getId());
	map.put("Mission leader :", task.getAssignee());
	map.put("Task Name :", task.getName());
	return map;
}
Copy the code
/** * query my to-do list *@param name
 * @return* /
@GetMapping("myTaskByName")
public Map<String, Map<String, Object>> myTaskByName(String name) {
	// My to-do list
	List<Task> taskList = taskService.createTaskQuery()
			/ / process the Key
			.processDefinitionKey("myProcess") 
			// Query only the tasks of the task owner
            .taskAssignee(name)						
            .list();
	
	// Display the task list
	Map<String, Map<String, Object>> maps = new HashMap<>();
       for(Task task : taskList){
           Map<String, Object> map = new HashMap<>();
   		map.put("Process instance ID:", task.getProcessInstanceId());
   		map.put("The task ID.", task.getId());
   		map.put("Mission leader :", task.getAssignee());
   		map.put("Task Name :", task.getName());
   		maps.put("data", map);
       }
	return maps;
}
Copy the code

7. Node approval

/** * process tasks *@param name
 * @return* /
@PostMapping("startTask")
public Map<String, Object> startTask(String name) {
	//1. My to-do list
	Task task = taskService.createTaskQuery()
			.processDefinitionKey("myProcess")
			.taskAssignee(name)
			.singleResult();
	
	//2, my task list display
	Map<String, Object> map = new HashMap<>();
	map.put("Process instance ID:", task.getProcessInstanceId());
	map.put("The task ID.", task.getId());
	map.put("Mission leader :", task.getAssignee());
	map.put("Task Name :", task.getName());
	map.put("msg", name + "->>> Submitted the task!");
	//3. Execute the approval process
	taskService.complete(task.getId());
	map.put("result1", name + "->>> Approval completed!");
	// query the next task point
	map.put("result2", name + "->>> Go to next task node!");
	List<Task> taskList = taskService.createTaskQuery().list();
	if(! taskList.isEmpty()) {for(Task task1 : taskList){
    		map.put("Process instance ID:", task1.getProcessInstanceId());
    		map.put("The task ID.", task1.getId());
    		map.put("Mission leader :", task1.getAssignee());
    		map.put("Task Name :", task1.getName()); }}else {
		map.put("msg"."The whole process approval task is over!!");
	}
	return map;
}
Copy the code

1. Involved table

Classification table The name of the table explain
General data
[act_ge_property] System related Attributes
Process history
[act_hi_actinst] Historical process instances
[act_hi_identitylink] History of user relationships during process runs
[act_hi_taskinst] Historical task instances
Run instance table
[act_ru_execution] Runtime process execution instance
[act_ru_identitylink] Runtime user relationship information, which stores information about task nodes and participants
[act_ru_task] Runtime task

2. Process and task processing

Update record of task table :(li si will process the next task)

Execution table update record :(next task node)

Add new records to hi_identitylink and ru_identitylink tables :(information about executed tasks, next task column ID, and node owner)

Add records to the taskinst table :(information about completed tasks, next task column ID, node owner, start time and end time, completed or not completed!!)

Add records to the actinst table :(information about tasks that have been executed, approval start time and end time in the approval process, and the next node owner and task ID)

Property table :(no process approval operation is performed, version number is updated plus 1)

Note: We proceed to the next task node:

Note: We finished executing the last node:

Viii. Completion of approval

When the approval is complete, all running instance tables are cleared.

And the ACT_HI_ACtinst table is a historical process instance that has recorded the entire approval process:

9. Process definition information query

/** * query all current process definitions */
@GetMapping("getAll")
public Map<String, Map<String, Object>> queryProcessDefinition(){
    //list returns the collection
    List<ProcessDefinition> definitionList = repositoryService.createProcessDefinitionQuery()
    		.processDefinitionKey("myProcess")
    		 .orderByProcessDefinitionVersion()
             .desc()
    		.list();
    // Output process definition information
    Map<String, Map<String, Object>> maps = new HashMap<>();
    for (ProcessDefinition processDefinition : definitionList) {
    	Map<String, Object> map = new HashMap<>();
        map.put("Process definition ID =",processDefinition.getId());
        map.put("Process definition name=",processDefinition.getName());
        map.put("Process definition key=",processDefinition.getKey());
        map.put("Process definition Version=",processDefinition.getVersion());
        map.put("Process Deployment ID =",processDefinition.getDeploymentId());
        maps.put("data", map);
    }
    return maps;
}
Copy the code

X. Deletion process

/** * delete process *@return* /
@PostMapping("deleteDeployment")
public Map<String, Object> deleteDeployment(a) {
	Map<String, Object> map = new HashMap<>();
	// Process deployment ID
	String deploymentId = "1";
	// Delete the process definition. If the process definition has an existing process instance started, the deletion will fail
	repositoryService.deleteDeployment(deploymentId, false);
	// Set true to cascade the process definition. The process can be deleted even if a process instance is started. Set false to non-level deletion
	//repositoryService.deleteDeployment(deploymentId, true);
	map.put("message"."Process ID is:"+deploymentId+"Deleted successfully");
	return map;
}
Copy the code

1) Use repositoryService to delete the process definition. All historical table information will not be deleted

2) If there is no running process under the process definition, you can use normal delete.

If running processes exist under the process definition, an error is reported using common deletion. You can delete all processes and related records using cascading deletion.

You can delete the process definition information completely by removing the incomplete process node first

The project development intermediate link deletion operation is generally available only to the super administrator.

Download deployed process resources

Before the process is deleted, our process resource files have been uploaded to the database and can be downloaded locally from the database if other users want to view these resource files.

1. Introduce dependencies

<! -- file IO -->
<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.6</version>
</dependency>
Copy the code

2. Download files

/** * Download the flow file and save it locally *@throws IOException
 */
@PostMapping("download")
public void  queryBpmnFile(a) throws IOException {
	// Get ProcessDefinitionQuery, set query criteria, get the desired process definition
	ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
          .processDefinitionKey("myProcess")
          .singleResult();
	//4. Obtain the deployment ID through the process definition information
	String deploymentId = processDefinition.getDeploymentId();
	//5. RepositoryService is used to repositoryService the image information and BPMN information
	// PNG image stream
	InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
	// Stream of BPMN files
	InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
	// create an OutputStream
	File file_png = new File("D:/myflow.png");
  	File file_bpmn = new File("D:/myflow.bpmn");
  	FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
  	FileOutputStream pngOut = new FileOutputStream(file_png);
  	// Input stream, output stream conversion
  	IOUtils.copy(pngInput,pngOut);
  	IOUtils.copy(bpmnInput,bpmnOut);
  	// Close the stream
  	pngOut.close();
  	bpmnOut.close();
  	pngInput.close();
  	bpmnInput.close();
 }
Copy the code

conclusion

That’s the end of the basics. This is a very important and fundamental post. From this post, we know that there are a lot of things we need to master in Activiti, and we need to get down to it and taste it.

Stay up late dry goods, creation is not easy, move small hands point praise !!!! Behind will continue to output more dry goods to you, like please pay attention to xiaobian CSDN: blog.csdn.net/qq_41107231 and nuggets: juejin.cn/user/394024…