看了3天JBPM中与在群里兄弟的帮助下简单运行了一条流程,把自己的一点心得写出来留做纪念:
使用JBPM3是需要注意的几个小问题:
1)在使用jbpm-db-3.0.zip包中自带的ANT脚本来生成各种数据库脚本的时候,JDK的版本需要是5.0否则报不支持的功能错误!
2)在JBMP3上面执行的流程定义一定是符合3.0规范的,2.0与3.0的JPDL文件有比较大的差别!
我就是疏忽了这点导致白忙活了一天!
简单的请假流程(JPDL):
<?xml version="1.0" encoding="UTF-8"?>
<process-definition
xmlns="http://jbpm.org/3/jpdl"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://jbpm.org/3/jpdl http://jbpm.org/xsd/jpdl-3.0.xsd"
name="leave process1">
<start-state name="start">
<transition to="leave draft"/>
</start-state>
<swimlane name="chief">
<assignment class="com.starocean.jbpm.swimlane.leaveprocess.ChiefHandler"/>
</swimlane>
<swimlane name="boss">
<assignment class="com.starocean.jbpm.swimlane.leaveprocess.BossHandler"/>
</swimlane>
<state name="leave draft">
<transition to="isChief"/>
</state>
<decision name="isChief">
<handler class="com.starocean.jbpm.swimlane.leaveprocess.IsChiefHandler"/>
<transition to="chief auditing" name="notchief"/>
<transition to="boss auditing" name="ischief"/>
</decision>
<task-node name="chief auditing">
<task name="ca" swimlane="chief"/>
<transition to="boss auditing"/>
</task-node>
<task-node name="boss auditing">
<task name="ba" swimlane="boss"/>
<transition to="end"/>
</task-node>
<end-state name="end"/>
</process-definition>
这个JPDL主要表达的意思是一个3步的请假流程:
1)请假人起草请假单,送交部门领导处理,然后送公司领导处理
2)如果请假人是部门领导那直接转到公司领导处理
里面没有回退等环节,后面陆续加上
首先定义了两个 SWIMLANE:chief&boss,用来定义两个角色:
public class BossHandler implements AssignmentHandler {
private static final long serialVersionUID = -995603186672306606L;
private static final Log log = LogFactory.getLog(ChiefHandler.class);
public void assign(Assignable arg0, ExecutionContext arg1) throws Exception {
log.debug("BossHandler start");
arg0.setActorId("boss");
log.debug("BossHandler end");
}
}
对请求者身份来做验证,如果是不门领导请假就直接给公司BOSS来处理,普通用户首先要经部门领导审批后
才能带公司BOSS:
<decision name="isChief">
<handler class="com.starocean.jbpm.swimlane.leaveprocess.IsChiefHandler"/>
<transition to="chief auditing" name="notchief"/>
<transition to="boss auditing" name="ischief"/>
</decision>
public class IsChiefHandler implements DecisionHandler {
private static final long serialVersionUID = -6311809219060093239L;
private static final Log log = LogFactory.getLog(IsChiefHandler.class);
public String decide(ExecutionContext arg0) throws Exception {
log.debug("IsChiefHandler start");
if(arg0.getVariable("userName").equals("snake")){
log.debug("IsChiefHandler end");
return "ischief";
}else{
log.debug("IsChiefHandler end");
return "notchief";
}
}
}
做了个接口,负责页面层也工作流引擎交互
public class WorkFlowAPI {
private static final Log log = LogFactory.getLog(WorkFlowAPI.class);
private static JbpmSessionFactory jbpmSessionFactory = JbpmSessionFactory.buildJbpmSessionFactory();
/**
* 取得用户的代办信息
* @param userName 用户名称
* @return 代办工作列表
*/
public List getPendingJob(String userName){
log.debug("getPendingJob start");
JbpmSession session = jbpmSessionFactory.openJbpmSession();
log.debug("getPendingJob end");
return session.getTaskMgmtSession().findTaskInstances(userName);
}
这是我任务比较重要的一个方法,他手工的使流程想下一个环节流转:
/**
* 将指定流程向下一步流转
* @param wfid 工作流实例编号
* @param userName 操作者名称
*/
public void todoNext(long wfid,String userName){
log.debug("todoNext start"+wfid);
JbpmSession session = jbpmSessionFactory.openJbpmSession();
session.beginTransaction();
GraphSession gSession = session.getGraphSession();
ProcessInstance pi = gSession.loadProcessInstance(wfid);
取得用户的TASK
List list = session.getTaskMgmtSession().findTaskInstances(userName);
log.debug(" process instance size = "+list.size());
if(list.size() > 0){
Iterator ite = list.iterator();
while(ite.hasNext()){
TaskInstance ti = (TaskInstance)ite.next();
log.debug(" user "+userName+" 's task "+ti.getName()+" done!");
if(ti.getActorId().equals(userName) && ti.getTaskMgmtInstance().getProcessInstance().getId() == wfid)
执行END()操作后系统回自动执行SIGNAL()操作!所以一旦执行了END就不要在执行SIGNAL了!
ti.end();
}
}else{
pi.signal();
}
gSession.saveProcessInstance(pi);
session.commitTransaction();
session.close();
log.debug("todoNext end");
}
/**
* 保存流程定义
* @param xmlStr 流程定义的JPDL的XML字符串形式
*/
public void saveWorkFlowDefinition(String xmlStr){
log.debug("saveWorkFlowDefinition start");
ProcessDefinition processDefinition = ProcessDefinition.parseXmlString(xmlStr);
JbpmSession session = jbpmSessionFactory.openJbpmSession();
session.beginTransaction();
session.getGraphSession().saveProcessDefinition(processDefinition);
session.commitTransactionAndClose();
log.debug("saveWorkFlowDefinition end");
}
/**
* 取得所有的工作流定义
* @return 工作流定义列表
*/
public List getAllWorkFlow(){
log.debug("getAllWorkFlow start");
JbpmSession session = jbpmSessionFactory.openJbpmSession();
GraphSession graphSession = session.getGraphSession();
log.debug("getAllWorkFlow end");
return graphSession.findAllProcessDefinitions();
}
/**
* 取得指定工作流的可用实例
* @param workFlowName 工作流名称
* @return 工作流的实例列表
*/
public List getAllInstanceOfWorkFlow(String workFlowName){
log.debug("getAllInstanceOfWorkFlow start");
JbpmSession session = jbpmSessionFactory.openJbpmSession();
GraphSession graphSession = session.getGraphSession();
ProcessDefinition pd = graphSession.findLatestProcessDefinition(workFlowName);
List processInstances = graphSession.findProcessInstances(pd.getId());
log.debug("getAllInstanceOfWorkFlow end");
return processInstances;
}
/**
* 启动工作流
* @param workFlowName 工作流名称(JPDL中的process-definition name='xxx'name属性)
* @param userName 用户标识
* @return 工作流实例编号
*/
public long startWorkFlow(String workFlowName,String userName){
log.debug("startworkflow "+workFlowName+" start");
long workFlowID = -1;
ProcessDefinition processDefinition = null;
JbpmSession jbpmSession = jbpmSessionFactory.openJbpmSession();
//启动事务
jbpmSession.beginTransaction();
//按照工作流名称自数据库中取得流程定义
processDefinition = jbpmSession.getGraphSession().findLatestProcessDefinition(workFlowName);
//实例化流程定义
ProcessInstance instance = new ProcessInstance(processDefinition);
workFlowID = instance.getId();
//加入流程启动人的信息
instance.getContextInstance().setVariable("userName",userName);
//保存工作流
jbpmSession.getGraphSession().saveProcessInstance(instance);
jbpmSession.commitTransaction();
jbpmSession.close();
return workFlowID;
}
}
Trackback: http://blog.csdn.net/snake_liu/archive/2005/10/25/516412.aspx