JBPM 之介绍,使用

JBPM,全称是Java Business Process Management(业务流程管理),它是覆盖了业务流程管理、工作流、服务协作等领域的一个开源的、灵活的、易扩展的可执行流程语言框架。jBPM是公开源代码项目,它使用要遵循 Apache License,。

  jBPM在2004年10月18日,发布了2.0版本,并在同一天加入了JBoss,成为了JBoss企业中间件平台的一个组成部分,它的名称也改成JBoss jBPM。随着jBPM加入JBoss组织,jBPM也将进入一个全新的发展时代,它的前景是十分光明的。

  jBPM最大的特色就是它的商务逻辑定义没有采用目前的一些规范,如WfMC, XPDL, BPML, ebXML, BPEL4WS等,而是采用了它自己定义的JBoss jBPM Process definition language (jPdl)。jPdl认为一个商务流程可以被看作是一个UML状态图。jPdl就是详细定义了这个状态图的每个部分,如起始、结束状态,状态之间的转换,过图型化的流程定义,直观地描述业务流程。

  jBPM的另一个特色是它使用Hibernate来管理它的数据库。Hibernate是目前Java领域最好的一种数据存储层解决方案,只要是 Hibernate 支持的数据库, jBPM 也就支持.过Hibernate,jBPM将数据的管理职能分离出去,自己专注于商务逻辑的处理。

     JBPM由于各个版本之间差异比较大,所以在晚上找的很多资料跟自己使用的情况并不相符,很难找到一个完整的,能够运行的例子(Web程序例子)。
     本文以jbpm-starters-kit-3.1.2版本为例。下载地址:http://www.mirrorservice.org/sites/download.sourceforge.net/pub/sourceforge/j/project/jb/jbpm/jBPM%203/jbpm-3.1.2/。请下载:jbpm-starters-kit-3.1.2.zip版本,网上的参考资料比较多。
     OK,我们接下来讨论JBPM的流程图

上图是一个比较完整的JBPM流程图(Finance中的子流程未写)。

 上图的XML定义代码:

为方便大家Copy,所有代码均不显示行号
<?xml version="1.0" encoding="UTF-8"?>
<process-definition
name="simple">
<start-state name="start">
<description>This process's name is simple</description>
<task name="fill reimburse">
<controller>
<variable name="baoxiaoId" access="read,write,required" mapped-name="报销ID"/>
</controller>
</task>
<transition name="" to="Manager"></transition>
</start-state>
<task-node name="Manager">
<task name="department audit">
<controller>
<variable name="baoxiaoId" access="read" mapped-name="报销ID"/>
</controller>
<assignment class="com.workflow.hander.ManagerAssignment"/>
</task>
<transition name="approve" to="AutoDecide"></transition>
<transition name="requiremodify" to="Modify"></transition>
<transition name="unapprove" to="Message"></transition>
</task-node>
<decision name="AutoDecide">
<handler class="com.workflow.hander.ProcessDecision"/>
<transition name="&lt;10000" to="Finance"></transition>
<transition name="&gt;10000" to="Boss"></transition>
</decision>
<task-node name="Boss">
<task name="boss audit">
<controller>
<variable name="baoxiaoId" access="read" mapped-name="报销ID"/>
</controller>
<assignment class="com.workflow.hander.BossAssignment"/>
</task>
<transition name="approve" to="Finance"></transition>
<transition name="unapprove" to="Message"></transition>
</task-node>
<process-state name="Finance">
<sub-process name="finance"/>
<variable name="baoxiaoId" access="read" mapped-name="报销ID"/>
<transition name="reimburse" to="Message"></transition>
</process-state>
<task-node name="Modify">
<task name="modify reimburse">
<controller>
<variable name="baoxiaoId" access="read,write,required" mapped-name="报销ID"/>
</controller>
<assignment class="com.workflow.hander.UserAssignment"/>
</task>
<transition name="modified" to="Manager"></transition>
<transition name="cancel" to="Message"></transition>
</task-node>
<node name="Message">
<event type="node-enter">
<action class="com.workflow.hander.ProcessResultAction"/>
</event>
<transition name="" to="end1"></transition>
</node>
<end-state name="end1"></end-state>
</process-definition>

涉及到的Java Handler:

