咱們直接來看看原型圖,看看需求是怎麼樣的: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(); }
效果: