在企业应用中,会有很多这样的情况,一个人起草之后,会需要他的上级一级一级的签,直到签到符合要求的那个主管等级,然后结束。这种情况,有不过不固定,因为每个人的上级不一样,所以如果要把这个图都画出来的话及其复杂,这样就有了以下的构思。通过同一个node的循环,来实现这种需要上级签合的情况。
下面是一个我们公司的资讯申请单流程
xml 代码
- <?xml version="1.0" encoding="UTF-8"?>
- <process-definition xmlns="urn:jbpm.org:jpdl-3.1"
- name="IT_InformationRequisition">
- <swimlane name="user" />
- <swimlane name="userHandler">
- <assignment class="com.ivo.engine.wf.swinlane.UserSwimlane" />
- </swimlane>
- <swimlane name="handler">
- <assignment class="com.ivo.engine.wf.swinlane.HandlerSwimlane" />
- </swimlane>
- <swimlane name="handlerClose">
- <assignment class="com.ivo.engine.wf.swinlane.HandlerCloseSwimlane" />
- </swimlane>
- <swimlane name="leader">
- <assignment class="com.ivo.engine.wf.swinlane.DomainLeaderSwimlane" />
- </swimlane>
- <swimlane name="userManager">
- <assignment class="com.ivo.engine.wf.swinlane.UserManagerSwimlane" />
- </swimlane>
- <start-state name="start">
- <task swimlane="user"> </task>
- <transition name="draft" to="Drafting"></transition>
- <transition name="accept" to="HandlerAcceptance"></transition>
- </start-state>
- <end-state name="end"></end-state>
- <task-node name="HandlerAcceptance" create-tasks="false">
- <task name="HandlerAcceptance"></task>
- <event type="node-enter">
- <action name="createInstance" class="com.ivo.engine.wf.action.DynamicTaskAction">
- </action>
- </event>
- <transition name="accept" to="LeaderConfirmation"></transition>
- </task-node>
- <task-node name="LeaderConfirmation">
- <task swimlane="leader"> </task>
- <transition name="accept" to="HandlerClose"></transition>
- <transition name="reject" to="Drafting"></transition>
- </task-node>
- <task-node name="Drafting">
- <task swimlane="userHandler"> </task>
- <transition name="accept" to="HandlerAcceptance"></transition>
- <transition name="delete" to="end"></transition>
- </task-node>
- <task-node name="HandlerClose">
- <task swimlane="handler"> </task>
- <transition name="accept" to="UserAcceptance"></transition>
- </task-node>
- <task-node name="UserAcceptance">
- <task swimlane="userHandler"> </task>
- <transition name="accept" to="UserDeptAcceptance"></transition>
- <transition name="reject" to="HandlerClose"></transition>
- </task-node>
- <task-node name="UserDeptAcceptance" create-tasks="false">
- <task name="deptAcceptance"></task>
- <event type="node-enter">
- <action name="createInstance" class="com.ivo.engine.wf.action.UserManagerAction">
- </action>
- </event>
- <transition name="loop" to="UserDeptAcceptance"></transition>
- <transition name="accept" to="DomainLeaderClose"></transition>
- <transition name="reject" to="HandlerClose"></transition>
- </task-node>
- <task-node name="DomainLeaderClose">
- <task swimlane="leader"> </task>
- <transition name="accept" to="end"></transition>
- <transition name="reject" to="HandlerClose"></transition>
- </task-node>
- </process-definition>
这里应用到循环节点的是UserDeptAcceptance,需要签上级,直到处级主管。
通过UserManagerAction,来动态创建taskInstance,jbpm好像有一个特性,一个node的task第一次创建之后,如果重新回到这个node,这个taskInstance的actorId还是原来的那个,所以我就用动态创建taskInstance,这样可以在每次进入这个node的时候给这个赋予不同的actorId。
java 代码
- package com.ivo.engine.wf.action;
- import org.jbpm.graph.def.ActionHandler;
- import org.jbpm.graph.exe.ExecutionContext;
- import org.jbpm.graph.exe.Token;
- import org.jbpm.graph.node.TaskNode;
- import org.jbpm.taskmgmt.def.Task;
- import org.jbpm.taskmgmt.exe.TaskMgmtInstance;
- import com.ivo.engine.dao.HRDao;
- import com.ivo.engine.model.Employee;
- public class UserManagerAction implements ActionHandler {
- private static final long serialVersionUID = 1L;
- public void execute(ExecutionContext executionContext) throws Exception {
- String actorId = "";
- String currDeptLevel = null;
- String loopActorId = (String)executionContext.getVariable("LoopActorId");
- String startActorId = (String)executionContext.getVariable("StartActorId");
- String emp = null;
- Employee manager = null;
- if ( loopActorId == null ){
- emp = startActorId;
- } else {
- emp = loopActorId;
- }
- manager = HRDao.getManager(emp);
- actorId = manager.getDeptManager_FK();
- currDeptLevel = manager.getDeptLevel();
- // set variables
- executionContext.setVariable("LoopActorId", actorId.trim());
- executionContext.setVariable("CurrDeptLevel", currDeptLevel);
- executionContext.setVariable("LoopTag", "loop");
- // create task
- Token token = executionContext.getToken();
- TaskMgmtInstance tmi = executionContext.getTaskMgmtInstance();
- TaskNode taskNode = (TaskNode) executionContext.getNode();
- Task task = (Task)taskNode.getTasks().iterator().next();
- tmi.createTaskInstance(task, token).setActorId(actorId.trim());
- }
- }
通过两个variable,来控制这个loop是否继续。
在taskInstance end的时候判断两个variable。
下面是end的方法实现。
java 代码
- ContextInstance contextInstance = taskInstance.getTaskMgmtInstance().getProcessInstance().getContextInstance();
- String loopTag = (String)contextInstance.getVariable("LoopTag");
- if (loopTag != null && loopTag.equals("loop")) {
- Integer deptLevel = Integer.valueOf((String)contextInstance.getVariable("DeptLevel"));
- if ( deptLevel == null )
- throw new WorkflowException("in loop node , variable(DeptLevel) is null, pls set at start node");
- Integer currDeptLevel = Integer.valueOf((String)contextInstance.getVariable("CurrDeptLevel"));
- if ( currDeptLevel == null)
- throw new WorkflowException("in loop node , variable(CurrDeptLevel) is null, pls set at swimlane");
- if (currDeptLevel <=deptLevel) {
- taskInstance.end("accept");
- contextInstance.setVariable("LoopTag", null);
- }
- else taskInstance.end("loop");
- }else {
- taskInstance.end("accept");
- }
- jbpmContext.save(taskInstance);