[Java][activiti]同步或者重构activiti identify用户数据的方法

同步或者重构Activiti Identify用户数据的多种方案比较

相信每个涉及到用户的系统都有一套用户权限管理平台或者模块,用来维护用户以及在系统内的功能、数据权限,我们使用的Activiti工作流引擎配套设计了包括User、Group的Identify模块,怎么和业务数据同步呢,这个问题是每个新人必问的问题之一,下面介绍几种同步方案,最后总结比较。

如果你在考虑直接使用Activiti引擎的Identify模块作为系统的用户数据管理模块,您真是奇才~开个玩笑

方案一:调用IdentifyService接口完成同步

参考IdentifyService接口Javadoc:http://www.activiti.org/javadocs/org/activiti/engine/IdentityService.html

接口定义:

[java]  view plain copy
  1. importjava.util.List;  
  2.    
  3. importcom.foo.arch.entity.id.User;  
  4. importcom.foo.arch.service.ServiceException;  
  5.    
  6. /** 
  7.  * 维护用户、角色、权限接口 
  8.  * 
  9.  * @author HenryYan 
  10.  * 
  11.  */  
  12. publicinterface AccountService {  
  13.    
  14.     /** 
  15.      * 添加用户并[同步其他数据库] 
  16.      * 
       
    •      * 
    • step 1: 保存系统用户,同时设置和部门的关系
    •  
    •      * 
    • step 2: 同步用户信息到activiti的identity.User,同时设置角色
    •  
    •      * 
     
  17.      * 
  18.      * @param user              用户对象 
  19.      * @param orgId             部门ID 
  20.      * @param roleIds           角色ID集合 
  21.      * @param synToActiviti     是否同步到Activiti数据库,通过配置文件方式设置,使用属性:account.user.add.syntoactiviti 
  22.      * @throws OrganizationNotFoundException    关联用户和部门的时候从数据库查询不到哦啊部门对象 
  23.      * @throws  Exception                       其他未知异常 
  24.      */  
  25.     publicvoid save(User user, Long orgId, List<long> roleIds, booleansynToActiviti)  
  26.             throws OrganizationNotFoundException, ServiceException, Exception;  
  27.        
  28.     /** 
  29.      * 删除用户 
  30.      * @param userId        用户ID 
  31.      * @param synToActiviti     是否同步到Activiti数据库,通过配置文件方式设置,使用属性:account.user.add.syntoactiviti 
  32.      * @throws Exception 
  33.      */  
  34.     publicvoid delete(Long userId, booleansynToActiviti) throwsServiceException, Exception;  
  35.    
  36.     /** 
  37.      * 同步用户、角色数据到工作流 
  38.      * @throws Exception 
  39.      */  
  40.     publicvoid synAllUserAndRoleToActiviti() throwsException;  
  41.    
  42.     /** 
  43.      * 删除工作流引擎Activiti的用户、角色以及关系 
  44.      * @throws Exception 
  45.      */  
  46.     publicvoid deleteAllActivitiIdentifyData() throwsException;  
  47. }  


同步单个接口实现片段:

