最近的jBPM项目总结

★使用jbpm提供的eclipse plugin在画流程图的时候, 一般的步骤是先画各种节点(我画流程图的顺序是这样的:start node, end node, task node, common node....),然后保存关闭,再打开继续添加transition,因为插件设计器有一个缺点就是第一次就画好transition之后再打开会"惨不忍睹", 各种node会摆放的乱七八糟.

★一般我们认为未命名的那个transtion是默认要执行的transtion,其实不是这样的,通过看源代码:
public Transition getDefaultLeavingTransition() {
Transition defaultTransition = null;
if ( (leavingTransitions!=null)
&& (leavingTransitions.size()>0) ) {
defaultTransition = (Transition) leavingTransitions.get(O);
} else if ( superState!=null ){
defaultTransition = superState.getDefaultLeavingTransition();
}
return defaultTransition;
}

我们可以看出,实际上第一个transtion才是默认的transition,所以在画流程图的时候要注意这一点,为了让未命名的transtion作为默认的transtion,必须将其放在第一个.

★jbpm数据表结构分析
不管是task变量还是process变量,都保存在jbpm_variableinstance表中,从该表中我们可以看出, 只能存取byte, date, double, long和string这几种类型的变量,所以如果你设置的变量类型为int类型,那么实际上取出来的是long类型的,所以在使用getVariable()方法要取得int类型变量,注意要造型为long.

★不管是task变量还是process变量, 如果要取变量值, 有两种方式, 一种是通过中间表jbpm_tokenvariablemap和jbpm_moduleinstance, jbpm使用hibernate就是通过该方式来取得的, 另一种是通过jbpm_variableinstance表的processinstantce_字段来取得, 一般如果我们手工来获取的话,可以通过该字段来取得.

★ContextInstance实例对应的表是jbpm_moduleinstance,ProcessInstance实例对应的表是jbpm_processintance

★进入子流程之前的事件是subprocess-created而不时node-enter

★token类是一个非常底层的东东,在实际的工作流中很少用到,而用到最多的就是task node以及附加在各个节点上的action handler, 因为只有task node才是人能参与流程的地方, 而jBPM工作流的主要任务就是通过人的操作来让流程运行, 如果在很多地方使用token,那说明你的流程不是人在操作,而是机器在操作.所以大部分我看到的使用token的地方都是在测试中,因为需要通过代码来让流程自动运行.

★state node会将当前的流程挂起,这跟org.jbpm.graph.node.State类有关:
public class State extends Node {

private static final long serialVersionUID = 1L;

public State() {
this(null);
}

public State(String name) {
super( name );
}

public void execute(ExecutionContext executionContext) {
}
}

因为它的execute()方法为空, 而其他的节点的execute方法中都会调用leave()方法继续流程的执行,跑到下一个节点,也别指望在state node中通过ProcessInstance.signal()方法来启动流程,因为没有地方提供你放该执行代码,即使通过在event的actionhandler中来让流程继续执行也不行,因为在执行execute方法之前有一个流程锁定的动作,而在execute方法执行之后则有一个解锁的处理,而位于action中execute方法中的signal方法也会检查当前节点是否锁定,因为在执行execute方法之前已经锁定所以会抛出node被锁定的异常.而要让流程继续执行需要在流程之外通过调用ProcessInstance.signal()方法让流程继续执行.

★一般流程图的画法, 一般按照流程的顺序遵循从上到下,从左到右的原则[img]http://macrochen.iteye.com/upload/picture/pic/14941/61a7b9f3-29e3-322a-9d76-9b927bec236e.jpg [/img]
★申请界面可能千差万别,但是审核页面都基本类似:审核内容,审核历史,审核意见, 所以我做成了通用的页面[img]http://macrochen.iteye.com/upload/picture/pic/14945/b3966fb3-2a30-331e-b40a-4fec6cdd9316.png [/img]

★为了将业务表单数据挂到jBPM流程引擎上,一般需要使用一个全局的流程实例变量(我一般采用FORM_ID)将指定的业务表单记录主键保存,这样在流程中的不同节点就可以取得所需要的业务数据,并交给不同的操作对象(Actor)进行处理.

