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

标签: java activiti 同步 | 发表时间:2014-05-13 01:31 | 作者:szwangdf
出处:http://blog.csdn.net

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

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

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

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

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

接口定义:

importjava.util.List;
 
importcom.foo.arch.entity.id.User;
importcom.foo.arch.service.ServiceException;
 
/**
 * 维护用户、角色、权限接口
 *
 * @author HenryYan
 *
 */
publicinterface AccountService {
 
    /**
     * 添加用户并[同步其他数据库]
     * <ul>
     * <li>step 1: 保存系统用户,同时设置和部门的关系</li>
     * <li>step 2: 同步用户信息到activiti的identity.User,同时设置角色</li>
     * </ul>
     *
     * @param user              用户对象
     * @param orgId             部门ID
     * @param roleIds           角色ID集合
     * @param synToActiviti     是否同步到Activiti数据库,通过配置文件方式设置,使用属性:account.user.add.syntoactiviti
     * @throws OrganizationNotFoundException    关联用户和部门的时候从数据库查询不到哦啊部门对象
     * @throws  Exception                       其他未知异常
     */
    publicvoid save(User user, Long orgId, List<long> roleIds, booleansynToActiviti)
            throws OrganizationNotFoundException, ServiceException, Exception;
     
    /**
     * 删除用户
     * @param userId        用户ID
     * @param synToActiviti     是否同步到Activiti数据库,通过配置文件方式设置,使用属性:account.user.add.syntoactiviti
     * @throws Exception
     */
    publicvoid delete(Long userId, booleansynToActiviti) throwsServiceException, Exception;
 
    /**
     * 同步用户、角色数据到工作流
     * @throws Exception
     */
    publicvoid synAllUserAndRoleToActiviti() throwsException;
 
    /**
     * 删除工作流引擎Activiti的用户、角色以及关系
     * @throws Exception
     */
    publicvoid deleteAllActivitiIdentifyData() throwsException;
}


同步单个接口实现片段:

@Service
@Transactional
publicclass AccountServiceImpl implementsAccountService { 
    /**
     * 保存用户信息,并且同步用户信息到activiti的identity.User和identify.Group
     * @param user              用户对象{@link User}
     * @param roleIds           用户拥有的角色ID集合
     * @param synToActiviti     是否同步数据到Activiti
     * @see Role
     */
    publicvoid saveUser(User user, List<long> roleIds, booleansynToActiviti) {
        String userId = ObjectUtils.toString(user.getId());
 
        // 保存系统用户
        accountManager.saveEntity(user);
 
        // 同步数据到Activiti Identify模块
        if(synToActiviti) {
            UserQuery userQuery = identityService.createUserQuery();
            List<org.activiti.engine.identity.user> activitiUsers = userQuery.userId(userId).list();
 
            if(activitiUsers.size() == 1) {
                updateActivitiData(user, roleIds, activitiUsers.get(0));
            }elseif (activitiUsers.size() > 1) {
                String errorMsg = "发现重复用户:id="+ userId;
                logger.error(errorMsg);
                thrownew RuntimeException(errorMsg);
            }else{
                newActivitiUser(user, roleIds);
            }
        }
 
    }
 
    /**
     * 添加工作流用户以及角色
     * @param user      用户对象{@link User}
     * @param roleIds   用户拥有的角色ID集合
     */
    privatevoid newActivitiUser(User user, List<long> roleIds) {
        String userId = user.getId().toString();
 
        // 添加用户
        saveActivitiUser(user);
 
        // 添加membership
        addMembershipToIdentify(roleIds, userId);
    }
 
    /**
     * 添加一个用户到Activiti {@link org.activiti.engine.identity.User}
     * @param user  用户对象, {@link User}
     */
    privatevoid saveActivitiUser(User user) {
        String userId = user.getId().toString();
        org.activiti.engine.identity.User activitiUser = identityService.newUser(userId);
        cloneAndSaveActivitiUser(user, activitiUser);
        logger.debug("add activiti user: {}", ToStringBuilder.reflectionToString(activitiUser));
    }
 
    /**
     * 添加Activiti Identify的用户于组关系
     * @param roleIds   角色ID集合
     * @param userId    用户ID
     */
    privatevoid addMembershipToIdentify(List<long> roleIds, String userId) {
        for(Long roleId : roleIds) {
            Role role = roleManager.getEntity(roleId);
            logger.debug("add role to activit: {}", role);
            identityService.createMembership(userId, role.getEnName());
        }
    }
 
    /**
     * 更新工作流用户以及角色
     * @param user          用户对象{@link User}
     * @param roleIds       用户拥有的角色ID集合
     * @param activitiUser  Activiti引擎的用户对象,{@link org.activiti.engine.identity.User}
     */
    privatevoid updateActivitiData(User user, List<long> roleIds, org.activiti.engine.identity.User activitiUser) {
 
        String userId = user.getId().toString();
 
        // 更新用户主体信息
        cloneAndSaveActivitiUser(user, activitiUser);
 
        // 删除用户的membership
        List<group> activitiGroups = identityService.createGroupQuery().groupMember(userId).list();
        for(Group group : activitiGroups) {
            logger.debug("delete group from activit: {}", ToStringBuilder.reflectionToString(group));
            identityService.deleteMembership(userId, group.getId());
        }
 
        // 添加membership
        addMembershipToIdentify(roleIds, userId);
    }
 
    /**
     * 使用系统用户对象属性设置到Activiti User对象中
     * @param user          系统用户对象
     * @param activitiUser  Activiti User
     */
    privatevoid cloneAndSaveActivitiUser(User user, org.activiti.engine.identity.User activitiUser) {
        activitiUser.setFirstName(user.getName());
        activitiUser.setLastName(StringUtils.EMPTY);
        activitiUser.setPassword(StringUtils.EMPTY);
        activitiUser.setEmail(user.getEmail());
        identityService.saveUser(activitiUser);
    }
 
    @Override
    publicvoid delete(Long userId, booleansynToActiviti, booleansynToChecking) throwsServiceException, Exception {
        // 查询需要删除的用户对象
        User user = accountManager.getEntity(userId);
        if(user == null) {
            thrownew ServiceException("删除用户时,找不到ID为"+ userId + "的用户");
        }
 
        /**
         * 同步删除Activiti User Group
         */
        if(synToActiviti) {
            // 同步删除Activiti User
            List<role> roleList = user.getRoleList();
            for(Role role : roleList) {
                identityService.deleteMembership(userId.toString(), role.getEnName());
            }
 
            // 同步删除Activiti User
            identityService.deleteUser(userId.toString());
        }
 
        // 删除本系统用户
        accountManager.deleteUser(userId);
 
        // 删除考勤机用户
        if(synToChecking) {
            checkingAccountManager.deleteEntity(userId);
        }
    }
}

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

