转载

JBPM 7.17 学习笔记(4)流程变量和任务变量

在 HumanTask 示例中,使用了流程变量和任务变量。根据二者作用范围的不同,我们又分别把它们称之为全局变量和局部变量。

流程变量

将 HumanTask.bpmn 导入到 workbench 中用流程设计器查看流程图。

JBPM 7.17 学习笔记(4)流程变量和任务变量

查看流程实例变量。

JBPM 7.17 学习笔记(4)流程变量和任务变量

打开 HumanTaskExample.java,找到以下代码:

// start a new process instance
Map<String, Object> params = new HashMap<String, Object>();
params.put("userId", "krisv");
params.put("description", "Need a new laptop computer");
ksession.startProcess("com.sample.humantask", params);

在流程启动时,在 startProcess 方法的第二个参数中传递一个 Map,这 map 将会用于初始化流程变量的值。也就是说流程实例启动后,流程变量中的 userId 和 description 将被赋值。

此外,还有一个 date 变量也会被赋值,但是不是通过 startProcess() 方法赋值的,而是通过一个脚本任务来赋值的。

选中流程图中的名为 Time 的任务,打开属性面板:

JBPM 7.17 学习笔记(4)流程变量和任务变量

脚本任务是自动执行的,它调用了一段 java 代码,利用 kcontext 的 setVariable 方法将 date 变量设置为当前时间。

为了验证这一点,我们可以在任务执行前打印出流程变量的值。打印流程变量的代码是这段代码:

Map<String, Object> content = taskService.getTaskContent(task4.getId());
for (Map.Entry<?, ?> entry : content.entrySet()) {
	System.out.println(entry.getKey() + " = " + entry.getValue());
}

在 HumanTaskExample.java 中找到这段代码,选中它,右键 Refactor -> Extract -> Method …,将它抽取成一个私有方法:

private static void getVariables(TaskService taskService, TaskSummary task4) {
        Map<String, Object> content = taskService.getTaskContent(task4.getId());
        for (Map.Entry<?, ?> entry : content.entrySet()) {
            System.out.println(entry.getKey() + " = " + entry.getValue());
        }
}

jBMP 7 似乎不允许直接读取流程变量,尝试了各种直接访问流程变量的方法都不成功。

实际上这个方法打印的并不会打印流程变量,而只会打印任务变量,即 Assignments 中的输入变量。因为这些变量已经和全局变量进行了绑定,所以也可以用这种方式查看全局变量。

然后在,每次 taskService.start() 语句后调用这个方法,比如 getVariables(taskService,task1); ,注意改变 task1 为不同的变量。

在每个 getVariables() 调用之后添加断点。Debug 运行。

当第一个断点停下时,控制台中会打印出:

date = Fri Mar 08 13:39:17 CST 2019
TaskName = Request Review
NodeName = Review
description = Need a new laptop computer
SwimlaneActorId = null
userId = krisv
GroupId = sales

这是第一个用户任务,当第一个用户任务开始时,脚本任务已经执行,所以这里的 date 变量是有值的,TaskName 是当前任务(流程图中的 Review 节点)的任务名称,NodeName 是当前任务的节点名称,这两者可以一样,也可以不一样。

description 和 userId 的值就是 startProcess 方法赋值的,值和代码中设置的是一样的。

GroupId 是任务的 Groups 属性所设置的。

JBPM 7.17 学习笔记(4)流程变量和任务变量

继续执行,断点在第二个任务(即 User Approval 节点)start 后停下,此时控制台打印:

result = Accept

date = Fri Mar 08 13:39:17 CST 2019

TaskName = Request Approval

NodeName = User Approval

description = Need a new laptop computer

comment = Agreed, existing laptop needs replacing

ActorId = krisv

userId = krisv

和之前相比,增加了 result 和 comment 变量。在上一个任务完成时:

Map<String, Object> results = new HashMap<String, Object>();
results.put("comment", "Agreed, existing laptop needs replacing");
results.put("outcome", "Accept");
taskService.complete(task1.getId(), "sales-rep", results);

