1.概述
我們知道,activiti是一個不錯的流程引擎,它有自身的人員組織架構,但僅限於用戶、用戶組的管理,流程產生的任務(UserTask),就涉及到任務的所屬人(Owner),任務的執行人(assignee),還有任務的候選人、候選用戶等。而在中國的流程業務需求裏,僅靠這塊的人員查找是沒有辦法滿足目前的業務需求的。舉個請假流程的例子,其流程如下所示:
【說明】:其中上級主管、及所在部門的領導都跟發起人所有的組織架構有關,這種查找算法可以理解爲彙報線的查找處理。另外在國內的流程處理方案中,還存在一些如其他業務的人員查找算法。因此,我們一般都是需要使用我們的業務的組織架構來實現流程的處理。
2.讓Activiti引擎掛接自身的組織架構
要實現流程中的與組織架構有關的整合,我們需要先了解一下目前在哪些業務需求上使用了組織架構的需求,在我們以往的大量實施國內的業務流程的基礎上,我們總結有以下幾點:
任務的執行人員的分配
任務的代理
任務的通知
流程啓動的權限
而Activiti在流程引擎與組織架構的整合過程中,只有第一項跟組織架構是有關的,其他的方面只需要通過我們自身的擴展表來實現即可。
2.1 任務的處理人分配
2.1.1. activiti中對與人員的組織掛接的默認處理
在Activiti中,跟組織架有關的只有以下幾個表,我們把它的表結構展示如下:
CREATE TABLE `act_ru_task` ( `ID_` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '', `REV_` int(11) DEFAULT NULL, `EXECUTION_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `NAME_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `PARENT_TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `DESCRIPTION_` varchar(4000) COLLATE utf8_bin DEFAULT NULL, `TASK_DEF_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `OWNER_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `ASSIGNEE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `DELEGATION_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `PRIORITY_` int(11) DEFAULT NULL, `CREATE_TIME_` timestamp(3) NOT NULL DEFAULT CURRENT_TIMESTAMP(3) ON UPDATE CURRENT_TIMESTAMP(3), `DUE_DATE_` datetime(3) DEFAULT NULL, `CATEGORY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `SUSPENSION_STATE_` int(11) DEFAULT NULL, `TENANT_ID_` varchar(255) COLLATE utf8_bin DEFAULT '', `FORM_KEY_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `CREATE_BY_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '創建人ID', `UPDATE_BY_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '更新人ID', `UPDATE_TIME_` datetime DEFAULT NULL COMMENT '更新時間', `SOL_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '業務解決方案ID', `AGENT_USER_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL COMMENT '代理人ID', PRIMARY KEY (`ID_`), KEY `ACT_IDX_TASK_CREATE` (`CREATE_TIME_`), KEY `ACT_FK_TASK_EXE` (`EXECUTION_ID_`), KEY `ACT_FK_TASK_PROCINST` (`PROC_INST_ID_`), KEY `ACT_FK_TASK_PROCDEF` (`PROC_DEF_ID_`), CONSTRAINT `ACT_FK_TASK_EXE` FOREIGN KEY (`EXECUTION_ID_`) REFERENCES `act_ru_execution` (`ID_`), CONSTRAINT `ACT_FK_TASK_PROCDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`), CONSTRAINT `ACT_FK_TASK_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;CREATE TABLE `act_ru_identitylink` ( `ID_` varchar(64) COLLATE utf8_bin NOT NULL DEFAULT '', `REV_` int(11) DEFAULT NULL, `GROUP_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `TYPE_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `USER_ID_` varchar(255) COLLATE utf8_bin DEFAULT NULL, `TASK_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `PROC_INST_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, `PROC_DEF_ID_` varchar(64) COLLATE utf8_bin DEFAULT NULL, PRIMARY KEY (`ID_`), KEY `ACT_IDX_IDENT_LNK_USER` (`USER_ID_`), KEY `ACT_IDX_IDENT_LNK_GROUP` (`GROUP_ID_`), KEY `ACT_IDX_ATHRZ_PROCEDEF` (`PROC_DEF_ID_`), KEY `ACT_FK_TSKASS_TASK` (`TASK_ID_`), KEY `ACT_FK_IDL_PROCINST` (`PROC_INST_ID_`), CONSTRAINT `ACT_FK_ATHRZ_PROCEDEF` FOREIGN KEY (`PROC_DEF_ID_`) REFERENCES `act_re_procdef` (`ID_`), CONSTRAINT `ACT_FK_IDL_PROCINST` FOREIGN KEY (`PROC_INST_ID_`) REFERENCES `act_ru_execution` (`ID_`), CONSTRAINT `ACT_FK_TSKASS_TASK` FOREIGN KEY (`TASK_ID_`) REFERENCES `act_ru_task` (`ID_`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
【說明】其中act_ru_task中的owner,assignee爲任務的所屬人與執行人,而act_ru_identitylink爲任務的人員關聯表,裏面的字段,groupId爲用戶組Id,userId爲用戶Id,taskId爲關聯的任務Id,type爲用戶參與任務的類型。
若我們爲了更加簡化人員對任務的參與算法,可以不需要act_ru_identitylink表,進而擴展自己的參與表,不過這個表從目前來說是可以滿足我們對任務的人員計算需求的。
2.1.2.任務的人員授予
如何通過activiti原生的api來實現人員的授予?首先我們來說授予的時機,activiti的任務產生是在流程的狀態跳至某個任務節點時,其會產生一條記錄至act_ru_task表中,這時我們需要在其產生的時候,通過流程定義的人員配置屬性,結合自身的組織架構及業務查找(如彙報線)計算出參與該任務的人與組,從而把任務分配給這些用戶。另外是任務手工進行分配授權。
我們來說第一種,任務產生時進行人員授權
activiti提供了任務的創建事件,所以我們可以在它的這個事件上定義一個監聽即可,如何配置這個監聽,請參考我們另一個文章
關於activiti的全局事件定義,我們只需要定義以下任務創建監聽器(TaskCreateListener),並且獲得任務的實體對象TaskEntity,通過setAssignee及setOwner改變任務的執行人、任務的所屬人即可。
taskEntity.setAssignee(nodePath.getAssignee());taskEntity.setOwner(userId);taskEntity.addCandidateUsers(Arrays.asList(uIds));taskEntity.addCandidateGroup(identityInfo.getIdentityInfoId());
現在來說另一種:任務產生時進行任務手工分配
這種方式就需要通過taskService以下api實現即可
2.2.擴展自身的人員查找架構
流程的節點的人員配置很難提供一組通用的配置規則以實現用戶的查找,因爲,我們只爲節點的人員查找設置config的屬性配置,開發用戶則根據這些配置實現對應的定義分類,並且實現自己的流程查找方式。
流程的配置方式如下所示:
我們提供一個總的人員計算分類,以使得我們在流程節點的人員配置中可以顯示如下的人員配置分類列表:
package com.redxun.bpm.core.identity.service;import java.util.ArrayList;import java.util.LinkedHashMap;import java.util.List;import java.util.Map;import org.springframework.beans.factory.InitializingBean;/** * 實體類型分類服務類 * @author csx * */public class IdentityTypeService implements InitializingBean{ //流程任務人員計算服務類映射 private Map<String, IdentityCalService> identityCalServicesMap=new LinkedHashMap<String, IdentityCalService>(); //程任務人員計算服務類 private List<IdentityCalService> identityCalServices=new ArrayList<IdentityCalService>(); @Override public void afterPropertiesSet() throws Exception { for(IdentityCalService service:identityCalServices){ identityCalServicesMap.put(service.getTypeKey(), service); } } public List<IdentityCalService> getIdentityCalServices() { return identityCalServices; } public void setIdentityCalServices(List<IdentityCalService> identityCalServices) { this.identityCalServices = identityCalServices; } public Map<String, IdentityCalService> getIdentityCalServicesMap() { return identityCalServicesMap; } } 同時以根據流程的節點配置,實現用戶的信息計算,以獲得人員配置的信息,由用戶根據這個人員的配置實現人員的查找,其接口的定義如下:import java.util.Collection;import com.redxun.org.api.model.IdentityInfo;/** * 任務人員計算服務接口類 * @author mansan * */public interface IdentityCalService { //人員計算類型 public String getTypeKey(); //人員計算名稱 public String getTypeName(); //人員計算描述 public String getDescp(); /** * 計算節點返回的人員實體 * @param idCalConfig * @return */ public Collection<IdentityInfo> calIdentities(IdentityCalConfig idCalConfig); } 其中用戶組的配置及人員查找如下所示:package com.redxun.bpm.core.identity.service;/** * 抽象的實體計算服務類 * @author csx * */public abstract class AbstractIdentityCalService implements IdentityCalService { //分類Key protected String typeKey; //分類名稱 protected String typeName; //分類描述 protected String description; //處理的類名 protected String handlerClass; public String getTypeKey() { return typeKey; } public void setTypeKey(String typeKey) { this.typeKey = typeKey; } public String getTypeName() { return typeName; } public void setTypeName(String typeName) { this.typeName = typeName; } public String getDescription() { return description; } public void setDescription(String description) { this.description = description; } @Override public String getDescp() { return this.description; } }
package com.redxun.bpm.core.identity.service.impl;import java.util.ArrayList;import java.util.Collection;import java.util.List;import javax.annotation.Resource;import org.apache.commons.lang3.StringUtils;import com.redxun.bpm.core.identity.service.AbstractIdentityCalService;import com.redxun.bpm.core.identity.service.IdentityCalConfig;import com.redxun.core.constants.MBoolean;import com.redxun.org.api.model.IdentityInfo;import com.redxun.saweb.context.ContextUtil;import com.redxun.sys.org.entity.OsGroup;import com.redxun.sys.org.entity.OsRelType;import com.redxun.sys.org.entity.OsUser;import com.redxun.sys.org.manager.OsGroupManager;import com.redxun.sys.org.manager.OsRelTypeManager;import com.redxun.sys.org.manager.OsUserManager;/** * 用戶組計算 * @author mansan * */public class GroupCalServiceImpl extends AbstractIdentityCalService{ @Resource private OsGroupManager osGroupManager; @Resource private OsRelTypeManager osRelTypeManager; @Resource private OsUserManager osUserManager; @Override public Collection<IdentityInfo> calIdentities(IdentityCalConfig idCalConfig) { OsRelType osRelType=osRelTypeManager.getBelongRelType(); //是否需要計算用戶 boolean isCalUsers=MBoolean.YES.name().equals(idCalConfig.getIsCalUser()); List<IdentityInfo> identityList=new ArrayList<IdentityInfo>(); //獲得流程的節點配置信息,並且根據節點獲得用戶或組 String jsonConfig=idCalConfig.getJsonConfig(); if(StringUtils.isNotEmpty(jsonConfig)){ String[] groupIds=jsonConfig.split("[,]"); for(String gId:groupIds){ if(isCalUsers){//計算用戶 List<OsUser> users=osUserManager.getByGroupIdRelTypeId(gId, osRelType.getId()); identityList.addAll(users); }else{//僅計算其用戶組 OsGroup osGroup=osGroupManager.get(gId); if(osGroup!=null){ identityList.add(osGroup); } } } } return identityList; } }
2.3.自定義查找我的待辦
雖然TaskService有提供按人員的查找任務API,但從我的個人來看,那些是不能滿足我們的查找算法的,因此,很有必要自定義查找我的任務列表。查找無非是按Activiti的act_ru_task表來查,若結合了用戶對應的用戶組,還需要結合act_ru_identitylink來查找。這塊看你的底層的數據庫訪問的採用是什麼ORM框架,在JSAAS中,我們的界面如下,提供按時間、事項名稱、狀態等來查找我的待辦列表,並且分頁返回,其界面如下:
其查找的自定義Sql如下所示:
<!-- 按用戶及條件查找待辦列表 --> <select id="getByUserIdRelTypeId" parameterType="java.util.Map" resultMap="BpmTask"> SELECT V.* FROM( SELECT T.* FROM ACT_RU_TASK T WHERE T.ASSIGNEE_=#{userId} UNION SELECT T.* FROM ACT_RU_TASK T LEFT JOIN ACT_RU_IDENTITYLINK I ON T.ID_=I.TASK_ID_ WHERE I.USER_ID_=#{userId} AND I.TYPE_='candidate' AND T.ASSIGNEE_ IS NULL UNION SELECT T.* FROM ACT_RU_TASK T,ACT_RU_IDENTITYLINK I,OS_REL_INST R WHERE T.ASSIGNEE_ IS NULL AND T.ID_=I.TASK_ID_ AND I.GROUP_ID_=R.PARTY1_ and R.PARTY2_=#{userId} and I.TYPE_='candidate' AND R.REL_TYPE_ID_=#{relTypeId} ) V WHERE 1=1 <if test="name!=null"> and NAME_ like #{name} </if> <if test="description!=null"> and DESCRIPTION_ like #{description} </if> <if test="createtime1"> and CREATE_TIME_ >= #{createtime1} </if> <if test="createtime2"> and CREATE_TIME_ <= #{createtime2} </if> <if test="orderByClause!=null"> ORDER BY ${orderByClause} </if> </select>
開源社區試用DEMO,以及資料,請聯繫QQ:1361783075