工作流引擎Activiti使用总结
1.簡(jiǎn)單介工作流引擎與Activiti
對(duì)于工作流引擎的解釋請(qǐng)參考百度百科:工作流引擎
1.1 我與工作流引擎
在第一家公司工作的時(shí)候主要任務(wù)就是開(kāi)發(fā)OA系統(tǒng),當(dāng)然基本都是有工作流的支持,不過(guò)當(dāng)時(shí)使用的工作流引擎是公司一些牛人開(kāi)發(fā)的(據(jù)說(shuō)是用一個(gè)開(kāi)源的引擎修改的),名稱叫CoreFlow;功能相對(duì)Activiti來(lái)說(shuō)比較弱,但是能滿足日常的使用,當(dāng)然也有不少的問(wèn)題所以后來(lái)我們只能修改引擎的代碼打補(bǔ)丁。
現(xiàn)在是我工作的第二家公司,因?yàn)橐_(kāi)發(fā)ERP、OA等系統(tǒng)需要使用工作流,在項(xiàng)目調(diào)研階段我先搜索資料選擇使用哪個(gè)開(kāi)源工作流引擎,最終確定了Activiti5并基于公司的架構(gòu)做了一些DEMO。
1.2 Activiti與JBPM5?
對(duì)于Activiti、jBPM4、jBPM5我們應(yīng)該如何選擇,在InfoQ上有一篇文章寫的很好,從大的層面比較各個(gè)引擎之間的差異,請(qǐng)參考文章:縱觀jBPM:從jBPM3到j(luò)BPM5以及Activiti5
1.3 Activiti資料
-
官網(wǎng):http://www.activiti.org/
-
下載:http://www.activiti.org/download.html
-
版本:Activiti的版本是從5開(kāi)始的,因?yàn)锳ctiviti是使用jBPM4的源碼;版本發(fā)布:兩個(gè)月發(fā)布一次。
-
Eclipse Plugin:?http://activiti.org/designer/update/
-
Activit中文群:236540304
2.初次使用遇到問(wèn)題收集
因?yàn)锳ctiviti剛剛退出不久所以資料比較空缺,中文資料更是少的可憐,所以開(kāi)始的時(shí)候一頭霧水(雖然之前用過(guò)工作流,但是感覺(jué)差距很多),而且官方的手冊(cè)還不是很全面;所以我把我在學(xué)習(xí)使用的過(guò)程遇到的一些疑問(wèn)都羅列出來(lái)分享給大家;以下幾點(diǎn)是我遇到和想到的,如果你還有什么疑問(wèn)可以在評(píng)論中和我交流再補(bǔ)充。
2.1 部署流程圖后中文亂碼
亂碼是一直纏繞著國(guó)人的問(wèn)題,之前各個(gè)技術(shù)、工具出現(xiàn)亂碼的問(wèn)題寫過(guò)很多文章,這里也不例外……,Activiti的亂碼問(wèn)題在流程圖中。
流程圖的亂碼如下圖所示:
解決辦法有兩種:
2.1.1 修改源代碼方式
修改源碼<pre>org.activiti.engine.impl.bpmn.diagram.ProcessDiagramCanvas</pre>
在構(gòu)造方法<pre>public ProcessDiagramCanvas(int width, int height)</pre> 中有一行代碼是設(shè)置字體的,默認(rèn)是用Arial字體,這就是亂碼產(chǎn)生的原因,把字改為本地的中文字體即可,例如:
?
| 1 | Font font = new Font("WenQuanYi Micro Hei", Font.BOLD, 11); |
當(dāng)然如果你有配置文件讀取工具那么可以設(shè)置在*.properties文件中,我就是這么做的:
?
| 1 | Font font = new Font(PropertyFileUtil.get("activiti.diagram.canvas.font"), Font.BOLD, 11); |
從**5.12**版本開(kāi)始支持設(shè)置字體名稱,在引擎中添加如下設(shè)置,在生成圖片時(shí)即可使用**微軟雅黑**設(shè)置圖片中的文字。
?
| 1 | <property name="activityFontName" value="微軟雅黑"></property> |
2.1.2 使用壓縮包方式部署
Activiti支持部署*.bpmn20.xml、bar、zip格式的流程定義。
使用Activit Deisigner工具設(shè)計(jì)流程圖的時(shí)候會(huì)有三個(gè)類型的文件:
-
.activiti設(shè)計(jì)工具使用的文件
-
.bpmn20.xml設(shè)計(jì)工具自動(dòng)根據(jù).activiti文件生成的xml文件
-
.png流程圖圖片
解決辦法就是把xml文件和圖片文件同時(shí)部署,因?yàn)樵趩为?dú)部署xml文件的時(shí)候Activiti會(huì)自動(dòng)生成一張流程圖的圖片文件,但是這樣在使用的時(shí)候坐標(biāo)和圖片對(duì)應(yīng)不起來(lái)……
所以把xml和圖片同時(shí)部署的時(shí)候Activiti自動(dòng)關(guān)聯(lián)xml和圖片,當(dāng)需要獲取圖片的時(shí)候直接返回部署時(shí)壓縮包里面的圖片文件,而不是Activiti自動(dòng)生成的圖片文件
2.1.2.1 使用工具打包Bar文件
在“Package Explorer”視圖中右鍵項(xiàng)目名稱然后點(diǎn)擊“Create deployment artifacts”,會(huì)在src目錄中創(chuàng)建deployment文件夾,里面包含*.bar文件.
2.1.2.2 使用Ant腳本打包Zip文件
這也是我們采用的辦法,你可以手動(dòng)選擇xml和png打包成zip格式的文件,也可以像我們一樣采用ant target的方式打包這兩個(gè)文件。
| ? | <?xml version="1.0" encoding="UTF-8"?> |
| ? | <project name="foo"> |
| ? | ? |
| ? | <property name="workflow.definition" value="foo-common-core/src/main/resources/diagrams" /> |
| ? | <property name="workflow.deployments" value="foo-common-core/src/main/resources/deployments" /> |
| ? | ? |
| ? | <target name="workflow.package.oa.leave"> |
| ? | <echo>打包流程定義及流程圖::OA-請(qǐng)假</echo> |
| ? | <zip destfile="${workflow.deployments}/oa/leave.zip" basedir="${workflow.definition}/oa/leave" update="true" |
| ? | includes="*.xml,*.png" /> |
| ? | </target> |
| ? | </project> |
view rawbuild.xml?hosted with ? by?GitHub
這樣當(dāng)修改流程定義文件后只要運(yùn)行ant命令就可以打包了:<pre>ant workflow.package.oa.leave</pre>
現(xiàn)在部署bar或者zip文件查看流程圖圖片就不是亂碼了,而是你的壓縮包里面的png文件。
2.2 使用引擎提供的Form還是自定義業(yè)務(wù)Form
2.2.1 引擎提供的Form
定義表單的方式在每個(gè)Task標(biāo)簽中定義extensionElements和activiti:formProperty即可,到達(dá)這個(gè)節(jié)點(diǎn)的時(shí)候可以通過(guò)API讀取表單元素。
Activiti官方的例子使用的就是在流程定義中設(shè)置每一個(gè)節(jié)點(diǎn)顯示什么樣的表單哪些字段需要顯示、哪些字段只讀、哪些字段必填。
但是這種方式僅僅適用于比較簡(jiǎn)單的流程,對(duì)于稍微復(fù)雜或者頁(yè)面需要業(yè)務(wù)邏輯的判斷的情況就不適用了。
對(duì)于數(shù)據(jù)的保存都是在引擎的表中,不利于和其他表的關(guān)聯(lián)、對(duì)整個(gè)系統(tǒng)的規(guī)劃也不利!
2.2.2 自定義業(yè)務(wù)Form
這種方式應(yīng)該是大家用的最多的了,因?yàn)橐话愕臉I(yè)務(wù)系統(tǒng)業(yè)務(wù)邏輯都會(huì)比較復(fù)雜,而且數(shù)據(jù)庫(kù)中很多表都會(huì)有依賴關(guān)系,表單中有很多狀態(tài)判斷。
例如我們的系統(tǒng)適用jQuery UI作為UI,有很多javascript代碼,頁(yè)面的很多操作需要特殊處理(例如:多個(gè)選項(xiàng)的互斥、每個(gè)節(jié)點(diǎn)根據(jù)類型和操作人顯示不同的按鈕);基本每個(gè)公司都有一套自己的UI風(fēng)格,要保持多個(gè)系統(tǒng)的操作習(xí)慣一致只能使用自定義表單才能滿足。
2.3 業(yè)務(wù)和流程的關(guān)聯(lián)方式
這個(gè)問(wèn)題在群里面很多人都問(wèn)過(guò),這也是我剛剛開(kāi)始迷惑的地方;
后來(lái)看了以下API發(fā)現(xiàn)RuntimeService有兩個(gè)方法:
2.3.1 startProcessInstanceByKey
javadoc對(duì)其說(shuō)明:
startProcessInstanceByKey(String processDefinitionKey, Map<String,Object> variables) Starts a new process instance in the latest version of the process definition with the given key其中businessKey就是業(yè)務(wù)ID,例如要申請(qǐng)請(qǐng)假,那么先填寫登記信息,然后(保存+啟動(dòng)流程),因?yàn)檎?qǐng)假是單獨(dú)設(shè)計(jì)的數(shù)據(jù)表,所以保存后得到實(shí)體ID就可以把它傳給processInstanceBusinessKey方法啟動(dòng)流程。當(dāng)需要根據(jù)businessKey查詢流程的時(shí)候就可以通過(guò)API查詢:
?
| 1 | runtimeService.createProcessInstanceQuery().processInstanceBusinessKey(processInstanceBusinessKey, processDefinitionKey) |
建議數(shù)據(jù)庫(kù)冗余設(shè)計(jì):在業(yè)務(wù)表設(shè)計(jì)的時(shí)候添加一列:PROCESS_INSTANCE_ID varchar2(64),在流程啟動(dòng)之后把流程ID更新到業(yè)務(wù)表中,這樣不管從業(yè)務(wù)還是流程都可以查詢到對(duì)方!
特別說(shuō)明:?此方法啟動(dòng)時(shí)自動(dòng)選擇最新版本的流程定義。
2.3.2 startProcessInstanceById
javadoc對(duì)其說(shuō)明:
startProcessInstanceById(String processDefinitionId, String businessKey, Map<String,Object> variables) Starts a new process instance in the exactly specified version of the process definition with the given id.processDefinitionId:這個(gè)參數(shù)的值可以通過(guò)repositoryService.createProcessDefinitionQuery()方法查詢,對(duì)應(yīng)數(shù)據(jù)庫(kù):ACT_RE_PROCDEF;每次部署一次流程定義就會(huì)添加一條數(shù)據(jù),同名的版本號(hào)累加。
特別說(shuō)明:?此可以指定不同版本的流程定義,讓用戶多一層選擇。
2.3.3 如何選擇
建議使用startProcessInstanceByKey,特殊情況需要使用以往的版本選擇使用startProcessInstanceById。
2.4 同步用戶數(shù)據(jù)
這個(gè)問(wèn)題也是比較多的人詢問(wèn)過(guò),Activiti支持對(duì)任務(wù)分配到:指定人、指定組、兩者組合,而這些人和組的信息都保存在ACT_ID..表中,有自己的用戶和組(角色)管理讓很多人不知所措了;原因是因?yàn)槊總€(gè)系統(tǒng)都會(huì)存在一個(gè)權(quán)限管理模塊(維護(hù):用戶、部門、角色、授權(quán)),不知道該怎么和Activiti同步。
2.4.1 建議處理方式
Activiti有一個(gè)IdentityService接口,通過(guò)這個(gè)接口可以操控Activiti的ACT_ID_*表的數(shù)據(jù),一般的做法是用業(yè)務(wù)系統(tǒng)的權(quán)限管理模塊維護(hù)用戶數(shù)據(jù),當(dāng)進(jìn)行CRUD操作的時(shí)候在原有業(yè)務(wù)邏輯后面添加同步到Activiti的代碼;例如添加一個(gè)用戶時(shí)同步Activiti User的代碼片段:
| ? | /** |
| ? | * 保存用戶信息 并且同步用戶信息到activiti的identity.User,同時(shí)設(shè)置角色 |
| ? | * @param user |
| ? | * @param roleIds |
| ? | */ |
| ? | public void saveUser(User user, List<Long> roleIds, boolean synToActiviti) { |
| ? | accountManager.saveEntity(user); |
| ? | String userId = user.getId().toString(); |
| ? | ? |
| ? | if (synToActiviti) { |
| ? | List<org.activiti.engine.identity.User> activitiUsers = identityService.createUserQuery().userId(userId).list(); |
| ? | if (activitiUsers.size() == 1) { |
| ? | //更新信息 |
| ? | org.activiti.engine.identity.User activitiUser = activitiUsers.get(0); |
| ? | activitiUser.setFirstName(user.getName()); |
| ? | activitiUser.setLastName(""); |
| ? | activitiUser.setPassword(user.getPassword()); |
| ? | activitiUser.setEmail(user.getEmail()); |
| ? | identityService.saveUser(activitiUser); |
| ? | ? |
| ? | // 刪除用戶的membership |
| ? | List<Group> activitiGroups = identityService.createGroupQuery().groupMember(userId).list(); |
| ? | for (Group group : activitiGroups) { |
| ? | identityService.deleteMembership(userId, group.getId()); |
| ? | } |
| ? | ? |
| ? | // 添加membership |
| ? | for (Long roleId : roleIds) { |
| ? | Role role = roleManager.getEntity(roleId); |
| ? | identityService.createMembership(userId, role.getEnName()); |
| ? | } |
| ? | ? |
| ? | } else { |
| ? | org.activiti.engine.identity.User newUser = identityService.newUser(userId); |
| ? | newUser.setFirstName(user.getName()); |
| ? | newUser.setLastName(""); |
| ? | newUser.setPassword(user.getPassword()); |
| ? | newUser.setEmail(user.getEmail()); |
| ? | identityService.saveUser(newUser); |
| ? | ? |
| ? | // 添加membership |
| ? | for (Long roleId : roleIds) { |
| ? | Role role = roleManager.getEntity(roleId); |
| ? | identityService.createMembership(userId, role.getEnName()); |
| ? | } |
| ? | } |
| ? | } |
| ? | ? |
| ? | } |
view rawAccountServiceImpl.java?hosted with ? by?GitHub
刪除操作也和這個(gè)類似!
?
不管從業(yè)務(wù)系統(tǒng)維護(hù)用戶還是從Activiti維護(hù),肯定要確定一方,然后CRUD的時(shí)候同步到對(duì)方,如果需要同步多個(gè)子系統(tǒng)那么可以再調(diào)用WebService實(shí)現(xiàn)。
2.5 流程圖設(shè)計(jì)工具用什么
Activiti提供了兩個(gè)流程設(shè)計(jì)工具,但是面向?qū)ο蟛煌?/span>
-
Activiti Modeler,面向業(yè)務(wù)人員,使用開(kāi)源的BPMN設(shè)計(jì)工具Signavio,使用BPMN描述業(yè)務(wù)流程圖
-
Eclipse Designer,面向開(kāi)發(fā)人員,Eclipse的插件,可以讓開(kāi)發(fā)人員定制每個(gè)節(jié)點(diǎn)的屬性(ID、Name、Listener、Attr等)
2.5.1 我們的方式
可能你會(huì)驚訝,因?yàn)槲覀儧](méi)有使用Activiti Modeler,我們認(rèn)為用Viso已經(jīng)能表達(dá)流程圖的意思了,而且項(xiàng)目經(jīng)理也是技術(shù)出身,和開(kāi)發(fā)人員也容易溝通。
目前這個(gè)項(xiàng)目是第一個(gè)使用Activiti的,開(kāi)始我們?cè)谛枨笳{(diào)研階段使用Viso設(shè)計(jì)流程圖,利用泳道流程圖設(shè)計(jì)和客戶溝通,確定后由負(fù)責(zé)流程的開(kāi)發(fā)人員用Eclipse Designer設(shè)計(jì)得到bpmn20.xml,最后部署。
2.6 Eclipse Designer存在的問(wèn)題
這個(gè)插件有一個(gè)很討厭的Bug一直未修復(fù),安裝了插件后Eclipse的復(fù)制和粘帖快捷鍵會(huì)被更換為(Ctrl+Insert、Shift+Insert);Bug描述請(qǐng)見(jiàn):
-
Activit Forums中報(bào)告的Bug
-
Jira的登記
所以最后我們只能單獨(dú)開(kāi)一個(gè)安裝了Eclipse Designer的Eclipse專門用來(lái)設(shè)計(jì)流程圖,這樣就不影響正常使用Eclipse JAVAEE了。
3.配置
3.1 集成Spring
對(duì)于和Spring的集成Activiti做的不錯(cuò),簡(jiǎn)單配置一些Bean代理即可實(shí)現(xiàn),但是有兩個(gè)和事務(wù)相關(guān)的地方要提示:
-
配置processEngineConfiguration的時(shí)候?qū)傩?strong>transactionManager要使用和業(yè)務(wù)功能的同一個(gè)事務(wù)管理Bean,否則事務(wù)不同步。
-
對(duì)于實(shí)現(xiàn)了org.activiti.engine.delegate包中的接口的類需要被事務(wù)控制的實(shí)現(xiàn)類需要被Spring代理,并且添加事務(wù)的Annotation或者在xml中配置,例如:
?
| 1 2 3 4 5 6 7 8 9 10 | /** ?* 創(chuàng)建繳費(fèi)流程的時(shí)候自動(dòng)創(chuàng)建實(shí)體 ?* ?* @author HenryYan ?*/ @Service @Transactional public class CreatePaymentProcessListener implements ExecutionListener { ???.... } |
4.使用單元測(cè)試
單元測(cè)試均使用Spring的AbstractTransactionalJUnit4SpringContextTests作為SuperClass,并且在測(cè)試類添加:
?
| 1 2 | @ContextConfiguration(locations = { "/applicationContext-test.xml" }) @RunWith(SpringJUnit4ClassRunner.class) |
雖然Activiti也提供了測(cè)試的一些超類,但是感覺(jué)不好用,所以自己封裝了一些方法。
代碼請(qǐng)轉(zhuǎn)移:https://gist.github.com/2182847
4.1 驗(yàn)證流程圖設(shè)計(jì)是否正確
代碼請(qǐng)轉(zhuǎn)移:https://gist.github.com/2182869
4.2 業(yè)務(wù)對(duì)象和流程關(guān)聯(lián)測(cè)試
代碼請(qǐng)轉(zhuǎn)移:https://gist.github.com/2182973
5.各種狀態(tài)的任務(wù)查詢以及和業(yè)務(wù)對(duì)象關(guān)聯(lián)
我們目前分為4中狀態(tài):未簽收、辦理中、運(yùn)行中、已完成。
查詢到任務(wù)或者流程實(shí)例后要顯示在頁(yè)面,這個(gè)時(shí)候需要添加業(yè)務(wù)數(shù)據(jù),最終結(jié)果就是業(yè)務(wù)和流程的并集,請(qǐng)參考6.2。
5.1 未簽收(Task)
此類任務(wù)針對(duì)于把Task分配給一個(gè)角色時(shí),例如部門領(lǐng)導(dǎo),因?yàn)?strong>部門領(lǐng)導(dǎo)角色可以指定多個(gè)人所以需要先簽收再辦理,術(shù)語(yǔ):搶占式
對(duì)應(yīng)的API查詢:
?
| 1 2 3 4 5 6 7 8 9 10 | /** ?* 獲取未簽收的任務(wù)查詢對(duì)象 ?* @param userId??? 用戶ID ?*/ @Transactional(readOnly = true) public TaskQuery createUnsignedTaskQuery(String userId) { ????TaskQuery taskCandidateUserQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()) ????????????.taskCandidateUser(userId); ????return taskCandidateUserQuery; } |
5.2 辦理中(Task)
此類任務(wù)數(shù)據(jù)類源有兩種:
-
簽收后的,5.1中簽收后就應(yīng)該為辦理中狀態(tài)
-
節(jié)點(diǎn)指定的是具體到一個(gè)人,而不是角色
對(duì)應(yīng)的API查詢:
?
| 1 2 3 4 5 6 7 8 9 | /** ?* 獲取正在處理的任務(wù)查詢對(duì)象 ?* @param userId??? 用戶ID ?*/ @Transactional(readOnly = true) public TaskQuery createTodoTaskQuery(String userId) { ????TaskQuery taskAssigneeQuery = taskService.createTaskQuery().processDefinitionKey(getProcessDefKey()).taskAssignee(userId); ????return taskAssigneeQuery; } |
5.3 運(yùn)行中(ProcessInstance)
說(shuō)白了就是沒(méi)有結(jié)束的流程,所有參與過(guò)的人都應(yīng)該可以看到這個(gè)實(shí)例,但是Activiti的API沒(méi)有可以通過(guò)用戶查詢的方法,這個(gè)只能自己用hack的方式處理了,我目前還沒(méi)有處理。
從表ACT_RU_EXECUTION中查詢數(shù)據(jù)。
對(duì)應(yīng)的API查詢:
?
| 1 2 3 4 5 6 7 8 9 10 | /** ?* 獲取未經(jīng)完成的流程實(shí)例查詢對(duì)象 ?* @param userId??? 用戶ID ?*/ @Transactional(readOnly = true) public ProcessInstanceQuery createUnFinishedProcessInstanceQuery(String userId) { ????ProcessInstanceQuery unfinishedQuery = runtimeService.createProcessInstanceQuery().processDefinitionKey(getProcessDefKey()) ????????????.active(); ????return unfinishedQuery; } |
5.4 已完成(HistoricProcessInstance)
已經(jīng)結(jié)束的流程實(shí)例。
從表ACT_HI_PROCINST中查詢數(shù)據(jù)。
?
| 1 2 3 4 5 6 7 8 9 10 | /** ?* 獲取已經(jīng)完成的流程實(shí)例查詢對(duì)象 ?* @param userId??? 用戶ID ?*/ @Transactional(readOnly = true) public HistoricProcessInstanceQuery createFinishedProcessInstanceQuery(String userId) { ????HistoricProcessInstanceQuery finishedQuery = historyService.createHistoricProcessInstanceQuery() ????????????.processDefinitionKey(getProcessDefKey()).finished(); ????return finishedQuery; } |
5.5 查詢時(shí)和業(yè)務(wù)關(guān)聯(lián)
提示:之前在業(yè)務(wù)對(duì)象添加了PROCESS_INSTANCE_ID字段
思路:現(xiàn)在可以利用這個(gè)字段查詢了,不管是Task還是ProcessInstance都可以得到流程實(shí)例ID,可以根據(jù)流程實(shí)例ID查詢實(shí)體然后把流程對(duì)象設(shè)置到實(shí)體的一個(gè)屬性中由Action或者Controller輸出到前臺(tái)。
代碼請(qǐng)參考:https://gist.github.com/2183557
6.UI及截圖
結(jié)合實(shí)際業(yè)務(wù)描述一個(gè)業(yè)務(wù)從開(kāi)始到結(jié)束的過(guò)程,對(duì)于迷惑的同學(xué)看完豁然開(kāi)朗了;這里使用請(qǐng)假作為例子。
6.1 單獨(dú)一個(gè)列表負(fù)責(zé)申請(qǐng)
這樣的好處是申請(qǐng)和流程辦理分離開(kāi)處理,列表顯示未啟動(dòng)流程的請(qǐng)假記錄(數(shù)據(jù)庫(kù)PROCESS_INSTANCE_ID為空)。
申請(qǐng)界面的截圖:
6.2 流程狀態(tài)
6.3 流程跟蹤
圖片方式顯示當(dāng)前節(jié)點(diǎn):
列表形式顯示流程流轉(zhuǎn)過(guò)程:
6.3.1 當(dāng)前節(jié)點(diǎn)定位JS
Java代碼請(qǐng)移步:https://gist.github.com/2183712
Javascript思路:先通過(guò)Ajax獲取當(dāng)前節(jié)點(diǎn)的坐標(biāo),在指定位置添加紅色邊框,然后加載圖片。
代碼移步:https://gist.github.com/2183804
7.開(kāi)啟Logger
8.結(jié)束
之前就想寫這篇文章,現(xiàn)在終于完成了,花費(fèi)了幾個(gè)小時(shí),希望能節(jié)省你幾天的時(shí)間。
請(qǐng)讀者仔細(xì)閱讀Activiti的用戶手冊(cè)和Javadoc。
如果有什么疑問(wèn)或者對(duì)于功能的實(shí)現(xiàn)有更好的辦法歡迎提出、分享。
9.動(dòng)態(tài)指定任務(wù)辦理人
9.1 手動(dòng)設(shè)置任務(wù)辦理人
?
| 1 | <usertask id="hrAudit" name="人事審批" activiti:assignee="${hrUserId}"></usertask> |
動(dòng)態(tài)指定任務(wù)辦理人是群里面詢問(wèn)比較多的問(wèn)題之一,其實(shí)就是一層窗戶紙,只要在任務(wù)完成的時(shí)候傳遞activiti:assignee屬性中的變量即可。
Map<String, Object> variables = new HashMap<String, Object>();
variables.put(“hrUserId”, hrUserId);
taskService.complete(taskId, variables);
9.2 自動(dòng)設(shè)置任務(wù)辦理人
下面的代碼是利用initiator功能,設(shè)置一個(gè)名稱(不是變量而是變量名)到啟動(dòng)事件上,并且在啟動(dòng)流程時(shí)調(diào)用一些下面的方法:
?
| 1 | identityService.setAuthenticatedUserId(currentUserId); |
其中currentUserId表示當(dāng)前用戶,也就是啟動(dòng)流程的人,配置如下所示:
?
| 1 2 | <startevent id="startevent1" name="Start" activiti:initiator="applyUserId"></startevent> <usertask id="reportBack" name="銷假" activiti:assignee="${applyUserId}"></usertask> |
這樣流程啟動(dòng)之后如果任務(wù)流轉(zhuǎn)至”銷假”節(jié)點(diǎn)則會(huì)自動(dòng)把任務(wù)分配給啟動(dòng)流程的人。
9.3 獲取流程發(fā)起人
如果在啟動(dòng)流程的時(shí)候調(diào)用了下面的代碼:
?
| 1 | identityService.setAuthenticatedUserId(currentUserId); |
引擎會(huì)記錄啟動(dòng)人,即在ACT_HI_PROINST表的START_USER_ID字段,可以通過(guò)下面的代碼獲取。
?
| 1 2 | HistoricProcessInstance hi = historyService.createHistoricProcessInstanceQuery().singleResult(); hi.getStartUserId(); |
10. 任務(wù)代辦
很多人問(wèn)“Owner”屬性為什么是空的,什么時(shí)候用?要了解它的作用首先要了解“代辦”。
代辦的概念可以用下面的一句話概括:
<span style="color:#333333"><span style="color:black"><code>你領(lǐng)導(dǎo)接到一個(gè)任務(wù),讓你代辦,你辦理完成后任務(wù)還是回歸到你的領(lǐng)導(dǎo),事情是你做的,功勞是你領(lǐng)導(dǎo)的,此乃代辦也! </code></span></span>看到這個(gè)單元測(cè)試你就明白什么是代辦:ProcessTestDelegateTask
最好把activiti-study這個(gè)項(xiàng)目下載下來(lái)導(dǎo)入到Eclipse中運(yùn)行一下:https://github.com/henryyan/activiti-study
原創(chuàng)文章,轉(zhuǎn)載請(qǐng)注明:轉(zhuǎn)載自:工作流引擎Activiti使用總結(jié)
?
from:?http://www.kafeitu.me/activiti/2012/03/22/workflow-activiti-action.html
總結(jié)
以上是生活随笔為你收集整理的工作流引擎Activiti使用总结的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 日期格式YYYY-mm-dd HH:MM
- 下一篇: Activiti 工作流引擎的初步使用