jBPM 7 似乎不允许直接设置全局变量,尝试了各种方法都不成功,complete 方法似乎是唯一的设置全局变量的方法。

TaskService 的 complete 方法设置全局变量其实比较绕。首先要通过一个 Map 来设置任务的输出变量,然后引擎将它同步到全局变量。然后在下一个任务中,又要通过读取输入变量,才能读取到全局变量的值。

例如在第一个任务 complete 时,我们在 map 中设置了 comment 和 outcome。这两个其实是任务的输入变量。然后运行时引擎会根据 Assignments 的设置将它们同步给全局变量 comment 和 result。

其中 outcome 变量会绑定到全局变量 result。你可以查看任务的分配属性(Assignments):

JBPM 7.17 学习笔记(4)流程变量和任务变量

outcome 绑定了全局变量 result。所以 taskService.complete 方法实际上是对局部任务变量进行赋值,然后由运行时引擎同步给全局变量。

而在第二个任务中,当我们用 getVariables 打印第二个任务的局部变量时,局部变量中就包括了 result:

JBPM 7.17 学习笔记(4)流程变量和任务变量

这个 result 绑定的是全局变量 result。所以上面的打印结果中包含了 result。

最后一个是 ActorId 变量。这来自于任务的 Actors 属性:

JBPM 7.17 学习笔记(4)流程变量和任务变量

#{userId} 引用了变量 userId。

继续执行,断点在第三个任务(Manager Approval 节点)执行时停下。控制台:

result = Accept
date = Fri Mar 08 13:39:17 CST 2019
TaskName = Request Approval
NodeName = Manager Approval
description = Need a new laptop computer
comment = Agreed, existing laptop needs replacing
userId = krisv
GroupId = PM

除了 GroupId 变量(来自任务的 Groups 属性)外,没有增加新的变量。但是在 User Approval 节点的办结代码中,修改了 outcome 变量:

results = new HashMap<String, Object>();
results.put("outcome", "Agree");
taskService.complete(task2.getId(), "krisv", results);

但是,这个 outcome 变量绑定的不再是 result 全局变量,而是 resultUser 全局变量:

JBPM 7.17 学习笔记(4)流程变量和任务变量

但在 Manager Approval 任务的打印中,我们并没有看到 resultUser 变量!

这是因为 User Approval 和 Manager Approval 使用的并行网关!二者不是前后关系,而是并行关系。也就是说,User Approval 节点的下一节点并不是 Manager Approval,而是 Notification 节点。而 TaskService.complete 方法传递变量的方式是向下一节点传递,因此在 Manager Approval 节点不会收到 User Approval 节点传递的变量。如果想看到 User Approval 的传递的局部变量,应该在 Notification 节点进行打印。

继续执行,断点在第四个节点(Notification节点)停下。控制台:

result = Accept
date = Fri Mar 08 13:39:17 CST 2019
resultUser = Agree
resultManager = Agree
TaskName = Request Notification
NodeName = Notification
description = Need a new laptop computer
comment = Agreed, existing laptop needs replacing
SwimlaneActorId = sales-rep
userId = krisv
GroupId = sales

看到了吧!在 Notification 节点,你不仅看到了 User Approval 新增的 resultUser 变量,还看到了 Manager Approval 增加的 resultManager 变量!因为 Manager Approval 的下一节点还是 Notification(再次使用了一个并行网关)。

再看一眼打印全局变量的方法,它需要一个 TaskService 实例,和一个 TaskSummary 对象(其实只需要 taskId 就行了)。那么假设这个任务已经 complete,甚至整个运行时已经被销毁了,它还能工作吗?还是报空指针异常?

让我们来试一试,在任务 complete 和 disposeRuntimeEngine 之后增加一个 getVariables 语句:

taskService.complete(task4.getId(), "sales-rep", null);

getVariables(taskService,task4);
System.out.println("Process instance completed");
    		
manager.disposeRuntimeEngine(runtime);
getVariables(taskService,task4);

变量仍然打印出来了,没有任何问题。

原文  https://blog.csdn.net/kmyhy/article/details/88391028
正文到此结束
Loading...