View Code
//在start完成之后触发此Handler
public class ManagerAssignment implements AssignmentHandler {

public void assign(Assignable assignable, ExecutionContext executionContext)
throws Exception {

List<TbUser> list=new TbUserDAO().findByUserType(1);
String [] manager=new String[list.size()];
int i=0;
for (Iterator<TbUser> iter = list.iterator(); iter.hasNext();) {
TbUser el = (TbUser)iter.next();
manager[i++]=el.getUserId()+"";
}
assignable.setPooledActors(manager);
}

}
//在Manager审批完成之后(approve)触发此Handler
public class ProcessDecision implements DecisionHandler {

public String decide(ExecutionContext executionContext) throws Exception {

String baixiaoId=executionContext.getContextInstance().getVariable("baoxiaoId").toString();
TbBaoxiao baoxiao=new TbBaoxiaoDAO().findById(new Integer(Integer.parseInt(baixiaoId)));
Set<TbBaoXiaoItem> bxItem=baoxiao.getTbBaoXiaoItems();
int count=0;
for (Iterator<TbBaoXiaoItem> iter = bxItem.iterator(); iter.hasNext();) {
TbBaoXiaoItem item = (TbBaoXiaoItem) iter.next();
count+=Integer.parseInt(item.getItemMoney());
}
if(count>10000)
{
return ">10000";
}
return "<10000";
}

}
//在 Decision判断之后>1000时触发此Handler
public class BossAssignment implements AssignmentHandler {

public void assign(Assignable assignable, ExecutionContext executionContext)
throws Exception {

List<TbUser> list=new TbUserDAO().findByUserType(2);
String [] boss=new String[list.size()];
int i=0;
for (Iterator<TbUser> iter = list.iterator(); iter.hasNext();) {
TbUser el = (TbUser) iter.next();
boss[i++]=el.getUserId()+"";
}
assignable.setPooledActors(boss);
}
}
//Manager审批unapprove时出发的Handler
public class UserAssignment implements AssignmentHandler {

private static final long serialVersionUID = 1L;

public void assign(Assignable assignable, ExecutionContext executionContext)
throws Exception {

String issueUser = executionContext.getContextInstance().getVariable("issueUser").toString();
assignable.setActorId(issueUser);
}

}
//所有task结束之后触发此Handler给创建者发送Message,然后end
public class ProcessResultAction implements ActionHandler {

public void execute(ExecutionContext executionContext) throws Exception {

String baoxiaoId=executionContext.getContextInstance().getVariable("baoxiaoId").toString();
TbBaoxiaoDAO baoxiaoDao=new TbBaoxiaoDAO();
TbBaoxiao baoxiao=baoxiaoDao.findById(new Integer(Integer.parseInt(baoxiaoId)));
String issueUser=baoxiao.getTbUser().getUserName();
baoxiao.setBaoxiaoDate(new Date());

List<TbApprove> list=new TbApproveDAO().findByApproveByBaoxiaoId(baoxiao.getBaoxiaoId());
String result="驳回";
if(list.iterator().hasNext())
{
TbApprove tbapp=(TbApprove) list.iterator().next();
result=tbapp.getApproveResult();
}
baoxiao.setBaoxiaoFlag((result.indexOf("不同意")!=-1?"驳回":"批准"));
baoxiaoDao.merge(baoxiao);
StringBuffer message=new StringBuffer();
message.append(issueUser+":您好! ");
message.append("您申请的"+baoxiao.getBaoxiaoTitle());
message.append("已经被"+(result.indexOf("不同意")!=-1?"驳回":"批准"));

Message msg=new TextMessage(message.toString());
msg.setDestination(issueUser);
msg.setToken(executionContext.getProcessInstance().getRootToken());

DbMessageService msgService=new DbMessageService();
msgService.send(msg);
msgService.close();
}
}

使用的数据表(除了JBPM自身以外的表):

