Activiti 简介

Java 通用型工作流引擎:Activiti。

源代码:​​https://github.com/Activiti/Activiti​


Spring Boot 集成 Activiti 工作流引擎 极简教程_spring


Activiti is the leading lightweight, java-centric open-source BPMN engine supporting real-world process automation needs.

Activiti 项目是一项新的基于Apache许可的开源BPM平台,从基础开始构建,旨在提供支持新的BPMN 2.0标准。

Activiti 是一种轻量级,可嵌入的BPM引擎,而且还设计适用于可扩展的云架构。 Activiti将提供宽松的 Apache 许可2.0,同时促进Activiti BPM引擎和BPMN 2.0的匹配。

Activiti 的核心服务组件

1.RepositoryService:提供一系列管理流程部署和流程定义的API。
2.RuntimeService:在流程运行时对流程实例进行管理与控制。
3.TaskService:对流程任务进行管理,例如任务提醒、任务完成和创建任务等。
4.IdentityService:提供对流程角色数据进行管理的API,这些角色数据包括用户组、用户及它们之间的关系。
5.ManagementService:提供对流程引擎进行管理和维护的服务。
6.HistoryService:对流程的历史数据进行操作,包括查询、删除这些历史数据。
7.FormService:表单服务。

Activiti应用场景:

多人协作的(或者需要动态变动)的业务流程场景。


Spring Boot 集成 Activiti 工作流引擎 极简教程_spring_02


业务流程模型 BPMN xml 配置文件

一个xml文件,activiti去解析这个文件,了解我们到底想干什么事。

test01.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"
typeLanguage="http://www.w3.org/2001/XMLSchema" expressionLanguage="http://www.w3.org/1999/XPath"
targetNamespace="http://www.activiti.org/processdef">

<process id="test01" name="test01" isExecutable="true">
<startEvent id="sid-d0c54d06-2073-4018-8381-e5e43f1b5578" name="Start"/>

<serviceTask id="sid-0396a986-7e6b-4634-883b-1ee7db9aeb45"
activiti:exclusive="true"
name="Step1"
activiti:class="com.example.actividemo.ServiceTask1">
<extensionElements>
<activiti:field name="text1">
<activiti:string><![CDATA[test1]]></activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>

<sequenceFlow id="sid-05a29cc5-7a04-4282-be89-4d83f943774b" sourceRef="sid-d0c54d06-2073-4018-8381-e5e43f1b5578"
targetRef="sid-0396a986-7e6b-4634-883b-1ee7db9aeb45"/>

<serviceTask id="sid-c43c4370-4407-4746-893f-dcee3e4e9936"
activiti:exclusive="true"
name="Step2"
activiti:class="com.example.actividemo.ServiceTask2">
<extensionElements>
<activiti:field name="text2">
<activiti:string><![CDATA[test2]]></activiti:string>
</activiti:field>
</extensionElements>
</serviceTask>

<endEvent id="sid-665b6b28-9b81-4ab7-ba77-6eb50da3c810" name="End"/>
<sequenceFlow id="sid-26493bea-97f7-44d4-b7ec-255266dcb8ab" sourceRef="sid-0396a986-7e6b-4634-883b-1ee7db9aeb45"
targetRef="sid-c43c4370-4407-4746-893f-dcee3e4e9936"/>
<sequenceFlow id="sid-9f0f635b-4e97-4e95-b1fd-c9996bf659af" sourceRef="sid-c43c4370-4407-4746-893f-dcee3e4e9936"
targetRef="sid-665b6b28-9b81-4ab7-ba77-6eb50da3c810"/>
</process>
</definitions>

其中,​​activiti:class="com.example.actividemo.ServiceTask1"​​​ 和 ​​activiti:class="com.example.actividemo.ServiceTask2"​

对应到代码里:

package com.example.actividemo;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.JavaDelegate;

public class ServiceTask1 implements JavaDelegate {
//流程变量
private Expression text1;

//重写委托的提交方法
@Override
public void execute(DelegateExecution execution) {
System.out.println("serviceTask1 已经执行已经执行!");
String value1 = (String) text1.getValue(execution);
System.out.println(value1);
execution.setVariable("var1", new StringBuffer(value1).reverse().toString());
}
}

package com.example.actividemo;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.JavaDelegate;

public class ServiceTask2 implements JavaDelegate {
//流程变量
private Expression text2;

//重写委托的提交方法
@Override
public void execute(DelegateExecution execution) {
System.out.println("serviceTask2 已经执行已经执行!");
String value1 = (String) text2.getValue(execution);
System.out.println(value1);
execution.setVariable("var1", new StringBuffer(value1).reverse().toString());
}
}

