很多时候,JBPM自己提供的用户系统是不够用的,这时候就要求我们自己去扩展自己的用户体系。JBPM允许外挂一个用户体系。
如果想嵌入自己的用户体系,只需如下五步:
一:创建MesUser,MesGroup,MesMembership三个类,分别实现接口User,Group。由于类MesMembership是独立的,因此没有必要继承或实现其他接口。
Jbpm4提供了实现接口
interface User interface Group interface GroupMember interface IdentitySession
想要集成自己的表,首先需要实现jbpm提供的接口,然后再进行配置。
MesUser.java 用户表
package com.amnet.jbpm.identify; import java.io.Serializable; import java.sql.Blob; import org.jbpm.api.identity.User; public class MesUser implements Serializable, User { private static final long serialVersionUID = 1L; protected long dbid; // 数据库内部自生成的ID private String id; private String userNo;// 员工工号 private String userName;// 员工姓名 private String userSex;// 性别 private String userPassword;// 密码 private String userType;// 类型 private String userMail;// 电子邮件 private String isValid;// 是否有效Y/N private Blob signaturePic;// 电子签名 private String remarks;// 备注 protected int dbversion; public int getDbversion() { return dbversion; } public MesUser() { } public MesUser(String id, String userName, String userMail) { this.id = id; this.userName = userName; this.userMail = userMail; } public void setDbversion(int dbversion) { this.dbversion = dbversion; } public long getDbid() { return dbid; } public void setDbid(long dbid) { this.dbid = dbid; } public void setId(String id) { this.id = id; } public String getUserNo() { return userNo; } public void setUserNo(String userNo) { this.userNo = userNo; } public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getUserSex() { return userSex; } public void setUserSex(String userSex) { this.userSex = userSex; } public String getUserPassword() { return userPassword; } public void setUserPassword(String userPassword) { this.userPassword = userPassword; } public String getUserType() { return userType; } public void setUserType(String userType) { this.userType = userType; } public String getUserMail() { return userMail; } public void setUserMail(String userMail) { this.userMail = userMail; } public String getIsValid() { return isValid; } public void setIsValid(String isValid) { this.isValid = isValid; } public Blob getSignaturePic() { return signaturePic; } public void setSignaturePic(Blob signaturePic) { this.signaturePic = signaturePic; } public String getRemarks() { return remarks; } public void setRemarks(String remarks) { this.remarks = remarks; } public String getDisplayName() { return userName + "(" + id + ")"; } // 实现User接口所必须实现的几个方法 public String getId() { return this.id; } public String getGivenName() { return null; } public String getFamilyName() { return null; } public String getBusinessEmail() { return this.userMail; } }
MesGroup.java 部门表
package com.amnet.jbpm.identify; import java.io.Serializable; import org.jbpm.api.identity.Group; public class MesGroup implements Serializable, Group { private static final long serialVersionUID = 1L; private String id; private String groupName;// 组织名称 private String groupType;// 组织类型 private MesGroup parentGroup;// 父组织 private String remarks;// 备注 protected long dbid; protected int dbversion; public int getDbversion() { return dbversion; } public void setDbversion(int dbversion) { this.dbversion = dbversion; } public long getDbid() { return dbid; } public void setDbid(long dbid) { this.dbid = dbid; } public String getParentGroupID() { return parentGroup != null ? parentGroup.getId() : null; } public String getParentGroupName() { return parentGroup == null ? "xxx" : parentGroup.getGroupName(); } public void setId(String id) { this.id = id; } public String getGroupName() { return groupName; } public void setGroupName(String groupName) { this.groupName = groupName; } public String getGroupType() { return groupType; } public void setGroupType(String groupType) { this.groupType = groupType; } public MesGroup getParentGroup() { return parentGroup; } public void setParentGroup(MesGroup parentGroup) { this.parentGroup = parentGroup; } public String getRemarks() { return remarks; } public void setRemarks(String remarks) { this.remarks = remarks; } // 实现Group接口必须的几个方法 public String getName() { return this.groupName; } public String getType() { return this.groupType; } public String getId() { return id; } }
MesGroupMembership.java 用户部门关系表
package com.amnet.jbpm.identify; import java.io.Serializable; public class MesGroupMembership implements Serializable { private static final long serialVersionUID = 1L; protected long dbid; protected int dbversion; private MesUser user; private MesGroup group; protected String role; public int getDbversion() { return dbversion; } public void setDbversion(int dbversion) { this.dbversion = dbversion; } public long getDbid() { return dbid; } public String getRole() { return role; } public void setRole(String role) { this.role = role; } public void setDbid(long dbid) { this.dbid = dbid; } public MesGroup getGroup() { return group; } public void setGroup(MesGroup group) { this.group = group; } public String getUserNo() { return user.getUserNo(); } public String getUserID() { return user.getId(); } public String getUserName() { return user.getUserName(); } public MesUser getUser() { return user; } public void setUser(MesUser user) { this.user = user; } }
二:第一步完成了,那么就开始第二步。第二步的主要任务就是将这些类映射到数据库里。由于JBPM的持久层的操作采用的是Hibernate进行的。所以我们必须编写一个Hibernate的映射文件将实体类映射到数据库。
jbpm.customize.identify.hbm.xml
<?xml version="1.0"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <!-- ### USER ########################################################### --> <class name="com.amnet.jbpm.identify.MesUser" table="JBPM4_CUSTOMIZE_USER"> <id name="dbid" column="DBID_"> <generator class="assigned" /> </id> <version name="dbversion" column="DBVERSION_" /> <property name="id" column="USERID_" /> <!-- 登陆ID --> <property name="userNo" column="USERNO_" /> <!-- 员工工号 --> <property name="userName" column="USERNAME_" /> <!-- 姓名 --> <property name="userSex" column="USERSEX_" /> <!-- 性别 --> <property name="userPassword" column="USERPASSWORD_" /> <!-- 密码 --> <property name="userType" column="USERTYPE_" /> <!-- 类型 --> <property name="userMail" column="USERMAIL_" /> <!-- 电子邮件 --> <property name="signaturePic" column="SIGNATUREPIC_" /> <!-- 电子签名 --> <property name="remarks" column="REMARKS_" /> <!-- 备注 --> </class> <!-- ### MEMBERSHIP ##################################################### --> <class name="com.amnet.jbpm.identify.MesGroupMembership" table="JBPM4_CUSTOMIZE_MEMBERSHIP"> <id name="dbid" column="DBID_"> <generator class="assigned" /> </id> <version name="dbversion" column="DBVERSION_" /> <many-to-one name="user" column="USER_" class="com.amnet.jbpm.identify.MesUser" foreign-key="FK_MEM_USER" index="IDX_MEM_USER" /> <many-to-one name="group" column="GROUP_" class="com.amnet.jbpm.identify.MesGroup" foreign-key="FK_MEM_GROUP" index="IDX_MEM_GROUP" /> <property name="role" column="NAME_" /> </class> <!-- ### GROUP ########################################################### --> <class name="com.amnet.jbpm.identify.MesGroup" table="JBPM4_CUSTOMIZE_GROUP"> <id name="dbid" column="DBID_"> <generator class="assigned" /> </id> <version name="dbversion" column="DBVERSION_" /> <!-- private String groupID;//数据库内部ID号 private String groupName;//组织名称 private String groupType;//组织类型 private MesGroup parentGroup;//父组织 private String remarks;//备注 --> <property name="id" column="ID_" /> <property name="groupName" column="NAME_" /> <property name="groupType" column="TYPE_" /> <property name="remarks" column="REMARKS_" /> <many-to-one name="parentGroup" column="PARENT_" class="com.amnet.jbpm.identify.MesGroup" foreign-key="FK_GROUP_PARENT" index="IDX_GROUP_PARENT" /> </class> </hibernate-mapping>
上面的代码是仿照JBPM默认的映射文件jbpm.identity.hbm.xml写的。这个文件可以在JBPM的源代码里面找到,导入jar包时,它被封装在jbpm.jar里面。映射文件配置好了之后,在applicationContext.xml注入自己的mappingResources:
<property name="mappingResources"> <list> <value>com/amnet/jbpm/identify/jbpm.customize.identify.hbm.xml</value> </list> </property>
三:通过以上两步,就完成了由实体类到数据库的映射,也就是说,当你启动tomcat运行JBPM的时候,数据库里就会多出三张表:JBPM4_CUSTOMIZE_USER,JBPM4_CUSTOMIZE_GROUP,JBPM4_CUSTOMIZE_MEMBERSHIP。虽然如此,但是这只是利用了hibernate的自动生成数据表的功能产生了三个表而已,JBPM凭什么知道我需要使用的是我新创建的这三张表,而不会去调用原来的那三张表呢?答案是,他不知道。所以我们要继续进行配置。找到jbpm的一个配置文件叫:spring-jbpm4.xml。在这个文件里面原来有一句话:
import resource="jbpm.identity.cfg.xml"。我们可以去查看spring-jbpm4.xml的实际内容,结果里面就一句话: <transaction-context><identity-session /></transaction-context>。有了这句话,就相当于告诉了JBPM,它将会去调用JBPM自带的关于用户体系操作的一个接口IdentitySession。这个类的实现IdentitySessionImpl里就会默认去调用JBPM自带的用户关系管理的数据表。所以为了改变JBPM的这种习惯,我们就必须自己创建一个类MesIdentitySessionImpl.java,并实现接口IdentitySession。这样JBPM就会去调用我们自己的实现,而不会再去调用它自己的东东。要实现这个只需要把他的配置文件spring-jbpm4.xml 的import resource="jbpm.identity.cfg.xml“注释掉,然后加上一句:
<transaction-context> <hibernate-session current="true"/> <object class="xxx . Xxx . xxx . MesIdentitySessionImpl"> </object> </transaction-context>
在spring-jbpm4.xml注释掉jbpm4自己的cfg.xml文件
<!-- <import resource="jbpm.identity.cfg.xml" /> -->
spring-jbpm4.xml
<?xml version="1.0" encoding="UTF-8"?> <jbpm-configuration> <process-engine-context> <string name="spring.cfg" value="spring-jbpm4.xml" /> </process-engine-context> <import resource="jbpm.default.cfg.xml" /> <import resource="jbpm.tx.spring.cfg.xml" /> <import resource="jbpm.jpdl.cfg.xml" /> <import resource="jbpm.bpmn.cfg.xml" /> <import resource="jbpm.businesscalendar.cfg.xml" /> <import resource="jbpm.console.cfg.xml" /> <!-- <import resource="jbpm.identity.cfg.xml" /> --> <!-- <import resource="jbpm.jobexecutor.cfg.xml" /> --> <transaction-context> <hibernate-session current="true" /> <object class="com.amnet.jbpm.identify.MesIdentitySessionImpl"> </object> </transaction-context> </jbpm-configuration>
这样就OK了。下面的任务就是去实现MesIdentitySessionImpl中的方法了。
四:实现MesIdentitySessionImpl中的方法
MesIdentitySessionImpl.java 实现类
package com.amnet.jbpm.identify; import java.util.Arrays; import java.util.List; import org.hibernate.Session; import org.hibernate.criterion.Projections; import org.hibernate.criterion.Restrictions; import org.jbpm.api.JbpmException; import org.jbpm.api.identity.Group; import org.jbpm.api.identity.User; import org.jbpm.pvm.internal.env.BasicEnvironment; import org.jbpm.pvm.internal.env.EnvironmentImpl; import org.jbpm.pvm.internal.id.DbidGenerator; import org.jbpm.pvm.internal.identity.spi.IdentitySession; @SuppressWarnings("unchecked") public class MesIdentitySessionImpl implements IdentitySession { protected Session session; public MesIdentitySessionImpl() { this.session = BasicEnvironment.getFromCurrent(Session.class); } // public String createH() { // // Test t = new Test(); // // long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class) // // .getNextId(); // // t.setDbid(dbid); // // t.setId("abc"); // // return null; // // } public String createUser(String id, String userName, String businessEmail, String familName) { MesUser user = new MesUser(id, userName, businessEmail); long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class) .getNextId(); user.setDbid(dbid); session.save(user); return user.getId(); } public MesUser findUserById(String userId) { return (MesUser) session.createCriteria(MesUser.class).add( Restrictions.eq("id", userId)).uniqueResult(); } public List<User> findUsersById(String... userIds) { List<User> users = session.createCriteria(MesUser.class).add( Restrictions.in("id", userIds)).list(); if (userIds.length != users.size()) { throw new JbpmException("not all users were found: " + Arrays.toString(userIds)); } return users; } public List<User> findUsers() { return session.createCriteria(MesUser.class).list(); } public void deleteUser(String userId) { // lookup the user MesUser user = findUserById(userId); // cascade the deletion to the memberships List<MesGroupMembership> memberships = session.createCriteria( MesGroupMembership.class).add(Restrictions.eq("user", user)).list(); // delete the related memberships for (MesGroupMembership membership : memberships) { session.delete(membership); } // delete the user session.delete(user); } public String createGroup(String groupName, String groupType, String parentGroupId) { MesGroup group = new MesGroup(); String groupId = groupType != null ? groupType + "." + groupName : groupName; group.setId(groupId); long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class) .getNextId(); group.setDbid(dbid); group.setGroupName(groupName); group.setGroupType(groupType); if (parentGroupId != null) { MesGroup parentGroup = findGroupById(parentGroupId); group.setParentGroup(parentGroup); } session.save(group); return group.getId(); } public List<User> findUsersByGroup(String groupId) { return session.createCriteria(MesGroupMembership.class).createAlias( "group", "g").add(Restrictions.eq("g.id", groupId)) .setProjection(Projections.property("user")).list(); } public MesGroup findGroupById(String groupId) { return (MesGroup) session.createCriteria(MesGroup.class).add( Restrictions.eq("id", groupId)).uniqueResult(); } public List<Group> findGroupsByUserAndGroupType(String userId, String groupType) { return session.createQuery( "select distinct m.group" + " from " + MesGroupMembership.class.getName() + " as m where m.user.id = :userId" + " and m.group.type = :groupType").setString("userId", userId).setString("groupType", groupType).list(); } public List<Group> findGroupsByUser(String userId) { List<Group> gList = session.createQuery( "select distinct m.group" + " from " + MesGroupMembership.class.getName() + " as m where m.user.id = :userId").setString( "userId", userId).list(); return gList; } public List<Group> findGroups() { return session.createCriteria(MesGroup.class).list(); } public void deleteGroup(String groupId) { // look up the group MesGroup group = findGroupById(groupId); // cascade the deletion to the memberships List<MesGroupMembership> memberships = session.createCriteria( MesGroupMembership.class).add(Restrictions.eq("group", group)) .list(); // delete the related memberships for (MesGroupMembership membership : memberships) { session.delete(membership); } // delete the group session.delete(group); } public void createMembership(String userId, String groupId, String role) { MesUser user = findUserById(userId); if (user == null) { throw new JbpmException("user " + userId + " doesn't exist"); } MesGroup group = findGroupById(groupId); if (group == null) { throw new JbpmException("group " + groupId + " doesn't exist"); } MesGroupMembership membership = new MesGroupMembership(); membership.setUser(user); membership.setGroup(group); membership.setRole(role); long dbid = EnvironmentImpl.getFromCurrent(DbidGenerator.class) .getNextId(); membership.setDbid(dbid); session.save(membership); } public void deleteMembership(String userId, String groupId, String role) { MesGroupMembership membership = (MesGroupMembership) session .createCriteria( MesGroupMembership.class).createAlias("user", "u").createAlias( "group", "g").add(Restrictions.eq("u.id", userId)).add( Restrictions.eq("g.id", groupId)).uniqueResult(); session.delete(membership); } }
五:测试类
集成自己的表就完成了。当你调用 identityService.createUser()方法时,就往你自定义的user表里插入了一条记录。
TestMesIdentitySession.java 新建用户和组
package com.amnet.action; import org.jbpm.api.IdentityService; import org.jbpm.api.ProcessEngine; import org.springframework.context.support.ClassPathXmlApplicationContext; public class TestMesIdentitySession { /** * @param args */ public static void main(String[] args) { ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext( "applicationContext.xml"); applicationContext.start(); ProcessEngine processEngine = (ProcessEngine) applicationContext .getBean("processEngine"); // ExecutionService executionService = processEngine.getExecutionService(); // // TaskService taskService = processEngine.getTaskService(); IdentityService identityService = processEngine.getIdentityService(); identityService.createGroup("user_dept"); // 部门 identityService.createUser("user1", "test1", "test1"); // 新建用户1 identityService.createUser("user2", "test2", "test2"); // 新建用户2 identityService.createMembership("user1", "user_dept"); // 绑定用户和部门的关系 identityService.createMembership("user2", "user_dept"); } }
发布流程
ProcessEngine processEngine = Configuration.getProcessEngine(); RepositoryService repositoryService = processEngine .getRepositoryService(); String deployId = repositoryService.createDeployment().addResourceFromClasspath("com/contract/contract.jpdl.xml").deploy();
删除流程
repositoryService.deleteDeploymentCascade(deployId));
开始流程实例
executionService.startProcessInstanceById(request.getParameter("id"));