7 jBPM 的客户端开发
有了前面的 HelloWorld 后台流程,我们就要开始客户端程序了。正如前面提到的,本文不写 JSP ,而改采用 JUnit 的形式,输出则用 System.out.println 。举一反三,知道在方法中输入及用 println 输出,在 JSP 和 SWING 等 GUI 界面还不是一样嘛。
这个 JUnit 客户端,我们就借用创建项目时自动生成的 SimpleProcessTest.java 了,改写后如下:
package com.sample;
import junit.framework.TestCase;
import org.jbpm.JbpmConfiguration;
import org.jbpm.JbpmContext;
import org.jbpm.context.exe.ContextInstance;
import org.jbpm.graph.def.ProcessDefinition;
import org.jbpm.graph.exe.ProcessInstance;
public class SimpleProcessTest extends TestCase {
private JbpmConfiguration config = JbpmConfiguration.getInstance();
private JbpmContext ctx = config.createJbpmContext();
// helloworld 对应于 jbpm_processdefinition 表的 name 字段值,也即 processdefinition.xml 的 name
// 这个值得取比较耗时,实际项目里最好和“数据库的 JDBC 连接”一样,让它共享,不要频繁打开关闭。
private ProcessDefinition processDefinition = ctx.getGraphSession().findLatestProcessDefinition("helloworld");
public void testNewRequest() {
long id = newRequest();
System.out.println("id=" + id);
checkNewRequest(id);
confirmRequest(id);
checkconfirmRequest(id);
ctx.close();// 关闭 jbpm 容器
}
/**
* 创建一个请假单
*
* @return
*/
private long newRequest() {
// 创建一个新流程
ProcessInstance pi = processDefinition.createProcessInstance();
// 取得流程的数据环境
ContextInstance ci = pi.getContextInstance();
// 创建一张请假单
ci.setVariable("name", " 陈刚 www.chengang.com.cn" );
ci.setVariable("day", 2);
assertEquals(null, ci.getVariable("note"));
// 请假申请结束,转到下一个流程结点
pi.signal();
return pi.getId();
}
/**
* 检查请假单的数据
*
* @param id
*/
private void checkNewRequest(long id) {
// 从数据库提取原流程
ProcessInstance pi = ctx.loadProcessInstance(id);
// 取得流程的数据环境
ContextInstance ci = pi.getContextInstance();
// 创建一张请假单
assertEquals(" 陈刚 www.chengang.com.cn" , ci.getVariable("name"));
assertEquals(Integer.valueOf(2), ci.getVariable("day"));
assertEquals(" 我要请假 " , ci.getVariable("note"));
// 当前是结点为 confirm
assertEquals(pi.getRootToken().getNode().getName(), "confirm");
// 流程还没结束
assertFalse(pi.hasEnded());
}
/**
* 审批 陈刚 的请假申请
*
* @param id
*/
private void confirmRequest(long id) {
ProcessInstance pi = ctx.loadProcessInstance(id);
ContextInstance ci = pi.getContextInstance();
// 不通过
ci.setVariable("note", " 不准请假,继续加班 " );
// 审批结束,到下一个流程结点
pi.signal();
}
private void checkConfirmRequest(long id) {
ProcessInstance pi = ctx.loadProcessInstance(id);
ContextInstance ci = pi.getContextInstance();
// ConfirmAction 类在 signal 后执行,所以覆盖了经理的审批意见
assertEquals(" 准假 " , ci.getVariable("note"));
// 当前是结点为 end
assertEquals(pi.getRootToken().getNode().getName(), "end");
// 流程结束了
assertTrue(pi.hasEnded());
}
}
这个例子还是很简单,而且关键是缺少用户、组、权限等工作流系统必须的东西,不过没关系。下面的内容我将完成一个更完整的实例。
几个重点:
(1) jBPM没有角色的概念!!! 很多人把ActorID理解成角色,那是相当错误的。jBPM只有参与者的概念,也就是ActorID,它可以是用户ID,也可以是角色ID,也可以什么都不是。你要自己去把用户角色等东东和ActorID映射起来。不过一般我们把ActorID设置成角色,但jbpm websale却是设置成用户的。
(2)用户信息的入口是JbpmContext,里面有一个setActorID方法。你用户登录时候,把一些用户信息set进去。
(3)泳道概念:你去看看UML中的带泳道的活动图,那就是象一个游泳池里的泳道一样。
安装提示:
<classpathentry kind="con" path="JBPM/jBPM 3.1.2"/>
.classpath的这一句很可能和你电脑的设置不符,这是jbpm插件的一个设置,指向jbpm的HOME目录,以便找到jbpm的jar包。你按照你电脑上的设置相应修改一下这一行。
websale的eclipse项目ZIP包: http://www.blogjava.net/Files/chengang/chen-jbpm_websale.zip