JBPM4.4 使用泳道動態指定下一個任務節點任務人的兩種方式之一 (assignment-handler)
近期在學習 JBPM 工作流,上一篇博文描述了實現一個簡單請假工作流的過程
之後花了好幾天的時間來實現一個基於泳道的任務釋出工作流:
簡要流程如下:
某級部門(暫定為A級部門)manager 啟動一個新任務釋出工作流
通過泳道將該任務釋出給A級部門的子部門(B)和孫子部門(C)
B和C部門的所有成員都能夠看到該任務,並可以點選連結檢視該任務的詳細資訊
一旦有成員apply 該任務,則其他人都不能再次apply該任務
如果該成員只是C級部門的成員,不具有manager 的角色,則該次申請還需要提交給C級部門的經理進行稽核。
如果該成員是C級部門的經理,則不需要稽核,直接進入tryfinish 待辦任務
當獲取了任務的assignee 認為自己完成了該項任務時,則可以提交tryfinish 任務,然後該請求進入工作流釋出人的待辦任務列表中
如果工作流釋出者批准該次任務完成,則該次工作流結束。否則重新進入tryfinish 環節。
具體jbpm。xml 程式碼如下所示
<?xml version="1.0" encoding="UTF-8"?>
<process name="assignment" xmlns="http://jbpm.org/4.4/jpdl">
<swimlane candidate-groups="#{assignGroup}" name="assignmentswin">
</swimlane>
<start g="336,33,64,58" name="start1">
<transition to="assign"/>
</start>
<task assignee="#{assignOwner}" form="/SSH/LeaveJSP/assign_add.jsp" g="322,107,80,40" name="assign">
<transition to="tryAssign"/>
</task>
<task form="/SSH/LeaveJSP/assign_trytake.jsp" g="323,180,92,52" name="tryAssign" swimlane="assignmentswin">
<transition to="exclusive1"/>
</task>
<decision expr="#{role=='manager'? 'totryFinish':'tomanagerAprove'}" g="351,278,48,48" name="exclusive1">
<transition g="-92,-18" name="tomanagerAprove" to="managerAprove"/>
<transition to="tryFinish" name="totryFinish"/>
</decision><!--
<task assignee="#{assignManager}" form="leaveAction!toAssign_Manager.action" g="118,287,92,52" name="managerAprove">
-->
<task form="leaveAction!toAssign_Manager.action" g="118,287,92,52" name="managerAprove">
<assignment-handler class="com.util.AssignTask">
<field name="assignee">
<string value="1"/>
</field>
</assignment-handler>
<transition g="-61,-18" name="approveTry" to="tryFinish"/>
<transition g="-59,-18" name="notApproveTry" to="tryAssign"/>
</task>
<task form="leaveAction!toAssign_tryFinish.action" g="332,464,92,52" name="tryFinish" swimlane="assignmentswin">
<transition to="ifFinish"/>
</task>
<end g="355,711,48,48" name="end1"/>
<task assignee="#{assignOwner}" form="leaveAction!toAssign_ifFinish.action" g="339,611,92,52" name="ifFinish">
<transition name="AcceptFinish" to="end1" g="-65,-18"/>
<transition g="504,599:-82,-18" name="NotAcceptFinish" to="tryFinish"/>
</task>
</process>
這個版本的jbpm。xml 檔案採用了 assignment-handler 來實現根據C級部門成員apply 任務時確定C級部門的manager ,即確定批准C級成員apply 該任務的manager。
我這次的工作就花了很長的時間在確定manager 上。
當C級部門成員apply 該才任務時,工作流進入了部門manager 批准的環節,在這個環節中使用到了 assignment-handler,通過該環節的executionId來獲取到該次工作流的歷史任務列表。然後從歷史人物列表的最後一個歷史任務中取到apply 任務的C級部門成員的assign name。取到了上一個任務的assign name ,也就可以將 assign 所在部門的manager name 放入到當前任務的assingee 。從而確定了當前任務的assignee。
下面是AssignTask 的程式碼。
AssignTask.java
package com.util;
import java.util.List;
import org.jbpm.api.ProcessEngine;
import org.jbpm.api.TaskService;
import org.jbpm.api.history.HistoryTask;
import org.jbpm.api.model.OpenExecution;
import org.jbpm.api.task.Assignable;
import org.jbpm.api.task.AssignmentHandler;
import org.jbpm.api.task.Task;
import org.jbpm.pvm.internal.history.model.HistoryTaskImpl;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.model.User;
import com.service.UserService;
import com.service.imp.UserServiceImp;
public class AssignTask implements AssignmentHandler{
String assignee;
private UserService userService;
private ProcessEngine processEngine;
@Override
public void assign(Assignable assignable, OpenExecution openExecution) throws Exception {
ApplicationContext context=new ClassPathXmlApplicationContext("applicationContext.xml");
processEngine=(ProcessEngine) context.getBean("processEngine");
userService=(UserService)context.getBean("userService");
String executionId= openExecution.getId();
System.out.println("executionId-----------"+executionId);
List <HistoryTask>list = processEngine.getHistoryService().createHistoryTaskQuery().executionId(executionId).list();
String tryAssignUserName="";
for(int i=0;i<list.size();i++){
HistoryTaskImpl taskImpl=(HistoryTaskImpl)list.get(i);
tryAssignUserName= taskImpl.getAssignee();
Task task = processEngine.getTaskService().getTask(list.get(i).getId());
if(task!=null&&task.getName().equals("tryAssign")){
}
}
if(!tryAssignUserName.equals("")){
User user1=userService.findUserByName(tryAssignUserName);
User assignManager=user1.getDepartment().getManagerUser();
assignable.setAssignee(assignManager.getUsername());
}
}
}
對這段程式碼需要作如下的說明:
// 我們已經知道了上一個任務節點的名稱是“tryAssign”,所以可以對歷史任務列表中的每一個歷史任務進行取出任務名稱並和“tryAssign”進行比對,如果相同,則將該歷史任務的assignee 取出。該assingee 就是C級部門apply 任務的組成員名。
不過在這裡只能取到 tryAssign 的HistoryTaskImpl 而不能取到 task,不過由於上一個任務節點肯定是在歷史任務列表的最後一個位置,所以可以通過取巧的方式獲取到歷史人物列表最後一個HistoryTaskImpl 的assignee 來確定tryAssign 的assingee。
對泳道的說明:
在jbpm.xml 檔案中,有兩處swimlane="assignmentswin" ,分別是在tryAssign 和tryFinish 任務節點時。
因為在tryAssign 時,泳道確定了獲取tryAssign 任務的assignee ,則jbpm 會將assignee 儲存起來,在下次D任務節點用到swimlane="assignmentswin" 時,D任務節點會將任務的assingee 自動分配給這個泳道的assignee
下面是action 中tryAssign 方法的程式碼:
public String applayAssign(){
Map map=new HashMap();
String tryAssignUserName="";
User user=(User)ActionContext.getContext().getSession().get("user");
User user2=user.getDepartment().getManagerUser();
if(user.equals(user2)){
map.put("role", "manager");
}
else {map.put("role", "common");
}
map.put("tryTime", tryTime);
map.put("tryCondition", tryCondition);
taskService.takeTask(taskId,user.getUsername() );
String executionId = processEngine.getTaskService().getTask(taskId).getExecutionId();
List <HistoryTask>list = processEngine.getHistoryService().createHistoryTaskQuery().executionId(executionId).list();
for(int i=0;i<list.size();i++){
HistoryTaskImpl taskImpl=(HistoryTaskImpl)list.get(i);
String tempName= taskImpl.getAssignee();
Task task = processEngine.getTaskService().getTask(list.get(i).getId());
if(task!=null&&task.getName().equals("tryAssign")){
tryAssignUserName=tempName;
}
}
User user4= this.userServcie.findUserByName(tryAssignUserName);
User assignManager=user4.getDepartment().getManagerUser();
// map.put("assignManager", assignManager.getUsername());
taskService.completeTask(taskId,map);
return "addLeaveApplay";
}
方法一和方法二在這裡的區別,就是沒有將 assignManager進行賦值並傳遞給 managerAprove 任務中。
相關推薦
JBPM4.4 使用泳道動態指定下一個任務節點任務人的兩種方式之一 (assignment-handler)
近期在學習 JBPM 工作流,上一篇博文描述了實現一個簡單請假工作流的過程 之後花了好幾天的時間來實現一個基於泳道的任務釋出工作流: 簡要流程如下: 某級部門(暫定為A級部門)manager 啟動一個新任務釋出工作流 通過泳道將該任務釋出給A級部門的子部門(B)和孫子部
C#動態獲取本機可用串口的兩種方式
buffer for local span 實現 != oid 獲取 簡單 1. private void GetSerialPort() //獲取串口列表 { Regi
Android Studio下Git的兩種使用方法(超詳細)
提了好久的筆,終於開始寫部落格了。 今天要說的是版本控制工具,作為個人開發者,我一般使用的就是gitoso(碼雲)管理程式碼,因為可以建立私人(不公開)的專案。今天我就來講一講AndroidStudio下git的使用。 首先,要下載Git。Git官網下載
獲取Executor提交的併發執行的任務返回結果的兩種方式/ExecutorCompletionService使用
當我們通過Executor提交一組併發執行的任務,並且希望在每一個任務完成後能立即得到結果,有兩種方式可以採取: 方式一: 通過一個list來儲存一組future,然後在迴圈中輪訓這組future,直到每個future都已完成。如果我們不希望出現因為排在前面的任務阻
C# Winform下一個熱插拔的MIS/MRP/ERP框架(多語言方案)
文件加載 全局 查詢 分享 技術 變量 支持 對象 style 個別時候,我們需要一種多語種切換方案。 我的想方案是這樣的: 1、使用文本文本存儲多語言元素,應用程序啟動時加載到內存表中; 2、應用程序啟動時從配置文件加載語種定義; 3、所有窗體繼承自一個Base
malloc動態申請一個二維陣列的兩種方法
方法一:利用二級指標申請 #include <stdio.h> #include <malloc.h> const int num = 2; int main() { int **a = (int**)malloc(num*sizeof(int*)); for (i
MyBatis_動態sql_foreach_mysql下foreach批量插入的兩種方式
方法1: 筆記要點出錯分析與總結工程組織資料庫組織0.重新修改Bean類 修改1.定義介面 //批量插入 public void addEmps(@Param("emps")List<Employee> emps); 2.定義XML對映檔案
C# Winform下一個熱插拔的MIS/MRP/ERP框架(簡介)
Programmer普弱哥們都喜歡玩自己的框架,我也不例外。 理想中,這個框架要易於理解、易於擴充套件、易於維護;最重要的,易於CODING。 系統是1主體框架+N模組的多個EXE/DLL組成的,在主體框架開啟的時候,編譯完模組EXE可以馬上響應需求,不用退系統,不用重登入。 大概的目標:來一
C# Winform下一個熱插拔的MIS/MRP/ERP框架(通用控制元件)
一直對商業控制元件不感冒, 結合日常工作, 我寫了幾個常用控制元件. 一、下拉框控制元件(仿Access下拉框:F4下拉,自動輸入,支援單/多列顯示),可在Datagridview中使用。 1、常規: 2、Datagridview: 二、帶按鈕的文字框(可在Datagridview中使用): 1、常
C語言用陣列1. 簡單約瑟夫環問題: N個人,編號從1~N圍成一圈,輸入一個數T,從1號開始報數,報到T的人出圈;下一人又從1開始報數,下一個報到T的人出圈,輸出出圈順序。 考慮問實現約瑟夫環問題
1. 簡單約瑟夫環問題: N個人,編號從1~N圍成一圈,輸入一個數T,從1號開始報數,報到T的人出圈;下一人又從1開始報數,下一個報到T的人出圈,輸出出圈順序。 考慮問題: 報到T的人出圈,怎麼表示出圈?要麼刪除對應的標號,其他的標號前移(如果是陣列結構,要依次移動
C#兩種方式獲取指定資料夾下所有子目錄及檔案
using System.IO; /// <summary> /// 獲取指定目錄下的所有資料夾名 /// </summary> /// <param name="path">目錄路徑</param> /// <
對陣列 [3, 1, 2, 4, 2, 4, 5, 3, 7] 進行去重, 寫出至少兩種方法 (請寫出一段Python程式碼實現刪除一個list裡面的重複元素)
1. 對陣列 [3, 1, 2, 4, 2, 4, 5, 3, 7] 進行去重, 寫出至少兩種方法 (請寫出一段Python程式碼實現刪除一個list裡面的重複元素)In [1]:def unique1
activiti 個人任務指定辦理人三種方式(十)
1. 流程圖 2. 執行人指定類、實現類 package com.hxzq.workflow.taskperson; import org.activiti.engine.delegate.DelegateTask; import org.activiti.eng
LeetCode 第117題 填充每個節點的下一個右側節點指針||
pre 填充 src node return lee null != 給定 給定一個二叉樹 struct Node { int val; Node *left; Node *right; Node *next; } 填充它的每個 next 指針
leetcode 117. 填充每個節點的下一個右側節點指針 II(Populating Next Right Pointers in Each Node II)
常量 設置 public ref etc 圖片 lee nec 一個 目錄 題目描述: 示例: 解法: 題目描述: 給定一個二叉樹 struct Node {
C#利用WebClient 兩種方式下載文件
sys end adf ati stream pac pub 利用 static WebClient client = new WebClient(); 第一種 string URLAddress = @"http://files.cnblogs.com/x4646/tre
C++服務器下載文件的兩種方式
roo eric gets sizeof let ont domain write 文件 #include <afxinet.h>#include "wininet.h" #pragma comment( lib, "wininet.lib" )string
win7下python2.7安裝 pip,setuptools的正確方法(親測)
真是奇葩了,我在win7下測試python2.7安裝 pip,setuptools老是不行,好像是指令碼不行,使用的版本是python2.7.6版本。沒辦法看來只能換低點的版本了,高版本的也蛋疼啊,win7下python2.7.5安裝 pip,setuptools的正確方法(親測) window
git 一個分支程式碼提交到遠端倉新分支(新建分支)
背景: 從branchA分支拉了一份程式碼,做了一些修改,但是不想提交到branchA分支,想新建一個分支branchB儲存程式碼。 操作方法: 新增本地需要提交程式碼 git add . 1 提交原生代碼 git commit -m "add my code to new branchB" 1
Mac下配置環境變數的兩種方式[轉]
1.配置全域性變數(永久有效) root使用者登入,修改 /etc/profile檔案,末尾新增環境變數如下: 編輯檔案 sudo vi /etc/profile 提示readonly,加許可權 chmod a+rwx /etc/profile 寫入全域性變數 expo