要利用jbpm实现工作流程处理,就避免不了权限处理。jbpm提供的数据库中提供了三个表,分别是:jbpm4_id_user、jbpm4_id_membership、jbpm4_id_group,能够实现简单的权限,但是这里并不能满足我们企业的实际需求。正常在企业软件中我们是要能够把不同的模块或者功能让不同的角色去使用。简单的来说就是实现不同身份的用户可以使用不同的功能。我这里实现的权限管理只能控制把不同的模块分配给不同的用户使用。因为如果要控制到功能,实现起来太麻烦了!
1、在jbpm数据库中添加额外2个表,分别是:jbpm_id_resource、jbpm_id_re_grounp_resource。分别代表资源表和资源--用户组关系表。在资源表中pid是关联到自身的一个外键列,代表该资源是否是一个模块,如果不为“0”,代表是一个功能。关系图如下:
2、利用hibernate反向生成工具生成设计权限操作的映射文件、pojo类以及数据访问类。
3、把各个映射文件中的set、关联对象的延迟加载设置为false并指定排序依据。其中一个文件的实例代码如下:
<set name="resources" lazy="false" inverse="true" order-by="id">
<key>
<column name="pid"></column>
</key>
<one-to-many class="com.tc.entity.JbpmIdResource"/>
</set>
4、修改JbpmIdResource类以及对应的映射文件添加自身的一对多关系,即:模块到资源的一对多关系
a)在JbpmIdResource添加Set集合并提供get、set方法。
b)在对应的映射文件中添加set标签
<set name="resources" lazy="false" inverse="true" order-by="id">
<key>
<column name="pid"></column>
</key>
<one-to-many class="com.tc.entity.JbpmIdResource"/>
</set>
5、由于这里使用现成的js代码生成树形菜单,所以要准备一个工具类用来生成符合js要求的字符串,代码如下:
package com.tc.toolit;
import java.util.Iterator;
import java.util.Set;
import com.tc.entity.JbpmIdResource;
public class GiveMenuToolit {
private StringBuffer sb=new StringBuffer();
/**
* @param args
*/
public String giveMenu(JbpmIdResource t) {
printName(t);
return sb.toString();
}
public StringBuffer printName(JbpmIdResource t){
sb.append("L"+t.getId()+" = theMenu.addChild(L0, '"+t.getResType()+"', '"+t.getResName()+"', '"+t.getResUrl()+"', '"+t.getResComment()+"');\r\n");
Set set=t.getResources();
for (Iterator iterator = set.iterator(); iterator.hasNext();) {
JbpmIdResource object = (JbpmIdResource) iterator.next();
sb.append("L"+object.getId()+" = theMenu.addChild(L"+t.getId()+", '"+object.getResType()+"', '"+object.getResName()+"', '"+object.getResUrl()+"', '"+object.getResComment()+"');\r\n");
Set s=object.getResources();
if(s.size()>0){
printName(object);
}
}
return sb;
}
}
6、在准备一个用于生成树形字符串的biz,该biz用来生成最后传递给js用来生成字符串的信息并在该biz中创建main方法来测试代码是否要求,代码如下:
package com.tc.biz;
import java.util.Iterator;
import java.util.Set;
import org.jbpm.api.RepositoryService;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.tc.dao.Jbpm4IdUserDAO;
import com.tc.entity.Jbpm4IdMembership;
import com.tc.entity.Jbpm4IdUser;
import com.tc.entity.JbpmIdResource;
import com.tc.toolit.GiveMenuToolit;
public class GiveMenuBiz {
public String giveMenu(Jbpm4IdUser user){
String mes="";
if(user!=null){
GiveMenuToolit gmt=new GiveMenuToolit();
Set<Jbpm4IdMembership> membershops=user.getJbpm4IdMemberships();
for (Iterator iterator = membershops.iterator(); iterator.hasNext();) {
Jbpm4IdMembership membership = (Jbpm4IdMembership) iterator.next();
Set<JbpmIdResource> jrs=membership.getJbpm4IdGroup().getJbpmIdResources();
for (Iterator iterator2 = jrs.iterator(); iterator2.hasNext();) {
JbpmIdResource jbpmIdResource = (JbpmIdResource) iterator2
.next();
mes=gmt.giveMenu(jbpmIdResource);
}
}
//System.out.println(mes);
}
return mes;
}
public static void main(String[] args) {
Jbpm4IdUserDAO rs=(Jbpm4IdUserDAO)new ClassPathXmlApplicationContext("applicationContext.xml").getBean("Jbpm4IdUserDAO");
Jbpm4IdUser user=(Jbpm4IdUser)rs.findById("wang02").get(0);
System.out.println(new GiveMenuBiz().giveMenu(user));
}
}
7、创建登陆表单,用来提交登陆的用户信息,代码如下:
<%@ page language="java" import="java.util.*" pageEncoding="UTF-8"%>
<%
String path = request.getContextPath();
String basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path+"/";
%>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
<base href="<%=basePath%>">
<title>My JSP 'login.jsp' starting page</title>
<meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page">
<!--
<link rel="stylesheet" type="text/css" href="styles.css">
-->
</head>
<body>
<form action="doLogin.action" method="post" >
用户名:<input name="user.id"/>
密码:<input name="user.password" type="password"/><input type="submit" value="login"/>
</form>
</body>
</html>
8、创建处理登陆业务的biz,在biz中依赖Jbpm4IdUserDAO,使用spring的setter注入为该dao提供对象,代码如下:
package com.tc.biz;
import java.util.List;
import com.tc.dao.Jbpm4IdUserDAO;
import com.tc.entity.Jbpm4IdUser;
public class LoginBiz {
private Jbpm4IdUserDAO userDao;
public Jbpm4IdUser login(Jbpm4IdUser user){
List<Jbpm4IdUser> us=userDao.findById(user.getId());
if(us!=null&&us.size()>0){
Jbpm4IdUser res=us.get(0);
if(res.getPassword().equals(user.getPassword())){
return res;
}
}
return null;
}
public Jbpm4IdUserDAO getUserDao() {
return userDao;
}
public void setUserDao(Jbpm4IdUserDAO userDao) {
this.userDao = userDao;
}
}
9、在action包下创建处理登陆功能的Action类,如果登陆成功向session中存储用户信息并跳转至index.html页面中,代码如下:
package com.tc.action;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.tc.biz.LoginBiz;
import com.tc.entity.Jbpm4IdUser;
public class LoginAction {
private Jbpm4IdUser user;
private LoginBiz loginBiz;
public String execute(){
Jbpm4IdUser res=loginBiz.login(user);
if(res!=null){
ActionContext.getContext().getSession().put("user", res);
return Action.SUCCESS;
}else{
return Action.LOGIN;
}
}
public Jbpm4IdUser getUser() {
return user;
}
public void setUser(Jbpm4IdUser user) {
this.user = user;
}
public LoginBiz getLoginBiz() {
return loginBiz;
}
public void setLoginBiz(LoginBiz loginBiz) {
this.loginBiz = loginBiz;
}
}
10、编写index.html页面,该页面是一个框架页,典型的上中下结构,中间部分被分为:左侧树形导航,右侧主显示区域。左侧导航路径指向一个action地址,代码如下:
<html>
<head>
<title>请假流程管理</title>
<meta http-equiv="Content-Type" content="text/html; charset=gb2312">
</head>
<frameset rows="85,*,40" frameborder="NO" noresize Borders="NO" framespacing="0">
<frame name="topFrame" frameborder="NO" scrolling="NO" noresize Borders="NO" src="top.jsp" marginwidth="value" marginheight="value" >
<frame name="mainFrame" noresize Borders="NO" src="doGiveMenu.action" marginwidth="value" marginheight="value" >
<frame src="footer.html" name="top1Frame" frameborder="NO" scrolling="NO" noresize marginwidth="0" marginheight="0" Borders="NO" >
</frameset>
<noframes><body bgcolor="#FFFFFF">
</body></noframes>
</html>
11、编写一个action用来调用GiveMenuBiz生成符合js要求的树形字符串并传递给tree.jsp显示在树形菜单上,在action中biz利用spring注入,代码如下:
package com.tc.action;
import com.opensymphony.xwork2.Action;
import com.opensymphony.xwork2.ActionContext;
import com.tc.biz.GiveMenuBiz;
import com.tc.entity.Jbpm4IdUser;
public class GiveMenuAction {
private GiveMenuBiz giveMenuBiz;
public String execute(){
Jbpm4IdUser user=(Jbpm4IdUser)ActionContext.getContext().getSession().get("user");
String mes=giveMenuBiz.giveMenu(user);
ActionContext.getContext().put("mes", mes);
return Action.SUCCESS;
}
public GiveMenuBiz getGiveMenuBiz() {
return giveMenuBiz;
}
public void setGiveMenuBiz(GiveMenuBiz giveMenuBiz) {
this.giveMenuBiz = giveMenuBiz;
}
}
12、编写tree.jsp用于接收上面Action中所传递的字符串信息并绑定到树形菜单上,由于页面js代码较多,我只把利用el表达式接收字符串的代码粘在这里,其他的代码在代码附件中查找! 代码如下:
var level1ID = -1;
var level2ID = -1;
var level3ID = -1;
var level4ID = -1;
var level5ID = -1;
//level表示最高级,level2子级,level3子子级,Document文件,folder文件夹。
//Set the initial state of the folder to "open"
L0 = theMenu.addEntry(-1, "Folder", "请假流程管理", "mywork.htm", "请假流程管理");
${mes}
theMenu.entry[L0].isopen = true;
}
self.defaultStatus = "";
13、在web.xml配置ContextLoaderListener用于监听spring配置文件并配置contextConfigLocation参数,代码如下:
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
14、在struts中配置loginaction以及menuaction,代码如下:
<?xml version="1.0" encoding="UTF-8" ?>
<!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.1//EN" "http://struts.apache.org/dtds/struts-2.1.dtd">
<struts>
<package name="myMenu" extends="struts-default" namespace="/">
<action name="doGiveMenu" class="doGiveMenuBean">
<result>/tree.jsp</result>
</action>
<action name="doLogin" class="doLoginBean">
<result>/index.html</result>
<result name="login" >/login.jsp</result>
</action>
</package>
</struts>
15、在spring的配置文件中配置各个biz、action等,代码如下:
<bean id="menuBiz" class="com.tc.biz.GiveMenuBiz"></bean>
<bean id="loginBiz" class="com.tc.biz.LoginBiz">
<property name="userDao" ref="Jbpm4IdUserDAO"></property>
</bean>
<bean id="doLoginBean" class="com.tc.action.LoginAction">
<property name="loginBiz" ref="loginBiz"></property>
</bean>
<bean id="doGiveMenuBean" class="com.tc.action.GiveMenuAction">
<property name="giveMenuBiz" ref="menuBiz"></property>
</bean>
注意:在添加struts2框架的时候一定要添加:struts-spring-plugin-2.1.8.jar,他是用来集成spring的。
可能遇到的问题:
javax.servlet.ServletException: java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jasper.servlet.JspServlet.service(JspServlet.java:275) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
root cause
java.lang.LinkageError: loader constraint violation: when resolving interface method "javax.servlet.jsp.JspApplicationContext.getExpressionFactory()Ljavax/el/ExpressionFactory;" the class loader (instance of org/apache/jasper/servlet/JasperLoader) of the current class, org/apache/jsp/OnDuty/wfmanage_jsp, and the class loader (instance of org/apache/catalina/loader/StandardClassLoader) for resolved class, javax/servlet/jsp/JspApplicationContext, have different Class objects for the type javax/el/ExpressionFactory used in the signature org.apache.jsp.OnDuty.wfmanage_jsp._jspInit(wfmanage_jsp.java:27) org.apache.jasper.runtime.HttpJspBase.init(HttpJspBase.java:52) org.apache.jasper.servlet.JspServletWrapper.getServlet(JspServletWrapper.java:159) org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:329) org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:342) org.apache.jasper.servlet.JspServlet.service(JspServlet.java:267) javax.servlet.http.HttpServlet.service(HttpServlet.java:717)
原因是项目中WEB-INF/lib 中的三个jar 包 (juel.jar, juel-engine.jar, juel-impl.jar )和tomcat6 下lib 中jar 包( el-api.jar ) 冲突
解决方法:
方法一:换成tomcat5.5 一点问题也没有了(有新版本了还用老版本?)
方法二:将 juel.jar, juel-engine.jar, juel-impl.jar 这三个包复制到tomcat6 下lib 中,并删除原来的 el-api.jar ,切记要把WEB-INF/lib 中的juel.jar, juel-engine.jar, juel-impl.jar 删除。不然还是要冲突。
不足的地方:由于js的问题,最好使用ie访问页面。
项目发布后默认访问路径为:http://localhost:8080/jbpmTest/
附件中提供本博客的源代码,欢迎下载!!!
未完待续。。。。。。
欢迎拍砖!!!!