activiti05
什么是流程实例
参与者(可以是用户也可以是程序)按照流程定义内容发起一个流程,这就是一个流程实例。是动
态的。
流程定义部署在 activiti 后,就可以在系统中通过 activiti 去管理该流程的执行,执行流程表示流
程的一次执行。
多个用户可同时执行该流程,每个执行互不影响,每个执行是单独的流程实例
流程实例的部署与启动
1 /** 2 * 流程变量的测试---新的请假流程定义的部署 3 * 1.得到ProcessEngine 4 * 2.得到ReposuitoryService对象 5 * 3.实现部署 6 * 7 */ 8 9 public static void main(String[] args) { 10 /* ProcessEngine ProcessEngine = ProcessEngines.getDefaultProcessEngine(); 11 RepositoryService repositoryService = ProcessEngine.getRepositoryService(); 12 Deployment deployment = repositoryService.createDeployment() 13 .addClasspathResource("diagram/holiday4.bpmn") 14 .addClasspathResource("diagram/holiday4.png").name("请假流程-流程变量") 15 .deploy(); 16 System.out.println(deployment.getId()); 17 System.out.println(deployment.getName());*/
18 //流程实例的启动
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday");
System.out.println("流程定义ID"+processInstance.getProcessDefinitionId()); //92503
System.out.println("流程实例ID"+processInstance.getId());
19
BussinessKey 业务标识
启动流程实例时,指定的businesskey,就会在act_ru_execution #流程实例的执行表中存储businesskey
Businesskey:业务标识,通常为业务表的主键,业务标识和流程实例一一对应。业务标识来源于业
务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据
1 /** 2 * 添加bussinessKey 3 * 1.得到ProcenessEngine 4 * 2.得到RuntimeService 5 * 3.管理流程实例,指定业务标识bussinessKey 6 * ---params 流程定义的key ,业务标识bussinessKey 7 * 4.输出processInstance属性 8 * 9 * 本质:act_ru_execution表的bussinessKey要存入标识 10 * 11 */ 12 13 14 public static void main(String[] args) { 15 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 16 RuntimeService runtimeService = processEngine.getRuntimeService(); 17 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday", "1001"); 18 19 System.out.println(processInstance.getBusinessKey()); 20 }
挂起、激活流程实例
由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执行
全部流程实例挂起
1 /** 2 * 全部流程的挂起和激活 3 * 1.得到ProcessEngine对象 4 * 2.得到RepositoryService 5 * 3.查询流程定义对象 6 * 4.得到当前流程定义是否为暂停状态 7 * 5.判断 8 */ 9 public static void main(String[] args) { 10 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 11 RepositoryService repositoryService = processEngine.getRepositoryService(); 12 ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionKey("请假流程").singleResult(); 13 boolean suspended = processDefinition.isSuspended(); 14 15 String processDefinitionId = processDefinition.getId(); 16 17 if (suspended){ 18 repositoryService.activateProcessDefinitionById(processDefinitionId,true,null); 19 System.out.println("流程定义:"+processDefinitionId+"激活"); 20 }else { 21 repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null); 22 System.out.println("流程定义:"+processDefinitionId+"挂起"); 23 } 24 25 26 27 }
单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行
/** 1.得到processEngine * 2.获取RuntimeService * 3.根据流程实例id查询流程实例 * 4.判段 */ public static void main(String[] args) { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId("35001").singleResult(); //act_ru_execution boolean suspended = processInstance.isSuspended(); String processInstanceId = processInstance.getId(); if (suspended){ runtimeService.activateProcessInstanceById(processInstanceId);; System.out.println("流程定义"+processInstanceId+"激活"); }else { runtimeService.suspendProcessInstanceById(processInstanceId); System.out.println("流程定义"+processInstanceId+"挂起"); }
个人任务
固定分配
Assigneee:任务负责人
表达式分配
UEL 表达式 activiti 支持两个 UEL 表达式: UEL-value 和 UEL-method, assignee 这个变量是 activiti 的一个流程变量
${ldapService.findManagerForEmployee(emp)}
ldapService 是 spring 容器的一个 bean,findManagerForEmployee 是该 bean 的一个方法,emp 是 activiti
流程变量, emp 作为参数传到 ldapService.findManagerForEmployee 方法中
表达式支持解析基础类型、 bean、 list、 array 和 map,也可作为条件判断。
如下:
${order.price > 100 && order.price < 250}
使用流程变量分配任务
start -》 填写请假申请单 -》部门经理审批 -》总经理审批 -》end
设部门经理审批的Assignee 为 ${assignee}
1.自动流程实例
/** *自动流程实例 * 1.得到ProcessEngine * 2.得到RuntimeService * 3.设置assignee的取值,用户可以在界面上设置流程执行人 * 4.启动流程实例,同时设置流程定义的assignee的值 * 5.输出 */ public static void main(String[] args) { ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); Map<String,Object> map = new HashMap<>(); map.put("assignee","zhangsan"); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday2", map); }
监听器分配
Task Listeners
Create:任务创建后触发
Assignment:任务分配后触发
Delete:任务完成后触发
All:所有事件发生都触发
定义任务监听类,且类必须实现 org.activiti.engine.delegate.TaskListener 接口
流程变量
流程变量就是 activiti 在管理工作流时根据管理需要而设置的变量
如果将 pojo 存储到流程变量中,必须实现序列化接口 serializable,为了防止由于新增字段无
法反序列化,需要生成 serialVersionUID
流程变量的作用域默认是一个流程实例(processInstance),也可以是一个任务(task)或一个执行实例
(execution),这三个作用域流程实例的范围最大,可以称为 global 变量,任务和执行实例仅仅是针对
一个任务和一个执行实例范围,范围没有流程实例大, 称为 local 变量。
设置流程变量
通过UEL表达式使用流程变量
1.在assignee处设置uel表达式,表达式的值为任务的负责人
2.在连线上设置uel表达式,决定流程走向
uel为true,决定流程走向
使用 Global 变量控制流程
需求:员工创建请假申请单,由部门经理审核,部门经理审核通过后请假 3 天及以下由人事经理直接
审核, 3 天以上先由总经理审核,总经理审核通过再由人事经理存档
Holiday
1 public class Holiday implements Serializable { 2 3 private Integer id; 4 private String holidayName; 5 private Date beginDate; 6 private Date endDate; 7 private Float num; 8 private String reason; 9 private String type; 10 11 //getter 12 //setter 13 16 17 }
启动流程时设置
在启动流程时设置流程变量,变量的作用域是整个流程实例
/** * 流程变量的测试---新的请假流程定义的部署 * 1.得到ProcessEngine * 2.得到ReposuitoryService对象 * 3.实现部署 * */ public static void main(String[] args) { /* ProcessEngine ProcessEngine = ProcessEngines.getDefaultProcessEngine(); RepositoryService repositoryService = ProcessEngine.getRepositoryService(); Deployment deployment = repositoryService.createDeployment() .addClasspathResource("diagram/holiday4.bpmn") .addClasspathResource("diagram/holiday4.png").name("请假流程-流程变量") .deploy(); System.out.println(deployment.getId()); System.out.println(deployment.getName());*/ /** * 启动流程实例,设置流程变量 * 1.得到ProcessEngine * 2.得到RuntimeService * 3.流程定义的key myProcess_1 * act_ge_bytearray * act_ru_variable */ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); RuntimeService runtimeService = processEngine.getRuntimeService(); String key = "myProcess_1"; Map<String,Object> map = new HashMap<>(); Holiday holiday = new Holiday(); holiday.setNum(1F); map.put("holiday",holiday); ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key, map); System.out.println(processInstance.getProcessDefinitionId()); }
startProcessInstanceByKey(processDefinitionKey, variables)流程变量作用域是一个流程实例,流程变量使用 Map 存储,同一个流程实例设置变量 map 中 key 相同,后者覆盖前者
任务办理时设置
1 public static void main(String[] args) { 2 3 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 4 TaskService taskService = processEngine.getTaskService(); 5 String key = "myProcess_1"; 6 Task task = taskService.createTaskQuery().processDefinitionKey(key) 7 .taskAssignee("zhangsan").singleResult(); 8 9 Map<String,Object> map = new HashMap<>(); 10 11 Holiday holiday = new Holiday(); 12 holiday.setNum(5F); 13 14 map.put("holiday",holiday); 15 if (task != null){ 16 taskService.complete(task.getId(),map); 17 System.out.println("任务执行完成"); 18 } 19 }
3.通过当前流程实例设置
1 /** 2 *通过流程实例ID设置全局变量 3 *1.得到ProcessEngine 4 * 2.得到RuntimeService 5 * 3.流程定义的key问题 6 * 4.通过实例id,来设置流程变量 7 * 参数:流程实例的id,流程变量名,流程变量名所对应的值 8 * 5. 9 */ 10 11 12 /* //流程实例的定义 13 public static void main(String[] args) { 14 15 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 16 17 RuntimeService runtimeService = processEngine.getRuntimeService(); 18 19 String key = "myProcess_1"; 20 21 22 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(key); 23 24 System.out.println(processInstance.getProcessDefinitionId()); 25 System.out.println(processInstance.getId()); //流程实例的id 70001 26 27 28 }*/ 29 30 public static void main(String[] args) { 31 32 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 33 34 RuntimeService runtimeService = processEngine.getRuntimeService(); 35 36 String key = "myProcess_1"; 37 Holiday holiday = new Holiday(); 38 holiday.setNum(5F); 39 40 runtimeService.setVariable("70001","holiday",holiday); 41 42 43 }
executionId 必须当前未结束 流程实例的执行 id,通常此 id 设置流程实例 的 id。
4.通过当前任务设置
gloal 变量
taskService.setVariblesLocal(......)
组任务
设置多个候选人,可以从候选人中选择参与者来完成任务
使用activiti:candiateUsers=”用户 1,用户 2,用户 3”的这种方式来实现设置一组候选人
组任务的办理流程
1.查询组任务
2.拾取(claim)任务
3.查询个人任务
4.办理个人任务
场景
start -> 填写请假单 -》部门经理审批(Candidate User : zhangsa,lisi) -》总经理
1.部署流程定义 2.启动流程实例
用户组查询任务
1 /** 2 * 1.得到ProcessEngine 3 * 2.得到TaskService 4 * 3.设置一些参数,流程 5 * 4.执行查询 6 */ 7 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 8 TaskService taskService = processEngine.getTaskService(); 9 10 String key = "myProcess_1"; 11 String candidate_users = "zhangsan"; 12 List<Task> list = taskService.createTaskQuery() 13 .processDefinitionKey(key) 14 .taskCandidateUser(candidate_users) //设置候选用户 15 .list(); 16 17 for (Task task : list){ 18 System.out.println(task.getProcessInstanceId()); 19 System.out.println(task.getId()); 20 System.out.println(task.getName()); 21 System.out.println(task.getAssignee()); 22 }
用户拾取任务
//拾取任务的过程就是将候选选用户转化为真正任务的负责人(让任务的assignee有值) ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); String key = "myProcess_1"; String candidate_users = "zhangsan"; Task task = taskService.createTaskQuery() .processDefinitionKey(key) .taskCandidateUser(candidate_users) .singleResult(); if (task != null){ taskService.claim(task.getId(),candidate_users);//(参数任务的ID,具体的候选用户名) System.out.println("任务拾取完毕"); }
用户查询自己的任务
//当前的用户查询自己的任务 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); String key = "myProcess_1"; String assignee = "zhangsan"; List<Task> list = taskService.createTaskQuery() .processDefinitionKey(key) .taskAssignee(assignee) .list(); for (Task task : list){ System.out.println(task.getProcessInstanceId()); System.out.println(task.getId()); System.out.println(task.getName()); System.out.println(task.getAssignee()); }
用户办理个人任务
1 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 2 TaskService taskService = processEngine.getTaskService(); 3 String key = "myProcess_1"; 4 String assignee="zhangsan"; 5 Task task = taskService.createTaskQuery() 6 .processDefinitionKey(key) 7 .taskAssignee(assignee) //设置任务的负责人 8 .singleResult(); 9 10 if (task != null){ 11 taskService.complete(task.getId()); 12 System.out.println("任务执行完毕!"); 13 }
归还组任务
1 TaskService taskService = processEngine.getTaskService(); 2 // 当前待办任务 3 String taskId = "6004"; 4 // 任务负责人 5 String userId = "zhangsan2"; 6 // 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务 7 Task task = taskService.createTaskQuery().taskId(taskId) 8 .taskAssignee(userId).singleResult(); 9 if (task != null) { 10 // 如果设置为null,归还组任务,该 任务没有负责人 11 taskService.setAssignee(taskId, null);
任务交接
任务交接,任务负责人将任务交给其它候选人办理该任务
1 //8.任务交接,前提要保证当前用户是这个任务的负责人,这时候他才可以有权限去将任务交接给其他候选人 2 public static void main(String[] args) { 3 //1.得到ProcessEngine对象 4 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 5 6 //2.得到TaskService对象 7 TaskService taskService = processEngine.getTaskService(); 8 9 //3.设置一些参数,流程定义的key,用户 10 String key = "myProcess_1"; 11 String assignee="zhangsan"; 12 13 //4.执行查询 14 Task task = taskService.createTaskQuery() 15 .processDefinitionKey(key) 16 .taskAssignee(assignee) //设置任务的负责人 17 .singleResult(); 18 //5.判断是否有这个任务 19 if(task!=null){ 20 taskService.setAssignee(task.getId(),"lisi");//交接任务为lisi ,交接任务就是一个候选人拾取用户的过程 21 System.out.println("交接任务完成~!"); 22 } 23 }
网关
排他网关(也叫异或(XOR)网关,或叫基于数据的排他网关),用来在流程中实现决策。 当流程
执行到这个网关,所有分支都会判断条件是否为 true,如果为 true 则执行该分支
在condition上设置条件
排他网关只会选择一个为 true 的分支执行
部署流程定义
//1.部署流程定义 public static void main(String[] args) { //1.创建ProcessEngine对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.得到RepositoryService实例 RepositoryService repositoryService = processEngine.getRepositoryService(); //3.进行部署 Deployment deployment = repositoryService.createDeployment() .addClasspathResource("diagram/day05/holiday5.bpmn") //添加bpmn资源 //.addClasspathResource("diagram/holiday5.png") .name("请假申请单流程") .deploy(); //4.输出部署的一些信息 System.out.println(deployment.getName()); System.out.println(deployment.getId()); }
启动流程实例
1 public static void main(String[] args) { 2 //1.得到ProcessEngine对象 3 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); 4 5 //2.得到RunService对象 6 RuntimeService runtimeService = processEngine.getRuntimeService(); 7 8 Holiday holiday = new Holiday(); 9 holiday.setNum(5F); 10 Map<String,Object> map = new HashMap<>(); 11 map.put("holiday",holiday);//流程变量赋值 12 13 //3.创建流程实例 流程定义的key需要知道 holiday 14 ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holidayExclusive",map); 15 16 17 //4.输出实例的相关信息 18 System.out.println("流程定义ID"+processInstance.getProcessDefinitionId());//holiday:1:4 19 System.out.println("流程实例ID"+processInstance.getId());//2501 20 }
依次执行任务
public static void main(String[] args) { //1.得到ProcessEngine对象 ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //2.得到TaskService对象 TaskService taskService = processEngine.getTaskService(); //3.查询当前用户的任务 Task task = taskService.createTaskQuery() .processDefinitionKey("holidayExclusive") .taskAssignee("zhangsan") .singleResult(); //4.处理任务,结合当前用户任务列表的查询操作的话,任务ID:task.getId() if(task!=null){ taskService.complete(task.getId()); System.out.println("用户任务执行完毕..."); }
并行网关
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进
入和外出顺序流的
fork 分支:
并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
join 汇聚:
所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通
过汇聚网关
并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略
财务结算和入库是两个 execution 分支,在 act_ru_execution 表有两条记录分别是财务结算和入库,
act_ru_execution 还有一条记录表示该流程实例。
待财务结算和入库任务全部完成,在汇聚点汇聚,通过 parallelGateway 并行网关。
并行网关在业务应用中常用于会签任务,会签任务即多个参与者共同办理的任务
包含网关
包含网关可以看做是排他网关和并行网关的结合体。 和排他网关一样,你可以在外出顺序流上
定义条件,包含网关会解析它们。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行
网关一样。
包含网关的功能是基于进入和外出顺序流的:
分支
所有外出顺序流的条件都会被解析,结果为 true 的顺序流会以并行方式继续执行, 会为每个顺序流 创建一个分支。
汇聚
所有并行分支到达包含网关,会进入等待状态, 直到每个包含流程 token 的进入顺序流的分支都到达。
先走到汇聚结点的分支,要等待其它分支走到汇聚。
等所有分支走到汇聚,包含网关就执行完成。包含网关执行完成,分支和汇聚就从act_ru_execution删除
完