SpringBoot集成Activiti7工作流引擎的示例代码
作者:动物园首领
本文主要介绍了SpringBoot集成Activiti7工作流引擎的示例代码,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
一. 版本信息
- IntelliJ IDEA 2023.3.6
- JDK 17
- Activiti 7
二. IDEA依赖插件安装
安装 BPM流程图插件,如果IDEA的版本超过2020,则不支持actiBPM插件。我的IDEA是2023版本我装的是 Activiti BPMN visualizer 插件。
在Plugins 搜索 Activiti BPMN visualizer 安装
创建BPMN文件
使用视图模式打开bpmn.xml
三. 创建SpringBoot 集成 activiti7
使用 IDEA 创建SpringBoot项目
设置项目参数
在 pom.xml 依赖配置文件中添加(Mysql,Lombok,activiti7)依赖
<?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>3.3.4</version> <relativePath/> <!-- lookup parent from repository --> </parent> <groupId>com</groupId> <artifactId>activiti-demo</artifactId> <version>0.0.1-SNAPSHOT</version> <name>activiti-demo</name> <description>activiti-demo</description> <properties> <java.version>17</java.version> </properties> <dependencies> <!-- web依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <!-- mysql依赖 --> <dependency> <groupId>com.mysql</groupId> <artifactId>mysql-connector-j</artifactId> <version>8.2.0</version> </dependency> <!-- lombok依赖 --> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <optional>true</optional> </dependency> <!-- mybatis数据访问层 --> <dependency> <groupId>com.baomidou</groupId> <artifactId>mybatis-plus-spring-boot3-starter</artifactId> <version>3.5.7</version> </dependency> <!-- activiti7 工作流引擎依赖 --> <dependency> <groupId>org.activiti</groupId> <artifactId>activiti-spring-boot-starter</artifactId> <version>7.1.0.M6</version> </dependency> <!-- 模块测试依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <excludes> <exclude> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> </exclude> </excludes> </configuration> </plugin> </plugins> </build> </project>
创建本地连接的数据库
创建数据库 activiti
CREATE DATABASE `activiti` /*!40100 DEFAULT CHARACTER SET utf8 */;
创建数据库表 user
-- activiti.`user` definition CREATE TABLE `user` ( `ID` bigint(20) NOT NULL AUTO_INCREMENT COMMENT '主键', `NAME` varchar(100) DEFAULT NULL COMMENT '名称', `AGE` varchar(100) DEFAULT NULL COMMENT '年龄', `CREATED_BY` varchar(32) DEFAULT NULL COMMENT '创建人名称', `CREATED_TIME` datetime DEFAULT NULL COMMENT '创建时间', `CREATED_ID` varchar(32) DEFAULT NULL COMMENT '创建人ID', `UPDATED_BY` varchar(32) DEFAULT NULL COMMENT '更新人名称', `UPDATED_TIME` datetime DEFAULT NULL COMMENT '更新时间', `UPDATED_ID` varchar(32) DEFAULT NULL COMMENT '更新人ID', PRIMARY KEY (`ID`) ) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4 COMMENT='用户信息表';
添加一条测试数据
INSERT INTO activiti.`user` (ID, NAME, AGE, CREATED_BY, CREATED_TIME, CREATED_ID, UPDATED_BY, UPDATED_TIME, UPDATED_ID) VALUES(1, '小王', '24', NULL, NULL, NULL, NULL, NULL, NULL);
添加 application.yml 配置文件
spring: application: name: activiti-demo datasource: #url切换数据库之后如果对应数据库名称和路径有变动,需要修改url url: jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf-8&useSSL=false username: root password: root driver-class-name: com.mysql.cj.jdbc.Driver
添加 activiti.cfg.xml 配置文件(文件名不能随便改)
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE beans [ <!ELEMENT beans (bean)*> <!ATTLIST beans xmlns CDATA #REQUIRED xmlns:xsi CDATA #REQUIRED xsi:schemaLocation CDATA #REQUIRED> <!ELEMENT bean (property)*> <!ATTLIST bean id CDATA #REQUIRED class CDATA #REQUIRED> <!ELEMENT property (#PCDATA)> <!ATTLIST property name CDATA #REQUIRED value CDATA #REQUIRED> ]> <beans xmlns="http://www.springframework.org/schema/beans" 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"> <!-- processEnqine Activiti 的流程引擎 --> <bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration"> <property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver"/> <property name="jdbcUrl" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=UTF-8&serverTimezone=Asia/Shanghai&useSSL=false&nullCatalogMeansCurrent=true"/> <property name="jdbcUsername" value="root"/> <property name="jdbcPassword" value="root"/> <!-- activiti 数据库表处理策略 --> <!-- databaseSchemaUpdate 属性的值可以设置为以下几种 --> <!-- none:这是默认值,表示不对数据库模式做任何变更,应用程序启动时不会检查数据库表结构是否与实体类匹配--> <!-- true:设置为 true 时,Spring会在应用程序启动时检查数据库表结构,并在发现不匹配时自动创建或修改表结构以匹配实体类定义。这相当于执行了数据库迁移--> <!-- create:与 true 类似,但 create 会在每次启动时删除并重新创建表,这可能会导致数据丢失,因此使用时需要谨慎--> <!-- create-drop:在每次启动应用程序时创建表,在关闭应用程序时删除表。这通常用于测试环境--> <!-- validate:在启动时验证数据库表结构是否与实体类定义匹配,如果不匹配则抛出异常,但不会自动进行任何更改--> <property name="databaseSchemaUpdate" value="true"/> </bean> </beans>
启动SpringBoot项目成功
开始添加一个查询数据测试接口(Controller,Service,Mapper,Entity)
Controller类
package com.activitidemo.act.controller; import com.activitidemo.act.entity.UserEntity; import com.activitidemo.act.service.impl.UserServiceImp; import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper; import jakarta.annotation.Resource; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; /** * <p> * 前端控制器 * </p> * * @author ningbeibei * @since 2024-09-26 */ @RestController @RequestMapping("/user-entity") public class UserController { @Resource private UserServiceImp userService; @PostMapping("/user") public Object getUser(@RequestBody UserEntity user){ QueryWrapper<UserEntity> queryWrapper = new QueryWrapper<>(); queryWrapper.eq("id",user.getId()); return userService.getBaseMapper().selectList(queryWrapper); } }
Service 类
package com.activitidemo.act.service; import com.activitidemo.act.entity.UserEntity; import com.baomidou.mybatisplus.extension.service.IService; /** * @author ningbeibei * @since 2024-09-26 */ public interface UserService extends IService<UserEntity> { }
package com.activitidemo.act.service.impl; import com.activitidemo.act.mapper.UserMapper; import com.activitidemo.act.service.UserService; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import org.springframework.stereotype.Service; import com.activitidemo.act.entity.UserEntity; /** * <p> * 服务实现类 * </p> * * @author ningbeibei * @since 2024-09-26 */ @Service public class UserServiceImp extends ServiceImpl<UserMapper, UserEntity> implements UserService { }
Mapper 类
package com.activitidemo.act.mapper; import com.activitidemo.act.entity.UserEntity; import com.baomidou.mybatisplus.core.mapper.BaseMapper; import org.apache.ibatis.annotations.Mapper; /** * <p> * Mapper 接口 * </p> * * @author ningbeibei * @since 2024-09-26 */ @Mapper public interface UserMapper extends BaseMapper<UserEntity> { }
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.activitidemo.act.entity.UserEntity"> </mapper>
Entity 类
package com.activitidemo.act.entity; import com.baomidou.mybatisplus.annotation.TableField; import com.baomidou.mybatisplus.annotation.TableName; import lombok.Getter; import lombok.Setter; import java.io.Serializable; import java.time.LocalDateTime; /** * @author ningbeibei * @since 2024-09-26 */ @Getter @Setter @TableName("user") public class UserEntity implements Serializable { private static final long serialVersionUID = 1L; @TableField("ID") private Integer id; @TableField("NAME") private String name; @TableField("AGE") private int age; @TableField("CREATED_BY") private String createdBy; @TableField("CREATED_TIME") private LocalDateTime createdTime; @TableField("CREATED_ID") private String createdId; @TableField("UPDATED_BY") private String updatedBy; @TableField("UPDATED_TIME") private LocalDateTime updatedTime; @TableField("UPDATED_ID") private String updatedId; }
目录结构
使用Postman接口测试工具,测试接口是否正常
四. Activiti 使用步骤
Activiti 主要流程操作步骤:
定义流程:按照BPMN的规范,使用流程定义工具,用流程符号把整个流程描述出来。
部署流程:把画好的流程定义文件,加载到数据库中,生成表的数据。
启动流程:使用 java 代码来操作数据库表中的内容。
处理任务:操作流程当中的各个任务。
1. 定义流程
2. 初始库表、定义、部署、操作任务代码
创建测试类
测试代码:
package com.activitidemo; import org.activiti.engine.HistoryService; import org.activiti.engine.ProcessEngine; import org.activiti.engine.ProcessEngineConfiguration; import org.activiti.engine.ProcessEngines; import org.activiti.engine.RepositoryService; import org.activiti.engine.RuntimeService; import org.activiti.engine.TaskService; import org.activiti.engine.history.HistoricActivityInstance; import org.activiti.engine.repository.Deployment; import org.activiti.engine.repository.ProcessDefinition; import org.activiti.engine.runtime.ProcessInstance; import org.activiti.engine.task.Comment; import org.activiti.engine.task.Task; import org.junit.jupiter.api.Test; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.util.FileCopyUtils; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.Paths; import java.util.List; @SpringBootTest class ActivitiDemoApplicationTests { // 创建 ProcessEngine 对象 // private ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // /** // * 初始化数据库表:第一种方式 // */ // @Test // public void testInitOne() { // ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // System.err.println("processEngine = " + processEngine); // } /** * 初始化数据库表 * 通过读取 activiti.cfg.xml 配置文件 */ @Test public void testInitTwo() { ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml"); ProcessEngine processEngine = configuration.buildProcessEngine(); System.err.println("processEngine = " + processEngine); } /** * 流程部署 */ @Test public void testDeploy() { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取 repositoryService 对象 RepositoryService repositoryService = processEngine.getRepositoryService(); // 进行部署 Deployment deployment = repositoryService.createDeployment() .addClasspathResource("process/leave.bpmn20.xml") .addClasspathResource("process/leave.bpmn20.png") .name("请假流程") .deploy(); // 输出部署的一些信息 System.out.println("流程部署ID:" + deployment.getId()); System.out.println("流程部署名称:" + deployment.getName()); System.out.println("流程部署成功"); } /** * 启动流程实例 */ @Test public void testStartProcess() { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取 runtimeService 对象 RuntimeService runtimeService = processEngine.getRuntimeService(); // 1.根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的 ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave"); // 2.根据流程定义id启动流程实例 // ProcessInstance instance = runtimeService.startProcessInstanceById("leave:1:4"); // 获取流程实例的相关信息 System.out.println("流程定义的id = " + instance.getProcessDefinitionId()); System.out.println("流程实例的id = " + instance.getId()); System.out.println("启动流程成功 "); } /** * 查询待办任务 */ @Test public void testSelectTodoTaskList() { String assignee = "李四"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取指定用户审核任务 TaskService taskService = processEngine.getTaskService(); // 使用面对对象方式查询数据库 List<Task> tasks = taskService.createTaskQuery() .processDefinitionKey("leave") .taskAssignee(assignee) // 返回多个结果 .list(); // 只返回一个结果 // .singleResult(); // 自定义 sql 查询 // taskService.createNativeTaskQuery(); // 获取流程实例的相关信息 for (Task task : tasks) { System.out.println("流程定义的id = " + task.getProcessDefinitionId()); System.out.println("流程实例的id = " + task.getProcessInstanceId()); System.out.println("任务id = " + task.getId()); System.out.println("任务名称 = " + task.getName()); } } /** * 指定用户去完成任务待办:多人审批在这操作,改变审核人名称就行了 */ @Test public void testCompleteTask() { String assignee = "李四"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取指定用户审核任务 TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery() .processDefinitionKey("leave") .taskAssignee(assignee) .list(); if (tasks != null && !tasks.isEmpty()){ // 当前流程图所限制,只能做审核同意的动作 for (Task task : tasks) { taskService.complete(task.getId()); } } } /** * 审批添加备注 */ @Test public void testAddComment() { String assignee = "张三"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取指定用户审核任务 TaskService taskService = processEngine.getTaskService(); List<Task> tasks = taskService.createTaskQuery() .processDefinitionKey("leave") .taskAssignee(assignee) .list(); if (tasks != null && !tasks.isEmpty()) { // 当前流程图所限制,只能做审核同意的动作 for (Task task : tasks) { // 添加备注 taskService.addComment(task.getId(), task.getProcessInstanceId(), assignee + "表示同意"); taskService.complete(task.getId()); } } } /** * 查询审批历史 */ @Test public void testSelectHistoryTask() { String processInstanceId = "2501"; String assignee = "张三"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 查看历史信息 HistoryService historyService = processEngine.getHistoryService(); // 获取指定用户审核任务 TaskService taskService = processEngine.getTaskService(); // 获取历史审核信息 List<HistoricActivityInstance> userTask = historyService.createHistoricActivityInstanceQuery() .activityType("userTask") // 指定实例的id .processInstanceId(processInstanceId) .taskAssignee(assignee) .finished() .list(); for (HistoricActivityInstance instance : userTask) { System.out.println("任务名称 = " + instance.getActivityName()); System.out.println("任务开始时间 = " + instance.getStartTime()); System.out.println("任务结束时间 = " + instance.getEndTime()); System.out.println("任务耗时 = " + instance.getDurationInMillis()); // 获取审批批注信息 List<Comment> taskComments = taskService.getTaskComments(instance.getTaskId()); if (!taskComments.isEmpty()){ System.out.println("审批批注 = " + taskComments.get(0).getFullMessage()); } } } /** * 查询流程相关信息 */ @Test public void testDefinitionQuery() { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取仓库服务 RepositoryService repositoryService = processEngine.getRepositoryService(); // 获取流程定义集合 List<ProcessDefinition> processDefinitionList = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("leave") // 最新的一个版本 .latestVersion() .list(); // 遍历集合 for (ProcessDefinition definition : processDefinitionList) { System.out.println("流程定义id = " + definition.getId()); System.out.println("流程定义名称 = " + definition.getName()); System.out.println("流程定义key = " + definition.getKey()); System.out.println("流程定义版本 = " + definition.getVersion()); System.out.println("流程部署id = " + definition.getDeploymentId()); System.out.println("==============="); } } /** * 资源文件下载 */ @Test public void testDownloadResource() throws IOException { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取仓库服务 RepositoryService repositoryService = processEngine.getRepositoryService(); // 获取流程定义集合 List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("leave") // 按照版本降序 .orderByProcessDefinitionVersion() // 降序 .desc() .list(); // 获取最新那个 ProcessDefinition definition = list.get(0); // 获取部署id String deploymentId = definition.getDeploymentId(); // 获取bpmn的输入流 InputStream bpmnInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getResourceName()); // 获取png的输入流 // InputStream pngInputStream = repositoryService.getResourceAsStream(deploymentId, definition.getDiagramResourceName()); String resourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getResourceName(); File file = new File(resourcePath); if (!file.exists()) { file.getParentFile().mkdirs(); } String diagramResourcePath = "C:/Users/ASUS/Desktop/" + File.separator + definition.getDiagramResourceName(); file = new File(diagramResourcePath); if (!file.exists()) { file.getParentFile().mkdirs(); } //复制文件 FileCopyUtils.copy(bpmnInputStream, Files.newOutputStream(Paths.get(resourcePath))); // FileCopyUtils.copy(pngInputStream, Files.newOutputStream(Paths.get(diagramResourcePath))); } /** * 删除已经部署的流程定义 */ @Test public void testDeleteDeploy() { // 删除已经部署的流程定义 String deploymentId = "45001"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取仓库服务 RepositoryService repositoryService = processEngine.getRepositoryService(); // 删除流程定义,如果改流程定义已有流程实例启动,则会报错 // repositoryService.deleteDeployment(deploymentId); // 设置 true,级联删除流程定义,即使有启动的实例也可以删除 repositoryService.deleteDeployment(deploymentId, true); } /** * 启动流程,需要进行 BusinessKey 绑定流程实例 */ @Test public void testStartBindBusinessKey() { String businessKey = "1"; // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); // 根据流程定义的key启动流程实例,这个key是在定义bpmn的时候设置的 // 在启动流程的时候将业务key加进去 ProcessInstance instance = runtimeService.startProcessInstanceByKey("leave", businessKey); // 获取流程实例的相关信息 System.out.println("流程定义id = " + instance.getProcessDefinitionId()); System.out.println("流程实例id = " + instance.getId()); System.out.println("业务标识 = " + instance.getBusinessKey()); } /** * 跑到下一个节点,需要进行审批了,此时需要获取 BusinessKey 进而获取请假单信息 */ @Test public void testGetBusinessKey() { // 1、获取李四的待办信息 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); List<Task> task = taskService.createTaskQuery() .taskAssignee("李四") .processDefinitionKey("leave") .list(); // 2、获取 businessKey // 获取流程实例id String processInstanceId = task.get(1).getProcessInstanceId(); RuntimeService runtimeService = processEngine.getRuntimeService(); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId) .singleResult(); String businessKey = processInstance.getBusinessKey(); System.out.println("业务标识 = " + businessKey); } /** * 流程定义挂起与激活 */ @Test public void testSuspendAllProcessInstance() { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); // 获取仓库服务 RepositoryService repositoryService = processEngine.getRepositoryService(); // 获取流程定义对象 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionKey("leave") .singleResult(); boolean suspended = processDefinition.isSuspended(); // 输出流程定义状态 System.out.println("流程定义状态:" + (suspended ? "已挂起" : "已激活")); String processDefinitionId = processDefinition.getId(); if (suspended) { repositoryService.activateProcessDefinitionById(processDefinitionId, true, null); System.out.println("流程id:" + processDefinitionId + "已激活"); } else { repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null); System.out.println("流程id:" + processDefinitionId + "已挂起"); } } /** * 流程实例挂起与激活 */ @Test public void testProcessInstance() { // 创建 ProcessEngine 对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); // 获取流程定义对象 List<ProcessInstance> processInstanceList = runtimeService.createProcessInstanceQuery() .processDefinitionKey("leave") .list(); // 遍历集合 for (ProcessInstance processInstance : processInstanceList) { boolean suspended = processInstance.isSuspended(); // 输出流程定义状态 System.out.println("流程实例状态:" + processInstance + "," + (suspended ? "已挂起" : "已激活")); String processDefinitionId = processInstance.getId(); if (suspended) { runtimeService.activateProcessInstanceById(processDefinitionId); System.out.println("流程实例id:" + processDefinitionId + "已激活"); } else { runtimeService.suspendProcessInstanceById(processDefinitionId); System.out.println("流程实例id:" + processDefinitionId + "已挂起"); } } } }
到此这篇关于SpringBoot集成Activiti7工作流引擎的示例代码的文章就介绍到这了,更多相关SpringBoot Activiti7 内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!