同步全部数据步骤:

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

  • 复制Role对象数据到Group

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

ActivitiIdentifyCommonDao.java
publicclass ActivitiIdentifyCommonDao {
 
    protectedLogger logger = LoggerFactory.getLogger(getClass());
     
    @Autowired
    privateJdbcTemplate jdbcTemplate;
 
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllUser() {
        String sql = "delete from ACT_ID_USER";
        jdbcTemplate.execute(sql);
        logger.debug("deleted from activiti user.");
    }
 
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllRole() {
        String sql = "delete from ACT_ID_GROUP";
        jdbcTemplate.execute(sql);
        logger.debug("deleted from activiti group.");
    }
 
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllMemerShip() {
        String sql = "delete from ACT_ID_MEMBERSHIP";
        jdbcTemplate.execute(sql);
        logger.debug("deleted from activiti membership.");
    }
 
}


ActivitiIdentifyService.java
publicclass ActivitiIdentifyService extendsAbstractBaseService {
     
    @Autowired
    protectedActivitiIdentifyCommonDao activitiIdentifyCommonDao;
     
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllUser() {
        activitiIdentifyCommonDao.deleteAllUser();
    }
     
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllRole() {
        activitiIdentifyCommonDao.deleteAllRole();
    }
     
    /**
     * 删除用户和组的关系
     */
    publicvoid deleteAllMemerShip() {
        activitiIdentifyCommonDao.deleteAllMemerShip();
    }
}


AccountServiceImpl.java
publicclass AccountServiceImpl implementsAccountService {
@Override
    publicvoid synAllUserAndRoleToActiviti() throwsException {
 
        // 清空工作流用户、角色以及关系
        deleteAllActivitiIdentifyData();
 
        // 复制角色数据
        synRoleToActiviti();
 
        // 复制用户以及关系数据
        synUserWithRoleToActiviti();
    }
 
    /**
     * 复制用户以及关系数据
     */
    privatevoid synUserWithRoleToActiviti() {
        List<user> allUser = accountManager.getAll();
        for(User user : allUser) {
            String userId = user.getId().toString();
 
            // 添加一个用户到Activiti
            saveActivitiUser(user);
 
            // 角色和用户的关系
            List<role> roleList = user.getRoleList();
            for(Role role : roleList) {
                identityService.createMembership(userId, role.getEnName());
                logger.debug("add membership {user: {}, role: {}}", userId, role.getEnName());
            }
        }
    }
 
    /**
     * 同步所有角色数据到{@link Group}
     */
    privatevoid synRoleToActiviti() {
        List<role> allRole = roleManager.getAll();
        for(Role role : allRole) {
            String groupId = role.getEnName().toString();
            Group group = identityService.newGroup(groupId);
            group.setName(role.getName());
            group.setType(role.getType());
            identityService.saveGroup(group);
        }
    }
 
    @Override
    publicvoid deleteAllActivitiIdentifyData() throwsException {
        activitiIdentifyService.deleteAllMemerShip();
        activitiIdentifyService.deleteAllRole();
        activitiIdentifyService.deleteAllUser();
    }
}


