目录
1、在idea中安装插件
2、导入activiti7 jar依赖
<?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>com.zhang</groupId>
<artifactId>activiti01</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</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>
<!-- bpmn 模型处理 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-model</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn json数据转换 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-json-converter</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- bpmn 布局 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-bpmn-layout</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- activiti 云支持 -->
<dependency>
<groupId>org.activiti.cloud</groupId>
<artifactId>activiti-cloud-services-api</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- mysql驱动 -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.20</version>
</dependency>
<!-- mybatis -->
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.4.5</version>
</dependency>
<!-- 链接池 -->
<dependency>
<groupId>commons-dbcp</groupId>
<artifactId>commons-dbcp</artifactId>
<version>1.4</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<!-- log start -->
<dependency>
<groupId>log4j</groupId>
<artifactId>log4j</artifactId>
<version>${log4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>${slf4j.version}</version>
</dependency>
</dependencies>
</project>
3、添加 activiti 文件
activiti.cfg.xml:
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<!-- 数据源 -->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti?useUnicode=true&characterEncoding=utf8&nullCatalogMeansCurrent=true&useSSL=false&useLegacyDatetimeCode=false&serverTimezone=UTC"/>
<property name="username" value="root"/>
<property name="password" value="123456"/>
<property name="maxActive" value="3" />
<property name="maxIdle" value="1" />
</bean>
<!-- 工作流引擎配置bean -->
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<!-- 数据源 -->
<property name="dataSource" ref="dataSource"/>
<!-- 使用spring事务管理器 -->
<property name="transactionManager" ref="transactionManager"/>
<!--flase: 默认值。activiti在启动时,会对比数据库表中保存的版本,如果没有表或者版本不匹配,将抛出异常。(生产
环境常用)
true: activiti会对数据库中所有表进行更新操作。如果表不存在,则自动创建。(开发时常用)
create_drop: 在activiti启动时创建表,在关闭时删除表(必须手动关闭引擎,才能删除表)。(单元测试常用)
drop-create: 在activiti启动时删除原来的旧表,然后在创建新表(不需要手动关闭引擎)。-->
<!-- 数据库策略 -->
<!-- <property name="databaseSchemaUpdate" value="drop-create"/>-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
<!-- 流程引擎 -->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
<!-- 资源服务service -->
<bean id="repositoryService" factory-bean="processEngine" factory-method="getRepositoryService"/>
<!-- 流程运行service -->
<bean id="runtimeService" factory-bean="processEngine" factory-method="getRuntimeService"/>
<!-- 任务管理service -->
<bean id="taskService" factory-bean="processEngine" factory-method="getTaskService"/>
<!-- 历史管理service -->
<bean id="historyService" factory-bean="processEngine" factory-method="getHistoryService"/>
<!-- 事务管理器 -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<!-- 通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 传播行为 -->
<tx:method name="save*" propagation="REQUIRED"/>
<tx:method name="insert*" propagation="REQUIRED"/>
<tx:method name="delete*" propagation="REQUIRED"/>
<tx:method name="update*" propagation="REQUIRED"/>
<tx:method name="find*" propagation="SUPPORTS" read-only="true"/>
<tx:method name="get*" propagation="SUPPORTS" read-only="true"/>
</tx:attributes>
</tx:advice>
<!-- 切面,根据具体项目修改切点配置
<aop:config proxy-target-class="true">
<aop:advisor advice-ref="txAdvice"
pointcut="execution(*com.itheima.service.impl..(..))"/>
</aop:config>-->
</beans>
log4j.properties:
# Set root category priority to INFO and its only appender to CONSOLE.
#log4j.rootCategory=INFO, CONSOLE debug info warn error fatal
log4j.rootCategory=debug, CONSOLE, LOGFILE
# Set the enterprise logger category to FATAL and its only appender to CONSOLE.
log4j.logger.org.apache.axis.enterprise=FATAL, CONSOLE
# CONSOLE is set to be a ConsoleAppender using a PatternLayout.
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
# LOGFILE is set to be a File appender using a PatternLayout.
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=f:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8601} %-6r[%15.15t] %-5p %30.30c %x - %m\n
4、画流程图
4、创建数据库25个表
/**
* 创建数据库25个表
*/
@org.junit.Test
public void Test00() {
// 1、默认
// ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService repositoryService = processEngine.getRepositoryService();
// repositoryService.createDeployment();
// 2、自定义配置
ProcessEngine engine = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
.buildProcessEngine();
System.out.println("engine = " + engine);
}
5、部署第一个流程
流程只有一个,且有唯一的key标识。只有部署了流程,才可以启动我们的流程实例。
比如张三请假、李四也请假了,他们可以共用一个流程。但是,有不同的流程实例id。
/**
* 部署流程定义
*/
@org.junit.Test
public void Test02() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("流程部署")
.addClasspathResource("bpmn/evection.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
6、部署多个流程
企业不可能一个个部署项目。效率低,开发人员、用户感人。
使用zip批量部署。
/**
* 通过zip完成多文件流程定义部署
*/
@org.junit.Test
public void Test06() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream zipInputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
if (zipInputStream != null) {
ZipInputStream stream = new ZipInputStream(zipInputStream);
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(stream)
.deploy();
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
}
7、启动流程实例
流程实例(ProcessInstance)代表流程定义的执行实例。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。例如:用户或程序按照流程定义内容发起一个流程,这就是一个流程实例。
比如,张三提交了一个请假申请单。
测试用例代码:
/**
* 启动流程实例
*/
@org.junit.Test
public void Test03() {
// 启动第一个流程实例
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");
System.out.println("evection.getId() = " + evection.getId());
System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
// 当前活动ID
System.out.println("evection.getActivityId() = " + evection.getActivityId());
}
8、个人任务查询
流程实例的参与者,可以看到自己的任务信息。比如,经理是任务中间人,如果张三提交了一个请假申请,作为经理,jack可以看到自己的任务。
/**
* 查询个人任务
*/
@org.junit.Test
public void Test04() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "zhangsan";
List<Task> tasks = taskService
.createTaskQuery()
.processDefinitionKey("evection") // 流程实例key:evection
.taskAssignee(assignee)
.list();
if (tasks.size() > 0) {
for (Task task : tasks) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
}
} else {
System.out.println(assignee + "暂时没有任务");
}
}
控制台sql:
SELECT DISTINCT
RES.*
FROM
ACT_RU_TASK RES
INNER JOIN ACT_RE_PROCDEF D ON RES.PROC_DEF_ID_ = D.ID_
WHERE
RES.ASSIGNEE_ = 'zhangsan'
AND D.KEY_ = 'evection'
ORDER BY
RES.ID_ ASC
9、完成个人任务
/**
* 完成个人任务
*/
@org.junit.Test
public void Test05() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "jack";
String taskId = "72505";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.singleResult();
if (task != null) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
taskService.complete(task.getId());
} else {
System.out.println(assignee + "暂时没有任务了");
}
}
10、使用zip批量部署流程
用例代码:
@org.junit.Test
public void Test05() {
// 完成个人任务
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream zipInputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
if (zipInputStream != null) {
ZipInputStream stream = new ZipInputStream(zipInputStream);
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(stream)
.deploy();
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
}
11、查询流程定义
/**
* 查询流程定义
*/
@org.junit.Test
public void Test06() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService
.createProcessDefinitionQuery();
List<ProcessDefinition> processDefinitions = processDefinitionQuery
.processDefinitionKey("evection")
.orderByProcessDefinitionVersion()
.desc()
.list();
if (processDefinitions.size() > 0) {
for (ProcessDefinition item : processDefinitions) {
System.out.println("item.getId() = " + item.getId());
System.out.println("item.getName() = " + item.getName());
System.out.println("item.getDeploymentId() = " + item.getDeploymentId());
System.out.println("==================");
}
}
}
12、删除流程定义
/**
* 删除部署
*/
@org.junit.Test
public void Test07() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
String deleteDeployId = "1";
repositoryService.deleteDeployment(deleteDeployId);
// 即使该部署已经有了示例在跑,级联删除,不管流程实例是否在运行中,也照样删
// repositoryService.deleteDeployment(deleteDeployId,true);
}
13、流程资源文件下载
领导要看流程图,看看流程怎么走的;
开发人员也想看看;
项目经理也要看。
这时候开发人员就只能给他们看了。
现在我们的流程资源文件已经上传到数据库了,如果其他用户想要查看这些资源文件,可以从数据库中把资源文件下载到本地。
解决方案有:
1、jdbc对blob类型,clob类型数据读取出来,保存到文件目录
2、使用activiti的api来实现
使用commons-io.jar 解决IO的操作
引入commons-io依赖包
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
@org.junit.Test
public void Test10() throws IOException {
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("evection")
.singleResult();
// 4、通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
// 5、通过repositoryService的方法,实现读取图片信息和bpmn信息
// png图片的流
String pngName = processDefinition.getDiagramResourceName();
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
// bpmn文件的流
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
// 6、构造OutputStream流
File file_png = new File("d:/evectionflow01.png");
File file_bpmn = new File("d:/evectionflow01.bpmn");
FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
FileOutputStream pngOut = new FileOutputStream(file_png);
// 7、输入流,输出流的转换
IOUtils.copy(pngInput,pngOut);
IOUtils.copy(bpmnInput,bpmnOut);
// 8、关闭流
pngOut.close();
bpmnOut.close();
pngInput.close();
bpmnInput.close();
}
14、关联activi业务
实际工作中,启动流程实例时,指定的businesskey,就会在act_ru_execution 流程实例的执行表中存储businesskey。
比如:出差流程启动一个流程实例,就可以将出差单的id作为业务标识存储到activiti中,将来查询activiti的流程实例信息就可以获取出差单的id从而关联查询业务系统数据库得到出差单信息。
/**
* 实现 BusinessKey关联
* <p>
* 在启动流程实例时,指定的BusinessKey,
* 就会在`act_ru_execution`的流程实例的执行表中存储BusinessKey。
*/
@org.junit.Test
public void Test12() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// args1: 流程定义的key,这个key是字符串类型的,往往是申请单的主键ID,
// 也可以是拼接的字符串,只要我们能最后取到这个ID就行了,
// 取到后,我们就可以使用activiti查询任务了
// args2: 需要关联的表的唯一主键,比如用户表的ID字段
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("evection", "1001");
System.out.println("instance.getBusinessKey() = " + instance.getBusinessKey());
}
15、监听器
package com.zhang;
import org.activiti.engine.delegate.DelegateExecution;
import org.activiti.engine.delegate.ExecutionListener;
/**
* @Author lgz
* @Description activiti 监听器
* @Date 2023/10/14.
*/
public class TaskListener implements ExecutionListener {
@Override
public void notify(DelegateExecution delegateExecution) {
String event = delegateExecution.getEventName();
if ("start".equals(event)) {
System.out.println("start event");
} else if ("end".equals(event)) {
System.out.println("end event");
} else if ("take".equals(event)) {
System.out.println("take event");
}
}
}
16、流程变量
流程不可能一直是直线。如果当前有个需求,出差天数大于3天的,让总经理审批,否则让财务小姐姐去审批,那么就有一个问题,这个天数如何控制,这个天数就可以用activiti的流程变量来做了。
16.1 在属性上使用UEL表达式
可以在 assignee 处设置 UEL 表达式,表达式的值为任务的负责人,比如: ${assignee}, assignee 就是一个流程变量名称。
Activiti获取UEL表达式的值,即流程变量assignee的值 ,将assignee的值作为任务的负责人进行任务分配
16.2 在连线上使用UEL表达式
可以在连线上设置UEL表达式,决定流程走向。
比如:${price<10000} 。price就是一个流程变量名称,uel表达式结果类型为布尔类型。
如果UEL表达式是true,要决定 流程执行走向。
16.3 使用 Global变量控制流程(测试)
需求:员工创建出差申请单,由部门经理审核,部门经理审核通过后出差3天及以下由人财务直接审批,3天以上先由总经理审核,总经理审核通过再由财务审批。
建pojo类:
package com.zhang.pojo;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.io.Serializable;
import java.util.Date;
/**
* @Author lgz
* @Description
* @Date 2023/10/14.
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Evection implements Serializable {
private Long id;
/**
* 出差单名称
*/
private String evectionName ;
/**
* 出差天数
*/
private Double day;
private Date startTime;
private Date endTime;
/**
* 目的地
*/
private String destination;
private String reason;
}
启动流程时,设置变量
部署后,启动实例,测试代码如下
/**
* 启动流程一个实例
* 并且设置流程变量
* 全局变量
*/
@Test
public void Test06() {
Map<String, Object> map = new HashMap<String, Object>();
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Evection evection = new Evection();
evection.setDay(2d);
// evection是bpmn文件的流程变量 ${evection.day>3}
map.put("evection", evection);
map.put("assignee01", "张三");
map.put("assignee02", "总经理jack");
map.put("assignee03", "财务lily");
String definitionKey = "evectionGlobal";
runtimeService.startProcessInstanceByKey(definitionKey, map);
}
测试是否走分支:
天数小于3天:
/**
* 完成个人任务
* 看看Test06()方法设置的流程变量是否有效
* 并且设置流程变量
* 全局变量
*/
@Test
public void Test07(){
String definitionKey = "evectionGlobal";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)
.taskAssignee("张三")
.singleResult();
if (task != null) {
taskService.complete(task.getId());
System.out.println("完成任务======");
}
}
16.4 local变量
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。 Local 变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。Local 变量名也可以和 global 变量名相同,没有影响。
17、组任务
在流程定义中在任务结点的 assignee 固定设置任务负责人,在流程定义时将参与者固定设置在.bpmn 文件中,如果临时任务负责人变更则需要修改流程定义,系统可扩展性差。
针对这种情况可以给任务设置多个候选人,可以从候选人中选择参与者来完成任务。
设置多个候选人,如果张三没有上班,我们可以让李四审核,如果李四也不在,就让王五来审核。
他们都可以完成一个实例任务流程。
<userTask id="sid-6a7e9238-f1fd-4327-84d2-a5005d1bbc20"
name="经理审批" activiti:candidateUsers="lisi,wangwu"/>
部署、启动、查询:
/**
* 部署流程定义
* 组任务、候选人
*
*/
@Test
public void Test011(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-组任务")
.addClasspathResource("bpmn/evecton-candidate.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动流程一个实例
*/
@Test
public void Test09(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
String definitionKey = "evectonCandidate";
runtimeService.startProcessInstanceByKey(definitionKey);
}
/**
* 部署流程定义
* 组任务、候选人
*
*/
@Test
public void Test08(){
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskServicea = processEngine.getTaskService();
String definitionKey = "evectonCandidate";
String candidateUser = "wangwu";
List<Task> tasks = taskServicea.createTaskQuery()
.processDefinitionKey(definitionKey)
.taskCandidateUser(candidateUser)
.list();
if (tasks.size() > 0) {
for (Task task : tasks) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
}
}
}
17.1 拾取组任务
候选人变成负责人
/**
* 拾取组任务
* 组任务、候选人
*/
@Test
public void Test12() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String candidateUser = "wangwu";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if (task != null) {
taskService.claim(taskId, candidateUser);
System.out.println(candidateUser + "拾取成功!");
}
}
拾取任务后,别的候选人就做不了任务了,如果手滑点错了,又不想审批流程,这时候就可以归还任务了。
17.2 归还组任务
/**
* 归还组任务
* 组任务、候选人
*/
@Test
public void Test13() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String candidateUser = "wangwu";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(candidateUser)
.singleResult();
if (task != null) {
taskService.setAssignee(taskId, null);
System.out.println(candidateUser + "归还成功!");
}
}
17.3 数据库表操作
17.3.1查询当前任务执行表
SELECT * FROM act_ru_task
任务执行表,记录当前执行的任务,由于该任务当前是组任务,所有assignee为空,当拾取任务后该字段就是拾取用户的id
17.3.2查询任务参与者
SELECT * FROM act_ru_identitylink
任务参与者,记录当前参考任务用户或组,当前任务如果设置了候选人,会向该表插入候选人记录,有几个候选就插入几个
与act_ru_identitylink对应的还有一张历史表act_hi_identitylink,向act_ru_identitylink插入记录的同时也会向历史表插入记录。任务完成
18、任务交接(改变负责人)
把当前任务交接给另一个人。
/**
* 交接任务,把任务的负责人交给别的人做
* 组任务、候选人
*/
@Test
public void Test15() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "wangwu";
String candidateUser = "lisi";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
taskService.setAssignee(taskId, candidateUser);
System.out.println(assignee + "归还成功!" + candidateUser + "成了该任务的负责人!!");
}
}
19、网关
排他:如果分支都不符合条件,就走其中的小的id
并行:如果有两个并行分支,项目经理批准了,流程不会走到下一步,需要同一个分支的其他人审批通过,才能走到下一个分支
包含网关:如果有三个并行分支,出差天数大于3天,项目经理批准了,出差天数小于3天,人事小姐姐批准,另一个分支,不管是那种情况,人事经理都可以审批,并且,3个分支审批通过后,才可以走到下一步,需要同一个分支的其他人审批通过,才能走到下一个分支。
测试代码用例一
package com.zhang;
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 java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.zip.ZipInputStream;
/**
* @Author lgz
* @Description activiti7 Test测试用例
* @Date 2023/7/13.
*/
public class Test {
/**
* 创建activiti7的25张表
*/
@org.junit.Test
public void Test01() {
// 1、默认配置
// ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// RepositoryService repositoryService = processEngine.getRepositoryService();
// repositoryService.createDeployment();
// 2、自定义配置
ProcessEngine engine = ProcessEngineConfiguration
.createProcessEngineConfigurationFromResource("activiti.cfg.xml")
.buildProcessEngine();
System.out.println("engine = " + engine);
}
/**
* 部署流程定义
*/
@org.junit.Test
public void Test02() {
// 1、部署第一个流程
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("第一个流程部署")
.addClasspathResource("bpmn/evection.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动流程实例
*/
@org.junit.Test
public void Test03() {
// 启动第一个流程实例
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance evection = runtimeService.startProcessInstanceByKey("evection");
System.out.println("evection.getId() = " + evection.getId());
System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
// 当前活动ID
System.out.println("evection.getActivityId() = " + evection.getActivityId());
}
/**
* 查询个人任务
*/
@org.junit.Test
public void Test04() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "zhangsan";
List<Task> tasks = taskService
.createTaskQuery()
.processDefinitionKey("evection") // 流程实例key:evection
.taskAssignee(assignee)
.list();
if (tasks.size() > 0) {
for (Task task : tasks) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
}
} else {
System.out.println(assignee + "暂时没有任务");
}
}
/**
* 完成个人任务
*/
@org.junit.Test
public void Test05() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "jack";
Task task = taskService.createTaskQuery()
.taskId("72505")
.singleResult();
if (task != null) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
taskService.complete(task.getId());
} else {
System.out.println(assignee + "暂时没有任务了");
}
}
/**
* 通过zip完成多文件流程定义部署
*/
@org.junit.Test
public void Test06() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
InputStream zipInputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/evection.zip");
if (zipInputStream != null) {
ZipInputStream stream = new ZipInputStream(zipInputStream);
Deployment deployment = repositoryService.createDeployment()
.addZipInputStream(stream)
.deploy();
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getName() = " + deployment.getName());
}
}
/**
* 查询流程定义
*/
@org.junit.Test
public void Test07() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery processDefinitionQuery = repositoryService
.createProcessDefinitionQuery();
List<ProcessDefinition> processDefinitions = processDefinitionQuery
.processDefinitionKey("evection")
.orderByProcessDefinitionVersion()
.desc()
.list();
if (processDefinitions.size() > 0) {
for (ProcessDefinition item : processDefinitions) {
System.out.println("item.getId() = " + item.getId());
System.out.println("item.getName() = " + item.getName());
System.out.println("item.getDeploymentId() = " + item.getDeploymentId());
System.out.println("==================");
}
}
}
/**
* 删除流程部署
*/
@org.junit.Test
public void Test08() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
String deleteDeployId = "82501";
// 即使该部署已经有了示例在跑,也照样删
repositoryService.deleteDeployment(deleteDeployId, true);
}
/**
* 文件下载
*
* @throws IOException
*/
@org.junit.Test
public void Test10() throws IOException {
// 1、得到引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 2、获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 3、得到查询器:ProcessDefinitionQuery,设置查询条件,得到想要的流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("evection")
.singleResult();
// 4、通过流程定义信息,得到部署ID
String deploymentId = processDefinition.getDeploymentId();
// 5、通过repositoryService的方法,实现读取图片信息和bpmn信息
// png图片的流
String pngName = processDefinition.getDiagramResourceName();
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
// bpmn文件的流
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
// 6、构造OutputStream流
File file_png = new File("d:/evectionflow01.png");
File file_bpmn = new File("d:/evectionflow01.bpmn");
FileOutputStream bpmnOut = new FileOutputStream(file_bpmn);
FileOutputStream pngOut = new FileOutputStream(file_png);
// 7、输入流,输出流的转换
IOUtils.copy(pngInput, pngOut);
IOUtils.copy(bpmnInput, bpmnOut);
// 8、关闭流,不要忘记了关流,会耗资源
pngOut.close();
bpmnOut.close();
pngInput.close();
bpmnInput.close();
}
/**
* 查看历史信息
* 每完成一个任务,activiti都会在历史表记录相关的信息
*/
@org.junit.Test
public void Test11() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
HistoryService historyService = defaultProcessEngine.getHistoryService();
HistoricActivityInstanceQuery query = historyService
.createHistoricActivityInstanceQuery()
.orderByHistoricActivityInstanceStartTime().asc();
List<HistoricActivityInstance> histories = query.processInstanceId("5001").list();
if (histories.size() > 0) {
for (HistoricActivityInstance item : histories) {
System.out.println(item.getActivityId());
System.out.println(item.getActivityName());
System.out.println(item.getProcessDefinitionId());
System.out.println(item.getProcessInstanceId());
System.out.println("<==========================>");
}
}
}
/**
* 实现 BusinessKey关联
* <p>
* 在启动流程实例时,指定的BusinessKey,
* 就会在`act_ru_execution`的流程实例的执行表中存储BusinessKey。
*/
@org.junit.Test
public void Test12() {
ProcessEngine defaultProcessEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = defaultProcessEngine.getRuntimeService();
// args1: 流程定义的key,这个key是字符串类型的,往往是申请单的主键ID,
// 也可以是拼接的字符串,只要我们能最后取到这个ID就行了,
// 取到后,我们就可以使用activiti查询任务了
// args2: 需要关联的表的唯一主键,比如用户表的ID字段
ProcessInstance instance = runtimeService
.startProcessInstanceByKey("evection", "1001");
System.out.println("instance.getBusinessKey() = " + instance.getBusinessKey());
}
/**
* 实现全部流程实例挂起与激活
*/
@org.junit.Test
public void Test13() {
// 获取processEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取repositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
// 查询流程定义的对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().
processDefinitionKey("evection").
singleResult();
// 得到当前流程定义的实例是否都为暂停状态
boolean suspended = processDefinition.isSuspended();
// 流程定义id
String processDefinitionId = processDefinition.getId();
// 判断是否为暂停
if (suspended) {
// 如果是暂停(挂起了),可以执行激活操作 ,参数1 :流程定义id ,参数2:是否激活,参数3:激活时间
repositoryService
.activateProcessDefinitionById(processDefinitionId,
true,
null
);
System.out.println("流程定义:" + processDefinitionId + ",已激活");
} else {
// 如果是激活状态,可以暂停,参数1 :流程定义id ,参数2:是否暂停,参数3:暂停时间
repositoryService.suspendProcessDefinitionById(processDefinitionId,
true,
null);
System.out.println("流程定义:" + processDefinitionId + ",已挂起");
}
}
/**
* 实现单个流程实例挂起与激活
*/
@org.junit.Test
public void Test14() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("10001")
.singleResult();
if (processInstance.isSuspended()) {
runtimeService.activateProcessInstanceById(processInstance.getId());
System.out.println("actived!");
} else {
runtimeService.suspendProcessInstanceById(processInstance.getId());
System.out.println("suspended!");
}
}
}
测试代码用例二
package com.zhang;
import com.zhang.pojo.Evection;
import org.activiti.engine.*;
import org.activiti.engine.repository.Deployment;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.junit.Test;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @Author lgz
* @Description activiti7 Test测试用例二
* @Date 2023/7/14.
*/
public class Test02 {
/**
* 部署流程定义
* uel表达式
*/
@Test
public void Test00() {
// 1、部署第一个流程
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-UEL")
.addClasspathResource("bpmn/evection-uel.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动流程实例
*/
@Test
public void Test01() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Map<String, Object> map = new HashMap<String, Object>();
map.put("assignee0", "张三");
map.put("assignee1", "总经理Jack");
ProcessInstance evectionUel = runtimeService.startProcessInstanceByKey("evectionUel", map);
System.out.println("evection.getId() = " + evectionUel.getId());
System.out.println("evection.getProcessInstanceId() = " + evectionUel.getProcessInstanceId());
// 当前活动ID
System.out.println("evection.getActivityId() = " + evectionUel.getActivityId());
}
/**
* 部署流程定义
* 监听
*/
@Test
public void Test03() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-listener")
.addClasspathResource("bpmn/demo-listen.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动第一个流程实例
* 监听
*/
@Test
public void Test04() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance evection = runtimeService.startProcessInstanceByKey("testListener");
System.out.println("evection.getId() = " + evection.getId());
System.out.println("evection.getProcessInstanceId() = " + evection.getProcessInstanceId());
// 当前活动ID
System.out.println("evection.getActivityId() = " + evection.getActivityId());
}
/**
* 部署流程定义
* 流程变量
* 全局变量
*/
@Test
public void Test05() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-全局变量")
.addClasspathResource("bpmn/evection-global.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动流程一个实例
* 并且设置流程变量
* 全局变量
*/
@Test
public void Test06() {
Map<String, Object> map = new HashMap<String, Object>();
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
Evection evection = new Evection();
evection.setDay(2d);
// evection是bpmn文件的流程变量 ${evection.day>3}
map.put("evection", evection);
map.put("assignee01", "张三");
map.put("assignee02", "总经理jack");
map.put("assignee03", "财务lily");
String definitionKey = "evectionGlobal";
runtimeService.startProcessInstanceByKey(definitionKey, map);
}
/**
* 完成个人任务
* 看看Test06()方法设置的流程变量是否有效
* 并且设置流程变量
* 全局变量
*/
@Test
public void Test07() {
String definitionKey = "evectionGlobal";
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)
.taskAssignee("张三")
.singleResult();
if (task != null) {
taskService.complete(task.getId());
System.out.println("完成任务======");
}
}
/**
* 部署流程定义
* 组任务、候选人
*/
@Test
public void Test011() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-组任务")
.addClasspathResource("bpmn/evecton-candidate.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
/**
* 启动流程一个实例
*/
@Test
public void Test09() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
String definitionKey = "evectonCandidate";
runtimeService.startProcessInstanceByKey(definitionKey);
}
/**
* 部署流程定义
* 组任务、候选人
*/
@Test
public void Test08() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String definitionKey = "evectonCandidate";
String candidateUser = "wangwu";
List<Task> tasks = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)
.taskCandidateUser(candidateUser)
.list();
if (tasks.size() > 0) {
for (Task task : tasks) {
System.out.println("task.getAssignee() = " + task.getAssignee());
System.out.println("task.getProcessInstanceId() = " + task.getProcessInstanceId());
System.out.println("task.getName() = " + task.getName());
System.out.println("task.getId() = " + task.getId());
System.out.println("==========================");
}
}
}
/**
* 拾取组任务
* 组任务、候选人
*/
@Test
public void Test12() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String candidateUser = "wangwu";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(candidateUser)
.singleResult();
if (task != null) {
taskService.claim(taskId, candidateUser);
System.out.println(candidateUser + "拾取成功!");
}
}
/**
* 归还组任务
* 组任务、候选人
*/
@Test
public void Test13() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String candidateUser = "wangwu";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(candidateUser)
.singleResult();
if (task != null) {
taskService.setAssignee(taskId, null);
System.out.println(candidateUser + "归还成功!");
}
}
/**
* 交接任务,把任务的负责人交给别的人做
* 组任务、候选人
*/
@Test
public void Test15() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
TaskService taskService = processEngine.getTaskService();
String assignee = "wangwu";
String candidateUser = "lisi";
String taskId = "75002";
Task task = taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(assignee)
.singleResult();
if (task != null) {
taskService.setAssignee(taskId, candidateUser);
System.out.println(assignee + "归还成功!" + candidateUser + "成了该任务的负责人!!");
}
}
/**
* 排他网关
*/
@Test
public void Test16() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RepositoryService repositoryService = processEngine.getRepositoryService();
Deployment deployment = repositoryService
.createDeployment()
.name("出差申请-排他网关")
.addClasspathResource("bpmn/evection-exclusive.bpmn20.xml")
.deploy();
System.out.println("deployment.getName() = " + deployment.getName());
System.out.println("deployment.getId() = " + deployment.getId());
System.out.println("deployment.getCategory() = " + deployment.getCategory());
System.out.println("deployment.getDeploymentTime() = " + deployment.getDeploymentTime());
System.out.println("deployment.getTenantId() = " + deployment.getTenantId());
System.out.println("deployment.getKey() = " + deployment.getKey());
}
}