前面介绍了Activiti工作流的基本操作,但是在实际应用过程中,往往不满足项目需求,因此还需要了解一些其他的功能比如:连线、排他网关、并行网管、流程变量、个人任务及组任务的三种发布方式。
下面将介绍Activiti工作流中的连线操作
首先需要构建一个流程实例并且部署到项目中去
可以看出这个流程实例和之前的有一些区别,就是连线上多了一下文字,要想让流程引擎通过连线来辨别走哪个流程需要在连线上加上对应的条件,比如${message=="不紧急"},然后再在完成任务的时候讲该信息封装到map中并传递给流程引擎
@Test public void compileTask(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); //任务ID String taskID = "302"; //获得任务服务 TaskService taskService = processEngine.getTaskService(); Map<String, Object> map = new HashMap<String, Object>(); map.put("message", "不紧急"); taskService.complete(taskID, map); }
这样流程引擎就会将该任务分配给部门主管,通过对连线的设置可以手动的将任务分配给指定的人,但是在实际应用过程中,往往还需要一个默认执行的流程,这时候就需要排他网关
首先构建一个新的流程实例并且部署上去
在排他网关中,我们需要设置一个Default flow,里面填上需要默认执行连线的ID,且其它连线需要设置对应的Condition,在流程任务执行任务的过程中,当检测到没有一条连线符合我们需要执行的流程的条件时,排他网关会默认的将该任务分配给默认的连线,这里有几点需要注意:
1) 决策网关只会返回一条结果。当流程执行到排他网关时,流程引擎会自动检索网关出口,从上到下检索如果发现第一条决策结果为true或者没有设置条件的(默认为成立),则流出。
2) 如果没有任何一个出口符合条件,则抛出异常
3) 使用流程变量,设置连线的条件,并按照连线的条件执行工作流,如果没有条件符合的条件,则以默认的连线离开
接下来是并行网关,首先创建流程实例并且部署到项目上
当该流程启动之后,观察数据库中的表的数据
首先观察ACT_RU_TASK表,这里面是我们需要执行的task
然后再看ACT_RU_EXECUTION表,这张表很重要,体现了并行网关的功能
接下来我们先完成付款和收款任务,然后再观察这两张表里面的数据
可以看见在ACT_RU_TASK表中已经少了一项数据,但是在ACT_RU_EXECUTION表中数据还没有变,接下来再去完成发货和收获任务,然后再观察着两张表
可以看见这两张表中都已经没有了任何数据,尤其是ACT_RU_EXECUTION表,这张表只有当并行网关中的所有任务都执行完毕之后数据才会消失。
并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略,同时并行网关是不需要平衡的。
然后再看流程变量,流程变量相对简单,只需要写两个方法,一个方法设置流程变量,一个方法获取流程变量即可,只需要注意一点,流程变量可以设置和获取一个实体类对象,这里直接贴出代码
@Test public void setVariables(){ ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); String assigneeUser = "Asen"; String instanceId = "101"; TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .taskAssignee(assigneeUser) .processInstanceId(instanceId) .singleResult(); Person person = new Person("Meixi", 30, "Asen3245243", "13090908080"); taskService.setVariable(task.getId(), "取钱人", "Ronaldo"); taskService.setVariableLocal(task.getId(), "金额", "10000"); taskService.setVariable(task.getId(), "取钱人信息", person); } @Test public void getVariables(){ String assignUser = "Asen"; String instanceId = "101"; ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); TaskService taskService = processEngine.getTaskService(); Task task = taskService.createTaskQuery() .taskAssignee(assignUser) .processInstanceId(instanceId) .singleResult(); String user = (String) taskService.getVariable(task.getId(), "取钱人"); String money = (String) taskService.getVariable(task.getId(), "金额"); Person personMessage = (Person) taskService.getVariable(task.getId(), "取钱人信息"); System.out.println("user:" + user + " money:" + money + " personMessage:" + personMessage); }
最后就是个人任务及组任务的三种分配方式,其中个人任务和组任务的分配方式大同小异,首先是个人任务的分配,第一种就是直接Assign给一个人名(字符串)
第二种就是封装成一个map传递给流程引擎
ProcessEngine processEngine = ProcessEngines.getDefaultProcessEngine(); @Test public void testTask() throws Exception { InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn"); InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png"); processEngine.getRepositoryService()// .createDeployment()// .addInputStream("userTask.bpmn", inputStreamBpmn)// .addInputStream("userTask.png", inputStreamPng)// .deploy(); Map<String, Object> variables = new HashMap<String, Object>(); variables.put("userID", "Ronaldo"); ProcessInstance pi = processEngine.getRuntimeService() .startProcessInstanceByKey("taskProcess",variables); }
第三种分配方式使用类,这时候不需要指定办理人,直接添加一个类即可
此时的bpmn_xml文件内容已经发生变化
<userTask id="usertask1" name="付款" activiti:assignee="Asen"> <extensionElements> <activiti:taskListener event="create" class="com.asen.entity.Person"></activiti:taskListener> </extensionElements> </userTask>
最后我们需要手动添加一个类去实现TaskListener接口,并且重写notify方法,在该方法中我们需要去指定个人任务
@Override public void notify(DelegateTask delegateTask) { String assignee = "Ronaldo"; //指定个人任务 delegateTask.setAssignee(assignee); }
然后就可以去查询了
@Test public void findMyTaskList(){ String userId = "Ronaldo"; List<Task> list = processEngine.getTaskService()// .createTaskQuery()// .taskAssignee(userId)//指定个人任务查询 .list(); for(Task task:list ){ System.out.println("id="+task.getId()); System.out.println("name="+task.getName()); System.out.println("assinee="+task.getAssignee()); System.out.println("createTime="+task.getCreateTime()); System.out.println("executionId="+task.getExecutionId()); } }
组任务的三种分配方式就太过详细的写出来了
分配方式一:
分配方式二:
//部署流程定义,启动流程实例
@Test public void testTask() throws Exception { // 1 发布流程 InputStream inputStreamBpmn = this.getClass().getResourceAsStream("taskProcess.bpmn"); InputStream inputStreamPng = this.getClass().getResourceAsStream("taskProcess.png"); processEngine.getRepositoryService()// .createDeployment()// .addInputStream("userTask.bpmn", inputStreamBpmn)// .addInputStream("userTask.png", inputStreamPng)// .deploy(); // 2 启动流程 //启动流程实例,同时设置流程变量,用来指定组任务的办理人 Map<String, Object> variables = new HashMap<String, Object>(); variables.put("userIDs", "小红,小亮,小明"); ProcessInstance pi = processEngine.getRuntimeService()// .startProcessInstanceByKey("taskProcess",variables); System.out.println("pid:" + pi.getId()); }
分配方式三:
同样添加一个类,但是实现方法有所区别
public class TaskListenerImpl implements TaskListener { /**指定个人任务和组任务的办理人*/ @Override public void notify(DelegateTask delegateTask) { String userId1 = "小红"; String userId2 = "小亮"; //指定组任务 delegateTask.addCandidateUser(userId1); delegateTask.addCandidateUser(userId2); } }
最后补上一些很常用的方法
//可以分配个人任务从一个人到另一个人(认领任务) @Test public void setAssigneeTask(){ //任务ID String taskId = "3408"; //指定认领的办理者 String userId = "Meixi"; processEngine.getTaskService()// .setAssignee(taskId, userId); } //将组任务分配给个人任务(认领任务) @Test public void claimTask(){ String taskId = "4008"; //个人任务的办理人 String userId = "小明"; processEngine.getTaskService().claim(taskId, userId); } //可以分配个人任务回退到组任务,(前提之前是个组任务) @Test public void setAssigneeTask(){ //任务ID String taskId = "4008"; processEngine.getTaskService()// .setAssignee(taskId, null); } //向组任务中添加成员 @Test public void addUser(){ String taskId = "4008"; String userId = "小红"; processEngine.getTaskService().addCandidateUser(taskId, userId); } //向组任务中删除成员 @Test public void removeUser(){ String taskId = "4008"; String userId = "小亮"; processEngine.getTaskService().deleteCandidateUser(taskId, userId); }