一、前言
近期做了一個簡單的財務管理系統,在工作審批模塊中運用了工作流引擎。在對比了JBPM與Activiti後,毅然而然決定使用Activiti。本文對Activiti不做過多的介紹,重點在於分析其自身的用戶管理模塊。剛接觸,也只是闡述下自己的個人項目經驗。若有不足之處,還望指正。
二、Activiti的用戶管理
數據庫表:
act_id_user表:
act_id_group表:
act_id_membership表:
從圖中可以看出,activiti的用戶模塊只有用戶與組爲多對多的關係,僅此而已。
那麼現實中呢?我們往往是有分層級關係的。例如小組-->部門-->中心,一層一層的所屬關係,這該怎麼破?本身我們利用工作流的話,一般都是作爲中間件或服務來用。而自己的業務系統已經有一套用戶管理模塊了,又該如何去整合在一起呢?這些無疑是對於我們幹接觸的新手來說最爲困惱的方面。
接下來我就,以自身所做項目去分析下我是如何處理這些問題的。首先,先介紹下我的項目架構:
1、公司內部有自己的一套管理系統,所有內部系統的用戶模塊都由其進行管理。
2、工作流引擎將在今後作爲一個服務系統,所以運用其REST接口等可以單獨獨立出來成爲一個系統。
3、所以將涉及到業務系統、用戶管理系統、工作流引擎三者間的交互。
So……我在此次的項目中摒棄了Activiti的用戶管理模塊,重新自定義後與Uap系統整合起來。該如何自定義activiti的用戶管理模塊呢?不急,我會慢慢道來。先給大家介紹篇‘咖啡兔’大神(接觸過activiti的夥伴都懂得他是誰)的文章:《同步或者重構Activiti Identify用戶數據的多種方案比較》
文章中介紹三種方式:
1、調用IdentifyService接口完成同步。
2、自定義SessionFactory,重寫其關於用戶與組的增刪改查操作。
3、用視圖覆蓋同名的ACT_ID_系列表。
三種方式各有優劣,而我則用了第二種方式,對其進行重構。
三、如何重構Activiti用戶管理模塊增刪改查
對不同的表的CRUD操作均由一個對應的實體管理器(XxxEntityManager,有接口和實現類),引擎的7個Service接口在需要CRUD實體時會根據接口獲取註冊的實體管理器實現類(初始化引擎時用Map對象維護兩者的映射關係),並且引擎允許我們覆蓋內部的實體管理器,查看源碼後可以知道有關Identity操作的兩個接口分別爲:UserIdentityManager和GroupIdentityManager。
查看引擎配置對象ProcessEngineConfigurationImpl類可以找到一個名稱爲“customSessionFactories”的屬性,該屬性可以用來自定義SessionFactory(每一個XXxManager類都是一個Session<實現Session接口>,由SessionFactory來管理),爲了能替代內部的實體管理器的實現我們可以自定義一個SessionFactory並註冊到引擎。
這種自定義SessionFactory的方式適用於公司內部有獨立的身份系統或者公共的身份模塊的情況,所有和用戶、角色、權限的服務均通過一個統一的接口獲取,而業務系統則不保存這些數據,此時引擎的身份模塊表就沒必要存在(ACT_ID_*)。所以,我重寫了其增刪改查等方法後,就摒棄了Activiti的用戶表,讓其與公司的uap管理系統相關聯。
1、項目activiti項目使用的是spring mvc框架,所以先看配置:
<!-- Activiti begin --> <bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration"> ……………… <!-- 自定義用戶管理 --> <property name="customSessionFactories"> <list> <bean class="me.kafeitu.demo.activiti.service.activiti.custom.CustomUserEntityManagerFactory" /> <bean class="me.kafeitu.demo.activiti.service.activiti.custom.CustomGroupEntityManagerFactory" /> </list> </property> ……………… </beans>
自定義了:CustomUserEntityManagerFactory與CustomGroupEntityManagerFactory兩個類,並注入spring管理容器中。
2、自定義類代碼:
/** * 自定義的Activiti用戶會話工廠 * @author linhy * */ @Service public class CustomUserEntityManagerFactory implements SessionFactory { @Resource private CustomUserManager customUserManager; @Override public Class<?> getSessionType() { // 返回原始的UserManager類型 return UserIdentityManager.class; } @Override public Session openSession() { // 返回自定義的UserManager實例 return customUserManager; } }
注意點:(1)實現SessionFactory接口;(2)返回原始類型與返回自定義實例,如上註釋代碼;
/** * 自定義用戶管理器 * @author linhy * */ @Service("customUserManager") public class CustomUserManager extends UserEntityManager { private Logger logger = LoggerFactory.getLogger(getClass()); @Override public User findUserById(String userId) { User user = new UserEntity(); //引入Uap系統客戶端包,關聯進行查詢 BaseDto baseDto = RoomyUapUserUtils.getUser(userId); if (baseDto.getRemoteStatus() == RemoteStatus.SUCCESS) { UserDto userDto = (UserDto) baseDto; user.setId(userDto.getUserName()); user.setFirstName(userDto.getName()); user.setLastName(userDto.getName()); } else { user = null; logger.info("用戶名:" + userId + ";無法獲取用戶信息"); } return user; } @Override public List<Group> findGroupsByUser(String userId) { //…… return list; } @Override public Boolean checkPassword(String userId, String password) { //…… return Boolean.valueOf(true); } @Override public List<User> findUserByQueryCriteria(UserQueryImpl query, Page page) { //…… return list; } @Override public long findUserCountByQueryCriteria(UserQueryImpl query) { //…… } }
注意點:繼承UserEntityManager,進入去看其源碼,你就會恍然大悟。
重寫自己需要用到的方法,與自己的用戶管理系統相關聯。組的自定義方式也一樣,這裏省略。這樣,當Activiti要查詢用戶的時候,就通過uap客戶端去查詢公司自己的用戶管理系統。這就把已有的用戶管理模塊與Activiti整合在了一起,相對於調用內部接口同步用戶數據,我覺得自定義重寫過更適合目前的項目需求。
四、結語
本文只介紹瞭如何實現自定義用戶管理,但針對文章一開頭所提出的上下級層級關係卻未作出解答,將在下一篇文章向大家介紹。本文若有不足之處,敬請指正。