一 Activiti工作流介绍
1 Activiti 概述
1.1 Activiti
Activiti是一个工作流引擎,可以将业务系统中复杂的业务流程抽取出来,使用专门的建模语言BPMN2.0进行定义,业务流程按照预先定义的流程进行执行,实现了系统的流程流activiti进行管理,减少业务系统由于流程变更进行系统升级改造的工作量,从而提高系统的健壮性,同时也减少了系统开发维护成本.
1.2 BPM
BPM(Business Process Management) : 即业务流程管理, 是一种以规范化的构造端到端的卓越业务流程为中心,以持续的提高组织业务绩效为目的系统化方法,常见商业管理如EMBA/MBA
等均将BPM包含在内.
BPM软件: 根据企业中业务环境的变化,推进人与人之间,人与系统之间,以及系统与系统之间的整合及调整的经营方法与解决方案的IT工具.
BPMN(Business Process Model And Notation) :业务流程模型和符号,是由BPMI(Business Process Management Initiative)
开发的一套标准的业务流程建模符号,使用BPMN提供的符号可以创建业务流程.
1.3 BPMN符号简介
1 用一个圆圈表示,它是流程中运行中发生的事情.
2 活动用圆角矩形表示,一个流程由一个或多个活动组成的.
tips:
BPMN图形其实就是通过XML表示业务流程,用文本编辑器打开,里面就是xml文件.
2 Activiti使用步骤
1 部署Activiti
Activiti是一个工作流引擎(jar包API), 业务系统访问Activiti的接口,就可以方便操作流程相关数据,把工作流环境和业务环境集成.
2 流程定义
使用Activiti流程建模工具(Acitivity-designer)
定义业务流程(bpmn文件).
3 路程定义部署
Activiti部署业务流程定义,使用activiti提供的api把流程定义的内容存储,在activiti执行过程中可以查询定义的内容,activiti把流程定义内容存储在数据库中.
4 启动一个流程实例
流程实例:ProcessInstance
,启动一个流程实例表示开始一次业务流程的运行.
在员工请假流程定义部署完成后,张三请假启动一个流程实例,李四请假也启动一个流程实例,两个流程的执行互不干涉影响.
5 用户查询待办任务
通过activiti查询当前流程执行到了哪一步,当前用户需要办理什么任务.
6 用户办理任务
用户查询待办任务后,可以办理某个任务.
7 流程结束
当任务办理完成,且没有下一个任务节点,流程实例就完成了.
二 Activiti环境
1 开发环境
jdk1.8 / Mysql 5 / Tomcat8.5 / IDEA
Activiti7.0.0.Beta1(默认支持Spring5,注意版本号Beta后面是数字1)
2 准备Activiti7
1 从官网下载. http://activiti.org/download.html
2 在Maven导入坐标
<dependencies>
<!--activiti核心-->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>7.0.0.Beta1</version>
</dependency>
</dependencies>
3 Activiti的数据库支持
1 Activiti支持的数据库
2 在Mysql生成表
1 先创建数据库activiti(数据库名任意)
CREATE DATABASE activiti DEFAULT CHARACTER SET utf8;
2 创建java工程
使用IDEA创建java的maven项目,取名activiti-demo
3 导入maven坐标
1 pom.xml文件
<!-- 当前项目编码和JDK版本-->
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>1.8</maven.compiler.source>
<maven.compiler.target>1.8</maven.compiler.target>
<slf4j.version>1.6.6</slf4j.version>
<log4j.version>1.2.12</log4j.version>
<activiti.version>7.0.0.Beta1</activiti.version>
</properties>
<dependencies>
<!--activiti核心-->
<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>
<dependency>
<groupId>aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.5.4</version>
</dependency>
<!--mysql驱动-->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.40</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</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>
<!--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>
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.6</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.16</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.0.8.RELEASE</version>
</dependency>
</dependencies>
2 log4j.properties
log4j.rootLogger=debug, CONSOLE, LOGFILE
log4j.logger.org.apache.axis.enterprise=fatal, CONSOLE
log4j.appender.CONSOLE=org.apache.log4j.ConsoleAppender
log4j.appender.CONSOLE.layout=org.apache.log4j.PatternLayout
log4j.appender.CONSOLE.layout.ConversionPattern=%d{ISO8610} %-6R[%15.15t] %-5p %30.30.c %c - %m\n
log4j.appender.LOGFILE=org.apache.log4j.FileAppender
log4j.appender.LOGFILE.File=d:\act\activiti.log
log4j.appender.LOGFILE.Append=true
log4j.appender.LOGFILE.layout=org.apache.log4j.PatternLayout
log4j.appender.LOGFILE.layout.ConversionPattern=%d{ISO8610} %-6R[%15.15t] %-5p %30.30.c %c - %m\n
4 activiti配置文件
使用activiti提供的默认方式来创建mysql的表,需要在resources目录下创建activiti.cfg.xml文件.(文件的位置,文件的名称都不能修改)
<beans xmlns="http://www.springframework.org/schema/beans"
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/tx
http://www.springframework.org/schema/tx/spring-tx-3.0.xsd">
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!--数据库策略 true -数据库已经存在相应的表,直接使用,不存在,则创建表-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
</beans>
5 创建测试类,生成表
@Test
public void testCreateDbTable() {
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
System.out.println(processEngine);
}
6 表结构介绍
表分类 | 表名 | 解释 |
---|---|---|
一般数据 | ||
ACT_GE_BYTEARRAY | 通用的流程定义和流程资源 | |
ACT_GE_PROPERTY | 系统相关属性 | |
流程历史记录 | ||
ACT_HI_ACTINST | 历史的流程实例 | |
ACT_HI_ATACHMENT | 历史的流程附件 | |
ACT_HI_COMMENT | 历史的说明性信息 | |
ACT_HI_DETAIL | 历史的流程运行中的细节信息 | |
ACT_HI_IDENTITYLINK | 历史的流程运行过程中用户关系 | |
ACT_HI_PROCINST | 历史的流程实例 | |
ACT_HI_TASKINST | 历史的任务实例 | |
ACT_HI_VARINST | 历史的流程运行中的变量信息 | |
流程定义表 | ||
ACT_RE_DEPLOYMENT | 部署单元信息 | |
ACT_RE_MODEL | 模型信息 | |
ACT_RE_PROCDEF | 已部署的流程定义 | |
运行实例表 | ||
ACT_RU_EVENT_SUBSCR | 运行时事件 | |
ACT_RU_EXECUTION | 运行时流程执行实例 | |
ACT_RU_IDNTITYLINK | 运行时用户关系信息,存储任务节点与参与者的相关信息 | |
ACT_RU_JOB | 运行时作业 | |
ACT_RU_TASK | 运行时任务 | |
ACT_RU_VARIABLE | 运行时变量表 |
三 Activiti类关系图
1 类关系图
在新版本中dentityService,FormService两个Service已经删除了.
2 activiti.cfg.xml
activiti的引擎配置文件,包括ProcessEngineConfiguration的定义,数据源定义,事务管理等,类似一个spring的配置文件.
3 流程引擎配置类
流程引擎的配置类(ProcessEngineConfiguration),通过配置类可以创建工作流引擎ProcessEngine.
1 StandaloneProcessEngineConfiguration
使用该类来创建ProcessEngine,Activiti会自己处理事务. (优化: 数据源可以使用连接池)
<bean id="processEngineConfiguration" class="org.activiti.engine.impl.cfg.StandaloneProcessEngineConfiguration">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<!--数据库策略 true -数据库已经存在相应的表,直接使用,不存在,则创建表-->
<property name="databaseSchemaUpdate" value="true"/>
</bean>
2 SpringProcessEngineConfiguration
和Spring整合,使用该类,配置事务,让Spring管理
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/activiti"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
<property name="maxActive" value="3"/>
<property name="maxIdle" value="1"/>
</bean>
<!--事务管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
<!--数据源-->
<property name="dataSource" ref="dataSource"/>
<!--spring事务管理-->
<property name="transactionManager" ref="transactionManager"/>
<!--数据库策略-->
<property name="databaseSchemaUpdate" value="drop-create"/>
</bean>
<!--流程引擎-->
<bean id="processEngine" class="org.activiti.spring.ProcessEngineFactoryBean">
<property name="processEngineConfiguration" ref="processEngineConfiguration"/>
</bean>
4 工作流引擎创建
工作流引擎(ProcessEngine),相当于一个门面接口,通过ProcessEngineConfiguration创建ProcessEngine,通过ProcessEngine创建各个Service接口.
1 默认创建方式
固定activiti.cfg.xml文件名和路径,且activiti文件中有ProcessEngineConfiguration的配置,可以使用ProcessEngines工具类直接创建
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
2 一般创建方式
ProcessEngineConfiguration configuration = ProcessEngineConfiguration.createProcessEngineConfigurationFromResource("activiti.cfg.xml");
ProcessEngine processEngine = configuration.buildProcessEngine();
5 Service服务接口
Service是工作流引擎提供用于进行工作流部署,执行,管理的服务接口,我们使用这些接口可以操作服务对应的数据表.
1 Service创建方式
通过ProcessEngine创建Service
RepositoryService repositoryService = processEngine.getRepositoryService();
RuntimeService runtimeService = processEngine.getRuntimeService();
TaskService taskService = processEngine.getTaskService();
HistoryService historyService = processEngine.getHistoryService();
2 Service功能说明
service名称 | service作用 |
---|---|
RepositoryService | activiti的资源管理类 |
RuntimeService | activiti的流程运行管理类 |
TaskService | activiti的任务管理类 |
HistoryService | activiti的历史管理类 |
ManagerService | activiti的引擎管理类 |
四 Activiti入门操作
创建工作流的步骤:
- 定义流程: 按照BPMN,使用流程定义工具,用流程符号把整个流程描述出来.
- 部署流程: 把画好的流程定义文件,加载到数据库中,生成表的数据.
- 启动流程: 使用java代码来操作数据库中表内容
1 流程符号(BPMN2.0)
事件 Event
活动 Activiti
网关 Gateway
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nYg300VC-1610808984400)(assets/image-20210116172335147.png)]
流向 Flow
2 流程设计器的使用
前提在IDEA中安装插件actBPM
,创建一个BPMN文件
1 设计一个请假流程
2 指定任务负责人
3 生成png文件
1 先复制bpmn文件,把后缀改为xml
2 按照下图操作,得到png,保存图片
3 activiti入门操作
1 流程部署
/**
* 测试流程部署
*/
@Test
public void testDeployment() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3使用service进行流程的部署,定义一个流程的名字,把bpmn和png部署到数据中
Deployment deploy = repositoryService.createDeployment()
.name("出差申请流程")
.addClasspathResource("bpmn/evection.png")
.addClasspathResource("bpmn/evection.bpmn")
.deploy();
//4输出部署信息
System.out.println(deploy.getId() + " 流程部署id");
System.out.println(deploy.getName() + " 流程部署的名称");
}
总结:
1 使用流程设计器,使用流程符号,画出流程图
bpmn文件,png文件
都是流程资源文件,用来描述流程中需要的节点,节点负责人
出差申请流程,请假申请流程,报销申请流程,…
2 把流程的资源文件,进行部署
上传到数据库中,使用java代码来进行流程部署
一次部署操作:
ACT_RE_DEPLOYMENT
会生成一条记录
ACT_RE_PROCDEF
生成流程定义信息
3 deployment 和procdef表 一对多的关系
在procdef表中可以有多条记录,每条记录 对应一个流程的定义信息
2 启动流程实例
/**
* 启动流程实例
*/
@Test
public void teststartProcess() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3根据流程定义的id启动流程
String processInstanceByKey = "myEvection";
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey);
//4输出内容
System.out.println(processInstance.getProcessDefinitionId() + " 流程实例的id");
System.out.println(processInstance.getId() + " 流程实例id");
System.out.println(processInstance.getActivityId() + " 当前活动的id");
}
3 个人任务查询
/**
* 个人任务的查询
*/
@Test
public void testFindPersonTaskList() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据流程的key 和任务的负责人 查询任务
String assignee = "zhangsan";
String definitionKey = "myEvection";
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)//流程key
.taskAssignee(assignee)//要查询的负责人
.list();
//4输出内容
for (Task task : taskList) {
System.out.println(task.getProcessDefinitionId() + " 当前任务的实例的id");
System.out.println(task.getId() + " 当前任务的id");
System.out.println(task.getName() + " 当前任务的名称");
System.out.println(task.getAssignee() + " 当前任务的负责人");
}
}
4 个人任务完成
/**
* 完成个人任务
*/
@Test
public void completTask() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据任务id 完成(张三)任务
/* String taskId = "2505";
taskService.complete(taskId);*/
//4 根据指派人和实例key获取个人任务
String definitionKey = "myEvection";
String assignee = "rose";
Task task = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)//流程实例key
.taskAssignee(assignee)//任务指派人
.singleResult();//单个结果
taskService.complete(task.getId());
System.out.println("任务完成");
}
5 使用zip方式进行流程部署
/**
* 使用zip方式部署
*/
@Test
public void testZipDeployment() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3使用service进行流程的部署,定义一个流程的名字,zip部署
InputStream inputStream = this.getClass()
.getClassLoader()
.getResourceAsStream("bpmn/bpmn.zip");
System.out.println(inputStream);
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService
.createDeployment()//创建部署
.addZipInputStream(zipInputStream)//添加zip输入流
.name("请假流程")//流程名称
.key("myEvection")//实例key
.deploy();
//4输出部署信息
System.out.println(deploy.getId() + " 流程部署id");
System.out.println(deploy.getName() + " 流程部署的名称");
}
五 流程操作
1 流程定义信息查询
/**
* 查询流程定义
*/
@Test
public void queryProcessDefinition() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
ProcessDefinitionQuery definitionQuery = repositoryService.createProcessDefinitionQuery();
String key = "myEvection";
List<ProcessDefinition> definitionList = definitionQuery.processDefinitionKey(key)
.orderByProcessDefinitionVersion()
.desc()
.list();
for (ProcessDefinition processDefinition : definitionList) {
System.out.println("流程定义ID " + processDefinition.getId());
System.out.println("流程定义名称 " + processDefinition.getName());
System.out.println("流程定义key " + processDefinition.getKey());
System.out.println("流程定义部署ID " + processDefinition.getDeploymentId());
System.out.println("流程定义版本号 " + processDefinition.getVersion());
}
}
2流程删除
/**
* 流程定义删除
*/
@Test
public void deleteDeployMent() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
/* //普通删除流程部署信息
String deployMentId = "15001";
repositoryService.deleteDeployment(deployMentId);
*/
/**
* 删除流程部署信息
* 当前流程如果没有完成,想要删除的话,需要特殊的方式 原理就是 级联删除
*/
String deployMentId = "1";
repositoryService.deleteDeployment(deployMentId, true);
System.out.println("删除成功");
}
3流程资源下载
/**
* 下载 资源文件
* 方案1 使用Activiti的api,来下载资源文件
* 方案2 自己写代码从数据库中下载文件,使用jdbc对blob 类型,clob类型读取出来,保存到文件目录
* 解决IO操作: commons-io.jar
*/
@Test
public void getDeployment() throws IOException {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3 获取查询对象,查询流程定义信息
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
//4通过流程定义信息,获取部署ID
String deploymentId = processDefinition.getDeploymentId();
//5通过RepositoryService,传递部署id参数,读取资源信息(png和bpmn)
//5.1 获取png
//从流程定义表中,获取png图片的目录和名字
String pngName = processDefinition.getDiagramResourceName();
InputStream pngInput = repositoryService.getResourceAsStream(deploymentId, pngName);
//5.2 获取bpmn
String bpmnName = processDefinition.getResourceName();
InputStream bpmnInput = repositoryService.getResourceAsStream(deploymentId, bpmnName);
//6构造OutputStream流
File pngFile = new File("d/evection.png");
File bpmnFile = new File("d/evection.bpmn");
FileOutputStream pngOutStream = new FileOutputStream(pngFile);
FileOutputStream bpmnOutStream = new FileOutputStream(bpmnFile);
//7输入流,输出流的转换
IOUtils.copy(bpmnInput, bpmnOutStream);
IOUtils.copy(pngInput, pngOutStream);
//8关闭流
bpmnOutStream.close();
pngOutStream.close();
bpmnInput.close();
pngInput.close();
}
4流程历史信息的查看
/**
* 查看历史信息
*/
@Test
public void findHistoryInfo() {
//获取引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//获取HistoryService
HistoryService historyService = processEngine.getHistoryService();
//获取actinst表的查询对象
HistoricActivityInstanceQuery historicActivityInstanceQuery = historyService.createHistoricActivityInstanceQuery();
//查询actinst表
//1 使用流程实例id查询
//2 使用流程定义id查询
// String processInstanceId = "7501";
String processDefinitionId = "myEvection:1:5004";
List<HistoricActivityInstance> list = historicActivityInstanceQuery
// .processInstanceId(processInstanceId)
.processDefinitionId(processDefinitionId)
.orderByHistoricActivityInstanceStartTime()
.asc()
.list();
//输出
for (HistoricActivityInstance instance : list) {
System.out.println(instance.getActivityId()+"活动id");
System.out.println(instance.getActivityName()+"活动名称");
System.out.println(instance.getProcessDefinitionId()+"定义id");
System.out.println(instance.getProcessInstanceId()+"实例id");
System.out.println("================");
}
}
六 流程实例
1 流程实例(ProcessInstance) 代表流程定义的执行实例.
一个流程实例包含了所有的运行节点.
2 启动流程实例 并添加Businesskey(业务标识)
/**
* 添加业务key 到Activiti表
*/
@Test
public void addBusinessKey() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3 启动流程的过程中,添加businessKey
String processDefinitionKey = "myEvection";
String businessKey = "1001";
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(processDefinitionKey, businessKey);
System.out.println("businessKey : " + processInstance.getBusinessKey());
}
3 挂起和激活流程定义
流程处于激活状态才能向下进行,即任务处理人可以完成任务;挂起状态任务不能完成
1 流程定义的全部挂起和激活
/**
* 全部流程的挂起和激活
*/
@Test
public void suspendAllProcessInstance() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3查询流程定义,获取流程定义的查询对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("myEvection")
.singleResult();
//4 获取当前流程定义的实例是否是挂起状态
boolean suspended = processDefinition.isSuspended();
//5 获取流程定义的id
String definitionId = processDefinition.getId();
if (suspended) {
//6 挂机状态,可以激活的操作 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
repositoryService.activateProcessDefinitionById(definitionId,
true,
null);
System.out.println("流程定义id : " + definitionId + "已激活");
} else {
//7 激活状态,改为挂起装填 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
repositoryService.suspendProcessDefinitionById(definitionId,
true,
null);
System.out.println("流程定义id : " + definitionId + "已挂起");
}
}
2 单个流程的挂起和激活
/**
* 单个流程的挂起和激活
*/
@Test
public void suspendProcessInstance() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RepositoryService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3查询流程定义,获取流程定义的查询对象
String processInstanceId = "10001";
ProcessInstance processInstance = runtimeService
.createProcessInstanceQuery()
.processInstanceId(processInstanceId)
.singleResult();
//4 获取当前流程定义的实例是否是挂起状态
boolean suspended = processInstance.isSuspended();
//5 获取流程定义的id
String InstanceId = processInstance.getId();
if (suspended) {
//6 挂机状态,可以激活的操作 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
runtimeService.activateProcessInstanceById(InstanceId);
System.out.println("流程实例id : " + InstanceId + "已激活");
} else {
//7 激活状态,改为挂起装填 参数1:流程定义id 参数2: 是否激活 参数3:激活时间
runtimeService.suspendProcessInstanceById(InstanceId);
System.out.println("流程实例id : " + InstanceId + "已挂起");
}
}
七 个人任务
1 分配任务负责人
1 固定分配
2 表达式分配
Activiti使用UEL表达式,UEL是java EE6规范的一部分,UEL(Unified Expression Language)统一表达式语言,activiti支持两个UEL表达式:UEL-value和UEL-method
1UEL-value
2UEL-method
3 UEL-value和UEL-method结合
${UserService.findAll(emp)}
UserService是Spring容器的一个bean,findAll是该bean的一个流程变量,emp作为参数传到findAll方法中.
4 其他
表达式支持解析基础类型,bean,list,array,map,条件判断.
${order.price>100 && order.price<200}
/**
* 启动流程
*/
@Test
public void teststartProcess() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3根据流程定义的id启动流程
String processInstanceByKey = "evection-global";
Map<String, Object> variablesMap = new HashMap<>();
variablesMap.put("assignee0", "张三");
variablesMap.put("assignee1", "李四");
variablesMap.put("assignee2", "王五");
variablesMap.put("assignee3", "赵六");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey, variablesMap);
//4输出内容
System.out.println(processInstance.getProcessDefinitionId() + " 流程实例的id");
System.out.println(processInstance.getId() + " 流程实例id");
System.out.println(processInstance.getActivityId() + " 当前活动的id");
}
3 监听器分配
public class MyTaskListen implements TaskListener {
/**
* 使用监听器,指定任务负责人
* @param delegateTask
*/
@Override
public void notify(DelegateTask delegateTask) {
//判断是否是创建申请
if ( "出差申请".equals(delegateTask.getName()) && "create".equals(delegateTask.getEventName())) {
//指派任务负责人
delegateTask.setAssignee("张三");
}else {
delegateTask.setAssignee("李四");
}
}
}
2 查询任务
/**
* 个人任务的查询
*/
@Test
public void testFindPersonTaskList() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据流程的key 和任务的负责人 查询任务
String assignee = "zhangsan";
String definitionKey = "myEvection";
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)//流程key
.taskAssignee(assignee)//要查询的负责人
.list();
//4输出内容
for (Task task : taskList) {
System.out.println(task.getProcessDefinitionId() + " 当前任务的实例的id");
System.out.println(task.getId() + " 当前任务的id");
System.out.println(task.getName() + " 当前任务的名称");
System.out.println(task.getAssignee() + " 当前任务的负责人");
}
}
3 办理任务
/**
* 完成个人任务
*/
@Test
public void completTask() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据任务id 完成(张三)任务
/* String taskId = "2505";
taskService.complete(taskId);*/
//4 根据指派人和实例key获取个人任务
String definitionKey = "myEvection";
String assignee = "rose";
Task task = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)//流程实例key
.taskAssignee(assignee)//任务指派人
.singleResult();//单个结果
taskService.complete(task.getId());
System.out.println("任务完成");
}
八 流程变量
1 什么是流程变量
流程变量: activiti在管理工作流时根据管理需要设置的变量
2 流程变量类型
3 流程变量作用域
流程变量的作用域可以是一个流程实例,或是一个任务task,或一个执行实例.
1 global变量
流程变量的默认作用域是流程实例,当一个流程变量的作用域为流程实例时,可以称为global变量.
global变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值.
2 local变量
任务和执行实例仅仅是针对一个任务和一个执行实例范围,范围没有流程实例大,称为local变量.
4 流程变量的使用方法
1 在属性上使用UEL表达式
在assignee处设置UEL表达式,如 ${assignee}
2 在连线上使用UEL表达式
如 ${price<100}
5 使用Global变量控制流程
1 创建pojo对象
// 实体类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Evection implements Serializable {
private Long id;
private String evectionName;
private Double num;
private Date beginTime;
private Date endTime;
private String reason;
private String desraption;
}
2 启动流程时设置变量
/**
* 启动流程
*/
@Test
public void teststartProcess() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3根据流程定义的id启动流程
String processInstanceByKey = "evection-global";
//指定连线条件
Evection evection = new Evection();
evection.setNum(3.0);
Map<String, Object> variablesMap = new HashMap<>();
variablesMap.put("evection", evection);
//指定任务人
variablesMap.put("assignee0", "张三");
variablesMap.put("assignee1", "李四");
variablesMap.put("assignee2", "王五");
variablesMap.put("assignee3", "赵六");
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processInstanceByKey, variablesMap);
//4输出内容
System.out.println(processInstance.getProcessDefinitionId() + " 流程实例的id");
System.out.println(processInstance.getId() + " 流程实例id");
System.out.println(processInstance.getActivityId() + " 当前活动的id");
}
3任务办理时设置变量
@Test
public void completTask() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据任务id 完成(张三)任务
String definitionKey = "myEvection";
String assignee = "zhangsan";
String processInstanceId = "10001";
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.taskAssignee(assignee)
.singleResult();
//设置变量
Map<String, Object> variablesMap = new HashMap<>();
variablesMap.put("assignee0", "张三");
variablesMap.put("assignee1", "李四");
variablesMap.put("assignee2", "王五");
variablesMap.put("assignee3", "赵六");
taskService.complete(task.getId(),variablesMap);
}
4 通过当前流程实例设置
@Test
public void setGlobalVariableByExecutionId() {
//当前流程实例执行id,通常设置为当前执行的流程实例
String executionId = "2601";
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3创建出差pojo对象
Evection evection = new Evection();
//设置天数
evection.setNum(3d);
//通过流程实例, id设置流程变量
runtimeService.setVariable(executionId,"evection",evection);
//一次性设置多个值
// runtimeService.setVariable(executionId,variables);
}
5 通过当前任务设置
@Test
public void setGlobalVariableByTaskId() {
//当前待办任务id
String taskId = "2601";
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//3创建出差pojo对象
Evection evection = new Evection();
//设置天数
evection.setNum(3d);
//通过流程实例, id设置流程变量
taskService.setVariable(taskId,"evection",evection);
//一次性设置多个值
// taskService.setVariable(taskId,variables);
}
6 设置local变量
1 任务办理时设置
@Test
public void completTask() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据任务id 完成(张三)任务
String definitionKey = "myEvection";
String assignee = "zhangsan";
String processInstanceId = "10001";
Task task = taskService.createTaskQuery()
.processInstanceId(processInstanceId)
.taskAssignee(assignee)
.singleResult();
//设置变量
Map<String, Object> variablesMap = new HashMap<>();
variablesMap.put("assignee0", "张三");
variablesMap.put("assignee1", "李四");
variablesMap.put("assignee2", "王五");
variablesMap.put("assignee3", "赵六");
//设置local变量,作用域为该任务
taskService.setVariablesLocal(taskId,variables);
//完成任务
taskService.complete(task.getId());
}
2 通过当前任 设置
@Test
public void setGlobalVariableByTaskId() {
//当前待办任务id
String taskId = "2601";
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//3创建出差pojo对象
Evection evection = new Evection();
//设置天数
evection.setNum(3d);
//通过流程实例, id设置流程变量
taskService.setVariableLocal(taskId,"evection",evection);
//一次性设置多个值
// taskService.setVariableLocal(taskId,variables);
}
九 组任务
1 组任务办理流程
a 查询组任务
指定候选人,查询该候选人当前的待办任务. 候选人不能立即办理任务
b 拾取任务
该组任务的所有所有的候选人都能拾取.
将候选人的组任务,变成个人任务,原来候选人就变成了该任务的负责人.
如果拾取后不想办理? 需要将拾取的任务,归还到组任务里面,个人任务就变成了组任务.
c 查询个人任务
查询方式桶个人任务部分,根据assignee查询用户负责的个人任务.
2 查询组任务
@Test
public void findGroupTaskList() {
//流程定义key
String processDefinitionKey = "evection3";
//任务候选人
String candidateUser = "lisi";
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//查询组任务
List<Task> list = taskService.createTaskQuery()
.processDefinitionKey(processDefinitionKey)
.taskCandidateOrAssigned(candidateUser)
.list();
for (Task task : list) {
System.out.println("==============================");
System.out.println(task.getProcessDefinitionId() + " 当前任务的实例的id");
System.out.println(task.getId() + " 当前任务的id");
System.out.println(task.getName() + " 当前任务的名称");
System.out.println(task.getAssignee() + " 当前任务的负责人");
}
}
3 拾取组任务
@Test
public void claimTask() {
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//要拾取任务id
String taskId = "6302";
String userId = "lisi";
//查询组任务
Task task= taskService.createTaskQuery()
.taskId(taskId)
.taskCandidateUser(userId)
.singleResult();
if (task != null){
//拾取任务
taskService.claim(taskId,userId);
System.out.println("任务拾取完成");
}
}
4 查询个人待办业务
/**
* 个人任务的查询
*/
@Test
public void testFindPersonTaskList() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据流程的key 和任务的负责人 查询任务
String assignee = "zhangsan";
String definitionKey = "myEvection";
List<Task> taskList = taskService.createTaskQuery()
.processDefinitionKey(definitionKey)//流程key
.taskAssignee(assignee)//要查询的负责人
.list();
//4输出内容
for (Task task : taskList) {
System.out.println(task.getProcessDefinitionId() + " 当前任务的实例的id");
System.out.println(task.getId() + " 当前任务的id");
System.out.println(task.getName() + " 当前任务的名称");
System.out.println(task.getAssignee() + " 当前任务的负责人");
}
}
5 办理个人业务
/**
* 完成个人任务
*/
@Test
public void completTask() {
//1创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2获取TaskService
TaskService taskService = processEngine.getTaskService();
//3根据任务id 完成(张三)任务
String taskId = "2505";
taskService.complete(taskId);
System.out.println("任务完成");
}
6 归还组任务
@Test
public void setAssigneeToGroupTask() {
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//要拾取任务id
String taskId = "6004";
String userId = "zhangsan";
//查询组任务
Task task= taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(userId)
.singleResult();
if (task != null){
//如果设置为null,归还组任务,否则该任务没有负责人
taskService.setAssignee(taskId,null);
}
}
7 任务交接
@Test
public void setAssigneeToCandidateUser() {
// 创建ProcessEngine
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
// 获取TaskService
TaskService taskService = processEngine.getTaskService();
//要拾取任务id
String taskId = "6004";
String userId = "zhangsan";
//将任务给其他候选人
String candidateuser = "zhangsan";
//查询组任务
Task task= taskService.createTaskQuery()
.taskId(taskId)
.taskAssignee(userId)
.singleResult();
if (task != null){
//如果设置为null,归还组任务,否则该任务没有负责人
taskService.setAssignee(taskId,candidateuser);
}
}
十 网关
1 排他网关(ExclusiveGate
排他网关,用来在流程中实现决策,当流程执行到这个网关,所有分支都会判断条件是否为true,如果为true则执行该分支.
2 并行网关(ParallelGateway)
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进入和外出顺序流的:
- fork分支: 并行后的所有外出顺序流,为每一个顺序流都创建一个并发分支
- join汇聚: 所有达到并行网关,在此等待的进入分支,直到所有进入顺序流的分支都达到以后,流程就会通过汇聚网关.
所有进入的顺序流,然后再切分成多个并行分支.
与其他网关的主要区别是,并行网关不会解析条件,及时顺序流中定义了条件,也会被忽略.
3 包含网关(InclusiveGateway)
包含网关可以看做事排他网关和并行网关的结合体.和排他网关一样,你可以在外出顺序流上定义条件,包含网关会解析他们,但是主要的区别是包含网关可以选择多于一条顺序流,这个并行网关一样.
包含网关:
- 分支:所有外出顺序流的条件都会被解析,结果为true的顺序流会以并行方式继续执行,会为每一个顺序流创建一个分支.
- 汇聚:所有并行分支达到网关,会进入等待状态,直到每个包含流程token的进入顺序流的分支都达到.包含网关只会等待被选中执行的进入顺序流,在汇聚之后,流程会穿过包含网关继续执行.
**小结:**在分支时,需要判断条件,符合条件的分支,将会执行,符合条件的分支最终才进行汇聚.
4 事件网关 (EventGateway)
事件网关: 根据事件判断流向,网关的每个外出顺序都要连接到一个中间捕获事件.当流程达到一个基于事件网关,网关会进入等待状态,会暂停执行,与此同时,会为每个外出顺序流创建相对的事件订阅.