Spring Boot 集成 Activiti 项目实战

创建 Spring Boot 工程,目录结构如下:

.
├── HELP.md
├── activi-demo.iml
├── mvnw
├── mvnw.cmd
├── pom.xml
└── src
├── main
│ ├── java
│ │ └── com
│ │ └── example
│ │ └── actividemo
│ │ ├── ActivitiController.java
│ │ ├── ActivityConsumerService.java
│ │ ├── ActivityConsumerServiceImpl.java
│ │ ├── Application.java
│ │ ├── ServiceTask1.java
│ │ └── ServiceTask2.java
│ └── resources
│ ├── application.properties
│ ├── static
│ ├── templates
│ └── test01.bpmn20.xml
└── test
└── java
└── com
└── example
└── actividemo
└── ApplicationTests.java

14 directories, 14 files

源代码如下:

ActivitiController

package com.example.actividemo;


import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/activiti")
public class ActivitiController {

@Autowired
private ActivityConsumerService activityConsumerService;

/**
* 注册流程
*
* @return
*/
@RequestMapping("/createDeployment")
public Boolean createDeployment() {
return activityConsumerService.createDeployment();
}

/**
* 启动流程
*
* @return
*/
@RequestMapping("/startActivityDemo")
public Boolean startActivityDemo() {
return activityConsumerService.startActivityDemo("test01");
}

/**
* 获取待办
*
* @return
*/
@RequestMapping("/getTaskList")
public List getTaskList() {
return activityConsumerService.getTaskList();
}

/**
* 提交
*
* @param taskId
* @return
*/
@RequestMapping("/complete")
public boolean complete(String taskId) {
return activityConsumerService.complete(taskId);
}

/**
* 根据流程id直接结束流程
*
* @return
* @paramru
*/
@RequestMapping("/deleteProcessInstance")
public boolean deleteProcessInstance(String runId) {
return activityConsumerService.deleteProcessInstance(runId);
}


}

ActivityConsumerService

package com.example.actividemo;


import java.util.List;

public interface ActivityConsumerService {
boolean createDeployment();

boolean startActivityDemo(String key);

List getTaskList();

boolean complete(String taskId);

boolean deleteProcessInstance(String runId);
}

ActivityConsumerServiceImpl

package com.example.actividemo;


import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.repository.DeploymentBuilder;
import org.activiti.engine.runtime.ProcessInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;

@Service("activityService")
public class ActivityConsumerServiceImpl implements ActivityConsumerService {

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

/**
* 注册一个流程
*
* @return
*/
@Override
public boolean createDeployment() {
DeploymentBuilder builder = repositoryService.createDeployment();
builder.addClasspathResource("test01.bpmn20.xml");
builder.deploy();
return true;
}

/**
* 查询待办
*
* @return
*/
public List getTaskList() {
return historyService.createHistoricActivityInstanceQuery().list();
}


/**
* 根据流程key开启一个流程
*
* @param key
* @return
*/
@Override
public boolean startActivityDemo(String key) {
ProcessInstance test01 = runtimeService.startProcessInstanceByKey(key);
String id = test01.getId();
System.out.println("流程id=" + id);
return true;
}

/**
* 根据任务id提交任务
*
* @param taskId
* @return
*/
@Override
public boolean complete(String taskId) {
taskService.complete(taskId);
return true;
}

/**
* 根据流程id直接结束流程
*
* @param runId
* @return
*/
@Override
public boolean deleteProcessInstance(String runId) {
runtimeService.deleteProcessInstance(runId, "结束");
return true;
}


}

Application

package com.example.actividemo;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;


@SpringBootApplication(exclude = {
org.activiti.spring.boot.SecurityAutoConfiguration.class
})
public class Application {

public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}

}

ServiceTask1 、ServiceTask2

package com.example.actividemo;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.JavaDelegate;

public class ServiceTask1 implements JavaDelegate {
//流程变量
private Expression text1;

//重写委托的提交方法
@Override
public void execute(DelegateExecution execution) {
System.out.println("serviceTask1 已经执行已经执行!");
String value1 = (String) text1.getValue(execution);
System.out.println(value1);
execution.setVariable("var1", new StringBuffer(value1).reverse().toString());
}
}

package com.example.actividemo;


import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.Expression;
import org.activiti.engine.delegate.JavaDelegate;

