1.导包
<?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">
<modelVersion>4.0.0</modelVersion>
<groupId>org.example</groupId>
<artifactId>activiti_demo</artifactId>
<version>1.0-SNAPSHOT</version>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.5.RELEASE</version>
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
<mysql.version>5.1.29</mysql.version>
</properties>
<dependencies>
<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>
</dependency>
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring-boot-starter</artifactId>
<version>7.1.0.M3.1</version>
</dependency>
<!--解决activiti坐标导致的security注入问题-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
<version>2.3.4.RELEASE</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>${mysql.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
2.新建启动类,配置如下:
package com.wanglj;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
/**
* @Author 955
* @Date 2022-06-21 13:47
* @Description
*/
@SpringBootApplication(exclude = {
org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration.class,
org.springframework.boot.actuate.autoconfigure.security.servlet.ManagementWebSecurityAutoConfiguration.class
})
public class ActivitiApplication {
public static void main(String[] args) {
SpringApplication.run(ActivitiApplication.class, args);
}
}
3.idea下载bpmn画图插件Activiti BPMN visualizer
,安装重启idea(actiBPM插件早就不适配2021的idea了,想用可以降级idea版本或者用eclipse画,我相信没人想用这两个方法,推荐使用下文官方画图工具,Activiti BPMN visualizer
这个插件只能有一些简单的功能)
4.在resources目录下新建processes文件夹,并点击右键选择bpmn文件新建(注意:流程名字随便取,但文件必须是xx.bpmn20.xml
格式)
5.填写相应参数
6.打开新建的xml文件,点击右键打开流程图工具
7.画流程图(以user task为例,其他功能自行参考官网),点击右键新建开始–>Activities–>User task,注意每个步骤写好流程名称
注:流转下一步人名称得写上(这里提交请假申请-->worker,部门经理审批-->leader,财务审批-->finance)
拖动箭头使流程连接
最终效果
8.保存流程图到项目,右键Save to PNG,选择路径为xx.bpmn20.xml同路径
完整结构如图
9.新建activiti配置,也可使用yml方式springbean注入,这里使用xml方式配置(注:必须叫activiti.cfg.xml
且必须放resources根目录下,否则需要在代码配置放置路径,内容如下)
<?xml version="1.0" encoding="UTF-8"?>
<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">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="jdbcUrl" value="jdbc:mysql://xxxxxxx:3306/activiti_demo" />
<property name="jdbcDriver" value="com.mysql.cj.jdbc.Driver" />
<property name="jdbcUsername" value="root" />
<property name="jdbcPassword" value="root" />
<property name="databaseSchemaUpdate" value="true" />
</bean>
</beans>
10.编写测试代码
注:其中开始流程的key值为新建流程文件时的名称,如果不清楚可打开流程图面板,左键点击空白处,可显示id,对应key值
import lombok.extern.slf4j.Slf4j;
import org.activiti.engine.*;
import org.activiti.engine.history.HistoricActivityInstance;
import org.activiti.engine.history.HistoricActivityInstanceQuery;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.repository.ProcessDefinitionQuery;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.apache.commons.io.IOUtils;
import org.junit.Test;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.util.List;
/**
* @Author 955
* @Date 2022-06-21 15:01
* @Description
*/
@Slf4j
public class test {
/**
* 初始化流程部署
*/
@Test
public void testDeployment() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService.createDeployment().addClasspathResource("processes/process_955.bpmn20.xml").addClasspathResource("processes/process_955.png").name("请假申请流程").deploy();
System.out.println("流程部署id:" + deployment.getId());
System.out.println("流程部署名称:" + deployment.getName());
}
/**
* 开始流程
*/
@Test
public void testStartProcess() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("process_955");
System.out.println("流程部署id:" + processInstance.getId());
System.out.println("流程部署名称:" + processInstance.getName());
System.out.println("processInstanceId:" + processInstance.getProcessInstanceId());
}
/**
* 查询流转到该所属角色的任务
*/
@Test
public void testFindPersonalTaskList() {
//对应各流程节点流转下一步人名称,这里第一步从worker开始
//调用下方completTask方法可通过审批,再查询下一个名称leader,以此类推直到结束,因为流程图没有不通过的情况所以暂不考虑
String assignee = "worker";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey("process_955").taskAssignee(assignee).list();
for (Task task : list) {
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
/**
* 完成任务
*/
@Test
public void completTask() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
//根据流程key和任务的负责人 查询任务
//返回一个任务对象
//对应各流程节点流转下一步人名称,这里第一步从worker开始,分别为worker-->leader-->finance
Task task = taskService.createTaskQuery().processDefinitionKey("process_955").taskAssignee("worker").singleResult();
//完成任务,参数:任务id
taskService.complete(task.getId());
}
/**
* 查询出当前所有的流程定义
*/
@Test
public void queryProcessDefinition() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService.createProcessDefinitionQuery();
//查询出当前所有的流程定义
List<ProcessDefinition> list = processDefinitionQuery.processDefinitionKey("process_955").orderByProcessDefinitionVersion().desc().list();
//输出流程定义信息
for (ProcessDefinition processDefinition : list) {
System.out.println("流程定义 id=" + processDefinition.getId());
System.out.println("流程定义 name=" + processDefinition.getName());
System.out.println("流程定义 key=" + processDefinition.getKey());
System.out.println("流程部署id =" + processDefinition.getDeploymentId());
System.out.println("<=========================================>");
}
}
/**
* 删除流程
*/
@Test
public void deleteDeployment(){
String deploymentId = "1";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//通过流程引擎获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//删除流程定义,如果该流程定义已有流程实例启动则删除报错
repositoryService.deleteDeployment(deploymentId);
//设置为true,则有流程实例在启动也可以强制删除
// repositoryService.deleteDeployment(deploymentId,true);
}
/**
* 输出流程文件和流程图到文件夹
* @throws Exception
*/
@Test
public void queryBpmnFile()throws Exception{
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("process_955").singleResult();
//通过流程定义信息,得到部署id
String deploymentId = processDefinition.getDeploymentId();
//得到png图片流
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getDiagramResourceName());
//得到bpmn文件流
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, processDefinition.getResourceName());
File file_png = new File("C:\\Users\\HYGK\\Desktop\\bpmn\\process_955.png");
File file_bpmn = new File("C:\\Users\\HYGK\\Desktop\\bpmn\\process_955.bpmn");
FileOutputStream pngOut = new FileOutputStream(file_png);
FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
IOUtils.copy(pngInput,pngOut);
IOUtils.copy(bpmnInput,bpmnOut);
pngOut.close();
bpmnOut.close();
}
/**
* 根据instanceId查询整个流程
*/
@Test
public void findHistoryInfo(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = processEngine.getHistoryService();
//获取actinst表的查询对象
HistoricActivityInstanceQuery instanceQuery = historyService.createHistoricActivityInstanceQuery();
//根据instanceId查询整个流程
instanceQuery.processInstanceId("5001").orderByHistoricActivityInstanceStartTime().asc();
List<HistoricActivityInstance> list = instanceQuery.list();
for (HistoricActivityInstance historicActivityInstance : list) {
System.out.println(historicActivityInstance.getActivityId());
System.out.println(historicActivityInstance.getActivityName());
System.out.println(historicActivityInstance.getProcessDefinitionId());
System.out.println(historicActivityInstance.getCalledProcessInstanceId());
System.out.println("<=========================================>");
}
}
}
==============================================================================
进阶使用:activiti监听器使用
要使用监听器最好使用其他的画图工具,idea的画图工具支持不是很好,这里推荐官方的工具
https://download.csdn.net/download/m0_49605579/86177620
(0积分下载即可,资源内含3个war包,需要放到tomcat的webapps目录下,运行tomcat服务即可)
<1>成功运行后访问http://localhost:8080/activiti-app
(默认账号密码为:admin/test)
<2>登录成功后点击Kickstart App,并新建Process
<3>填写模块名
<4>新添加user task模块并点击,添加监听器,这里有两种监听器,具体区别参考如下文章
https://blog.csdn.net/yabushandaxue/article/details/119297080
这里以执行监听器为例(Execution listeners)
<5>填写监听器信息(class为项目对应的监听类,画好流程图需导出放入项目对应目录下)
<6>编写监听类,实现ExecutionListener接口重写notify方法即可,可以获取流程节点的信息,具体逻辑看业务需求,任务监听器类似,实现TaskListener接口重写notify方法即可,只要实现了这个接口,项目不启动也可以通过springbootTest监听到
package com.wanglj.listener;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/**
* @Author 955
* @Date 2022-06-30 14:46
* @Description
*/
public class OverExecutionListener implements ExecutionListener {
@Override
public void notify(DelegateExecution execution) {
String eventName = execution.getEventName();
System.out.println("sds");
}
}
项目整体结构