传智播客activiti课堂笔记4

更新时间:2023-09-26 00:30:01 阅读量: 综合文库 文档下载

说明:文章内容仅供预览,部分内容可能不全。下载后的文档,内容与下面显示的完全一致。下载之前请确认下面内容是否您想要的,是否完整无缺。

Activiti 第四天 组任务 网关

课程安排: 组任务: Candidate-user 候选人 Candidate-group 候选组(重点)

网关(重点): ExclusiveGateway 排他网关 parallelGateway 并行网关 InclusiveGateway 包含网关

综合案例(重点)

1 复习

采购流程监控查询(常用,重点) 当前流程实例查询,查询系统中当前正在运行所有流程,查看流程当前运行的状态

结束的流程信息,主要应用于对历史业务数据进行统计分析: 实现方法(掌握): 分工明确,业务系统记录了业务数据,统计来源于业务系统。

可能会需要acitiviti将流程的运行信息通过监听器写入业务系统中。 监听器: TaskListener ExecutionListener 历史任务查询:

根据流程实例id查询该流程执行过的所有任务 根据用户id(通常是当前用户)查询该 用户所执行过的任务

流程变量:

流程变量类型包括 : 简单类型:string double…

序列化类型:自定义的pojo,需要实现serializable接口。 流程变量作用域:

Global全局变量:activiti中常用,作用域最大,是整个流程实例,当流程实例结束,global变量无效。 Local局部变量:作用域可以是一个任务Task、或一个执行分支Execution,当这个任务结束,local变量无效。

可以通过historyService查询历史流程变量。

注意:流程变量是activiti用于控制流程设置的变量,不建议流程变量中存储业务数据。

流程变量使用:(重点) 通过UEL表达式来使用流程变量控制流程的执行。

通过在连线上设置condition条件,条件使用UEL表达式,表达式中使用流程变量。 注意:

如果UEL表达式中流程变量不存在会跑出异常。

如果UEL表达式中流程变量存在,没有符合的条件,流程会执行结束。(排他网关可以避免)

全局变量设置:

常用: 1》流程启动时设置流程变量,流程变量可以任何结点使用。

runtimeService.startProcessInstanceByKey(processDefinitionKey,variables) 2》任务完成时设置流程变量,在任务的后续结点可以使用该流程变量。 taskService.complete(tasked, variables)

3》通过当前流程实例 的id设置流程变量

runtimeService.setVariables(processInstanceId, variables) 通过:runtimeService.getVariables()方法获取全局变量 processInstanceId:必须是当前正在运行的流程实例id 4》通过当前待办任务的id设置流程变量。 taskService.setVariables(taskId, variables)

通过: taskService.getVariables()方法获取全局变量 taskId:必须是当前待办任务(未完成任务)的id

2 Candidate-user候选人

2.1 什么是候选人

采用固定分配方法给任务指定负责人,如果任务负责人出现变更,需要修改流程定义,就可以采用候选人分配方式,先给任务分配多个候选人,候选人通过拾取组任务进行个人任务办理。

给任务分配候选人,如果分配多个候选人中间使用半角逗号分隔。

2.2 什么是组任务

多个候选人有资格完成该 任务,这个任务叫做组任务。 组任务具备条件: 任务没有设置assignee任务负责人 任务具有候选人

2.3 候选人办理任务过程

第一步:给任务设置候选人(多个, 中间使用半角逗号分隔) 候选人是无法办理任务 第二步:候选人查询组任务

使用taskService查询,指定candidate候选人。 第三步:候选人拾取(claim)组任务

候选人拾取组任务后,该 候选人变为任务的负责人,该任务变为个人任务

如果候选人拾取组任务后,不想办理该 任务,可以将个人任务归还,该个人任务变为组任务

第四步:查询待办个人任务

第五步:办理任务

第六步:流程结束

2.4 Candidate-user办理任务api

2.4.1 候选人查询组任务

使用taskService指定candidateUser候选人查询组任务。

//任务查询对象

TaskQuery taskQuery = taskService.createTaskQuery();

//候选人

String candidateUser = \;

taskQuery.taskCandidateUser(candidateUser);

//流程定义key

String processDefinitionKey = \;

taskQuery.processDefinitionKey(processDefinitionKey);

List list = taskQuery.list();