public class ServiceTask2 implements JavaDelegate {
//流程变量
private Expression text2;

//重写委托的提交方法
@Override
public void execute(DelegateExecution execution) {
System.out.println("serviceTask2 已经执行已经执行!");
String value1 = (String) text2.getValue(execution);
System.out.println(value1);
execution.setVariable("var1", new StringBuffer(value1).reverse().toString());
}
}

项目配置文件 application.properties

server.port=8080
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/activi_demo?useUnicode=true&characterEncoding=utf-8&useSSL=false&autoReconnect=true&serverTimezone=UTC
spring.datasource.username=root
spring.datasource.password=88888888
spring.activiti.check-process-definitions=false
spring.activiti.process-definition-location-prefix=classpath:*
spring.activiti.process-definition-location-suffixes=.bpmn20.xml

Maven 项目配置文件 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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.5.1</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>activi-demo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>activi-demo</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>1.8</java.version>
<activiti.version>6.0.0</activiti.version>
</properties>
<dependencies>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>

<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>

<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter-basic</artifactId>
<version>${activiti.version}</version>
</dependency>

<!-- Activiti 流程图 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-common-rest</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- Activiti 在线设计 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-modeler</artifactId>
<version>5.22.0</version>
<exclusions>
<exclusion>
<artifactId>spring-beans</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-context</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-core</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-tx</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-web</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>spring-security-config</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
<exclusion>
<artifactId>spring-security-core</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
<exclusion>
<artifactId>spring-security-crypto</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
<exclusion>
<artifactId>spring-security-web</artifactId>
<groupId>org.springframework.security</groupId>
</exclusion>
<exclusion>
<artifactId>spring-webmvc</artifactId>
<groupId>org.springframework</groupId>
</exclusion>
<exclusion>
<artifactId>activation</artifactId>
<groupId>javax.activation</groupId>
</exclusion>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>


<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
</dependencies>

<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>

</project>

运行测试

先部署任务:​​http://127.0.0.1:8080/activiti/createDeployment​

然后启动工作流实例:​​http://127.0.0.1:8080/activiti/startActivityDemo​

运行输出:

serviceTask1 已经执行已经执行!
test1
serviceTask2 已经执行已经执行!
test2
流程id=7501

查看历史流程:​​http://127.0.0.1:8080/activiti/getTaskList​

[
{
"id": "10003",
"processInstanceId": "10001",
"processDefinitionId": "test01:3:5044",
"startTime": "2021-06-13T07:20:19.009+00:00",
"endTime": "2021-06-13T07:20:19.010+00:00",
"durationInMillis": 1,
"deleteReason": null,
"activityId": "sid-d0c54d06-2073-4018-8381-e5e43f1b5578",
"activityName": "Start",
"activityType": "startEvent",
"executionId": "10002",
"assignee": null,
"taskId": null,
"calledProcessInstanceId": null,
"tenantId": "",
"persistentState": {
"executionId": "10002",
"durationInMillis": 1,
"endTime": "2021-06-13T07:20:19.010+00:00",
"assignee": null,
"deleteReason": null
},
"time": "2021-06-13T07:20:19.009+00:00",
"inserted": false,
"deleted": false,
"updated": false
},
...
,
{
"id": "7514",
"processInstanceId": "7508",
"processDefinitionId": "test01:3:5044",
"startTime": "2021-06-13T06:47:16.733+00:00",
"endTime": "2021-06-13T06:47:16.733+00:00",
"durationInMillis": 0,
"deleteReason": null,
"activityId": "sid-665b6b28-9b81-4ab7-ba77-6eb50da3c810",
"activityName": "End",
"activityType": "endEvent",
"executionId": "7509",
"assignee": null,
"taskId": null,
"calledProcessInstanceId": null,
"tenantId": "",
"persistentState": {
"executionId": "7509",
"durationInMillis": 0,
"endTime": "2021-06-13T06:47:16.733+00:00",
"assignee": null,
"deleteReason": null
},
"time": "2021-06-13T06:47:16.733+00:00",
"inserted": false,
"deleted": false,
"updated": false
}
]

工作流的数据库表数据:


Spring Boot 集成 Activiti 工作流引擎 极简教程_java_03


数据库共28张表。一些比较重要的表有:

  1. act_ru_execution 执行对象表
  2. act_ru_task 用户任务表
  3. act_hi_actinst 活动节点历史表
  4. act_hi_procinst 流程实例历史表
  5. act_hi_taskinst 历史任务表

参考资料