`

最近的jBPM项目总结

    博客分类:
  • 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
0
分享到:
评论
12 楼 jslzl 2009-09-29  
请教:
    刚刚接触JBPM的东东,对于审核历史的功能,我应该有哪些思路去实现呢? 谢谢
11 楼 macrochen 2008-07-22  
引用
请问楼主是哪里的啊?

目前在昆明做项目
10 楼 macrochen 2008-07-22  
引用
看那几个页面截图, 好像 dorado?

是的,是dorado+jbpm的项目
9 楼 crabboy 2008-07-18  
请问楼主是哪里的啊?
8 楼 fcoffee 2008-06-20  
看那几个页面截图, 好像 dorado?
7 楼 macrochen 2008-06-05  
引用
在流程中有process state节点,此子流程的程序处理有需要注意的地方吗?

目前我还没有碰到特别需要注意的地方
6 楼 llandyl 2008-06-05  
在流程中有process state节点,此子流程的程序处理有需要注意的地方吗?
5 楼 altr 2008-05-26  
很好,谢谢!
4 楼 macrochen 2008-05-26  
引用

Spring有个jBPM的module,挺有用的,可以用一下。特别是里面的JbpmTemplate。
从文章里可以看出一点,你们好像不太看文档,哈哈。很多问题都在文档里有写。

这个我当然是知道的,只是开始一直没搞懂state node怎么用,后来才明白过来, spring的jbpm module没看过,有时间看看
3 楼 yujianqiu 2008-05-25  
Spring有个jBPM的module,挺有用的,可以用一下。特别是里面的JbpmTemplate。
从文章里可以看出一点,你们好像不太看文档,哈哈。很多问题都在文档里有写。

引用
state node会将当前的流程挂起,这跟org.jbpm.graph.node.State类有关:

这句话虽然正确,但是有点本末倒置。state node会将当前的流程挂起,这是State的定义决定的,因此才有了State类的实现。
2 楼 Luzifer 2008-05-25  
受益匪浅:)
1 楼 ttitfly 2008-05-24  
很好,谢谢

相关推荐

Global site tag (gtag.js) - Google Analytics