View Code
CREATE TABLE tb_approve (approve_id INTEGER NOT NULL AUTO_INCREMENT, user_id INTEGER, baoxiao_id INTEGER, approve_result VARCHAR(30), approve_memo VARCHAR(300), approve_date DATETIME, PRIMARY KEY (approve_id));
CREATE TABLE tb_baoxiao (baoxiao_id INTEGER NOT NULL AUTO_INCREMENT, user_id INTEGER, baoxiao_title VARCHAR(30), baoxiao_memo VARCHAR(30), baoxiao_date DATETIME, baoxiao_flag VARCHAR(30), PRIMARY KEY (baoxiao_id));
CREATE TABLE tb_baoxiao_item (item_id INTEGER NOT NULL AUTO_INCREMENT, baoxiao_id INTEGER, item_name VARCHAR(30), item_money VARCHAR(100), PRIMARY KEY (item_id));
CREATE TABLE tb_user (user_id INTEGER NOT NULL AUTO_INCREMENT, user_name VARCHAR(30), user_password VARCHAR(30), user_type INTEGER, PRIMARY KEY (user_id));
ALTER TABLE tb_approve ADD INDEX FKD0C46A7C5C89B0A (baoxiao_id), ADD CONSTRAINT FKD0C46A7C5C89B0A FOREIGN KEY (baoxiao_id) REFERENCES tb_baoxiao (baoxiao_id);
ALTER TABLE tb_approve ADD INDEX FKD0C46A7CD355B42A (user_id), ADD CONSTRAINT FKD0C46A7CD355B42A FOREIGN KEY (user_id) REFERENCES tb_user (user_id);
ALTER TABLE tb_baoxiao ADD INDEX FKEC067E1ED355B42A (user_id), ADD CONSTRAINT FKEC067E1ED355B42A FOREIGN KEY (user_id) REFERENCES tb_user (user_id);
ALTER TABLE tb_baoxiao_item ADD INDEX FKE2F5D8945C89B0A (baoxiao_id), ADD CONSTRAINT FKE2F5D8945C89B0A FOREIGN KEY (baoxiao_id) REFERENCES tb_baoxiao (baoxiao_id);

/*
-- test Data
insert into tb_user(user_name,user_password,user_type)
values('test','123',0);

insert into tb_user(user_name,user_password,user_type)
values('manager1','123',1);

insert into tb_user(user_name,user_password,user_type)
values('manager2','123',1);
insert into tb_user(user_name,user_password,user_type)
values('boss','123',2);

insert into tb_user(user_name,user_password,user_type)
values('caiwu','123',2);
*/

以上资料具体的action和dao处理我就不贴代码了,直接说怎么进入下一个task。

View Code

Start、End state是JBPM其实和结束状态的两个必不可少的Node。

task-node  

   一个task-node可以包含一个或多个task,这些task分配给特定的user。当流程执行到task-node时,task instance将会被创建,一个task对应一个task instance。task instances 创建后,task-node就处于等待状态。当所有的task instances被特定的user执行完毕后,将会发出一个新的signal 到token,即流程继续执行。

state

  state是一个纯粹的wait state(等待状态)。它和task-node的区别就是它不会创建task instances。很典型的用法是,当进入这个节点时(通过绑定一个action到node-enter event),发送一条消息到外部的系统,然后流程就处于等待状态。外部系统完成一些操作后返回一条消息,这个消息触发一个signal 到token,然后流程继续执行。(不常用)

decision

  当需要在流程中根据不同条件来判断执行不同路径时,就可以用decision节点。两种方法:最简单的是在transitions里增加 condition elements(条件),condition是beanshell script写的,它返回一个boolean。当运行的时候,decision节点将会在它的 leaving transitions里循环,同时比较 leaving transitions里的condition,最先返回'true'的condition,那个leaving transitions将会被执行;作为选择,你可以实现DecisionHandler接口,它有一个decide()方法,该方法返回一个 String(leaving transition的名字)。

fork  

   fork节点把一条执行路径分离成多条同时进行(并发)的执行路径,每条离开fork节点的路径产生一个子token。

join  

   默认情况下,join节点会认为所有到达该节点的token都有着相同的父token。join 节点会结束每一个到达该节点的token,当所有的子token都到达该节点后,父token会激活。当仍然有子token处于活动状态时,join 节点是wait state(等待状态)。

node  

   node节点就是让你挂自己的action用的(注意:不是event触发!!),当流程到达该节点时,action会被执行。你的action要实现ActionHandler接口。同样,在你的action里要控制流程!

欢迎加入我的QQ群(JAVA开发):216672921,程序 元 世界
原文地址:https://www.cnblogs.com/icerainsoft/p/2245946.html