Activiti7工作流学习笔记二 流程实例
参与者(可以是用户也可以是程序)按照流程定义内容发起一个流程,这就是一个流程实例。是动态的。
流程定义和流程实例的图解:
流程定义部署在 activiti 后,就可以在系统中通过 activiti 去管理该流程的执行,执行流程表示流程的一次执行。
比如部署系统请假流程后,如果某用户要申请请假这时就需要执行这个流程,如果另外一个用户也要申请请假则也需要执行该流程,每个执行互不影响,每个执行是单独的流程实例。
业务系统与Activiti整合原理
- 业务系统存储具体的请假信息
- activiti中存储流程相关的信息,并记录业务标识(
businesskey
)
启动流程实例时,指定的businesskey
,就会在act_ru_execution
(流程实例的执行表,当前流程进行的状态,一条记录)中存储businesskey
。
Businesskey
:业务标识,通常为业务表的主键
,业务标识和流程实例一一对应。业务标识来源于业务系统。存储业务标识就是根据业务标识来关联查询业务系统的数据。
比如:请假流程启动一个流程实例,就可以将请假单的 id 作为业务标识存储到 activiti 中,将来查询activiti 的流程实例信息就可以获取请假单的 id 从而关联查询业务系统数据库得到请假单信息。
启动流程实例,添加businessKey
/**
* com.lxf.activiti.ProcessDefinition
* 启动流程实例,添加进businessKey
*
* 本质:act_ru_execution表中的businessKey的字段要存入业务标识
* @author lxf
* @version 1.0
* @date 2020/4/25 20:18
*/
public class BusinessKeyAdd {
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.启动流程实例,同时还要指定业务标识businessKey 它本身就是请假单的id
//第一个参数:是指流程定义key
//第二个参数:业务标识businessKey
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday", "1001");
//4.输出processInstance相关的属性,取出businessKey使用:processInstance.getBusinessKey()
System.out.println(processInstance.getBusinessKey());
}
}
挂起、激活流程实例
某些情况可能由于流程变更需要将当前运行的流程暂停而不是直接删除,流程暂停后将不会继续执
行。
操作流程定义为挂起状态,该流程定义下边所有的流程实例全部暂停:
流程定义为挂起状态该流程定义将不允许启动新的流程实例,同时该流程定义下所有的流程实例将全部挂起暂停执行。
/**
* 全部流程实例挂起
*/
public void suspendOrActivateAllProcessDefinition(){
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RepositoryService
RepositoryService repositoryService = processEngine.getRepositoryService();
//3.查询流程定义的对象
ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
.processDefinitionKey("holiday").singleResult();
//4.得到当前流程定义的实例是否都为暂停状态
boolean suspended = processDefinition.isSuspended();
String processDefinitionId = processDefinition.getId();
//5.判断
if(suspended){
//说明是暂停,就可以激活操作
repositoryService.activateProcessDefinitionById(processDefinitionId,true
,null);
System.out.println("流程定义:"+processDefinitionId+"激活");
}else{
repositoryService.suspendProcessDefinitionById(processDefinitionId,true,null);
System.out.println("流程定义:"+processDefinitionId+"挂起");
}
}
操作流程实例对象,针对单个流程执行挂起操作,某个流程实例挂起则此流程不再继续执行,完成该流程实例的当前任务将报异常。
/**
* 单个流程实例挂起
*/
public void suspendOrActiveSingleProcessInstance(){
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.查询流程实例对象
ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
.processInstanceId("2501").singleResult();
//4.得到当前流程定义的实例是否都为暂停状态
boolean suspended = processInstance.isSuspended();
String processInstanceId = processInstance.getId();
//5.判断
if(suspended){
//说明是暂停,就可以激活操作
runtimeService.activateProcessInstanceById(processInstanceId);
System.out.println("流程:"+processInstanceId+"激活");
}else{
runtimeService.suspendProcessInstanceById(processInstanceId);
System.out.println("流程定义:"+processInstanceId+"挂起");
}
}
个人任务
分配任务负责人
固定分配
在进行业务流程建模时指定固定的任务负责人
在properties
视图中,填写 Assignee
项为任务负责人。
由于固定分配方式,任务只管一步一步执行任务,执行到每一个任务将按照 bpmn 的配置去分配任务负责人。
表达式分配
UEL
表达式:Activiti
使用 UEL
表达式,UEL
是java EE6
规范的一部分,UEL
(Unified Expression Language
)即统一表达式语言,activiti
支持两个 UEL
表达式:UEL-value
和 UEL-method
。
-
UEL-value 定义如下:
assignee
这个变量是activiti
的一个流程变量。
或:
user
也是activiti
的一个流程变量,user.assignee
表示通过调用user
的getter
方法获取值。 -
UEL-method
方式如下:
userBean
是spring
容器中的一个bean
,表示调用该bean
的getUserId()
方法。 -
UEL-method
与UEL-value
结合
再比如:
${ldapService.findManagerForEmployee(emp)}
,ldapService
是spring
容器的一个bean
,findManagerForEmployee
是该 bean 的一个方法,emp
是activiti
流程变量,emp
作为参数传到ldapService.findManagerForEmployee
方法中。 -
其它
表达式支持解析基础类型、bean、list、array
和map
,也可作为条件判断。
如下:${order.price > 100 && order.price < 250}
使用流程变量分配任务
- 定义任务分配流程变量
- 设置流程变量
在启动流程实例时设置流程变量,如下:
//启动流程实例时设计流程变量
//定义流程变量
Map<String, Object> variables = new HashMap<String, Object>();
//设置流程变量assignee
variables.put("assignee", "张三");
ProcessInstance processInstance = runtimeService
.startProcessInstanceByKey(processDefinitionKey, variables);
由于使用了表达式分配,必须保证在任务执行过程表达式执行成功,比如:
某个任务使用了表达式${order.price > 100 && order.price < 250}
,当执行该任务时必须保证order
在流程变量中存在,否则activiti
异常.
动态设置assignee
/**
* com.lxf.activiti.processInstance
* 启动流程实例,动态设置assignee
* @author lxf
* @version 1.0
* @date 2020/4/26 7:54
*/
public class AssigneeUEL {
public static void main(String[] args) {
//1.得到ProcessEngine对象
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine();
//2.得到RuntimeService对象
RuntimeService runtimeService = processEngine.getRuntimeService();
//3.设置assignee的取值 用户可以在界面上设置流程的执行人
//key的值与流程定义中的UEL表达式对应
Map<String,Object> map = new HashMap<>();
map.put("assignee0","zhangsan");
map.put("assignee1","lishi");
map.put("assignee2","wangwu");
//4.启动流程实例,同时还要设置流程定义的assignee的值
ProcessInstance processInstance = runtimeService.startProcessInstanceByKey("holiday2", map);
//5.输出
System.out.println(processEngine.getName());
}
}
监听器分配
任务监听器是发生对应的任务相关事件时执行自定义 java 逻辑 或表达式。
任务相当事件包括:
Create
:任务创建后触发Assignment
:任务分配后触发Delete
:任务完成后触发All
:所有事件发生都触发
java
逻辑 或表达式:
表达式参考上边的介绍的UEL
表达式,这里主要介绍监听类使用。
定义任务监听类,且类必须实现org.activiti.engine.delegate.TaskListener
接口
public class MyTaskListener implements TaskListener {
@Override
public void notify(DelegateTask delegateTask) {
//这里指定任务负责人
delegateTask.setAssignee("张三");
}
}
使用监听器分配方式,按照监听事件去执行监听类的
notify
方法,方法如果不能正常执行也会影响任务的执行。
Class
类需要指定到实现 org.activiti.engine.delegate.TaskListener
的具体类上,但一般使用较少,使用UEL表达式较多。
查询任务
查询任务负责人的待办任务:
// 查询当前个人待执行的任务
@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());
}
}
关联 businessKey
在 activiti
实际应用时,查询待办任务可能要显示出业务系统的一些相关信息.
比如:查询待审批请假单任务列表需要将请假单的日期、请假天数等信息显示出来,请假天数等信息在业务系统中存在,而并没有在 activiti
数据库中存在,所以是无法通过 activiti
的 api
查询到请假天数等信息。
实现:
在查询待办任务时,通过businessKey
(业务标识 )关联查询业务系统的请假单表,查询出请假天数等信息。
办理任务
指定任务 id
,调用 TaskService
完成任务:
// 完成任务
@Test
public void completTask() {
//任务id
String taskId = "10305";
// 创建TaskService
TaskService taskService = processEngine.getTaskService();
Task task = taskService.createTaskQuery().taskId(taskId)
.taskAssignee(assignee).singleResult();
if(task != null){
taskService.complete(taskId);
System.out.println("完成任务");
}
}
注意:在实际应用中,完成任务前需要校验任务的负责人是否具有该任务的办理权限。