[java]  view plain copy
  1. @Service  
  2. @Transactional  
  3. publicclass AccountServiceImpl implementsAccountService {   
  4.     /** 
  5.      * 保存用户信息,并且同步用户信息到activiti的identity.User和identify.Group 
  6.      * @param user              用户对象{@link User} 
  7.      * @param roleIds           用户拥有的角色ID集合 
  8.      * @param synToActiviti     是否同步数据到Activiti 
  9.      * @see Role 
  10.      */  
  11.     publicvoid saveUser(User user, List<long> roleIds, booleansynToActiviti) {  
  12.         String userId = ObjectUtils.toString(user.getId());  
  13.    
  14.         // 保存系统用户  
  15.         accountManager.saveEntity(user);  
  16.    
  17.         // 同步数据到Activiti Identify模块  
  18.         if(synToActiviti) {  
  19.             UserQuery userQuery = identityService.createUserQuery();  
  20.             List activitiUsers = userQuery.userId(userId).list();  
  21.    
  22.             if(activitiUsers.size() == 1) {  
  23.                 updateActivitiData(user, roleIds, activitiUsers.get(0));  
  24.             }elseif (activitiUsers.size() > 1) {  
  25.                 String errorMsg = "发现重复用户:id="+ userId;  
  26.                 logger.error(errorMsg);  
  27.                 thrownew RuntimeException(errorMsg);  
  28.             }else{  
  29.                 newActivitiUser(user, roleIds);  
  30.             }  
  31.         }  
  32.    
  33.     }  
  34.    
  35.     /** 
  36.      * 添加工作流用户以及角色 
  37.      * @param user      用户对象{@link User} 
  38.      * @param roleIds   用户拥有的角色ID集合 
  39.      */  
  40.     privatevoid newActivitiUser(User user, List<long> roleIds) {  
  41.         String userId = user.getId().toString();  
  42.    
  43.         // 添加用户  
  44.         saveActivitiUser(user);  
  45.    
  46.         // 添加membership  
  47.         addMembershipToIdentify(roleIds, userId);  
  48.     }  
  49.    
  50.     /** 
  51.      * 添加一个用户到Activiti {@link org.activiti.engine.identity.User} 
  52.      * @param user  用户对象, {@link User} 
  53.      */  
  54.     privatevoid saveActivitiUser(User user) {  
  55.         String userId = user.getId().toString();  
  56.         org.activiti.engine.identity.User activitiUser = identityService.newUser(userId);  
  57.         cloneAndSaveActivitiUser(user, activitiUser);  
  58.         logger.debug("add activiti user: {}", ToStringBuilder.reflectionToString(activitiUser));  
  59.     }  
  60.    
  61.     /** 
  62.      * 添加Activiti Identify的用户于组关系 
  63.      * @param roleIds   角色ID集合 
  64.      * @param userId    用户ID 
  65.      */  
  66.     privatevoid addMembershipToIdentify(List<long> roleIds, String userId) {  
  67.         for(Long roleId : roleIds) {  
  68.             Role role = roleManager.getEntity(roleId);  
  69.             logger.debug("add role to activit: {}", role);  
  70.             identityService.createMembership(userId, role.getEnName());  
  71.         }  
  72.     }  
  73.    
  74.     /** 
  75.      * 更新工作流用户以及角色 
  76.      * @param user          用户对象{@link User} 
  77.      * @param roleIds       用户拥有的角色ID集合 
  78.      * @param activitiUser  Activiti引擎的用户对象,{@link org.activiti.engine.identity.User} 
  79.      */  
  80.     privatevoid updateActivitiData(User user, List<long> roleIds, org.activiti.engine.identity.User activitiUser) {  
  81.    
  82.         String userId = user.getId().toString();  
  83.    
  84.         // 更新用户主体信息  
  85.         cloneAndSaveActivitiUser(user, activitiUser);  
  86.    
  87.         // 删除用户的membership  
  88.         List activitiGroups = identityService.createGroupQuery().groupMember(userId).list();  
  89.         for(Group group : activitiGroups) {  
  90.             logger.debug("delete group from activit: {}", ToStringBuilder.reflectionToString(group));  
  91.             identityService.deleteMembership(userId, group.getId());  
  92.         }  
  93.    
  94.         // 添加membership  
  95.         addMembershipToIdentify(roleIds, userId);  
  96.     }  
  97.    
  98.     /** 
  99.      * 使用系统用户对象属性设置到Activiti User对象中 
  100.      * @param user          系统用户对象 
  101.      * @param activitiUser  Activiti User 
  102.      */  
  103.     privatevoid cloneAndSaveActivitiUser(User user, org.activiti.engine.identity.User activitiUser) {  
  104.         activitiUser.setFirstName(user.getName());  
  105.         activitiUser.setLastName(StringUtils.EMPTY);  
  106.         activitiUser.setPassword(StringUtils.EMPTY);  
  107.         activitiUser.setEmail(user.getEmail());  
  108.         identityService.saveUser(activitiUser);  
  109.     }  
  110.    
  111.     @Override  
  112.     publicvoid delete(Long userId, booleansynToActiviti, booleansynToChecking) throwsServiceException, Exception {  
  113.         // 查询需要删除的用户对象  
  114.         User user = accountManager.getEntity(userId);  
  115.         if(user == null) {  
  116.             thrownew ServiceException("删除用户时,找不到ID为"+ userId + "的用户");  
  117.         }  
  118.    
  119.         /** 
  120.          * 同步删除Activiti User Group 
  121.          */  
  122.         if(synToActiviti) {  
  123.             // 同步删除Activiti User  
  124.             List roleList = user.getRoleList();  
  125.             for(Role role : roleList) {  
  126.                 identityService.deleteMembership(userId.toString(), role.getEnName());  
  127.             }  
  128.    
  129.             // 同步删除Activiti User  
  130.             identityService.deleteUser(userId.toString());  
  131.         }  
  132.    
  133.         // 删除本系统用户  
  134.         accountManager.deleteUser(userId);  
  135.    
  136.         // 删除考勤机用户  
  137.         if(synToChecking) {  
  138.             checkingAccountManager.deleteEntity(userId);  
  139.         }  
  140.     }  
  141. }  