方案二:覆盖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即可。

<beanid="processEngineConfiguration"class="org.activiti.spring.SpringProcessEngineConfiguration">
    ...
    <propertyname="dbIdentityUsed"ref="false">
    ...
</property></bean>

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

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

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

作者:szwangdf 发表于2014-5-12 17:31:22 原文链接
阅读:97 评论:0 查看评论

相关 [java activiti 同步] 推荐:

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

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

Java同步块(Synchronized Blocks)

- - 并发编程网 - ifeve.com
原文链接  作者:Jakob Jenkov  译者:李同杰. Java 同步块(synchronized block)用来标记方法或者代码块是同步的. Java同步关键字(synchronzied). Java 同步关键字( synchronized ). Java中的同步块用synchronized标记.

Java多线程(二)同步

- - CSDN博客编程语言推荐文章
如果你的java基础较弱,或者不大了解java多线程请先看这篇文章 java多线程(一)线程定义、状态和属性. 同步一直是java多线程的难点,在我们做android开发时也很少应用,但这并不是我们不熟悉同步的理由. 希望这篇文章能使更多的人能够了解并且应用java的同步. 在多线程的应用中,两个或者两个以上的线程需要共享对同一个数据的存取.

Activiti用户指南之Activiti的API

- - ITeye博客
 一、流程引擎的API和服务(services).      引擎的API是影响Activiti最常见的一种方法. 我们一开始最关注的中心是ProcessEngine,像之前描述的那样,流程引擎可以被多种方式创建. 从这个流程引擎里面,你能获得各个包含workflow/BPM方法的服务. 流程引擎和这些获得的服务是线程安全的.

Activiti学习笔记

- - 企业架构 - ITeye博客
第一个Activiti的HelloWorld. 获取核心ProcessEngine对象 2. 根据需求,获取对应的服务实例 3. 使用服务方法,做事情 * * @author Administrator * */ public class HelloWorld {. // 加载核心API ProcessEngine.

Activiti工作流demo

- - CSDN博客综合推荐文章
继上篇《 Activiti工作流的环境配置》.        前几篇对Activiti工作流进行了介绍,并讲解了其环境配置. 本篇将会用一个demo来展示Activiti工作流具体的体现,直接上干货.        以HelloWorld程序为例.       首先说一下业务流程,员工张三提交了一个申请,然后由部门经理李四审核,审核通过后再由总经理王五审核,通过则张三申请成功.

Activiti - 设置会签

- - 企业架构 - ITeye博客
前些天在群里聊工作流和Activiti,群里有人分享了自己的工作流引擎开源项目,大伙纷纷问这问那(比如为什么突然自己搞个process engine、有没有eclipse plugin、能不能绘制流程图等等). 现实生活中的工作流程,我们也经常碰到需要会签的情况,支持会签是很必要的. 正好有两个人问道:支持会签吗.

Java synchronized同步方法和同步块总结

- - 编程语言 - ITeye博客
今天做了一些实验,把Java synchronized同步方法和同步块总结一下,欢迎拍砖. Java synchronized同步方法和同步块总结:. synchronized method() {...} 锁对象的所有同步方法. 一个进程进入某对象同步方法后,其它线程不能同时访问这个对象中任何一个同步方法.

activiti工作流使用

- - 行业应用 - ITeye博客
activiti 开发流程. JBPM 与 Activiti. jBPM项目于2002年3月由Tom Baeyens发起,2003年12月发布1.0版本. 2004年10月18日,发布了2.0版本,并在同一天加入了JBoss. 2011 年 jBPM的创建者Tom Baeyens离开JBoss了, 他的离开产生了两个结果:.

ACTIVITI 学习笔记 - 监听

- - 企业架构 - ITeye博客
ACTIVITI 学习笔记 - 监听. 所有分发的事件都是org.activiti.engine.delegate.event.ActivitiEvent的子类. 监听器监听的流程引擎已经创建完毕,并准备好接受API调用. 监听器监听的流程引擎已经关闭,不再接受API调用. 创建了一个新实体,初始化也完成了.