简述
Activiti工作流引擎本身配套了包括User、Group的Identify模块,但是实际上公司内部各个部门关系、领导下级等关系都很复杂,Activiti自身的id模块就显得有些弱了。
有关自定义Activiti用户群组表的具体方式有三种,本文只详细介绍第二种:
-
方案一:通过数据推送方式同步数据到引擎的身份表,需要把数据备份到引擎的身份表或者公司有平台或者WebService推送用户数据的推荐使用
-
方案二:自定义SessionFactory,非侵入式替换接口实现,对于公司内部有统一身份访问接口的推荐使用
-
方案三:不需要编写Java代码,只需要创建同名视图即可
为何自定义SessionFactory
引擎内部与数据库交互使用的是MyBatis,Activiti的每一张表都有一个对应的XxxEntityManager(实体管理类,有接口和实现类)和XxxEntityManagerFactory(实体管理工厂类)。
引擎的7个Service接口在需要CRUD实体时会根据接口获取注册的实体管理器实现类(初始化引擎时引擎会使用Map对象维护两者的映射关系),而引擎允许我们自己注册实体管理器实现类,查看源码后可以知道有关Identity操作的两个接口分别为:UserIdentityManager和GroupIdentityManager。
例如下图:
User和Group同理,这里以User实体管理类举例,其继承的AbstractManager实现了Session。
如何注册自定义的实体管理器实现类
查看引擎配置对象ProcessEngineConfigurationImpl类可以找到一个名称为“customSessionFactories”的属性,该属性可以用来自定义SessionFactory(从上文可以看到每一个XxxEntityManager都是一个Session<实现了Session接口>,并由SessionFactory来管理)
为了能替代内部的实体管理器实现类,我们可以自定义一个SessionFactory并注册到引擎。
这种自定义SessionFactory的方式适用于公司内部有独立的身份系统或者公共的身份模块的情况,所有和用户、角色、权限的服务均通过一个统一的接口获取,而业务系统则不保存这些数据,此时引擎不会再使用原本的身份模块表(ACT_ID_*)。
具体实例
配置文件:
<bean id="processEngineConfiguration" class="org.activiti.spring.SpringProcessEngineConfiguration">
...
...
<!-- 自定义用户、用户组的配置 -->
<property name="customSessionFactories">
<list>
<bean class="xxx.xxx.xxx.xxx.CustomUserEntityManagerFactory">
<property name="customUserEntityManager">
<bean class="xxx.xxx.xxx.xxx.CustomUserEntityManager">
<property name="CustomUserManager">
<bean class="xxx.xxx.xxx.xxx.CustomUserManager"/>
</property>
</bean>
</property>
</bean>
<bean class="xxx.xxx.xxx.xxx.CustomGroupEntityManagerFactory">
<property name="customGroupEntityManager">
<bean class="xxx.xxx.xxx.xxx.CustomGroupEntityManager">
<property name="customGroupManager">
<bean class="xxx.xxx.xxx.xxx.CustomGroupManager"/>
</property>
</bean>
</property>
</bean>
</list>
</property>
</bean>
以自定义User为例
一、需要自定义对应的SessionFactory,这里是你能否成功注册自定义管理类的关键,getSessionType()是返回给引擎XxxEntityManager的接口(前文有说),而后通过openSession()返回给引擎你自定义的CustomXxxEntityManager。
public class CustomUserEntityManagerFactory implements SessionFactory {
private CustomUserEntityManager customUserEntityManager;
public void setCustomUserEntityManager(CustomUserEntityManager customUserEntityManager) {
this.customUserEntityManager = customUserEntityManager;
}
@Override
public Class<?> getSessionType() {
// 返回原始的UserManager类型
return UserIdentityManager.class;
}
@Override
public Session openSession() {
// 返回自定义的UserManager实例
return customUserEntityManager;
}
}
二、需要完成自定义的CustomXxxEntityManager类,这里我只覆盖了两种方法,其中CustomUserManager类与引擎无关,你可以在里面注入dao层接口(dao层接口和实现类,与CustomUserManager类分开可以方便日后维护)
public class CustomUserEntityManager extends UserEntityManager {
private CustomUserManager customUserManager;
public void setCustomUserManager(CustomUserManager customUserManager) {
this.customUserManager = customUserManager;
}
@Override
public BpmUser findUserById(String userId) {
return customUserManager.findUserById(userId);
}
@Override
public List<Group> findGroupsByUser(String userId) {
return customUserManager.findGroupsByUser(userId);
}
}
三、使用,因为我们已经成功注册即覆盖了引擎自带的管理类,所以直接使用service中的方法即可
Boolean judge = processEngine.getIdentityService()
.checkPassword(bpmUser.getUserId(),bpmUser.getUserPasswd());
注意
此种方法不是随心所欲的。首先,因为是引擎启动后我们自定义的管理类才被注册进去,而service中的方法是引擎启动前源码就定义好的,所以你只能重写引擎管理类中已有的那几个方法。
其次,重写主要的限制在于返回值,譬如上文我重写了两个方法,我自定义的BpmUser必须要继承引擎自带的User。另一个方法的返回值List<Group>更麻烦,我的BpmGroup不仅仅需要继承Group,更需要在装填List时“偷梁换柱”,如下,如果你直接返回bpmGroupList是一定会报错的!
public List<Group> findGroupsByUser(String userId) {
List<BpmGroup> bpmGroupList=customUserDao.findGroupsByUser(userId);
List<Group> groupList = new ArrayList<>();
for (BpmGroup bpmGroup:bpmGroupList){
groupList.add(bpmGroup);
}
return groupList;
}
如有问题
欢迎留言,欢迎联系我,互相学习, QQ:1144901177
希望转载的时候可以贴上本文地址,感谢!