同步全部数据接口实现片段:

同步全部数据步骤:

  • 删除Activiti的User、Group、Membership数据

  • 复制Role对象数据到Group

  • 复制用户数据以及Membership数据

ActivitiIdentifyCommonDao.java
[java]  view plain copy
  1. publicclass ActivitiIdentifyCommonDao {  
  2.    
  3.     protectedLogger logger = LoggerFactory.getLogger(getClass());  
  4.        
  5.     @Autowired  
  6.     privateJdbcTemplate jdbcTemplate;  
  7.    
  8.     /** 
  9.      * 删除用户和组的关系 
  10.      */  
  11.     publicvoid deleteAllUser() {  
  12.         String sql = "delete from ACT_ID_USER";  
  13.         jdbcTemplate.execute(sql);  
  14.         logger.debug("deleted from activiti user.");  
  15.     }  
  16.    
  17.     /** 
  18.      * 删除用户和组的关系 
  19.      */  
  20.     publicvoid deleteAllRole() {  
  21.         String sql = "delete from ACT_ID_GROUP";  
  22.         jdbcTemplate.execute(sql);  
  23.         logger.debug("deleted from activiti group.");  
  24.     }  
  25.    
  26.     /** 
  27.      * 删除用户和组的关系 
  28.      */  
  29.     publicvoid deleteAllMemerShip() {  
  30.         String sql = "delete from ACT_ID_MEMBERSHIP";  
  31.         jdbcTemplate.execute(sql);  
  32.         logger.debug("deleted from activiti membership.");  
  33.     }  
  34.    
  35. }  


ActivitiIdentifyService.java
[java]  view plain copy
  1. publicclass ActivitiIdentifyService extendsAbstractBaseService {  
  2.        
  3.     @Autowired  
  4.     protectedActivitiIdentifyCommonDao activitiIdentifyCommonDao;  
  5.        
  6.     /** 
  7.      * 删除用户和组的关系 
  8.      */  
  9.     publicvoid deleteAllUser() {  
  10.         activitiIdentifyCommonDao.deleteAllUser();  
  11.     }  
  12.        
  13.     /** 
  14.      * 删除用户和组的关系 
  15.      */  
  16.     publicvoid deleteAllRole() {  
  17.         activitiIdentifyCommonDao.deleteAllRole();  
  18.     }  
  19.        
  20.     /** 
  21.      * 删除用户和组的关系 
  22.      */  
  23.     publicvoid deleteAllMemerShip() {  
  24.         activitiIdentifyCommonDao.deleteAllMemerShip();  
  25.     }  
  26. }  


