Activiti5
Open Source Business Automation
Helping businesses solve automation challenges in distributed, highly-scalable and cost effective infrastructures.
工作流概述
工作流(Workflow),就是“业务过程的部分或整体在计算机应用环境下的自动化”,它主要解决的是“使在多个参与者之间按照某种预定义的规则传递文档、信息或任务的过程自动进行,从而实现某个预期的业务目标,或者促使此目标的实现”。
工作流管理系统(Workflow Management System, WfMS)是一个软件系统,它完成工作量的定义和管理,并按照在系统中预先定义好的工作流规则进行工作流实例的执行。工作流管理系统不是企业的业务系统,而是为企业的业务系统的运行提供了一个软件的支撑环境。
工作流管理联盟(WfMC,Workflow Management Coalition)给出的关于工作流管理系统的定义是:工作流管理系统是一个软件系统,它通过执行经过计算的流程定义去支持一批专门设定的业务流程。工作流管理系统被用来定义、管理、和执行工作流程。
工作流管理系统的目标:管理工作的流程以确保工作在正确的时间被期望的人员所执行——在自动化进行的业务过程中插入人工的执行和干预。
Activiti介绍
Activiti5是由Alfresco软件在2010年5月17日发布的业务流程管理(BPM)框架,它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。Activiti基于Apache许可的开源BPM平台,创始人Tom Baeyens是JBoss jBPM的项目架构师,它特色是提供了eclipse插件,开发人员可以通过插件直接绘画出业务
工作流引擎
ProcessEngine对象,这是Activiti工作的核心。负责生成流程运行时的各种实例及数据、监控和管理流程的运行。
BPMN
业务流程建模与标注(Business Process Model and Notation,BPMN) ,描述流程的基本符号,包括这些图元如何组合成一个业务流程图(Business Process Diagram)
数据库
Activiti数据库支持:
Activiti的后台是有数据库的支持,所有的表都以ACT_开头。 第二部分是表示表的用途的两个字母标识。 用途也和服务的API对应。
- ACT_RE: 'RE’表示repository。 这个前缀的表包含了流程定义和流程静态资源 (图片,规则,等等)。
- ACT_RU: 'RU’表示runtime。 这些运行时的表,包含流程实例,任务,变量,异步任务,等运行中的数据。 Activiti只在流程实例执行过程中保存这些数据, 在流程结束时就会删除这些记录。 这样运行时表可以一直很小速度很快。*
- ACT_ID: 'ID’表示identity。 这些表包含身份信息,比如用户,组等等。
- ACT_HI: 'HI’表示history。 这些表包含历史数据,比如历史流程实例, 变量,任务等等。_
- ACT_GE: 通用数据, 用于不同场景下,如存放资源文件。
资源库流程规则表
- act_re_deployment 部署信息表
- act_re_model 流程设计模型部署表
- act_re_procdef 流程定义数据表
运行时数据库表
-
act_ru_execution 运行时流程执行实例表
-
act_ru_identitylink 运行时流程人员表,主要存储任务节点与参与者的相关信息
-
act_ru_task 运行时任务节点表
-
act_ru_variable 运行时流程变量数据表
历史数据库表
-
act_hi_actinst 历史节点表
-
act_hi_attachment 历史附件表
-
act_hi_comment 历史意见表
-
act_hi_identitylink 历史流程人员表
-
act_hi_detail 历史详情表,提供历史变量的查询
-
act_hi_procinst 历史流程实例表
-
act_hi_taskinst 历史任务实例表
-
act_hi_varinst 历史变量表
组织机构表
- act_id_group 用户组信息表
- act_id_info 用户扩展信息表
- act_id_membership 用户与用户组对应信息表
- act_id_user 用户信息表
这四张表很常见,基本的组织机构管理,关于用户认证方面建议还是自己开发一套,组件自带的功能太简单,使用中有很多需求难以满足
通用数据表
-
act_ge_bytearray 二进制数据表
-
act_ge_property 属性数据表存储整个流程引擎级别的数据,初始化表结构时,会默认插入三条记录
Activiti5开发环境
基本的开发环境 + idea/eclipse 插件
idea -------> actiBPM
若出现中文乱码 需要在idea vm options 里增加一行
-Dfile.encoding=UTF-8
之后,就可以识别 *.bpmn文件了
pom.xml
<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.sxt.activiti</groupId>
<artifactId>bootDemo</artifactId>
<version>0.0.1-SNAPSHOT</version>
<properties>
<java.version>1.8</java.version>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<spring-boot.version>2.3.7.RELEASE</spring-boot.version>
<activiti.version>5.22.0</activiti.version>
</properties>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.3.4.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<exclusions><!-- 去掉默认配置 -->
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-logging</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jdbc</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!--lombok-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<!--mapper-->
<dependency>
<groupId>tk.mybatis</groupId>
<artifactId>mapper-spring-boot-starter</artifactId>
<version>2.1.5</version>
</dependency>
<!-- 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>
</dependencies>
<build>
<plugins>
<!-- 配置编译的jdk版本 -->
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.7.0</version>
<configuration>
<!-- 指定source和target的版本 -->
<source>1.8</source>
<target>1.8</target>
</configuration>
</plugin>
</plugins>
</build>
</project>
其中的核心依赖
<!-- activiti的依赖 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-engine</artifactId>
<version>${activiti.version}</version>
</dependency>
<!-- web集成的时候使用 -->
<dependency>
<groupId>org.activiti</groupId>
<artifactId>activiti-spring</artifactId>
<version>${activiti.version}</version>
</dependency>
初始化数据库
创建 activiti
数据库
public static void main(String[] args) {
// 创建流程引擎配置
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUrl("jdbc:mysql://localhost:3306/activiti?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("123456");
// 配置实例化方式
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 得到流程引擎
ProcessEngine processEngine = configuration.buildProcessEngine();
}
核心API
ProcessEngine
得到流程引擎常用的方法
ProcessEngine processEngine=ProcessEngines.getDefaultProcessEngine();
RepositoryService
是Activiti的仓库服务类。所谓的仓库指流程定义文档的两个文件,bpmn文件和流程图片。
RuntimeService
是activiti的流程执行服务类。可以从这个服务类中获取很多关于流程执行相关的信息。
TaskService
是activiti的任务服务类。可以从这个类中获取任务的信息。
HistoryService
是activiti的查询历史信息的类。在一个流程执行完成后,这个对象为我们提供查询历史信息。
ProcessDefinition (act_re_procdef)
流程定义类。可以从这里获得资源文件等。当流程图被部署之后,查询出来的数据就是流程定义的数据
ProcessInstance (act_ru_execution)
代表流程定义的执行实例。如范冰冰请了一天的假,她就必须发出一个流程实例的申请。一个流程实例包括了所有的运行节点。我们可以利用这个对象来了解当前流程实例的进度等信息。流程实例就表示一个流程从开始到结束的最大的流程分支,即一个流程中流程实例只有一个。
Execution (act_ru_execution)
Activiti用这个对象去描述流程执行的每一个节点。在没有并发的情况下,Execution就是同ProcessInstance。流程按照流程定义的规则执行一次的过程,就可以表示执行对象Execution。
简单说,流程中有多条分支,那每个分支就叫一个execution,整条流程是processInstance.
TaskInstance (act_ru_task)
任务实例
Hello World
模拟请假流程
画流程图
新建一个HelloWorld.bpmn
BPMN最初是由业务流程管理倡议组织(The Business Process Management Initiative,简称BPMI)开发制定的一套业务流程建模符号,2004年5月发布了BPMN 1.0 规范。而后因为BPMI并入OMG(对象管理组织),BPMN也就随之由OMG进行维护管理。2011年,OMG推出了BPMN2.0标准,沿用至今。
如果左边的Editor不显示,需将idea进行设置,可进行如下设置
setting ----> Editor ----> Color Scheme ----> 选择Intellj Light模式
完成后,将bpmn文件改成xml文件
选择第一个设计器,打开,如果不显示Diagrams
,需安装 JBoss JBPM
插件
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-6nbznrs5-1620723592828)(C:\Users\www\AppData\Roaming\Typora\typora-user-images\image-20210420142701734.png)]
然后导出图片
部署流程
@Configuration
public class ProcessEngineConfig {
@Bean
public ProcessEngine getProcessEngine() {
// 创建流程引擎配置
ProcessEngineConfiguration configuration = ProcessEngineConfiguration
.createStandaloneProcessEngineConfiguration();
configuration.setJdbcDriver("com.mysql.jdbc.Driver");
configuration.setJdbcUrl("jdbc:mysql://121.196.30.175:3306/activiti?serverTimezone=GMT%2B8&useUnicode=true&characterEncoding=utf8&useSSL=false");
configuration.setJdbcUsername("root");
configuration.setJdbcPassword("123456");
// 配置实例化方式
configuration.setDatabaseSchemaUpdate(ProcessEngineConfiguration.DB_SCHEMA_UPDATE_TRUE);
// 得到流程引擎
return configuration.buildProcessEngine();
}
}
注入流程引擎
@Autowired
private ProcessEngine processEngine;
@Test
public void deployProcess() {
//得到流程部署的service
RepositoryService repositoryService = this.processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment().name("请假流程001")
.addClasspathResource("HelloWorld.bpmn20.xml")
.addClasspathResource("HelloWorld.png")
.deploy();
System.out.println("部署成功:流程部署ID:"+deploy.getId());
}
注意:
流程.xml
文件需要加.bpmn20
不然有些表的数据会不插入源码中要求:
需要以bpmn或者bpmn20.xml结尾的资源
正例:
HelloWorld.bpmn20.xml
启动流程
@Test
public void startProcess() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String processDefinitionId="1";
runtimeService.startProcessInstanceById(processDefinitionId);
System.out.println("流程启动成功");
}
查询任务
@Test
public void findTask() {
TaskService taskService = this.processEngine.getTaskService();
String assignee="张三";
List<Task> list = taskService.createTaskQuery().taskAssignee(assignee).list();
if(null!=list&&list.size()>0) {
for (Task task : list) {
System.out.println("任务ID:"+task.getId());
System.out.println("流程实例ID:"+task.getProcessInstanceId());
System.out.println("执行实例ID:"+task.getExecutionId());
System.out.println("流程定义ID:"+task.getProcessDefinitionId());
System.out.println("任务名称:"+task.getName());
System.out.println("任务办理人:"+task.getAssignee());
System.out.println("################################");
}
}
}
处理任务
public void completeTask() {
TaskService taskService = this.processEngine.getTaskService();
String taskId="12504";
taskService.complete(taskId);
System.out.println("任务完成");
}
管理流程定义
对流程的增加 修改 删除 查询
流程图
部署流程
流程的key相同的时候,会通过version字段来区分,默认选最新版本启动。
classpath方式部署
@Test
public void deployProcess01() {
// 得到流程部署的service
RepositoryService repositoryService = this.processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment().name("请假流程001").addClasspathResource("HelloWorld.bpmn")
.addClasspathResource("HelloWorld.png").deploy();
System.out.println("部署成功:流程部署ID:" + deploy.getId());
}
zip方式部署
/**
* 部署流程使用zip 流程图的文件必须是xxxx.zip结尾
*/
@Test
public void deployProcess02() {
// 如果不加/代表从当前包里面找文件
// 如果加/代表从classpath的根目录里面找文件
InputStream inputStream = this.getClass().getResourceAsStream("/HelloWorld.zip");
RepositoryService repositoryService = this.processEngine.getRepositoryService();
ZipInputStream zipInputStream = new ZipInputStream(inputStream);
Deployment deploy = repositoryService.createDeployment().name("报销流程001").addZipInputStream(zipInputStream)// 添加流程图的流
.deploy();// 确定部署
System.out.println("部署成功,部署D:" + deploy.getId());
}
部署的流程查询
@Test
public void queryProcessDeploy() {
RepositoryService repositoryService = this.processEngine.getRepositoryService();
// 创建部署信息的查询
String deploymentId = "1";
DeploymentQuery deploymentQuery = repositoryService.createDeploymentQuery();
List<Deployment> list = deploymentQuery
.deploymentId(deploymentId)
.deploymentNameLike("请假%")
.orderByDeploymentId()
.desc()
.listPage(0, 10);
long count = deploymentQuery
.deploymentId(deploymentId)
.deploymentNameLike("请假%")
.orderByDeploymentId()
.desc()
.count();
for (Deployment deployment : list) {
System.out.println("部署ID:" + deployment.getId());
System.out.println("部署名称:" + deployment.getName());
System.out.println("部署时间:" + deployment.getDeploymentTime());
System.out.println("########################");
}
System.out.println("共查到" + count + "条");
}
流程定义查询
@Test
public void queryProcDef() {
RepositoryService repositoryService = this.processEngine.getRepositoryService();
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
//.deploymentId("1") // 根据部署ID查询
// .deploymentIds(deploymentIds) 根据部署ID的集合查询Set<String> deploymentIds
// .processDefinitionId(processDefinitionId)//根据流程定义IDHelloWorld:1:4
// .processDefinitionIds(processDefinitionIds)//根据流程定义的IDS查询
// .processDefinitionKey("HelloWorld")//根据流程定义的的key查询
// .processDefinitionKeyLike(processDefinitionKeyLike)//根据流程定义的的key模糊查询
// .processDefinitionName(processDefinitionName)//根据流程定义的名称查询
// .processDefinitionNameLike(processDefinitionNameLike)//根据流程定义的名称模糊查询
// .processDefinitionResourceName(resourceName)//根据流程图的BPMN文件名查询
// .processDefinitionResourceNameLike(resourceNameLike)//根据流程图的BPMN文件名模糊查询
// .processDefinitionVersion(processDefinitionVersion)//根据流程定义的版本查询
// .processDefinitionVersionGreaterThan(processDefinitionVersion)//version>num
// .processDefinitionVersionGreaterThanOrEquals(processDefinitionVersion)//version>=num
// .processDefinitionVersionLowerThan(processDefinitionVersion)//version<num
// .processDefinitionVersionLowerThanOrEquals(processDefinitionVersion)//version<=num
// 排序
// .orderByDeploymentId()
// .orderByProcessDefinitionId()
// .orderByProcessDefinitionKey()
// .orderByProcessDefinitionName()
// .orderByProcessDefinitionVersion()
// 结果集
.list();
// .listPage(firstResult, maxResults)\
// .count()
// .singleResult()
if (null != list && list.size() > 0) {
for (ProcessDefinition pd : list) {
System.out.println("流程定义ID:" + pd.getId());
System.out.println("流程部署ID:" + pd.getDeploymentId());
System.out.println("流程定义KEY:" + pd.getKey());
System.out.println("流程定义的名称:" + pd.getName());
System.out.println("流程定义的bpmn文件名:" + pd.getResourceName());// bpmn的name
System.out.println("流程图片名:" + pd.getDiagramResourceName());// png的name
System.out.println("流程定义的版本号:" + pd.getVersion());
System.out.println("##################");
}
}
}
启动流程
@Test
public void startProcess() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String processDefinitionKey = "HelloWorld";
runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流程启动成功");
}
删除流程定义
@Test
public void deleteProcessDef() {
RepositoryService repositoryService = this.processEngine.getRepositoryService();
String deploymentId = "2501";
// 根据流程部署id删除流程定义 如果当前id的流程正在执行,那么会报错
// repositoryService.deleteDeployment(deploymentId);
// 根据流程部署id删除删除流程定义 如果当前id的流程正在执行,会把正在执行的流程数据删除 act_ru_*和act_hi_*表里面的数据
repositoryService.deleteDeployment(deploymentId, true);
// repositoryService.deleteDeploymentCascade(deploymentId);==repositoryService.deleteDeployment(deploymentId, true);
System.out.println("删除成功");
}
根据流程定义ID查询流程图
@Test
public void viewProcessImg() {
RepositoryService repositoryService = this.processEngine.getRepositoryService();
String processDefinitionId = "HelloWorld:1:4";
InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
File file = new File("d:/HelloWorld.png");
try {
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
int len = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outputStream.write(b, 0, len);
outputStream.flush();
}
outputStream.close();
inputStream.close();
System.out.println("查询成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
根据流程部署查询流程图
@Test
public void viewProcessImg2() {
RepositoryService repositoryService = this.processEngine.getRepositoryService();
// 根据流程部署ID查询流程定义对象
String deploymentId = "1";
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.deploymentId(deploymentId).singleResult();
// 从流程定义对象里面查询出流程定义ID
String processDefinitionId = processDefinition.getId();
InputStream inputStream = repositoryService.getProcessDiagram(processDefinitionId);
File file = new File("d:/" + processDefinition.getDiagramResourceName());
try {
BufferedOutputStream outputStream = new BufferedOutputStream(new FileOutputStream(file));
int len = 0;
byte[] b = new byte[1024];
while ((len = inputStream.read(b)) != -1) {
outputStream.write(b, 0, len);
outputStream.flush();
}
outputStream.close();
inputStream.close();
System.out.println("查询成功");
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
查询最新的流程定义
@Test
public void queryNewProcessDef() {
Map<String, ProcessDefinition> map = new HashMap<>();
// 查询所有的流程定义根据版本号升序
RepositoryService repositoryService = this.processEngine.getRepositoryService();
List<ProcessDefinition> list = repositoryService.createProcessDefinitionQuery()
.orderByProcessDefinitionVersion().asc().list();
if (null != list && list.size() > 0) {
for (ProcessDefinition pd : list) {
map.put(pd.getKey(), pd);
}
}
// 循环map集合
Collection<ProcessDefinition> values = map.values();
for (ProcessDefinition pd : values) {
System.out.println("流程定义ID:" + pd.getId());
System.out.println("流程部署ID:" + pd.getDeploymentId());
System.out.println("流程定义KEY:" + pd.getKey());
System.out.println("流程定义的名称:" + pd.getName());
System.out.println("流程定义的bpmn文件名:" + pd.getResourceName());// bpmn的name
System.out.println("流程图片名:" + pd.getDiagramResourceName());// png的name
System.out.println("流程定义的版本号:" + pd.getVersion());
System.out.println("##################");
}
}
修改流程定义
重新部署,只要key不变,它的版本号就会+1,这样即可实现更新
任务的执行
部署流程
@Test
public void deployProcess() {
// 得到流程部署的service
RepositoryService repositoryService = this.processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment().name("请假流程001").addClasspathResource("HelloWorld.bpmn")
.addClasspathResource("HelloWorld.png").deploy();
System.out.println("部署成功:流程部署ID:" + deploy.getId());
}
启动流程
public void startProcess() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
// runtimeService.startProcessInstanceById(processDefinitionId)//根据流程定义ID启动流程
/**
* 参数1:流程定义ID 参数2:Map<String,Object> 流程变量
*/
// runtimeService.startProcessInstanceById(processDefinitionId, variables);
/**
* 参数1:流程定义ID 参数2:String 业务ID 把业务ID和流程执行实例进行绑定
*/
//runtimeService.startProcessInstanceById(processDefinitionId, businessKey);
/**
* 参数1:流程定义ID 参数2:String 业务ID 把业务ID和流程执行实例进行绑定 参数3:Map<String,Object> 流程变量
*/
// runtimeService.startProcessInstanceById(processDefinitionId, businessKey, variables)
//
// runtimeService.startProcessInstanceByKey(processDefinitionKey)//根据流程定义的key启动
/**
* 参数1:流程定义的Key 参数2:Map<String,Object> 流程变量
*/
// runtimeService.startProcessInstanceByKey(processDefinitionKey, variables)
/**
* 参数1:流程定义Key 参数2:String 业务ID 把业务ID和流程执行实例进行绑定
*/
// runtimeService.startProcessInstanceByKey(processDefinitionId, businessKey);
/**
* 参数1:流程定义Key 参数2:String 业务ID 把业务ID和流程执行实例进行绑定 参数3:Map<String,Object> 流程变量
*/
// runtimeService.startProcessInstanceByKey(processDefinitionId, businessKey, variables)
// 实际开发中使用的
// runtimeService.startProcessInstanceByKey(processDefinitionId, businessKey, variables)
// runtimeService.startProcessInstanceByKey(processDefinitionId, businessKey);
String processDefinitionKey = "HelloWorld";
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
System.out.println("流程启动成功:" + processInstance.getId() + " " + processInstance.getProcessDefinitionId() + " "
+ processInstance.getProcessInstanceId());
}
流程变量:可以决定流程图的走势
查询个人任务
@Test
public void queryMyTask() {
TaskService taskService = this.processEngine.getTaskService();
String assignee = "李四";
List<Task> list = taskService.createTaskQuery()
// 条件
.taskAssignee(assignee)// 根据任务办理人查询任务
// .deploymentId(deploymentId)//根据部署ID查询 where id=id
// .deploymentIdIn(deploymentIds)//根据部署ID集合查询 where id in (1,2,3,4)
// .executionId(executionId)//根据执行实例ID
// .processDefinitionId(processDefinitionId)//根据流程定义ID
// .processDefinitionKey(processDefinitionKey)//根据流程定义的key
// .processDefinitionKeyIn(processDefinitionKeys)
// .processDefinitionKeyLike(processDefinitionKeyLike)
// .processDefinitionName(processDefinitionName)
// .processDefinitionNameLike(processDefinitionNameLike)
// .processInstanceBusinessKey(processInstanceBusinessKey)
// 排序
.orderByTaskCreateTime().desc()
// 结果集
.list();
// .listPage(firstResult, maxResults)
// .count();
// .singleResult()
if (null != list && list.size() > 0) {
for (Task task : list) {
System.out.println("任务ID:" + task.getId());
System.out.println("任务办理人:" + task.getAssignee());
System.out.println("执行实例ID:" + task.getExecutionId());
System.out.println("任务名称:" + task.getName());
System.out.println("流程定义ID:" + task.getProcessDefinitionId());
System.out.println("流程实例ID:" + task.getProcessInstanceId());
System.out.println("任务创建时间:" + task.getCreateTime());
System.out.println("####################");
}
}
}
处理任务
@Test
public void completeTask() {
TaskService taskService = this.processEngine.getTaskService();
String taskId = "12504";
// 根据任务ID去完成任务
taskService.complete(taskId);
// 根据任务ID去完成任务并指定流程变量
// taskService.complete(taskId, variables);
System.out.println("任务完成");
}
判断任务是否完成
@Test
public void isComplete() {
// 已知流程实例ID
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String processInstanceId = "12504";
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId(processInstanceId).singleResult();
if (null != processInstance) {
System.out.println("流程未结束");
} else {
System.out.println("流程已结束");
}
根据任务判断流程是否完成
// 已知任务ID 5002 [了解]
// 根据任务ID查询任务实例对象
/*
* TaskService taskService = this.processEngine.getTaskService(); String
* taskId="5002"; Task task =
* taskService.createTaskQuery().taskId(taskId).singleResult();
* //从任务实例里面取出流程实例ID String processInstanceId2 = task.getProcessInstanceId();
* //使用流程实例ID去流程实例表里面查询有没有数据 ProcessInstanceQuery processInstance2 =
* runtimeService.createProcessInstanceQuery().processInstanceId(
* processInstanceId2); if (null != processInstance2) {
* System.out.println("流程未结束"); } else { System.out.println("流程已结束"); }
*/
查询当前流程实例
// act_ru_execution
@Test
public void queryProcessInstance() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().list();
if (null != list && list.size() > 0) {
for (ProcessInstance pi : list) {
System.out.println("执行实例ID:" + pi.getId());
System.out.println("流程定义ID:" + pi.getProcessDefinitionId());
System.out.println("流程实例ID:" + pi.getProcessInstanceId());
System.out.println("########################");
}
}
}
流程变量
流程变量在整个工作流中扮演很重要的作用。例如:请假流程中有请假天数、请假原因等一些参数都为流程变量的范围。流程变量的作用域范围是
只对应一个流程实例
也就是说各个流程实例的流程变量是不相互影响的。流程实例结束完成以后流程变量还保存在数据库中(存放到流程变量的历史表中)。
存在形式 <key,value>
部署流程
@Test
public void deployProcess() {
// 得到流程部署的service
RepositoryService repositoryService = this.processEngine.getRepositoryService();
Deployment deploy = repositoryService.createDeployment().name("请假流程001").addClasspathResource("HelloWorld.bpmn")
.addClasspathResource("HelloWorld.png").deploy();
System.out.println("部署成功:流程部署ID:" + deploy.getId());
}
启动流程
@Test
public void startProcess() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String processDefinitionKey = "HelloWorld";
// ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey);
//创建流程变量对象
Map<String,Object> variables=new HashMap<>();
variables.put("请假天数", 5);//int
variables.put("请假原因", "约会");
variables.put("请假时间", new Date());
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
System.out.println("流程启动成功:" + processInstance.getId() + " " + processInstance.getProcessDefinitionId() + " "
+ processInstance.getProcessInstanceId());
}
设置流程参数
@Test
public void setVariables() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String executionId="2501";
//runtimeService.setVariable(executionId, "请假人", "小明");
Map<String,Object> variables=new HashMap<>();
variables.put("请假天数", 6);//int
variables.put("请假原因", "约会妹子");
variables.put("请假时间", new Date());
variables.put("用户对象", new User(1,"小明"));
runtimeService.setVariables(executionId, variables);
System.out.println("流程变量设置成功");
}
设置流程参数2
@Test
public void setVariables2() {
TaskService taskService = this.processEngine.getTaskService();
String taskId="2507";
//runtimeService.setVariable(executionId, "请假人", "小明");
Map<String,Object> variables=new HashMap<>();
variables.put("任务ID设置的", 9);//int
// taskService.setVariable(taskId, variableName, value);
taskService.setVariables(taskId, variables);
System.out.println("流程变量设置成功");
}
获取流程变量
@Test
public void getVariables() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String executionId="2501";
Integer days=(Integer) runtimeService.getVariable(executionId, "请假天数");
Date date=(Date) runtimeService.getVariable(executionId, "请假时间");
User user=(User) runtimeService.getVariable(executionId, "用户对象");
System.out.println(days);
System.out.println(date.toLocaleString());
System.out.println(user.getId()+" "+user.getName());
}
查询历史流程变量
public void getHistoryVariables() {
HistoryService historyService = this.processEngine.getHistoryService();
/*HistoricVariableInstance singleResult = historyService.createHistoricVariableInstanceQuery().id("2503").singleResult();;
System.out.println(singleResult.getId());
System.out.println(singleResult.getValue());
System.out.println(singleResult.getVariableName());
System.out.println(singleResult.getVariableTypeName());*/
String processInstanceId="2501";
List<HistoricVariableInstance> list = historyService.createHistoricVariableInstanceQuery().processInstanceId(processInstanceId).list();
for (HistoricVariableInstance hvs : list) {
System.out.println("ID"+hvs.getId());
System.out.println("变量值"+hvs.getValue());
System.out.println("变量名"+hvs.getVariableName());
System.out.println("变量类型"+hvs.getVariableTypeName());
System.out.println("#####################");
}
}
设置Local流程变量
@Test
public void setVariables3() {
RuntimeService runtimeService = this.processEngine.getRuntimeService();
String executionId="2501";
//runtimeService.setVariable(executionId, "请假人", "小明");
Map<String,Object> variables=new HashMap<>();
variables.put("测试", "约会妹子");
runtimeService.setVariablesLocal(executionId, variables);
System.out.println("流程变量设置成功");
}
@Test
public void setVariables4() {
TaskService taskService = this.processEngine.getTaskService();
String taskId="2507";
//runtimeService.setVariable(executionId, "请假人", "小明");
Map<String,Object> variables=new HashMap<>();
variables.put("测试2", 9);//int
taskService.setVariablesLocal(taskId, variables);
System.out.println("流程变量设置成功");
}
Local流程变量和普通变量区别
- 普通变量
- 不会去设置task_id
- 可以理解成一个执行示例内共享的
- Local变量
- 绑定了当前任务,所以下一个任务是取不到该变量的
历史流程
查询历史流程示例
@Test
public void historyProcessInstince() {
List<HistoricProcessInstance> list = historyService.createHistoricProcessInstanceQuery()
//条件
// .processDefinitionId(processDefinitionId)
// .processDefinitionKey(processDefinitionKey)
// .processDefinitionKeyIn(processDefinitionKeys)
// .processDefinitionName(processDefinitionName)
// .processDefinitionVersion(processDefinitionVersion)
// .processInstanceBusinessKey(processInstanceBusinessKey)
// .processInstanceId(processInstanceId)
// .processInstanceIds(processInstanceIds)
//排序
// .orderByProcessDefinitionId()
// .orderByProcessInstanceBusinessKey()
// .orderByProcessInstanceDuration()
// .orderByProcessInstanceStartTime()
// .orderByProcessInstanceId()
//结果集
.list();
// .listPage(firstResult, maxResults)
// .count()
// .singleResult();
if(null!=list&&list.size()>0) {
for (HistoricProcessInstance hpi : list) {
System.out.println("历史流程实例ID:" + hpi.getId());
System.out.println("流程定义ID:" + hpi.getProcessDefinitionId());
System.out.println("历史流程实例的业务ID:" + hpi.getBusinessKey());
System.out.println("流程部署ID:" + hpi.getDeploymentId());
System.out.println("流程定义KEY:" + hpi.getProcessDefinitionKey());
System.out.println("开始活动ID:" + hpi.getStartActivityId());
System.out.println("结束活动ID:" + hpi.getEndActivityId());
System.out.println("########################");
}
}
}
查询历史活动节点
@Test
public void queryHistoryAct() {
List<HistoricActivityInstance> list = this.historyService.createHistoricActivityInstanceQuery()
//条件
// .activityId(activityId)
// .activityInstanceId(activityInstanceId)
// .activityName(activityName)
//排序
// .orderByActivityId()
// .orderByActivityName()
//结果集
.list();
if(null!=list&&list.size()>0)
{
for (HistoricActivityInstance hai : list) {
System.out.println("ID:"+hai.getId());
System.out.println("流程定义ID:"+hai.getProcessDefinitionId());
System.out.println("流程实例ID:"+hai.getProcessInstanceId());
System.out.println("执行实例ID:"+hai.getExecutionId());
System.out.println("活动ID:"+hai.getActivityId());
System.out.println("任务ID:"+hai.getTaskId());
System.out.println("活动名称:"+hai.getActivityName());
System.out.println("活动类型:"+hai.getActivityType());
System.out.println("任务办理人:"+hai.getAssignee());
System.out.println("开始时间:"+hai.getStartTime());
System.out.println("结束时间:"+hai.getEndTime());
System.out.println("持续时间:"+hai.getDurationInMillis());
System.out.println("#######################################");
}
}
}
查询历史任务
@Test
public void queryHistoryTask() {
List<HistoricTaskInstance> list = this.historyService.createHistoricTaskInstanceQuery()
//条件
// .deploymentId(deploymentId)
// .deploymentIdIn(deploymentIds)
// .executionId(executionId)
// .processDefinitionId(processDefinitionId)
// .processDefinitionKey(processDefinitionKey)
// .processDefinitionKeyIn(processDefinitionKeys)
// .processDefinitionKeyLike(processDefinitionKeyLike) processDefinitionKeyLike="%Hello%"
// .processDefinitionName(processDefinitionName)
// .processDefinitionNameLike(processDefinitionNameLike)
//排序
// .orderByTaskDefinitionKey()
//结果集
.list();
// .listPage(firstResult, maxResults)
// .count()
// .singleResult()
if(null!=list&&list.size()>0)
{
for (HistoricTaskInstance task : list) {
System.out.println("任务ID:" + task.getId());
System.out.println("任务办理人:" + task.getAssignee());
System.out.println("执行实例ID:" + task.getExecutionId());
System.out.println("任务名称:" + task.getName());
System.out.println("流程定义ID:" + task.getProcessDefinitionId());
System.out.println("流程实例ID:" + task.getProcessInstanceId());
System.out.println("任务创建时间:" + task.getCreateTime());
System.out.println("任务结束时间:" + task.getEndTime());
System.out.println("#######################################");
}
}
}
连线
核心:通过流程变量,判断流程走向
处理流程
@Test
public void completeTask() {
TaskService taskService = this.processEngine.getTaskService();
String taskId = "7503";
//Map<String, Object> variables = new HashMap<>();
//variables.put("outcome", "重要");
// 根据任务ID去完成任务
taskService.complete(taskId);
// 根据任务ID去完成任务并指定流程变量
//taskService.complete(taskId, variables);
System.out.println("任务完成");
}
排他网关
排他网关类似于 if、if-else、if-else、else
处理流程
@Test
public void completeTask2() {
TaskService taskService = this.processEngine.getTaskService();
String taskId = "20004";
Map<String, Object> variables=new HashMap<>();
variables.put("money", 1200);
// 根据任务ID去完成任务并指定流程变量
taskService.complete(taskId, variables);
System.out.println("任务完成");
}
并行网关
同时执行
下图启动后,会生成付款、发货两个任务
excution中会有三条记录,三个执行实例的流程实例是同一个
个人任务
之前创建流程图时候,办理人是事先写好的,后续不能修改,所以需动态分配
分配方式一(事先定义)
分配方式二(流程变量)
执行下一个节点前,先设置流程变量,指定办理人
分配方式二(使用类)
public class TaskListenerImpl implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
System.out.println("我来了");
String assignee = "李四";
delegateTask.setAssignee(assignee);
}
}
组任务(动态指定一组成员里里某个人来处理下一个任务)
一个流程节点的办理人是一个,但是希望能给多个人看到该任务,类似于抄送的功能
分配方式一(直接指定组成员)
流程启动后,
act_ru_task
表中不会有办理人需要手动拾取,act_ru_identitylink表
中每个组成员都会有两条数据
- candidate 候选者
- participant 参与者
查询组任务
@Test
public void findGroupTask() {
TaskService taskService = this.processEngine.getTaskService();
String candidateUser = "小B";
List<Task> list = taskService.createTaskQuery().taskCandidateUser(candidateUser).list();
if (null != list && list.size() > 0) {
for (Task task : list) {
System.out.println("任务ID:" + task.getId());
System.out.println("流程实例ID:" + task.getProcessInstanceId());
System.out.println("执行实例ID:" + task.getExecutionId());
System.out.println("流程定义ID:" + task.getProcessDefinitionId());
System.out.println("任务名称:" + task.getName());
System.out.println("任务办理人:" + task.getAssignee());
System.out.println("################################");
}
}
}
任务拾取(组任务变成个人任务)
@Test
public void claim() {
String taskId="2505";
TaskService taskService = this.processEngine.getTaskService();
taskService.claim(taskId, "小A");
System.out.println("任务拾取成功");
}
拾取后,去查候选人任务就查不到了
任务回退
@Test
public void claimBack() {
String taskId="2504";
TaskService taskService = this.processEngine.getTaskService();
taskService.setAssignee(taskId, null);
System.out.println("任务回退成功");
}
查询任务成员列表
@Test
public void findGroupUser(){
String taskId = "2504";
List<IdentityLink> list = processEngine.getTaskService()//
.getIdentityLinksForTask(taskId);
//List<IdentityLink> list = processEngine.getRuntimeService()//
// .getIdentityLinksForProcessInstance(instanceId);
for(IdentityLink identityLink:list ){
System.out.println("userId="+identityLink.getUserId());
System.out.println("taskId="+identityLink.getTaskId());
System.out.println("piId="+identityLink.getProcessInstanceId());
System.out.println("TYPE="+identityLink.getType());
System.out.println("######################");
}
}
添加组成员
@Test
public void addGroupUser() {
String taskId="2504";
TaskService taskService = this.processEngine.getTaskService();
taskService.addCandidateUser(taskId, "小E");
System.out.println("添加组成员成功");
}
删除组成员
@Test
public void deleteGroupUser() {
String taskId="2504";
TaskService taskService = this.processEngine.getTaskService();
taskService.deleteCandidateUser(taskId, "小E");
System.out.println("添加组成员成功");
}
分配方式二(使用流程变量)
分配方式三(使用类)
public class GroupTaskListenerImpl implements TaskListener{
@Override
public void notify(DelegateTask delegateTask) {
System.out.println("进来了");
delegateTask.addCandidateUser("小A");
delegateTask.addCandidateUser("小B");
delegateTask.addCandidateUser("小C");
delegateTask.addCandidateUser("小D");
}
}