时光匆匆,没想到转眼离上次写工作流Activiti5入门(上)已经过去快四个月了,上次主要写了有关环境的搭建、工作流的部署、启动、查询、认领、完成任务以及查询流程状态和删除流程等,今天我们看看一些更高级也是非常经常用到的一些功能。

一. 连线

一个流程图不可能都是一些孤立的点,点和点之间需要一些线连接,那么这些线该如何连接呢?

  1. 一个活动中可以指定一个或多个SequenceFlow。
    开始活动中有一个SequenceFlow 。
    结束活动中没有SequenceFlow 。
    其他活动中有1条或多条SequenceFlow
  2. 如果只有一个,则可以不使用流程变量设置codition的名称;

如果有多个,则需要使用流程变量设置codition的名称。message表示流程变量的名称,‘不重要’表示流程变量的值,${}中间的内容要使用boolean类型的表达式,用来判断应该执行的连线。例如可以这样,如果${}成立,则会按照这个方向走

  1. 流程图

1

  1. 完成任务

/*\*完成我的任务\*/  
@Test  
public void completeMyPersonalTask(){  
//任务ID  
String taskId = "3103";  
//完成任务的同时,设置流程变量,使用流程变量用来指定完成任务后,下一个连线,对应sequenceFlow.bpmn文件中${message==’不重要’}  
Map<String, Object> variables = new HashMap<String, Object>();  
variables.put("message", "重要");  
processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.complete(taskId,variables);  
System.out.println("完成任务:任务ID:"+taskId);  
}

连线比较简单,既不多做介绍了

二. 排他网关

  1. 一个排他网关对应一个以上的顺序流
    由排他网关流出的顺序流都有个conditionExpression元素,在内部维护返回boolean类型的决策结果。
    决策网关只会返回一条结果。当流程执行到排他网关时,流程引擎会自动检索网关出口,从上到下检索如果发现第一条决策结果为true或者没有设置条件的(默认为成立),则流出。
    如果没有任何一个出口符合条件,则抛出异常
    使用流程变量,设置连线的条件,并按照连线的条件执行工作流,如果没有条件符合的条件,则以默认的连线离开。

  2. 流程图

4

  1. 完成个人任务

/*\*完成我的任务\*/  
@Test  
public void completeMyPersonalTask(){  
//任务ID  
String taskId = "3904";  
//完成任务的同时,设置流程变量,使用流程变量用来指定完成任务后,下一个连线,对应exclusiveGateWay.bpmn文件中${money>1000}  
Map<String, Object> variables = new HashMap<String, Object>();  
variables.put("money", 200);  
processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.complete(taskId,variables);  
System.out.println("完成任务:任务ID:"+taskId);  
}

三. 并行网关

  1. 一个流程中流程实例只有1个,执行对象有多个
    并行网关的功能是基于进入和外出的顺序流的:
        分支(fork): 并行后的所有外出顺序流,为每个顺序流都创建一个并发分支。
        汇聚(join): 所有到达并行网关,在此等待的进入分支, 直到所有进入顺序流的分支都到达以后, 流程就会通过汇聚网关。
    并行网关的进入和外出都是使用相同节点标识
    如果同一个并行网关有多个进入和多个外出顺序流, 它就同时具有分支和汇聚功能。 这时,网关会先汇聚所有进入的顺序流,然后再切分成多个并行分支。
    并行网关不会解析条件。 即使顺序流中定义了条件,也会被忽略。
    并行网关不需要是“平衡的”(比如, 对应并行网关的进入和外出节点数目不一定相等)。

  2. 流程图

7

  1. 完成任务

/*\*启动流程实例\*/  
@Test  
public void startProcessInstance(){  
//流程定义的key  
String processDefinitionKey = "parallelGateWay";  
ProcessInstance pi = processEngine.getRuntimeService()//与正在执行的流程实例和执行对象相关的Service  
.startProcessInstanceByKey(processDefinitionKey);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动  
System.out.println("流程实例ID:"+pi.getId());//流程实例ID 101  
System.out.println("流程定义ID:"+pi.getProcessDefinitionId());//流程定义ID helloworld:1:4  
}

/*\*查询当前人的个人任务\*/  
@Test  
public void findMyPersonalTask(){  
String assignee = "商家";  
List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.createTaskQuery()//创建任务查询对象  
/*\*查询条件(where部分)\*/  
.taskAssignee(assignee)//指定个人任务查询,指定办理人  
// .taskCandidateUser(candidateUser)//组任务的办理人查询  
// .processDefinitionId(processDefinitionId)//使用流程定义ID查询  
// .processInstanceId(processInstanceId)//使用流程实例ID查询  
// .executionId(executionId)//使用执行对象ID查询  
/*\*排序\*/  
.orderByTaskCreateTime().asc()//使用创建时间的升序排列  
/*\*返回结果集\*/  
// .singleResult()//返回惟一结果集  
// .count()//返回结果集的数量  
// .listPage(firstResult, maxResults);//分页查询  
.list();//返回列表  
if(list!=null && list.size()>0){  
for(Task task:list){  
System.out.println("任务ID:"+task.getId());  
System.out.println("任务名称:"+task.getName());  
System.out.println("任务的创建时间:"+task.getCreateTime());  
System.out.println("任务的办理人:"+task.getAssignee());  
System.out.println("流程实例ID:"+task.getProcessInstanceId());  
System.out.println("执行对象ID:"+task.getExecutionId());  
System.out.println("流程定义ID:"+task.getProcessDefinitionId());  
System.out.println("########################################################");  
}  
}  
}

/*\*完成我的任务\*/  
@Test  
public void completeMyPersonalTask(){  
//任务ID  
String taskId = "4302";  
processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.complete(taskId);  
System.out.println("完成任务:任务ID:"+taskId);  
}

四. 接收活动(receiveTask,即等待活动)

接收任务是一个简单任务,它会等待对应消息的到达。 当前,官方只实现了这个任务的java语义。 当流程达到接收任务,流程状态会保存到数据库中。
在任务创建后,意味着流程会进入等待状态, 直到引擎接收了一个特定的消息, 这会触发流程穿过接收任务继续执行。

例如:

流程图:

8

完成任务:


/*\*启动流程实例+设置流程变量+获取流程变量+向后执行一步\*/  
@Test  
public void startProcessInstance(){  
//流程定义的key  
String processDefinitionKey = "receiveTask";  
ProcessInstance pi = processEngine.getRuntimeService()//与正在执行的流程实例和执行对象相关的Service  
.startProcessInstanceByKey(processDefinitionKey);//使用流程定义的key启动流程实例,key对应helloworld.bpmn文件中id的属性值,使用key值启动,默认是按照最新版本的流程定义启动  
System.out.println("流程实例ID:"+pi.getId());//流程实例ID 101  
System.out.println("流程定义ID:"+pi.getProcessDefinitionId());//流程定义ID helloworld:1:4

/*\*查询执行对象ID\*/  
Execution execution1 = processEngine.getRuntimeService()//  
.createExecutionQuery()//创建执行对象查询  
.processInstanceId(pi.getId())//使用流程实例ID查询  
.activityId("receivetask1")//当前活动的id,对应receiveTask.bpmn文件中的活动节点id的属性值  
.singleResult();

/*\*使用流程变量设置当日销售额,用来传递业务参数\*/  
processEngine.getRuntimeService()//  
.setVariable(execution1.getId(), "汇总当日销售额", 21000);

/*\*向后执行一步,如果流程处于等待状态,使得流程继续执行\*/  
processEngine.getRuntimeService()  
.signal(execution1.getId());

/*\*查询执行对象ID\*/  
Execution execution2 = processEngine.getRuntimeService()//  
.createExecutionQuery()//创建执行对象查询  
.processInstanceId(pi.getId())//使用流程实例ID查询  
.activityId("receivetask2")//当前活动的id,对应receiveTask.bpmn文件中的活动节点id的属性值  
.singleResult();

/*\*从流程变量中获取汇总当日销售额的值\*/  
Integer value = (Integer)processEngine.getRuntimeService()//  
.getVariable(execution2.getId(), "汇总当日销售额");  
System.out.println("给老板发送短信:金额是:"+value);  
/*\*向后执行一步,如果流程处于等待状态,使得流程继续执行\*/  
processEngine.getRuntimeService()  
.signal(execution2.getId());

}

五. 用户任务

流程图:

9

  1. 分配个人任务方式一(直接指定办理人),具体配置:

10

完成任务:


/*\*查询当前人的个人任务\*/  
@Test  
public void findMyPersonalTask(){  
String assignee = "周芷若";  
List<Task> list = processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.createTaskQuery()//创建任务查询对象  
/*\*查询条件(where部分)\*/  
.taskAssignee(assignee)//指定个人任务查询,指定办理人  
// .taskCandidateUser(candidateUser)//组任务的办理人查询  
// .processDefinitionId(processDefinitionId)//使用流程定义ID查询  
// .processInstanceId(processInstanceId)//使用流程实例ID查询  
// .executionId(executionId)//使用执行对象ID查询  
/*\*排序\*/  
.orderByTaskCreateTime().asc()//使用创建时间的升序排列  
/*\*返回结果集\*/  
// .singleResult()//返回惟一结果集  
// .count()//返回结果集的数量  
// .listPage(firstResult, maxResults);//分页查询  
.list();//返回列表  
if(list!=null && list.size()>0){  
for(Task task:list){  
System.out.println("任务ID:"+task.getId());  
System.out.println("任务名称:"+task.getName());  
System.out.println("任务的创建时间:"+task.getCreateTime());  
System.out.println("任务的办理人:"+task.getAssignee());  
System.out.println("流程实例ID:"+task.getProcessInstanceId());  
System.out.println("执行对象ID:"+task.getExecutionId());  
System.out.println("流程定义ID:"+task.getProcessDefinitionId());  
System.out.println("########################################################");  
}  
}  
}

/*\*完成我的任务\*/  
@Test  
public void completeMyPersonalTask(){  
//任务ID  
String taskId = "5505";  
processEngine.getTaskService()//与正在执行的任务管理相关的Service  
.complete(taskId);  
System.out.println("完成任务:任务ID:"+taskId);  
}
  1. 分配个人任务方式二(使用流程变量)

具体配置:

12

完成任务:


   // 2 启动流程  
   //启动流程实例的同时,设置流程变量  
Map<String, Object> variables = new HashMap<String, Object>();  
variables.put("userID", "张翠三");  
ProcessInstance pi = processEngine.getRuntimeService()//  
.startProcessInstanceByKey("taskProcess",variables);  
System.out.println("pid:" + pi.getId());  
}

//查询我的个人任务列表  
@Test  
public void findMyTaskList(){  
String userId = "张翠三";  
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 completeTask(){  
String taskId = "3209";  
processEngine.getTaskService()//  
.complete(taskId);//  
System.out.println("完成任务");  
}