注意:查询组任务,必须指定 candidateUser候选人,查询该 候选人有资格办理的组任务。

2.4.2 拾取组任务

通过taskService,指定任务id和候选人拾取任务:

TaskService taskService = processEngine.getTaskService();

//组任务id

String taskId = \;

//任务候选人,claim拾取后该 候选人变为任务负责人 String userId = \; //任务拾取

taskService.claim(taskId, userId);

注意:如果拾取人不是该任务的候选人也可以拾取成功,在拾取之前需要校验,该 候选人是否有资格拾取该 任务.

// 组任务id

String taskId = \;

// 任务候选人,claim拾取后该 候选人变为任务负责人 String candidateUser = \;

//根据候选人和组任务id查询,如果有记录说明该 候选人有资格拾取该 任务 Task task = taskService.createTaskQuery().taskId(taskId) .taskCandidateUser(candidateUser).singleResult();

if(task!=null){ // 任务拾取

taskService.claim(taskId, candidateUser);

System.out.println(\任务拾取成功\); }

2.4.3 组任务归还

// 归还组任务,由个人任务变为组任务,还可以进行任务交接

@Test

public void setAssignee() { // 查询任务使用TaskService

TaskService taskService = processEngine.getTaskService(); // 当前待办任务

String taskId = \; // 任务负责人

String userId = \;

//校验userId是否是taskId的负责人,如果是负责人才可以归还组任务 Task task =

taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult();

if(task!=null){

//如果设置为null,归还组任务,该 任务没有负责人 taskService.setAssignee(taskId, null); }

}

2.4.4 任务交接

任务负责人也可以将任务交给其它候选人办理该任务

代码如下:

@Test

public void setAssigneeToCandidateUser() { // 查询任务使用TaskService

TaskService taskService = processEngine.getTaskService(); // 当前待办任务

String taskId = \; // 任务负责人

String userId = \;

// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务 Task task = taskService.createTaskQuery().taskId(taskId) .taskAssignee(userId).singleResult();

if (task != null) {

// 将此任务交给其它候选人办理该 任务 String candidateuser = \;

// 根据候选人和组任务id查询,如果有记录说明该 候选人有资格拾取该 任务 Task task2 = taskService.createTaskQuery().taskId(taskId)

.taskCandidateUser(candidateuser).singleResult(); if (task2 != null) { // 才可以交接

taskService.setAssignee(taskId, candidateuser); }

} }

2.4.5 查询个人任务

参考个人任务章节

2.4.6 办理个人任务

参考个人任务章节

2.4.7 数据表跟踪

如果任务设置候选人,当前任务表中assignee(任务负责人)是空。

SELECT * FROM act_ru_task #当前任务表

SELECT * FROM act_ru_identitylink #流程参与者 如果任务设置候选,记录所有候选人信息

任务拾取后,task表中assignee记录任务的负责人

3 Candidate-group候选组

3.1 什么候选组

即使给任务指定了多个候选人,多个候选人都有办理任务资格,但是候选的人数有限,无法动态扩展,如果需要添加或删除候选,需要修改流程定义 文件,不利于系统 扩展。 采用候选组方式解决上边的问题。

给任务设置候选组,在组中有多个用户并且可以动态扩展用户,组中的用户都是候选人,候选人先拾取组任务,将组任务变为自己的个人任务,进行个人任务办理。

3.2 候选组办理任务过程

第一步:Activiti会自动从候选组中找用户,将这些用户作为该 任务的候选人。

下边的流程同候选人办理任务过程!!

第二步:给任务设置候选人(多个, 中间使用半角逗号分隔) 候选人是无法办理任务 第三步:候选人查询组任务

使用taskService查询,指定candidate候选人。 第四步:候选人拾取(claim)组任务

候选人拾取组任务后,该 候选人变为任务的负责人,该任务变为个人任务

如果候选人拾取组任务后,不想办理该 任务,可以将个人任务归还,该个人任务变为组任务

第五步:查询待办个人任务

第六步:办理任务

第七步:流程结束

3.3 设置候选组

多个组中间使用半角逗号分隔。

3.4 设置组和用户信息

Activiti中采用以下表记录组信息、用户信息、组和用户关系 信息

SELECT * FROM act_id_group #组信息

SELECT * FROM act_id_user #用户信息

SELECT * FROM act_id_membership #组和用户关系信息

3.4.1 Api设置方法

以下设置的信息和业务系统的用户信息、角色信息保存一致。

先设置组信息

再设置用户信息

再设置组和用户关系信息

代码如下:

//设置组和用户信息 @Test

public void setUserGroup(){

IdentityService identityService = processEngine.getIdentityService();

//设置组信息

//添加之前应该校验组信息是否存在,不存在再进行添加

if(identityService.createGroupQuery().groupId(\).singleResult()==null){ //添加新组

GroupEntity groupEntity = new GroupEntity(); groupEntity.setId(\);

groupEntity.setName(\员工\);

identityService.saveGroup(groupEntity); }

if(identityService.createGroupQuery().groupId(\).singleResult()==null){ //添加新组

GroupEntity groupEntity = new GroupEntity(); groupEntity.setId(\);

groupEntity.setName(\部门经理\);

identityService.saveGroup(groupEntity); }

if(identityService.createGroupQuery().groupId(\).singleResult()==null){ //添加新组

GroupEntity groupEntity = new GroupEntity(); groupEntity.setId(\);

groupEntity.setName(\总经理\);

identityService.saveGroup(groupEntity); }

if(identityService.createGroupQuery().groupId(\).singleResult()==null){ //添加新组

GroupEntity groupEntity = new GroupEntity(); groupEntity.setId(\); groupEntity.setName(\财务\);

identityService.saveGroup(groupEntity); }

//设置用户信息

//添加之前应该校验用户信息是否存在,不存在再进行添加

if(identityService.createUserQuery().userId(\).singleResult()==null){

//添加新用户

UserEntity userEntity = new UserEntity(); userEntity.setId(\); userEntity.setFirstName(\张三\);

identityService.saveUser(userEntity); }

if(identityService.createUserQuery().userId(\).singleResult()==null){ //添加新用户

UserEntity userEntity = new UserEntity(); userEntity.setId(\);

userEntity.setFirstName(\李四\);

identityService.saveUser(userEntity); }

if(identityService.createUserQuery().userId(\).singleResult()==null){

//添加新用户

UserEntity userEntity = new UserEntity(); userEntity.setId(\);

userEntity.setFirstName(\王五\);

identityService.saveUser(userEntity); }

if(identityService.createUserQuery().userId(\).singleResult()==null){

//添加新用户

UserEntity userEntity = new UserEntity(); userEntity.setId(\); userEntity.setFirstName(\赵六\);

identityService.saveUser(userEntity); }

//设置用户和组的关系信息 //采用先删除再添加

identityService.deleteMembership(\, \); identityService.createMembership(\, \);

identityService.deleteMembership(\, \); identityService.createMembership(\, \);

identityService.deleteMembership(\, \); identityService.createMembership(\, \);

identityService.deleteMembership(\, \); identityService.createMembership(\, \); }

3.4.2 与业务系统 同步方法(常用)

业务系统 中存在用户信息,activiti中也存在用户信息,需要只维护一处数据。

通常采用业务系统 向activiti同步方法:

需要将业务系统 中的用户信息和角色信息同步到activiti中。

数据同步:

业务系统---》activiti同步

方法1 :

数据库触发器方法

企业中在进行数据同步的常用方法,一般在一个数据库中采用此方法。 业务系统 用户表----》activiti的act_id_user

在业务系统 用户表添加触发器:新增、删除、修改

注意:如果act_id_user有外键关系,需要先删除依赖关系。

业务系统 角色表----》activiti的act_id_group

业务系统 角色和用户关系表—》activiti的act_id_membership

方法2 :

采用即时触发java程序。 ? 用户角色同步:

在操作业务系统 用户角色表时执行以下操作:

业务系统添加角色-?activiti添加角色 业务系统修改角色?activiti修改角色

业务系统删除角色?activiti删除角色,删除之前将用户角色关系表先删除(根据角色删除)

? 用户信息同步

在操作业务系统 用户表时执行以下操作

业务系统添加用户----》activiti添加用户,添加用户与角色关系表

业务系统修改用户---》activiti修改用户,先删除原来用户与角色关系表,再添加用户与角色关系 业务系统删除用户—》activiti删除用户,删除之前将用户角色关系表删除(根据用户删除)

3.5 组任务办理过程api

3.5.1 设置组和用户信息

参考上边设置组和用户api

正式开发时,需要将业务系统 用户和角色信息同步到activiti中。

3.5.2 候选人查询组任务

参考candidate-user的api

注意:

在activiti的用户、组、用户和组关系表中随时添加数据,不受流程启动先后顺序影响。

3.5.3 拾取组任务

参考candidate-user的api

3.5.4 查询个人任务

参考candidate-user的api

3.5.5 办理个人任务

参考candidate-user的api

3.5.6 数据表跟踪

和候选人不一样:

SELECT * FROM act_ru_identitylink #流程参与者 在group_id_字段设置了候选组的id

4 网关

4.1 排他网关

4.1.1 什么排他网关

排他网关用于决策,选择分支执行流程,分支上需要设置condition条件,如果分支的条件结果 为true,那么该 分

支会通过排他网关。排他网关只会选择一条分支去执行。

4.1.2 定义方法

图标:

流程定义:

4.1.3 排他网关测试

第一步:流程定义部署

第二步:启动流程实例

设置price流程变量值,因为price 在排他网关的两分支使用

第三步:查询待办任务 也可以在部门经理审核后设置price流程变量值,因为price 在排他网关的两分支使用 第四步:办理任务

如果分支上的条件都不满足,没有一条线经过排他网关,activiti会抛出异常:

org.activiti.engine.ActivitiException: No outgoing sequence flow of the exclusive gateway 'exclusivegateway1' could be selected for continuing the process

at

org.activiti.engine.impl.bpmn.behavior.ExclusiveGatewayActivityBehavior.leave(ExclusiveGatewayActivityBehavior.java:85)

如果多条分支都 满足,只会有一条线经过排他网关。

上边两种情况必须在开发避免!!!

4.2 并行网关

4.2.1 什么并行网关

并行网关(parallelGateway),包括分支和汇聚两个结点,所有的分支不判断条件都经过分支结点,所有经过分支结点的分支都要进行汇聚,所有的分支全部执行完成,并行网关执行完成。

Fork(分支) 所有的分支不判断条件都经过分支结点

Join(汇聚) 所有经过分支结点的分支都要进行汇聚

分支的数量等于汇聚数量!

4.2.2 流程定义

图标:

注意:经过并行网关的分支结点,不需要设置condition条件。

4.2.3 并行网关测试

当流程执行到并行的分支结点时,

向act_ru_execution #流程实例执行表执行并行分支(结算,入库)

Execution表中8501的记录数等于分支数+1

只有一条记录的流程实例 id和流程实例执行id相等的,这一条为流程执行主线。

向当前任务表中插入两条记录(结算、入库):

如果一条分支执行完成,在execution表中act_id_改为并行网关汇聚结点的id,表示分支执行完成到汇聚结点等待

其它分支。

当一个分支结束,在当前任务表中就删除该 分支的任务。

所有的分支执行完成,到汇聚结点,并行网关执行完成。

所有经过的结点如下:

历史活动表中,有几条分支就有几条汇聚。

4.3 包含网关

4.3.1 什么是包含网关

包含网关是排他网关和并行网关的结合体。 包含网关(IncluesiveGateway),包括分支和汇聚两个结点,经过分支结点需要判断条件,满足条件经过分支结点,所有经过分支结点的线边最终会进行汇聚。

Fork(分支) 所有的分支需要判断条件,满足条件的经过分支结点 Join(汇聚) 所有满足条件的分支都要进行汇聚

4.3.2 流程定义

图标:

员工类型:

通过流程变量userType来表示,如果等于1表示普通员工,如果等于2表示领导

注意:通过包含网关的每个分支的连线上设置condition条件。

需求如下:

领取完成体检单,对于普通员工体检内容包括 (常规项、抽血化验),对于领导体检内容包括 (常规项、抽血化验、增加项体检),

其中,抽血化验完成方可吃饭,吃饭完成表示抽血化验分支就完成。

设置candition条件:

常规项体检:${userType==’1’ || userType=’2’} 增加项体检:${userType==’2’}

抽血化验:${userType==’1’ || userType=’2’}

4.3.3 包含网关测试

包含网关与并行网关的不同就是经过分支结点的需要满足条件才进行汇聚,并行网关不判断条件,所有经过分支的都经过汇聚结点。

5 案例

5.1 需求

? 将采购流程改为组任务(使用候选组)实现 ? 在采购流程中实现排他网关 ? 在采购流程中实现并行网关

需求描述: 员工创建采购单 经过部门经理审核 审核通过:

部门经理审核通过,如果采购金额大于等于1万元,由总经理审核 部门经理审核通过,如果采购金额小于1万元,由财务审核 审核不通过: 部门经理审核不通过,由员工重新修改采购单进行提交

总经理审核 总经理审核通过由财务审核通过 总经理审核不通过,由员工重新修改采购单进行提交

财务审核 财务审核通过并行执行财务结算和入库

财务审核不通过,由员工重新修改采购单进行提交

财务结算和入库两个操作可以并行执行。

5.2 流程定义

部门经理审核通过后,通过排他网关决定走总经理审核还是财务审核。 财务审核通过后,经过并行网关,财务结算和入库并行执行。

审核分支设置condition 条件: 部门经理审核 :

审核通过candition:

${order.price>=10000 && firstAudit. status==’1’} 部门经理审核通过且采购金额大于等于10000元由总经理审核 ${order.price<10000 && firstAudit. status==’1’}部门经理审核通过且采购金额小于10000元由财务审核 firstAudit和order都是流程变量名称

审核 不通过candition :

${ firstAudit. status==’0’}:部门经理审核不通过由流程发起人重新修改采购单再提交

总经理审核 :

审核通过candition:${ secondAudit. status==’1’} 总经理审核通过 审核 不通过candition : ${ secondAudit. status==’0’}总经理审核不通过

财务审核 :

审核通过candition:${ thirdAudit. status==’1’} 财务审核通过 审核 不通过candition : ${ third Audit. status==’0’}财务审核不通过

5.3 分析

5.3.1 需要开发结算和入库功能

真正的结算和入库很复杂,确定一个功能将流程向后推进一步。 为了教学方便,开发结算和入库功能实现activiti任务完成。

5.3.2 候选人查询组任务

由于任务结点改变 候选组方式分配任务,实现候选人查询组任务。 实现 方法:

调用taskService,指定candidateUser候选人查询组任务。

5.3.3 候选人拾取组任务

由于任务结点改变 候选组方式分配任务,实现候选拾取组任务。

实现方法:

调用taskService,指定组任务id和candidateUserId候选人。 拾取任务之前需要校验候选人是否资格拾取该组任务。

5.4 开发

5.4.1 结算和入库功能

5.4.1.1 dao

不用开发。

实际采购系统 需要开发的,执行结算和入库。

5.4.1.2 service

接口功能:结算

接口参数:taskId任务id、userId用户id 接口实现: 调用 activiti的api执行任务完成

接口功能:入库

接口参数:taskId任务id、userId用户id 接口实现: 调用 activiti的api执行任务完成

@Override

public void saveSettlement(String taskId, String userId) throws Exception { // 根据任务id和assignee查询该任务

Task task = taskService.createTaskQuery().taskId(taskId) .taskAssignee(userId).singleResult(); }

@Override

public void saveStorage(String taskId, String userId) throws Exception { // 根据任务id和assignee查询该任务

Task task = taskService.createTaskQuery().taskId(taskId) .taskAssignee(userId).singleResult();

if (task != null) {

if (task != null) {

taskService.complete(taskId); }

}

taskService.complete(taskId); }

5.4.1.3 action

两个方法: 结算方法: 接收页面传入的个人任务id参数 入库方法:

接收页面传入的个人任务id参数

// 结算

@RequestMapping(\)

public String settlement(HttpSession session, String taskId) throws Exception {

// 当前登陆用户

ActiveUser activeuser = UserUtil.getUserFromSession(session); // 用户id

String userId = activeuser.getUserid();

orderService.saveSettlement(taskId, userId);

// 返回到采购单处理列表

return \; }

// 入库

@RequestMapping(\)

public String storage(HttpSession session, String taskId) throws Exception { }

// 当前登陆用户

ActiveUser activeuser = UserUtil.getUserFromSession(session); // 用户id

String userId = activeuser.getUserid(); orderService.saveStorage(taskId, userId); // 返回到采购单处理列表

return \;

5.4.1.4 页面

修改采购单处理列表页面,添加“结算”和“入库”连接:

本文来源:https://www.bwwdw.com/article/51ld.html

Top