一個JBPM工作流管理示例
一個JBPM工作流管理示例
示例:
在某一公司中,部門員工要休假的話需要部門主管的批準。如果休假天數大于10天的話,在部門主管的同意后,還必須上級主管批準。如果是部門主管要休假只要上級主管批準即可。在休假被批準之前,申請人可以撤銷休假申請。
每個員工還有多少天休假必須管理起來,在員工提交休假申請時要檢查申請天數是否超過可用天數。申請批準后,要在可用天數里減去申請天數。每次休假申請結束之后,不管通過未通過或是否取消,都必須記錄下來。主管在批復申請之后,系統要將批復結果Email給申請人。對于大于10天的申請,如果部門主管已批準同意而上級主管還未批準,這時申請人撤銷申請后,系統應發Email通知部門主管申請已撤銷。
processdefinition.xml如下:
<?xml version="1.0" encoding="UTF-8"?>
<!-- edited with XMLSPY v2004 rel. 3 U (http://www.xmlspy.com) by keller (zju) -->
<!DOCTYPE process-definition PUBLIC
"-//jBpm/jBpm Mapping DTD 2.0//EN"
"http://jbpm.org/dtd/processdefinition-2.0.dtd">
<process-definition name="RequestLeave">
<swimlane name="requester">
<description>申請者</description>
</swimlane>
<swimlane name="chief">
<description>部門主管</description>
<delegation class="kellerdu.jbpm.delegation.ChiefSwimlane"/>
</swimlane>
<swimlane name="boss">
<description>上級主管</description>
<delegation class="kellerdu.jbpm.delegation.BossSwimlane"/>
</swimlane>
<start-state name="request" swimlane="requester">
<transition to="BeginRequest"/>
</start-state>
<fork name="BeginRequest">
<transition to="RequesterCancel"/>
<transition to="IsChief"/>
</fork>
<decision name="IsChief">
<delegation class="kellerdu.jbpm.delegation.ChiefDecision"/>
<transition name="BossApprove" to="BossApprove"/>
<transition name="ChiefApprove" to="ChiefApprove"/>
</decision>
<state name="RequesterCancel">
<assignment swimlane="requester"/>
<transition name="cancel" to="Decided">
<action>
<!-- 將請假的狀態改變為“取消”-->
<delegation class="kellerdu.jbpm.action.RequestCancel"/>
</action>
</transition>
</state>
<state name="ChiefApprove">
<assignment swimlane="chief"/>
<transition name="approve" to="NeedBossApprove">
<action>
<!-- 將請假的狀態改變為“主管批準”-->
<delegation class="kellerdu.jbpm.action.ChiefApprove"/>
</action>
</transition>
<transition name="disapprove" to="Decided">
<action>
<!-- 將請假的狀態改變為“主管否決”-->
<delegation class="kellerdu.jbpm.action.ChiefDisapprove"/>
</action>
</transition>
</state>
<state name="BossApprove">
<assignment swimlane="boss"/>
<transition name="approve" to="Decided">
<action>
<!-- 將請假的狀態改變為“老板批準”-->
<delegation class="kellerdu.jbpm.action.BossApprove"/>
</action>
</transition>
<transition name="disapprove" to="Decided">
<action>
<!-- 將請假的狀態改變為“老板否決”-->
<delegation class="kellerdu.jbpm.action.BossDisapprove"/>
</action>
</transition>
</state>
<decision name="NeedBossApprove">
<!-- 請假天數大于10天的要老板批準 -->
<delegation class="kellerdu.jbpm.delegation.NeedBossApproveDecision"/>
<transition name="need" to="BossApprove"/>
<transition name="notNeed" to="Decided"/>
</decision>
<join name="Decided">
<description>有一個先到達即進行父Token</description>
<delegation class="kellerdu.jbpm.delegation.DecidedJoin"/>
<transition to="DoSomething"/>
</join>
<decision name="DoSomething">
<description>
根據請求的狀態決定。
(1)“主管或者老板批準”-‘approve’:修改員工休假的總天數,設定發給用戶E-Mail的信息。
(2)“主管或者老板否決”-“disapprove”:設定發給用戶E-Mail的信息。
(3)“撤銷”-"cancel"-設定發給用戶E-Mail的信息。如果主管批準,要發給主管消息說明已經撤銷。
</description>
<delegation class="kellerdu.jbpm.delegation.DoSomethingDecision"/>
<transition name="disapprove" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Disapprove"/>
</action>
</transition>
<transition name="approve" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Approve"/>
</action>
</transition>
<transition name="cancel" to="Finished">
<action>
<delegation class="kellerdu.jbpm.action.Cancel"/>
</action>
</transition>
</decision>
<end-state name="Finished"/>
<action event-type="process-end">
<!-- 發送E-Mail消息給申請者,記錄請假日志 -->
<delegation class="kellerdu.jbpm.action.ProcessEndAction"/>
</action>
</process-definition>
Action指明的是當前狀態要執行的一些額外的操作,如記錄log、發郵件等。
(1)Swimline的delegation要做的就是判別當前Actor的身份。
package kellerdu.jbpm.delegation;
import org.jbpm.delegation.*;
import kellerdu.jbpm.LogsFactory;
import org.apache.commons.logging.Log;
public class BossSwimlane implements AssignmentHandler {
public BossSwimlane() {
}
/**
* 當前的狀態有哪個actor來具體負責處理,選擇是老板的actor來處理。
*
* 如果王林是老板,那么他請假可以用他的名稱來開始一個請假流程,當他檢查他需要批示的
* 請假時,使用actorId=boss來找出所有的批示。這時selectActor返回的值就是一個常量“boss”
*
*
* @param assignmentContext AssignmentContext
* @return String
* @todo Implement this org.jbpm.delegation.AssignmentHandler method
*/
public String selectActor(AssignmentContext assignmentContext) {
Log log = LogsFactory.getLogInstance(this.getClass());
log.info("任務分配給老板");
return "boss";
}
}
========================================
ackage kellerdu.jbpm.delegation;
import org.jbpm.delegation.*;
import kellerdu.jbpm.LogsFactory;
import org.apache.commons.logging.Log;
public class ChiefSwimlane implements AssignmentHandler {
public ChiefSwimlane() {
}
/**
* selectActor
* @see BossSwimlane
*
* @param assignmentContext AssignmentContext
* @return String
* @todo Implement this org.jbpm.delegation.AssignmentHandler method
*/
public String selectActor(AssignmentContext assignmentContext) {
Log log = LogsFactory.getLogInstance(this.getClass());
log.info("任務分配給上級主管");
return "chief";
}
}
(二)Decision
package kellerdu.jbpm.delegation;
import org.jbpm.delegation.*;
import kellerdu.jbpm.LogsFactory;
import org.apache.commons.logging.Log;
import kellerdu.jbpm.Constants;
public class ChiefDecision implements DecisionHandler {
public ChiefDecision() {
}
/**
* 判斷是否需要主管批準,決定下一個要進行的transition
*
* @param executionContext ExecutionContext
* @return String
* @todo Implement this org.jbpm.delegation.DecisionHandler method
*/
public String decide(ExecutionContext executionContext) {
Log log=LogsFactory.getLogInstance(this.getClass());
String ac=(String)executionContext.getVariable(Constants.USER_NAME);
if(ac!=null&&(ac.equals("dali")||ac.equals("wang"))){
log.info(ac+"需要老板批準!");
return "BossApprove";
}else{
log.info(ac+"需要先經主管批準");
return "ChiefApprove";
}
}
}
=======================
(三)fork
package kellerdu.jbpm.delegation;
import org.jbpm.*;
import org.jbpm.delegation.*;
import org.jbpm.model.execution.*;
import java.util.*;
public class DecidedJoin implements JoinHandler {
public DecidedJoin() {
}
/**
* fork,只要一個分支到達,即可進行下一步操作,同時取消其它同時進行的分支。
* 這里就是用戶如果取消,請假就取消。如果用戶請假批準,則用戶不能取消。
*
* @param forkContext ForkContext
* @throws ExecutionException
* @todo Implement this org.jbpm.delegation.ForkHandler method
*/
public void join(JoinContext joinContext) throws ExecutionException {
Iterator it=joinContext.getConcurrentTokens().values().iterator();
Token arrivingToken = joinContext.getToken();
while(it.hasNext()){
Token to=(Token)it.next();
if(to.getId().equals(arrivingToken.getId())){
//取消其它執行的Token
joinContext.getExecutionService().cancelToken(to.getId());
}
}
// reactivate the parent token.
joinContext.reactivateToken( arrivingToken.getParent() );
}
}
(一) 開始一個請假流程
//user是請假人的actorId
ExecutionService es=JbpmServiceFactory.getInstance().openExecutionService(user);
HashMap vs=new HashMap();
//一些參數
vs.put(Constants.REQUEST_STATUS,String.valueOf(0));
vs.put(Constants.REQUEST_RETURN_INFO,"No info!");
vs.put(Constants.USER_NAME,EncodeTransfer.toISO(user));
vs.put(Constants.REQUEST_DAYS,String.valueOf(rea.getDays()));
try {
//開啟請假流程
es.startProcessInstance(Constants.WORK_NAME, vs);
log.info("["+user+"]"+"申請假期開始!請假"+rea.getDays()+"天!");
return am.findForward("main");
} catch (ExecutionException ex) {
ex.printStackTrace();
log.error("請假進程無法開始!");
return am.findForward("error");
}finally{
es.close();
}
(二)當前執行任務
對于部門經理或者老板,找到要處理的請假。
String actorId = (String) req.getSession().getAttribute(Constants.USER);
if(actorId.equals("wang")){
actorId="boss";
}else if(actorId.equals("bigli")){
actorId="chief";
}
// get the execution service
ExecutionService executionService = JbpmServiceFactory.getInstance().
openExecutionService(actorId);
// get the tasklist from jbpm for user
List tasks = new ArrayList();
// add the jbpm tasks
tasks.addAll(executionService.getTaskList(actorId));
// put the tasklist into the form
mf.setTasks(tasks);
// get the tasklist from jbpm for user
List definitions = new ArrayList();
// add the jbpm definitions
definitions.addAll(executionService.getLatestDefinitions());
// put the tasklist into the form
mf.setRequests(definitions);
// close the execution service
executionService.close();
req.getSession().setAttribute("mainForm",mf);
log.debug("任務: " + tasks);
log.debug("當前可以執行的請求: " + definitions);
(三)處理請假
String actorId = (String) reqrest.getSession().getAttribute(Constants.
USER);
Long tokenId=new Long(req.getParameter("tokenId"));
// get the execution service
ExecutionService executionService = JbpmServiceFactory.getInstance().
openExecutionService(actorId);
Map hm=executionService.getVariables(tokenId);//變量
String act=req.getParameter("action");//進行轉換的transition
executionService.endOfState(tokenId,hm,act);
executionService.close();
v