★为了使用指定的页面来处理每个流程任务节点,需要将页面的url保存为任务节点变量, 这样就将jsp页面跟jBPM流程的任务节点联系起来了.而这个工作是放在AssignmentHandler中来处理的.在本人的项目中这是一个通用的做法,所以写了一个AssignmentHandler抽象类:
/**
* 审核任务节点对应的分配处理handler 主要设置处理当前审核任务的actor和审核操作页面, 默认的审核页面不能对审核内容进行编辑
*
* @author Macro Chen
* @since Apr 18, 2008
*/
public abstract class BaseAssignmentHandler implements AssignmentHandler {

public void assign(Assignable assignable, ExecutionContext ctx)
throws Exception {
addContextInstanceVariables(ctx.getContextInstance());
String employeeId = getActorId(assignable, ctx);
assignable.setActorId(employeeId);
addTaskInstanceVariables(assignable, ctx);
}

/**
* 添加task instance变量
*
* @param assignable
* @param ctx
*/
protected void addTaskInstanceVariables(Assignable assignable,
ExecutionContext ctx) {
TaskInstance ti = (TaskInstance) assignable;
String url = getOperationUrl(assignable, ctx);
url += (url.indexOf("?") != -1 ? "&" : "?") + "taskId=" + ti.getId();
ti.setVariable(JbpmConstants.TIV_OPERATION_URL, url);
}

/**
* 根据业务需要添加其他的流程变量
*
* @param ci
*/
protected void addContextInstanceVariables(ContextInstance ci) {
}

/**
* 执行任务操作的页面 默认情况下使用通用的审核页面(不可对审核内容进行修改), 子类可以根据需要开发自己的审核页面(如可对审核内容进行修改)
*
* @return
*/
protected String getOperationUrl(Assignable assignable, ExecutionContext ctx) {
return "/workflow/common/common_audit.jsp";
}

/**
* 设置当前任务节点的执行者
*
* @param assignable
* @param ctx
* @return
* @throws Exception
*/
protected abstract String getActorId(Assignable assignable,
ExecutionContext ctx) throws Exception;

}


★以下是本人总结的一些公共的,方便的jBPM静态方法,在整个项目中通用:
/**
* @author Macro Chen
* @since Apr 8, 2008
*/
public class JbpmUtils {

public static Long getLongVariableOfProcess(IJbpmProvider provider,
String name) {
ContextInstance ci = provider.getContextInstance();
if (ci == null) {
return (long)0;
}
return (Long)ci.getVariable(name);
}

public static JbpmContext getJbpmContext() {
JbpmConfiguration config = JbpmConfiguration.getInstance();
return config.getCurrentJbpmContext();
}

/**
* 新建一个pi
*
* @param name
* @return
*/
public static ProcessInstance newProcessInstance(String name) {
ProcessDefinition pd = getJbpmContext().getGraphSession()
.findLatestProcessDefinition(name);
return new ProcessInstance(pd);
}

/**
* 根据taskId取得pi
*
* @param taskId
* @return
*/
public static ProcessInstance getProcessInstanceByTaskId(String taskId) {
TaskInstance ti = getTaskInstance(taskId);
return ti.getTaskMgmtInstance().getProcessInstance();
}

public static ProcessInstance getProcessInstanceByTaskId(Long taskId) {
TaskInstance ti = getTaskInstance(taskId);
return ti.getTaskMgmtInstance().getProcessInstance();
}

public static ContextInstance getContextInstance(String name) {
return newProcessInstance(name).getContextInstance();
}

public static ContextInstance getContextInstanceByTaskId(String taskId) {
TaskInstance ti = getTaskInstance(taskId);
if (ti == null)
return null;

return ti.getTaskMgmtInstance().getProcessInstance()
.getContextInstance();
}

public static ContextInstance getContextInstanceByTaskId(Long taskId) {
TaskInstance ti = getTaskInstance(taskId);
if (ti == null)
return null;
return ti.getTaskMgmtInstance().getProcessInstance()
.getContextInstance();
}

public static TaskInstance createStartTaskInstance(ProcessInstance pi) {
return pi.getTaskMgmtInstance().createStartTaskInstance();
}

public static Session getSession() {
return getJbpmContext().getSessionFactory().openSession();
}

public static List getQueryList(String hql) {
return getSession().createQuery(hql).list();
}

public static TaskMgmtSession getTaskMgmt() {
return getJbpmContext().getTaskMgmtSession();
}

public static TaskInstance loadTaskInstance(long taskId) {
return getTaskMgmt().loadTaskInstance(taskId);
}

public static TaskInstance getTaskInstance(String taskId) {
if (StringUtils.isEmpty(taskId))
return null;
return getJbpmContext().getTaskInstance(Long.parseLong(taskId));
}

public static TaskInstance getTaskInstance(long taskId) {
return getJbpmContext().getTaskInstance(taskId);
}

public static List<TaskInstance> findTaskInstances(String actorId) {
return getTaskMgmt().findTaskInstances(actorId);
}

public static List<TaskInstance> findPooledTaskInstances(String actorId) {
return getTaskMgmt().findPooledTaskInstances(actorId);
}

public static void saveTaskInstance(TaskInstance ti) {
getJbpmContext().save(ti);
}

public static String getTaskId() {
return DoradoUtils.getRequestParameter(JbpmConstants.TASK_ID);
}

}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值