Spring Boot 目前(2020年)已经成为Java后台的主流框架,各种技术都有关于 Spring Boot 的集成方案。本文将介绍 Activiti 工作流框架核心 API 在 Spring Boot 2.x 中的简易使用教程。
(1) SpringBoot 2.x 快速集成 Activiti
(2) 绘制一个 Activiti BPMN 流程图 — 2020-07-22
创建工作流的方式可以分为3种
第一种,通过代码配置:
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 创建流程引擎(通过代码的方式)
*/
@Test
public void createActivitiEngineByCode() {
ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
engineConfiguration.setJdbcDriver("com.mysql.cj.jdbc.Driver");
engineConfiguration.setJdbcUrl("jdbc:mysql://127.0.0.1:3306/demo_activiti?useUnicode=true&characterEncoding" +
"=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&useSSL" +
"=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true");
engineConfiguration.setJdbcUsername("root");
engineConfiguration.setJdbcPassword("root");
/**
* false: 不会自动创建表,没有表,则抛异常
* true: 假如没有表,则自动创建
* create-drop: 流程开始的时候创建表,流程结束之后删除表
*/
engineConfiguration.setDatabaseSchemaUpdate("true");
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
System.out.println("通过代码创建流程引擎成功!!!");
}
第二种,通过指定的 xml
配置文件:
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 创建流程引擎(通过配置文件的方式)
*/
@Test
public void createActivitiEngineByCfg() {
ProcessEngineConfiguration engineConfiguration = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
ProcessEngine processEngine = engineConfiguration.buildProcessEngine();
System.out.println("使用 activiti.cfg.xml 创建流程引擎 !!!");
}
配置文件:
./activiti-workflow/src/main/resources/activiti.cfg.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-2.5.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver">property>
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/demo_activiti?useUnicode=true&characterEncoding=utf8&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8&useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true">property>
<property name="jdbcUsername" value="root">property>
<property name="jdbcPassword" value="root">property>
<property name="databaseSchemaUpdate" value="true">property>
bean>
beans>
第三种,在 SpringBoot 的配置文件中配置 Activiti
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 创建流程引擎(读取 application.yml 中 activiti 配置)
*/
@Test
public void createProcessEngine() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println("通过 ProcessEngines 获取流程引擎");
}
配置文件application.yml
:
./activiti-workflow/src/main/resources/application.yml
## spring config
spring:
activiti:
check-process-definitions: false
database-schema-update: true
process-definition-location-prefix: classpath:/
datasource:
url: "jdbc:mysql://127.0.0.1:3306/demo_activiti?useUnicode=true&characterEncoding=utf8\
&useJDBCCompliantTimezoneShift=true&useLegacyDatetimeCode=false&serverTimezone=GMT%2b8\
&useSSL=true&allowMultiQueries=true&autoReconnect=true&nullCatalogMeansCurrent=true\
&nullCatalogMeansCurrent=true"
username: root
password: "root"
hikari:
driver-class-name: com.mysql.cj.jdbc.Driver
在 application.yml
中配置 Activiti 信息,数据源信息是可以重用的,无需配置两份。Activiti 已经完美集成到 Spring Boot 项目中。
部署流程即将先前创建的流程图(bpmn)文件部署到系统中,流程文件会被保存到数据库中,流程图中的执行逻辑也会被保存下来,后边的流程执行将按照这个流程图来进行。同一张流程图可以部署多次,不过个人认为不建议这么做,一个流程图只部署一套。
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 部署工作流
*/
@Test
public void deploy() {
// resource 目录下 bpmn 文件
String bpmnResource = "processes/student_leave.bpmn";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
Deployment deployment = processEngine.getRepositoryService()
.createDeployment()
.addClasspathResource(bpmnResource)
.name("studentLeave")
.category("demoCategory")
.deploy();
System.out.println("部署 id: " + deployment.getId());
System.out.println("部署名称: " + deployment.getName());
System.out.println("部署策略: " + deployment.getCategory());
}
流程部署之后相当于创建了模板,启动流程,将会按照这个模板来执行。启动的流程相当于这个流程模板的实例,同一个部署的流程可以启动多个实例。不同的用户发起请求,就启动一个新的流程实例。
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 启动工作流
*/
@Test
public void startProcess() {
// 进程 key:bpmn 文件中工作流 id
String processKey = "student_leave";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
// 获取流程实例
ProcessInstance instance = runtimeService.startProcessInstanceByKey(processKey);
System.out.println("流程实例 id: " + instance.getId());
System.out.println("流程定义 id: " + instance.getProcessDefinitionId());
}
可以查询到属于该代理人执行的任务节点,可以理解为某个用户待处理的任务。只有当流程执行到当前代理人的节点的时候,才能够查询到。
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 查询办理人当前流程信息
*/
@Test
public void queryTask() {
// 办理人
String assignee = "张三";
// 进程 key:bpmn 文件中工作流 id
String processKey = "student_leave";
// 获取任务服务
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
// 创建一个查询任务对象
TaskQuery taskQuery = taskService.createTaskQuery();
// 办理人列表
List<Task> taskList = taskQuery.taskAssignee(assignee).processDefinitionKey(processKey).list();
// 遍历列表
taskList.stream().forEach(task -> {
System.out.println("任务的办理人: " + task.getAssignee());
System.out.println("任务的 id: " + task.getId());
System.out.println("任务的名称: " + task.getName());
System.out.println("任务的所有者: " + task.getOwner());
System.out.println("任务的策略: " + task.getCategory());
System.out.println("任务的创建时间: " + task.getCreateTime());
System.out.println("任务的执行 id: " + task.getExecutionId());
System.out.println("任务的 kay: " + task.getTaskDefinitionKey());
System.out.println("任务的流程 id: " + task.getProcessDefinitionId());
System.out.println("------------------------------");
});
}
轮到某个代理人处理任务的时候,该代理人可以完成该节点任务,流程即执行到下一个节点。完成节点任务必须的参数是任务节点的 id
,不需要代理人的信息,因此需要在执行完成节点任务前,对代理人身份等信息进行校验。完成节点任务时,Activiti 支持批注信息
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 完成当前节点流程任务
*/
@Test
public void completeTask(){
String taskId = "2505";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 完成任务
processEngine.getTaskService().complete(taskId);
System.out.println("当前任务执行完毕");
}
查询流程的历史记录,包含的信息包括每个节点开始的时间、代理人、审批信息等。当需要查询流程进度的时候可以用到。
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 查询历史记录
*/
@Test
public void queryHistory3() {
// 流程 id
String processId = "student_leave_3:1:7504";
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
List<HistoricTaskInstance> historyList = engine.getHistoryService()
.createHistoricTaskInstanceQuery()
.processDefinitionId(processId)
.list();
historyList.stream().forEach(history -> {
System.out.println("任务的办理人: " + history.getAssignee());
System.out.println("任务的 id: " + history.getId());
System.out.println("流程实例 id: " + history.getProcessInstanceId());
System.out.println("任务的名称: " + history.getName());
System.out.println("任务的所有者: " + history.getOwner());
System.out.println("任务的策略: " + history.getCategory());
System.out.println("任务的创建时间: " + history.getCreateTime());
System.out.println("任务的执行 id: " + history.getExecutionId());
System.out.println("任务的 kay: " + history.getTaskDefinitionKey());
System.out.println("任务的流程 id: " + history.getProcessDefinitionId());
System.out.println("------------------------------");
});
}
当一个审批流程需要取消的时候,可以将流程的实例进行删除,包括流程的历史记录也可以删除。
./activiti-workflow/src/test/java/com/ljq/demo/springboot/activiti/ActivitiWorkflowApplicationTests.java
/**
* 删除流程实例(包括历史记录)
*/
@Test
public void deleteProcessInstance3() {
// 流程实例 id
String processInstanceId = "10001";
// 删除原因
String deleteReason = "需要删除";
ProcessEngine engine = ProcessEngines.getDefaultProcessEngine();
ProcessInstance processInstance = engine.getRuntimeService().createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
if (Objects.isNull(processInstance)) {
engine.getHistoryService().deleteHistoricProcessInstance(processInstanceId);
} else {
engine.getRuntimeService().deleteProcessInstance(processInstanceId, deleteReason);
engine.getHistoryService().deleteHistoricProcessInstance(processInstanceId);
}
}
以上即为 Activiti 的部分核心 API 使用,简单的流程操作已经足够了
【官方文档】Activiti User Guide
SpringBoot activiti 系列教程
Activiti工作流实战开发
Activiti 删除部署与流程实例
Gtihub 源码地址 : https://github.com/Flying9001/springBootDemo
个人公众号:404Code,分享半个互联网人的技术与思考,感兴趣的可以关注.