咱们直接来看看原型图,看看需求是怎么样的:java
咱们看到上图,就会发现角色模块主要仍是CRUD,惟一不一样的就是它再也不是单独的实体关系。角色与权限是存在关系的。sql
以前在Servlet+JSP+JavaBean的时候其实咱们已经作过了用户-角色-权限之间的操做【权限管理系统】http://blog.csdn.net/hon_3y/article/details/61926175数据库
角色与权限应该是多对多的关系的。数组
如今个人权限只有5个,有必要使用数据库表吗???没啥必要吧。权限基本就固定下来了。那多对多的关系怎么维护???以前咱们使用数据库表就很好作了呀。设计两个实体,使用中间表来描述它们之间的关系就作出来了。服务器
那如今怎么作呢??一个角色对应多个权限markdown
咱们在数据库中的表就能够这样设计:即便没有权限表,可是我使用了中间表维护了它们的数据。同样能够作到一个角色对应多个权限这样的功能。app
咱们权限是不须要表的,所以咱们把各个权限写下来,使用一个集合装载着就好了。固然啦,他们都应该被设计成常量。咱们保存在core模块中【被整个系统用到的】ide
package zhongfucheng.core.constant; import java.util.HashMap; import java.util.Map; /** * Created by ozc on 2017/5/26. */ public class Constant { /*----------------------系统权限集合--------------------------*/ public static String PRIVILEGE_XZGL = "xzgl"; public static String PRIVILEGE_HQFW = "hqfw"; public static String PRIVILEGE_ZXXX = "zxxx"; public static String PRIVILEGE_NSFW = "nsfw"; public static String PRIVILEGE_SPACE = "spaces"; //使用一个Map集合来装载着这些权限。 public static Map<String, String> PRIVILEGE_MAP; static { PRIVILEGE_MAP = new HashMap<String, String>(); PRIVILEGE_MAP.put(PRIVILEGE_XZGL, "行政管理"); PRIVILEGE_MAP.put(PRIVILEGE_HQFW, "后勤服务"); PRIVILEGE_MAP.put(PRIVILEGE_ZXXX, "在线学习"); PRIVILEGE_MAP.put(PRIVILEGE_NSFW, "纳税服务"); PRIVILEGE_MAP.put(PRIVILEGE_SPACE, "个人空间"); } }
咱们的角色类应该使用一个Set集合来保存对应的权限数据的,那么Set集合的元素类型是什么呢???想一下…学习
以前咱们在用的时候,若是有权限表。咱们在角色中Set集合的元素应该是Privilege类。可是如今是没有权限表的。咱们怎么经过角色来获取全部的权限呢??ui
再看回这样ER图:咱们在角色Set集合中保存着角色与关系表这个不就好了吗!!!
因而咱们这样设计:
package zhongfucheng.role.entity; import java.io.Serializable; import java.util.Set; /** * Created by ozc on 2017/5/26. */ public class Role implements Serializable { private String roleId; private String state; private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } private Set<RolePrivilege> rolePrivilegeSet; public static String USER_STATE_VALID = "1";//有效, public static String USER_STATE_INVALID = "0";//无效 public String getRoleId() { return roleId; } public void setRoleId(String roleId) { this.roleId = roleId; } public String getState() { return state; } public void setState(String state) { this.state = state; } public Set<RolePrivilege> getRolePrivilegeSet() { return rolePrivilegeSet; } public void setRolePrivilegeSet(Set<RolePrivilege> rolePrivilegeSet) { this.rolePrivilegeSet = rolePrivilegeSet; } public static String getUserStateValid() { return USER_STATE_VALID; } public static void setUserStateValid(String userStateValid) { USER_STATE_VALID = userStateValid; } public static String getUserStateInvalid() { return USER_STATE_INVALID; } public static void setUserStateInvalid(String userStateInvalid) { USER_STATE_INVALID = userStateInvalid; } }
角色与权限关系类只有两个属性:角色的id和权限的code….这两个是外键列。一张表中必定是要有主键列的,因而咱们采用的是复合主键的方式。
对于复合主键,它是要让该类维护一个复合主键类的:
将主键所对应属性提取出一个类(称之为主键类),而且主键类须要实现Serializable接口,重写hashCode和equals()方法
public class RolePrivilege implements Serializable { private CompositeKey compositeKey; public CompositeKey getCompositeKey() { return compositeKey; } public void setCompositeKey(CompositeKey compositeKey) { this.compositeKey = compositeKey; } }
按照ER图,咱们复合主键就两个属性:role_id和code。。
可是呢,咱们想一下需求:在获取角色全部权限的时候,Set集合装载着角色与权限的关系,而角色与权限的关系装载着role_id和code。而颇有可能:在我查看用户所拥有角色的时候,想要获得角色的名称。这里仅仅查出来的是角色id,还要经过角色id获得角色的名称…这样就有点麻烦了。因而咱们写成Role对象。到时候就能直接获取了。
package zhongfucheng.role.entity; import java.io.Serializable; /** * Created by ozc on 2017/5/26. */ public class CompositeKey implements Serializable { private String code; private Role role; @Override public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; CompositeKey that = (CompositeKey) o; if (code != null ? !code.equals(that.code) : that.code != null) return false; return role != null ? role.equals(that.role) : that.role == null; } @Override public int hashCode() { int result = code != null ? code.hashCode() : 0; result = 31 * result + (role != null ? role.hashCode() : 0); return result; } public String getCode() { return code; } public void setCode(String code) { this.code = code; } public Role getRole() { return role; } public void setRole(Role role) { this.role = role; } }
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="zhongfucheng.role.entity.Role" table="role"> <id name="roleId" type="java.lang.String"> <column name="roleId" length="32" /> <generator class="uuid.hex" /> </id> <property name="state" type="java.lang.String"> <column name="state" length="1" /> </property> <property name="name" type="java.lang.String"> <column name="name" length="20" not-null="true" /> </property> <!-- 一方维护多方的数据,inverse设置为true,没有控制权限 设置级联保存更新,在保存角色的时候,将权限也保存起来了。 不设置懒加载,直接获取到权限的数据 --> <set name="rolePrivilegeSet" lazy="false" inverse="true" cascade="save-update" > <key> <column name="role_id"></column> </key> <one-to-many class="zhongfucheng.role.entity.RolePrivilege" ></one-to-many> </set> </class> </hibernate-mapping>
<?xml version="1.0" encoding="utf-8"?> <!DOCTYPE hibernate-mapping PUBLIC "-//Hibernate/Hibernate Mapping DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd"> <hibernate-mapping> <class name="zhongfucheng.role.entity.RolePrivilege" table="role_privilege"> <composite-id name="id" class="zhongfucheng.role.entity.CompositeKey"> <key-many-to-one name="role" class="zhongfucheng.role.entity.Role" lazy="false"> <column name="role_id "></column> </key-many-to-one> <key-property name="code" type="java.lang.String"> <column name="code"></column> </key-property> </composite-id> </class> </hibernate-mapping>
没啥好说的,咱们在User模块中已经写过了。咱们能够直接复制过来,而后将不要的功能去掉。
dao–>service—>action这样改完,就有了Role模块的CRUD了。
最后:
把权限的集合带过去给JSP页面显示出来,JSP使用Struts的checkbox进行遍历【很好用】
public String addUI() { ActionContext.getContext().getContextMap().put("privilegeMap", Constant.PRIVILEGE_MAP); return "addUI"; }
使用checkbox标签遍历
<tr> <td class="tdBg" width="200px">角色权限:</td> <td> <%-- checkboxlist:自动把Map集合遍历出来,生成对应的key value,Map集合的key做为checkbox的key,value做为checkbox的value list:集合 name:把数据带过去给服务器 --%> <s:checkboxlist list="#privilegeMap" name="privilegeIds"/> </td> </tr>
/************数据自动封装权限的id*************************/ private String[] privilegeIds; public String[] getPrivilegeIds() { return privilegeIds; } public void setPrivilegeIds(String[] privilegeIds) { this.privilegeIds = privilegeIds; }
处理角色与权限的关系。在配置中使用了级联保存,所以能够直接保存数据
public String add() throws IOException { if (role != null) { //处理角色与权限的关系 if (privilegeIds != null) { HashSet<RolePrivilege> set = new HashSet<>(); //获得每个权限的值--->entity给出对应的构造方法... for (int i = 0; i < privilegeIds.length; i++) { set.add(new RolePrivilege(new CompositeKey(role, privilegeIds[i]))); } role.setRolePrivilegeSet(set); } roleServiceImpl.save(role); //跳转到列表显示页面 return "list"; } return null; }
在显示模块中,主要是显示角色的权限中有点绕…..
角色的权限用set集合保存起来,set集合元素是角色与权限的关系,角色与权限是一个类,该类保存着主键类,主键类存储的是角色和权限code。
咱们的目的是:获得角色含有的权限。而目前为止,咱们最多只能获得每一个权限code值:
而咱们想要显示的是权限的名称,因而咱们得把权限集合传过去,根据code获得权限的名称:
public String listUI() { roleList = roleServiceImpl.findObjects(); ActionContext.getContext().getContextMap().put("privilegeMap", Constant.PRIVILEGE_MAP); return "listUI"; }
JSP页面取值:注意懒加载的问题,设定不要懒加载。否则会出现: java.io.IOException: Stream closed
<s:iterator value="rolePrivilegeSet"> <s:property value="#privilegeMap[compositeKey.code]"/> </s:iterator>
跳转到Action中处理,把id传递过去…
function doDelete(id) { document.forms[0].action = "${basePath}role/role_delete.action?role.roleId="+id; document.forms[0].submit(); }
判断是否为空,不为空就删除。返回到列表页面
2017/5/31 12:59:27 //删除 public String delete() { if (role != null && role.getRoleId() != null) { roleServiceImpl.delete(role.getRoleId()); } return "list"; }
数据回显页面,主要就是角色的权限那里怎么回显。咱们把全部的权限带过去,用字符串数组记录当前角色有什么权限
//获得全部的权限 ActionContext.getContext().getContextMap().put("privilegeMap", Constant.PRIVILEGE_MAP); //外边已经传了id过来了,咱们要找到id对应的Role if (role != null && role.getRoleId() != null) { //直接获取出来,后面JSP会根据Role有getter就能读取对应的信息! role = roleServiceImpl.findObjectById(role.getRoleId()); //获得角色全部的权限,把它封装到privilegeIds字符数组中。 //处理权限回显 if (role.getRolePrivilegeSet() != null) { privilegeIds = new String[role.getRolePrivilegeSet().size()]; int i = 0; for (RolePrivilege rp : role.getRolePrivilegeSet()) { privilegeIds[i++] = rp.getCompositeKey().getCode(); } } } return "editUI";
在JSP页面,使用checkboxlist标签进行遍历。
<s:checkboxlist list="#privilegeMap" name="privilegeIds" ></s:checkboxlist>
获得JSP传递过来的ids,封装成一个set集合。将set集合赋值给role对象。
public String edit() throws IOException { //Struts2会自动把JSP带过来的数据封装到Role对象上 if (role.getRoleId() != null && role != null) { Set<RolePrivilege> set = new HashSet<>(); //获得修改的权限id,封装到set集合中。 for (String privilegeId : privilegeIds) { set.add(new RolePrivilege(new CompositeKey(role, privilegeId))); } role.setRolePrivilegeSet(set); roleServiceImpl.update(role); } return "list"; }
仅仅是使用update(role)方法是不够的,所以Hibernate在更新操做的时候,会先把数据查询出来。当咱们更改角色权限的时候,它会将咱们已有的权限保留下来,若是有新的就继续添加。它不会把咱们没勾选的剔除的。
所以,咱们须要在更新的以前,把当前角色全部的权限给删了。
//在修改以前,把角色的全部权限给删除了。否则会遗留以前的权限下来。 roleDaoImpl.deleteRolePrivilegeByRoleId(role.getRoleId());
/*** * 根据角色id删除全部的权限 * */ @Override public void deleteRolePrivilegeByRoleId(String roleId) { String sql = "DELETE FROM RolePrivilege WHERE compositeKey.role.roleId= ?"; Query query = getSession().createQuery(sql); query.setParameter(0, roleId); query.executeUpdate(); }
效果: