在上一篇文章《浅析JBPM工作流引擎》中我们介绍了什么是JBPM,以及一个简单的JBPM实例,并且我们知道了一个jpdl文件实际上就是一个业务流程,每一个流程实例就是这个业务流程的实例化,而在每一个流程中又可以有多个任务,而无论是在是流程实例中还是具体的任务中,由于业务的需要都不可避免的要使用到变量,我们分别称之为流程变量和任务变量,那流程变量和任务变量具体是怎样应用的,他们有什么区别等问题我将分别作具体的介绍。
首先来看我们的业务流程:
<?xml version="1.0" encoding="UTF-8"?>
<process name="test" key="test" xmlns="http://jbpm.org/4.4/jpdl">
<start name="start1" g="275,16,48,48">
<transition name="而提交到科长审批" to="科长审批" g="-110,-15"/>
</start>
<task assignee="张三" name="科长审批" g="255,101,92,52">
<transition name="提交到主任" to="主任审批" g="-69,-20"/>
</task>
<task assignee="李四" name="主任审批" g="259,186,92,52">
<transition name="通过" to="end1" g="-50,-20"/>
</task>
<end name="end1" g="283,283,48,48"/>
</process>
通过jpdl文件我们可以看出这个业务流程仍然非常的简单,就是一个简单的任务传递过程。当创建好一个流程实例的时候首先进入的是“科长审批”节点,执行人是“张三”,当张三完成任务后,提交给任务人李四,李四执行“主任审批”任务,执行完毕后结束整个流程。介绍完业务流程后我们通过java代码介绍流程变量和任务变量的具体应用和区别。
后台代码结构主要有三部分,第一个为父类JbpmTestCase,第二个为接口JbpmUtil,第三个为子类TestVariable,子类继承父类并实现接口。
父类JbpmTestCase中startUp()方法的作用主要是注入各种服务,省去了子类每次都要手动创建服务的麻烦,而接口主要是为了保证每个子类都至少具有上文提到的五分部。在这里我们主要来看子类代码:
/**
* 流程变量
* @author yang
*
*/
public class TestVariable extends JbpmTestCase implements JbpmUtil {
//部署流程
public void deploy() {
super.startUp();
repositoryService.createDeployment().addResourceFromClasspath("test.jpdl.xml").deploy();
}
//创建流程实例
public void createInstance() {
super.startUp();
Map<String,Object> variable = new HashMap<String, Object>();
variable.put("userId", "001");
variable.put("userName", "tom");
ProcessInstance processInstance = executionService.startProcessInstanceByKey("mytest", variable);
super.print("流程实例ID", String.valueOf(processInstance.getId()));
}
//取得特定实例的当前任务节点
public void getCurrentActivity() {
ProcessEngine processEngine = Configuration.getProcessEngine();
ExecutionService executionService = processEngine.getExecutionService();
String activityName = executionService.createProcessInstanceQuery().processInstanceId("mytest.10001").uniqueResult().findActiveActivityNames().toString();
System.out.println("当前任务所在节点======" + activityName);
}
//取得对应人员的第一个任务
public void getTask() {
ProcessEngine processEngine = Configuration.getProcessEngine();
TaskService taskService = processEngine.getTaskService();
List<Task> tasks = taskService.findPersonalTasks("张三");
Task task = tasks.get(0);
System.out.println("任务数量===" + tasks.size() );
System.out.println("任务名词===" + task.getActivityName());
System.out.println("任务人员===" + task.getAssignee() + "任务ID===" + task.getId());
}
//根据任务ID完成任务
public void completeTask() {
super.startUp();
taskService.completeTask("10004");
}
//添加任务变量
public void addTaskVariable(){
super.startUp();
Map<String ,Object> map = new HashMap<String,Object>();
map.put("taskUserId", "100");
map.put("taskUserName","jack");
taskService.setVariables("10004", map);
}
//取得任务变量
public void getTaskVariable(){
super.startUp();
String taskUserId = taskService.getVariable("10004", "taskUserId").toString();
String taskUserName = taskService.getVariable("10004", "taskUserName").toString();
print("taskUserId",taskUserId);
print("taskUserName",taskUserName);
}
//取得流程变量
public void getMyVariable(){
super.startUp();
String userId = executionService.getVariable("mytest.10001", "userId").toString();
String userName = executionService.getVariable("mytest.10001", "userName").toString();
this.print("userId", userId);
this.print("userName", userName);
}
//更新流程变量
public void updateMyVariable(){
super.startUp();
executionService.setVariable("test.90001", "userId", "002");
}
//查询某流程所有流程变量的名称和值
public void findMyVariable(){
super.startUp();
Set<String> set = executionService.getVariableNames("test.90001");
Iterator iter = set.iterator();
while(iter.hasNext()){
System.out.println(iter.next());
}
Map<String ,Object> map = executionService.getVariables("test.90001", set);
Iterator it = map.entrySet().iterator();
while(it.hasNext()){
Map.Entry m = (Map.Entry)it.next();
this.print(m.getKey().toString(), m.getValue().toString());
}
}
}
(1) 执行deploy()函数部署一个业务流程。
(2) 执行 createInstance()函数创建一个流程实例,在创建流程实例的同时创建了两个流程变量,变量名分别为“userId”和“userName”,变量值分别为“001”和“tom”。并且得到了流程实例ID为“mytest.10001”,此时这两个变量就和这个实例绑定了,也就是说这两个变量只属于ID为“mytest.10001”的流程实例。
(3) 执行getTask(),取得当前任务的任务ID为“10004”。
(4) 执行addTaskVariable()函数,给“10004”任务添加两个任务变量,变量名分为“taskUserId”和“taskUserName”,值分别为“100”和“jack”。
到上一步为止我们添加好了流程变量和任务变量,现在我们来执行getMyVariable()函数来取得流程实例ID为mytest.10001变量名为“userId”和“userName”的变量值。通过控制台我们可以看到能够取出流程实例变量。
(5) 执行getMyVariable()函数我们可以看到能够取出流程变量的值。
(6) 执行completeTask()完成任务ID为10004的任务。
(7) 再次执行getMyVariable(),我们可以看到仍然可以取得流程变量“userId”和“userName”的值。
(8) 再次执行getTaskVariable(),我们可以看到此时已经不能取得任务变量的值。
分析:流程实例变量和任务变量的关系我们可以用下图表示:
从上图中我们可以看出流程变量和任务变量一个最明显的区别是他们的作用域不同,流程变量的作用于是整个流程实例,而任务变量的作用于仅仅是它所在的任务。所以在我们第一次执行getMyVariable()和getTaskVariable()既能够取得流程变量又能够取得任务变量是因为流程没有结束,任务也没有结束,而第二次能够取得流程变量却不能取得任务变量,是因为我们虽然结束了“10004”任务,但是流程会进入第二个“主任审批”任务,也就是说“10004”科长审批任务虽然结束了,但是流程并没有结束,所以会出现上面的情况,如果我们再结束主任审批任务,可以执行一次getMyVariable()函数,肯定连流程变量也取不到了。综上所述,任务变量和流程变量能不能取得关键要看流程或任务是否结束,只要没有结束就一定可以取出,反之当任务(流程结束)的时候,任务变量(流程变量)也随任务(流程)的结束而销毁。至于更新流程变量和取得某个流程所有的流程变量有兴趣的可以看一下本文不做重点介绍。