1. What is activiti?
Activiti is a workflow engine, which can extract complex business processes from the business system and define them using the special modeling language BPMN 2.0, and the business processes are executed according to the pre-defined processes, so as to realize the management of the process flow of the system, reduce the workload of upgrading the business system due to process changes, thereby improving the robustness of the system, and also reducing the cost of system development and maintenance.
Activiti’s core service components
- RepositoryService: provides a series of management process deployments and process definitionsAPI。
- RuntimeService: manages and controls process instances while the process is running.
- TaskService: manages process tasks, such as task reminders, task completion, and task creation.
- IdentityService: Provides an API for managing process role data, including user groups, users, and the relationships between them.
- ManagementService: provides services that manage and maintain the process engine.
- HistoryService: Perform operations on the historical data of the process, including querying and deleting the historical data.
- FormService: a form service.
Business process model BPMN xml configuration file
An XML file, and Activiti parses it to understand what we’re trying to do. You can use the ideal plugin [Activiti BPMN visualizer] to edit this file, and the specific use of the plugin can be googled, so I won’t describe it here
2. MySQL database environment construction
Why do you need MySQL?
This is because activiti generates a lot of tables for process executions. Tables are all ACT At the beginning, it is used to record the recorded data generated by the workflow! This is shown in the figure below
Introduction to the table structure,forexample
Install
docker run --name docker-mysql-5.7 -e MYSQL_ROOT_PASSWORD=123456 -p 3306:3306 -d mysql:5.7
initialize
create database activity;
Default user and password
msyql username:root
mysql password:123456
3. Code engineering
Purpose: to achieve process-driven
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<parent>
<artifactId>springboot-demo</artifactId>
<groupId>com.et</groupId>
<version>1.0-SNAPSHOT</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<artifactId>activiti</artifactId>
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-autoconfigure</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>6.0.0</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
</dependencies>
</project>
application.properties
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
spring.datasource.url=jdbc:mysql://127.0.0.1:3306/activity?characterEncoding=utf8&useSSL=true
spring.datasource.username=root
spring.datasource.password=123456
spring.jpa.properties.hibernate.hbm2ddl.auto=update
spring.jpa.show-sql=true
server.session.timeout=10
server.tomcat.uri-encoding=UTF-8
server.port=8088
test.bpmn20.xml
<?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" xmlns:dc="http://www.omg.org/spec/DD/20100524/DC" xmlns:di="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/testm1510735932336" id="m1510735932336" name="">
<process id="leave" isExecutable="true" isClosed="false" processType="None">
<startEvent id="_2" name="StartEvent"/>
<endEvent id="_3" name="EndEvent"/>
<userTask id="approve" name="manager approve" activiti:assignee="${approve}"/>
<exclusiveGateway id="_5" name="ExclusiveGateway"/>
<sequenceFlow id="_6" sourceRef="approve" targetRef="_5"/>
<sequenceFlow id="_7" name="pass" sourceRef="_5" targetRef="_3">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${pass}]]></conditionExpression>
</sequenceFlow>
<userTask id="application" name="apply submit" activiti:assignee="${apply}"/>
<sequenceFlow id="_9" sourceRef="_2" targetRef="application"/>
<sequenceFlow id="_10" sourceRef="application" targetRef="approve"/>
<userTask id="modify" name="modify apply" activiti:assignee="${apply}"/>
<sequenceFlow id="_12" name="fail " sourceRef="_5" targetRef="modify">
<conditionExpression xsi:type="tFormalExpression"><![CDATA[${!pass}]]></conditionExpression>
</sequenceFlow>
<sequenceFlow id="_13" sourceRef="modify" targetRef="approve"/>
</process>
<bpmndi:BPMNDiagram id="BPMNDiagram_leave">
<bpmndi:BPMNPlane bpmnElement="leave" id="BPMNPlane_leave">
<bpmndi:BPMNShape bpmnElement="_2" id="BPMNShape__2">
<omgdc:Bounds height="35.0" width="35.0" x="15.0" y="60.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_3" id="BPMNShape__3">
<omgdc:Bounds height="35.0" width="35.0" x="630.0" y="63.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="approve" id="BPMNShape_approve">
<omgdc:Bounds height="55.0" width="85.0" x="315.0" y="50.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="_5" id="BPMNShape__5">
<omgdc:Bounds height="40.0" width="40.0" x="505.0" y="60.5"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="application" id="BPMNShape_application">
<omgdc:Bounds height="55.0" width="85.0" x="135.0" y="50.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNShape bpmnElement="modify" id="BPMNShape_modify">
<omgdc:Bounds height="55.0" width="85.0" x="315.0" y="150.0"/>
</bpmndi:BPMNShape>
<bpmndi:BPMNEdge bpmnElement="_6" id="BPMNEdge__6">
<omgdi:waypoint x="400.0" y="77.0"/>
<omgdi:waypoint x="505.0" y="80.5"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_7" id="BPMNEdge__7">
<omgdi:waypoint x="545.0" y="80.5"/>
<omgdi:waypoint x="630.0" y="80.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_9" id="BPMNEdge__9">
<omgdi:waypoint x="50.0" y="77.0"/>
<omgdi:waypoint x="135.0" y="77.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_10" id="BPMNEdge__10">
<omgdi:waypoint x="220.0" y="77.0"/>
<omgdi:waypoint x="315.0" y="77.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_12" id="BPMNEdge__12">
<omgdi:waypoint x="525.0" y="100.5"/>
<omgdi:waypoint x="525.0" y="177.0"/>
<omgdi:waypoint x="400.0" y="177.0"/>
</bpmndi:BPMNEdge>
<bpmndi:BPMNEdge bpmnElement="_13" id="BPMNEdge__13">
<omgdi:waypoint x="357.0" y="150.0"/>
<omgdi:waypoint x="357.0" y="105.0"/>
</bpmndi:BPMNEdge>
</bpmndi:BPMNPlane>
</bpmndi:BPMNDiagram>
</definitions>
controller
package com.et.activiti.controller;
import com.et.activiti.service.ActivityConsumerService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import java.util.HashMap;
import java.util.Map;
@RestController
public class HelloWorldController {
@Autowired
ActivityConsumerService activityConsumerService;
@RequestMapping(value="/startActivityDemo",method= RequestMethod.GET)
public boolean startActivityDemo(){
return activityConsumerService.startActivityDemo();
}
}
service
package com.et.activiti.service;
import org.activiti.engine.task.TaskQuery;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
public interface ActivityConsumerService {
public boolean startActivityDemo();
}
package com.et.activiti.service;
import java.util.HashMap;
import java.util.Map;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.impl.persistence.entity.ExecutionEntity;
import org.activiti.engine.task.Task;
import org.activiti.engine.task.TaskQuery;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service
public class ActivityConsumerServiceImpl implements ActivityConsumerService {
@Autowired
private RuntimeService runtimeService;
@Autowired
private TaskService taskService;
@Override
public boolean startActivityDemo() {
System.out.println("method startActivityDemo begin....");
Map<String, Object> map = new HashMap<String, Object>();
map.put("apply", "zhangsan");
map.put("approve", "lisi");
//flow start
ExecutionEntity pi1 = (ExecutionEntity) runtimeService.startProcessInstanceByKey("leave", map);
String processId = pi1.getId();
pi1.getExecutions().forEach(row->{
String taskId = row.getTasks().get(0).getId();
taskService.complete(taskId, map);//complete first step
Task task = taskService.createTaskQuery().processInstanceId(processId).singleResult();
String taskId2 = task.getId();
map.put("pass", false);
taskService.complete(taskId2, map);//refuse apply
System.out.println("method startActivityDemo end....");
});
return false;
}
}
The above are just some key codes. For all codes, please see the code repository below.
code repository
4. Testing
- Start the Spring Boot application
- Visit http://127.0.0.1:8088/startActivityDemo
You may need to login first, because activiti integrates Spring security by default, the default username user, and password are automatically generated when the program starts, as shown below
Using generated security password: 86f027ef-93c2-46ee-a054-c1ada840e64d