AccountServiceImpl.java
[java]  view plain copy
  1. publicclass AccountServiceImpl implementsAccountService {  
  2. @Override  
  3.     publicvoid synAllUserAndRoleToActiviti() throwsException {  
  4.    
  5.         // 清空工作流用户、角色以及关系  
  6.         deleteAllActivitiIdentifyData();  
  7.    
  8.         // 复制角色数据  
  9.         synRoleToActiviti();  
  10.    
  11.         // 复制用户以及关系数据  
  12.         synUserWithRoleToActiviti();  
  13.     }  
  14.    
  15.     /** 
  16.      * 复制用户以及关系数据 
  17.      */  
  18.     privatevoid synUserWithRoleToActiviti() {  
  19.         List allUser = accountManager.getAll();  
  20.         for(User user : allUser) {  
  21.             String userId = user.getId().toString();  
  22.    
  23.             // 添加一个用户到Activiti  
  24.             saveActivitiUser(user);  
  25.    
  26.             // 角色和用户的关系  
  27.             List roleList = user.getRoleList();  
  28.             for(Role role : roleList) {  
  29.                 identityService.createMembership(userId, role.getEnName());  
  30.                 logger.debug("add membership {user: {}, role: {}}", userId, role.getEnName());  
  31.             }  
  32.         }  
  33.     }  
  34.    
  35.     /** 
  36.      * 同步所有角色数据到{@link Group} 
  37.      */  
  38.     privatevoid synRoleToActiviti() {  
  39.         List allRole = roleManager.getAll();  
  40.         for(Role role : allRole) {  
  41.             String groupId = role.getEnName().toString();  
  42.             Group group = identityService.newGroup(groupId);  
  43.             group.setName(role.getName());  
  44.             group.setType(role.getType());  
  45.             identityService.saveGroup(group);  
  46.         }  
  47.     }  
  48.    
  49.     @Override  
  50.     publicvoid deleteAllActivitiIdentifyData() throwsException {  
  51.         activitiIdentifyService.deleteAllMemerShip();  
  52.         activitiIdentifyService.deleteAllRole();  
  53.         activitiIdentifyService.deleteAllUser();  
  54.     }  
  55. }  


方案二:覆盖IdentifyService接口的实现

此方法覆盖IdentifyService接口的默认实现类:org.activiti.engine.impl.IdentityServiceImpl

读者可以根据现有的用户管理接口实现覆盖IdentityServiceImpl的每个方法的默认实现,这样就等于放弃使用系列表:ACT_ID_。

此方法不再提供代码,请读者自行根据现有接口逐一实现接口定义的功能。

方案三:用视图覆盖同名的ACT_ID_系列表

此方案和第二种类似,放弃使用系列表:ACT_ID_,创建同名的视图。

1.删除已创建的ACT_ID_*表

创建视图必须删除引擎自动创建的ACT_ID_*表,否则不能创建视图。

2.创建视图:

  • ACT_ID_GROUP
  • ACT_ID_INFO
  • ACT_ID_MEMBERSHIP
  • ACT_ID_USER

创建的视图要保证数据类型一致,例如用户的ACT_ID_MEMBERSHIP表的两个字段都是字符型,一般系统中都是用NUMBER作为用户、角色的主键类型,所以创建视图的时候要把数字类型转换为字符型。

3.修改引擎默认配置

在引擎配置中设置属性dbIdentityUsedfalse即可。

[html]  view plain copy
  1. <beanidbeanid="processEngineConfiguration"class="org.activiti.spring.SpringProcessEngineConfiguration">  
  2.     ...  
  3.     <propertynamepropertyname="dbIdentityUsed"ref="false">  
  4.     ...  
  5. property>bean>  

总结
  • 方案:不破坏、不修改源码,面向接口编程推荐

  • 方案:放弃原有的Identify模块,使用自定义的实现,特殊情况可以使用此方式;

  • 方案:不需要编写Java代码,只需要创建同名视图即可对于现有系统的集成、强烈推荐

你可能感兴趣的:(Java)