Java_工作流_Acitivti
流程实例
启动流程实例
@Test
public void startProcessInstance() {
// 流程定义key
String processDefinitionKey = "";
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
// 根据流程定义key启动流程 businessKey(如,将请假单的id 作为业务标识)
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, businessKey);
System.out.println(" 流 程 定 义 id : " + processInstance.getProcessDefinitionId());
System.out.println("流程实例id:" + processInstance.getId());
System.out.println("当前活动Id:" + processInstance.getActivityId());
}
查询流程实例
@Test
public void queryProcessInstance() {
// 流程定义key
String processDefinitionKey = "holiday";
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
List<ProcessInstance> list = runtimeService.createProcessInstanceQuery().processDefinitionKey(processDefinitionKey).list();
for (ProcessInstance processInstance : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:" + processInstance.getProcessInstanceId());
System.out.println("所属流程定义id:" + processInstance.getProcessDefinitionId()); System.out.println("是否执行完成:" + processInstance.isEnded());
System.out.println("是否暂停:" + processInstance.isSuspended());
System.out.println(" 当 前 活 动 标 识 : " + processInstance.getActivityId());
}
}
流程挂起和激活
某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执 行。
所有流程挂起:
// 挂起激活流程定义
@Test
public void suspendOrActivateProcessDefinition() {
// 流程定义id
String processDefinitionId = "";
RepositoryService repositoryService = processEngine.getRepositoryService();
// 获得流程定义
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery() .processDefinitionId(processDefinitionId).singleResult();
//是否暂停
boolean suspend = processDefinition.isSuspended();
if(suspend){
//如果暂停则激活,这里将流程定义下的所有流程实例全部激活
repositoryService.activateProcessDefinitionById(processDefinitionId, true, null);
System.out.println("流程定义:"+processDefinitionId+"激活");
}else{
//如果激活则挂起,这里将流程定义下的所有流程实例全部挂起
repositoryService.suspendProcessDefinitionById(processDefinitionId, true, null); System.out.println("流程定义:"+processDefinitionId+"挂起");
}
}
单个流程实例挂起:
@Test
public void suspendOrActiveProcessInstance() {
// 流程实例id
String processInstanceId = "";
// 获取RunTimeService
RuntimeService runtimeService = processEngine.getRuntimeService(); //根据流程实例id查询流程实例
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery() .processInstanceId(processInstanceId).singleResult();
boolean suspend = processInstance.isSuspended();
if(suspend){
//如果暂停则激活
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程实例:"+processInstanceId+"激活");
}else{
//如果激活则挂起
runtimeService.suspendProcessInstanceById(processInstanceId); System.out.println("流程实例:"+processInstanceId+"挂起");
}
}
个人任务
分配任务负责人
在 properties 视图中,填写 Assignee 项为任务负责人。
1、固定分配
zhangsan
2、表达式分配
${ldapService.findManagerForEmployee(emp)} # ldapService 是spring容器的一个bean
${order.price > 100 && order.price < 250}
${assignee}
3、监听器分配
//在 properties 视图中,添加Listenters监听器。
public class MyTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
//这里指定任务负责人
delegateTask.setAssignee("张三");
}
}
查询任务
// 查询当前个人待执行的任务
@Test
public void findPersonalTaskList() {
// 流程定义key
String processDefinitionKey = "holiday";
// 任务负责人
String assignee = "张三丰";
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery()// .processDefinitionKey(processDefinitionKey)// .includeProcessVariables().taskAssignee(assignee).list();
for (Task task : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
办理任务
// 完成任务
@Test
public void completTask() {
//任务id
String taskId = "10305";
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
taskService.complete(taskId);
System.out.println("完成任务");
}
注意:在实际应用中,完成任务前需要校验任务的负责人是否具有该任务的办理权限。
流程变量
如果是对象,需要实现Serializable接口。
设置方式
1> 可以在 assignee 处设置 UEL表达式,表达式的值为任务的负责人
比如:${assignee},assignee 就是一个流程变量名称
Activiti获取 UEL 表达式的值 ,即流程变量 assignee 的值 ,将 assignee 的值作为任务的负责人 进行任务分配
2> 可以在连线上设置 UEL表达式,决定流程走向
比如:${price>=10000}和${price<10000}: price 就是一个流程变量名称,uel 表达式结果类型为 布尔类型
如果 UEL表达式是 true,要决定 流程执行走向。
流程变量作用域
流程变量的作用域默认是一个流程实例(processInstance),也可以是一个任务(task)或一个执行实例 (execution),这三个作用域流程实例的范围最大,可以称为 global变量,
任务和执行实例仅仅是针对 一个任务和一个执行实例范围,范围没有流程实例大,称为 local变量。
Global变量中变量名不允许重复,设置相同名称的变量,后设置的值会覆盖前设置的变量值。 Local变量由于在不同的任务或不同的执行实例中,作用域互不影响,变量名可以相同没有影响。 Local变量名也可以和 global变量名相同,没有影响。
设置 global 流程变量
1、启动流程设置
流程发起时,设置的变量会作用域整个流程实例
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
//变量名是num,变量值是8,变量名也可以是一个对象
//流程变量使用 Map存储,同一个流程实例设置变量map 中 key 相同,后者覆盖前者。
variables.put("num", 8);
RuntimeService runtimeService = processEngine.getRuntimeService();
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey(processDefinitionKey, variables);
2、任务办理时设置
在完成任务时设置流程变量,该流程变量只有在该任务完成后其它结点才可使用该变量
//任务id
String taskId = "";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday();
holiday.setNum(4);
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
//变量名是holiday,变量值是holiday对象
variables.put("holiday", holiday);
taskService.complete(taskId, variables);
3、通过当前流程实例设置
通过流程实例 id 设置全局变量,该流程实例必须未执行完成。
//当前流程实例执行 id,通常设置为当前执行的流程实例
String executionId="2601";
RuntimeService runtimeService = processEngine.getRuntimeService();
Holiday holiday = new Holiday();
holiday.setNum(3);
//通过流程实例 id设置流程变量
runtimeService.setVariable(executionId, "holiday", holiday);
//获取流程变量
runtimeService.getVariable();
4、通过当前任务设置
任务id必须是当前待办任务id,act_ru_task中存在。如果该任务已结束,报错
//当前待办任务id
String taskId="1404";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday();
holiday.setNum(3);
//通过任务设置流程变量
taskService.setVariable(taskId, "holiday", holiday);
//获取流程变量
taskService.getVariable();
流程变量注意事项
1 、 如果 UEL表达式中流程变量名不存在则报错。
2、 如果 UEL表达式中流程变量值为空NULL,流程不按 UEL 表达式去执行,而流程结束 。
3、 如果 UEL表达式都不符合条件,流程结束
4、 如果连线不设置条件,会走 flow 序号小的那条线
设置 local流程变量
1、任务办理时设置
任务办理时设置 local流程变量,当前运行的流程实例只能在该任务结束前使用,任务结束该变量无 法在当前流程实例使用,可以通过查询历史任务查询
// 办理任务时设置local流程变量
@Test
public void completTask() {
//任务id String taskId = "";
TaskService taskService = processEngine.getTaskService();
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
Holiday holiday = new Holiday ();
holiday.setNum(3);
// 定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
//变量名是holiday,变量值是holiday对象 variables.put("holiday", holiday);
// 设置local变量,作用域为该任务
taskService.setVariablesLocal(tasked, variables);
taskService.complete(taskId);
}
2、通过当前任务设置
任务 id 必须是当前待办任务 id,act_ru_task 中存在
@Test
public void setLocalVariableByTaskId(){
//当前待办任务id
String taskId="1404";
TaskService taskService = processEngine.getTaskService();
Holiday holiday = new Holiday ();
holiday.setNum(3);
//通过任务设置流程变量
taskService.setVariableLocal(taskId, "holiday", holiday);
}
3、查询局部变量
查询历史流程变量,特别是查询 pojo 变量需要经过反序列化,不推荐使用
// 创建历史任务查询对象
HistoricTaskInstanceQuery historicTaskInstanceQuery = historyService.createHistoricTaskInstanceQuery();
// 查询结果包括 local变量
historicTaskInstanceQuery.includeTaskLocalVariables();
for (HistoricTaskInstance historicTaskInstance : list) {
System.out.println("==============================");
System.out.println(" 任务id : " + historicTaskInstance.getId());
System.out.println(" 任 务 名 称 : " + historicTaskInstance.getName());
System.out.println(" 任 务 负 责 人 : " + historicTaskInstance.getAssignee()); System.out.println(" 任务local 变 量 : "+ historicTaskInstance.getTaskLocalVariables());
}
组任务
Candidate-users 候选人
在流程图中任务节点的配置中设置 candidate-users(候选人),多个候选人之间用逗号分开
第一步:查询组任务 指定候选人,查询该候选人当前的待办任务。 候选人不能办理任务。
第二步:拾取(claim)任务 该组任务的所有候选人都能拾取。 将候选人的组任务,变成个人任务。原来候选人就变成了该任务的负责人。 ***如果拾取后不想办理该任务? 需要将已经拾取的个人任务归还到组里边,将个人任务变成了组任务。
第三步:查询个人任务 查询方式同个人任务部分,根据 assignee 查询用户负责的个人任务。
第四步:办理个人任务
用户查询组任务
@Test
public void findGroupTaskList() {
// 流程定义key
String processDefinitionKey = "holiday4";
// 任务候选人
String candidateUser = "zhangsan";
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
//查询组任务
//根据候选人查询
List<Task> list = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey).taskCandidateUser(candidateUser).list();
for (Task task : list) {
System.out.println("----------------------------");
System.out.println("流程实例id:" + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
用户拾取组任务
候选人员拾取组任务后该任务变为自己的个人任务
@Test
public void claimTask(){
TaskService taskService = processEngine.getTaskService();
//要拾取的任务id
String taskId = "6302";
//任务候选人id
String userId = "lisi"; //拾取任务
//即使该用户不是候选人也能拾取(建议拾取时校验是否有资格)
//校验该用户有没有拾取任务的资格
Task task = taskService.createTaskQuery().taskId(taskId).taskCandidateUser(userId).singleResult();
if(task!=null){
taskService.claim(taskId, userId);
System.out.println("任务拾取成功");
}
}
用户查询个人待办任务
@Test
public void findPersonalTaskList() {
// 流程定义key
String processDefinitionKey = "holiday4";
// 任务负责人
String assignee = "zhangsan";
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
List<Task> list = taskService.createTaskQuery().processDefinitionKey(processDefinitionKey).taskAssignee(assignee).list();
for (Task task : list) {
System.out.println("----------------------------");
System.out.println(" 流 程 实 例 id : " + task.getProcessInstanceId());
System.out.println("任务id:" + task.getId());
System.out.println("任务负责人:" + task.getAssignee());
System.out.println("任务名称:" + task.getName());
}
}
用户办理个人任务
建议完成任务前校验该用户是否是该任务的负责人
/**完成任务*/
@Test
public void completeTask(){
//任务ID
String taskId = "12304";
processEngine.getTaskService().complete(taskId);
System.out.println("完成任务:"+taskId);
}
归还组任务
如果个人不想办理该组任务,可以归还组任务,归还后该用户不再是该任务的负责人
// 归还组任务,由个人任务变为组任务,还可以进行任务交接
@Test public void setAssigneeToGroupTask() {
// 查询任务使用TaskService
TaskService taskService = processEngine.getTaskService();
// 当前待办任务
String taskId = "6004";
// 任务负责人
String userId = "zhangsan2";
// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务
Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult();
if (task != null) {
// 如果设置为null,归还组任务,该任务没有负责人
taskService.setAssignee(taskId, null);
}
}
建议归还任务前校验该用户是否是该任务的负责人 也可以通过 setAssignee 方法将任务委托给其它用户负责,注意被委托的用户可以不是候选人(建议 不要这样使用)
任务交接
任务交接,任务负责人将任务交给其它候选人办理该任务
@Test
public void setAssigneeToCandidateUser() {
// 查询任务使用TaskService
TaskService taskService = processEngine.getTaskService();
// 当前待办任务
String taskId = "6004";
// 任务负责人
String userId = "zhangsan2";
// 校验userId是否是taskId的负责人,如果是负责人才可以归还组任务
Task task = taskService.createTaskQuery().taskId(taskId).taskAssignee(userId).singleResult();
if (task != null) {
// 将此任务交给其它候选人办理该 任务
String candidateuser = "zhangsan";
// 根据候选人和组任务id查询,如果有记录说明该 候选人有资格拾取该任务
Task task2 =taskService.createTaskQuery().taskId(taskId).taskCandidateUser(candidateuser).singleResult();
if (task2 != null) {
// 才可以交接
taskService.setAssignee(taskId, candidateuser);
}
}
}
网关
排他网关
当流程 执行到这个网关,所有分支都会判断条件是否为 true,如果为 true则执行该分支,
注意,排他网关只会选择一个为 true 的分支执行。 (即使有两个分支条件都为 true,排他网关也会只 选择一条分支去执行)
说明 :经过排他网关必须要有一条且只有一条分支走。
并行网关
并行网关允许将流程分成多条分支,也可以把多条分支汇聚到一起,并行网关的功能是基于进 入和外出顺序流的:
fork 分支: 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
join 汇聚: 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通 过汇聚网关。
注意,如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时, 网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
与其他网关的主要区别是,并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
包含网关
包含网关可以看做是排他网关和并行网关的结合体。 和排他网关一样,你可以在外出顺序流上 定义条件,包含网关会解析它们。 但是主要的区别是包含网关可以选择多于一条顺序流,这和并行 网关一样。 包含网关的功能是基于进入和外出顺序流的:
分支: 所有外出顺序流的条件都会被解析,结果为true 的顺序流会以并行方式继续执行, 会为每个顺序流创建一个分支。
汇聚: 所有并行分支到达包含网关,会进入等待状态, 直到每个包含流程 token 的进入顺序流的分支都 到达。 这是与并行网关的最大不同。换句话说,包含网关只会等待被选中执行了的进入顺序流。 在 汇聚之后,流程会穿过包含网关继续执行。