標籤:hibernate oa系統 資料庫 多對多單向串連 許可權管理
最近做一個OA系統,用到了Hibernate架構,我發現,許可權和角色的關係是一種多對多的關係,一個許可權可以分配給多個角色,一個角色擁有多個許可權。
多對多關係有兩種,一種是單向的,一種是多向的。對於這個問題,曾經讓我很犯難。單純在語言上理解,會比較複雜,而從代碼上理解,可能就會明白了。
下面類比為角色授權的過程:
1,Hibernate使用Annotation
2,使用Junit進行測試。
3,使用Mysql作為後台資料庫。
4,Hibernate不使用自動建表,也不採用反向工程。
過程 :
1,建表:
資料表結構採用:
SQL語句:
CREATE TABLE role( #角色表 RoleId INT PRIMARY KEY AUTO_INCREMENT , #角色ID RoleName VARCHAR(20) NOT NULL #角色名稱) ;CREATE TABLE privilege( #許可權表 PrivilegeId INT PRIMARY KEY , #許可權ID PrivilegeName VARCHAR(45) NOT NULL #許可權表) ;CREATE TABLE privilege_role( #許可權_角色中間表 RoleId INT , PrivilegeId INT , PRIMARY KEY (RoleId,PrivilegeId) , CONSTRAINT fk_privilege_role FOREIGN KEY(RoleId) REFERENCES role(RoleId) , CONSTRAINT fk_role_privilege FOREIGN KEY(PrivilegeId) REFERENCES privilege(PrivilegeId) ) ;
2,hibernate.cfg.xml檔案:
<?xml version='1.0' encoding='utf-8'?><!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd"><hibernate-configuration> <session-factory> <property name="connection.driver_class">com.mysql.jdbc.Driver</property> <property name="connection.url">jdbc:mysql://localhost:3306/hibernate</property> <property name="connection.username">root</property> <property name="connection.password">xxxx</property> <property name="dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property> <property name="show_sql">true</property> <mapping class="org.jian.domain.Role"/> <mapping class="org.jian.domain.Privilege"/> </session-factory></hibernate-configuration>
3,編寫實體類:
Role.java:
package org.jian.domain;import java.util.HashSet;import java.util.Set;import javax.persistence.CascadeType;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.Id;import javax.persistence.JoinTable;import javax.persistence.ManyToMany;import javax.persistence.Table;import javax.persistence.JoinColumn;import org.hibernate.annotations.GenericGenerator;@Entity@Table(name = "Role")public class Role {private int roleId;private String roleName;private Set<Privilege> privileges = new HashSet<Privilege>();@Id@GenericGenerator(name = "generator", strategy = "increment")@GeneratedValue(generator = "generator")public int getRoleId() {return roleId;}public void setRoleId(int roleId) {this.roleId = roleId;}@Column(name = "roleName")public String getRoleName() {return roleName;}public void setRoleName(String roleName) {this.roleName = roleName;}@ManyToMany(cascade = CascadeType.REFRESH, fetch = FetchType.EAGER)@JoinTable(name = "privilege_role", joinColumns = { @JoinColumn(name = "RoleId") }, inverseJoinColumns = { @JoinColumn(name = "PrivilegeId") })public Set<Privilege> getPrivileges() {return privileges;}public void setPrivileges(Set<Privilege> privileges) {this.privileges = privileges;}}
Privilege.java
package org.jian.domain;import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.Id;import javax.persistence.Table;@Entity@Table(name="Privilege")public class Privilege {private int privilegeId;private String privilegeName;@Id@Column(name="privilegeId")public int getPrivilegeId() {return privilegeId;}public void setPrivilegeId(int privilegeId) {this.privilegeId = privilegeId;}public String getPrivilegeName() {return privilegeName;}public void setPrivilegeName(String privilegeName) {this.privilegeName = privilegeName;}}
5,Junit測試類別:
package org.jian.domain;import java.util.Set;import org.hibernate.Session;import org.hibernate.SessionFactory;import org.hibernate.Transaction;import org.hibernate.cfg.AnnotationConfiguration;import org.junit.AfterClass;import org.junit.BeforeClass;import org.junit.Test;public class AuthorizeTest {private static SessionFactory sf ; @BeforeClass public static void beforeClass(){ sf = new AnnotationConfiguration().configure().buildSessionFactory() ; } @AfterClass public static void afterClass(){ sf.close(); } /** * 初始化系統,許可權由系統初始化的時候插入資料庫 */@Testpublic void initTest() {Privilege p1 = new Privilege() ;p1.setPrivilegeId(1);p1.setPrivilegeName("添加日誌");Privilege p2 = new Privilege() ;p2.setPrivilegeId(2);p2.setPrivilegeName("刪除日誌");Privilege p3 = new Privilege() ;p3.setPrivilegeId(3);p3.setPrivilegeName("修改日誌");Privilege p4 = new Privilege() ;p4.setPrivilegeName("查看日誌");p4.setPrivilegeId(4);Session session = sf.openSession() ;Transaction tx = session.beginTransaction() ;session.save(p1) ;session.save(p2) ;session.save(p3) ;session.save(p4) ;tx.commit();session.close() ;}/** * 添加角色 * 為角色添加許可權 * 我們類比有“添加日誌”和“查看日誌”許可權 * 即ID為1和4的許可權 */@Testpublic void authorizeTest(){Role role = new Role() ;role.setRoleName("經理");Session session = sf.openSession() ;Transaction tx = session.beginTransaction() ;//載入id為1和id為4的許可權Privilege p1 = (Privilege)session.get(Privilege.class, 1) ;Privilege p4 = (Privilege)session.get(Privilege.class, 4) ;//為角色role授權role.getPrivileges().add(p1) ;role.getPrivileges().add(p4) ;//儲存角色session.save(role) ;tx.commit();session.close() ;}/** * 測試剛添加的角色有什麼許可權 */@Testpublic void checkPrivilegeTest(){Session session = sf.openSession() ;Transaction tx = session.beginTransaction() ; Role role = (Role)session.get(Role.class, 1) ; Set<Privilege> privaleges = role.getPrivileges() ; System.out.println("角色"+role.getRoleName()+"擁有的許可權有:"); for (Privilege privilege : privaleges) { System.out.println(privilege.getPrivilegeName()); } tx.commit();session.close() ;}}
6,進行測試:
a,測試initTest(),看到綠條,成功
控制台輸出:
Hibernate: insert into Privilege (privilegeName, privilegeId) values (?, ?)Hibernate: insert into Privilege (privilegeName, privilegeId) values (?, ?)Hibernate: insert into Privilege (privilegeName, privilegeId) values (?, ?)Hibernate: insert into Privilege (privilegeName, privilegeId) values (?, ?)
b,測試authorizeTest(),看導綠條,成功
控制台輸出:
Hibernate: select privilege0_.privilegeId as privileg1_1_0_, privilege0_.privilegeName as privileg2_1_0_ from Privilege privilege0_ where privilege0_.privilegeId=?Hibernate: select privilege0_.privilegeId as privileg1_1_0_, privilege0_.privilegeName as privileg2_1_0_ from Privilege privilege0_ where privilege0_.privilegeId=?Hibernate: select max(roleId) from RoleHibernate: insert into Role (roleName, roleId) values (?, ?)Hibernate: insert into privilege_role (RoleId, PrivilegeId) values (?, ?)Hibernate: insert into privilege_role (RoleId, PrivilegeId) values (?, ?)
最後一步,測試checkPrivilegeTest(),綠條
控制台輸出:
Hibernate: select role0_.roleId as roleId0_1_, role0_.roleName as roleName0_1_, privileges1_.RoleId as RoleId0_3_, privilege2_.privilegeId as Privileg2_3_, privilege2_.privilegeId as privileg1_1_0_, privilege2_.privilegeName as privileg2_1_0_ from Role role0_ left outer join privilege_role privileges1_ on role0_.roleId=privileges1_.RoleId left outer join Privilege privilege2_ on privileges1_.PrivilegeId=privilege2_.privilegeId where role0_.roleId=?角色經理擁有的許可權有:添加日誌查看日誌
從上面我們可以看到已經為角色為“經理”的角色授予許可權了。
查看資料表:
在資料表上也可看到授權成功。
~綜:
對於這個測試裡,我把privilege的資料插入,設計成了是程式初始化的時候插入,而且資料表也沒設計成自動成長。我這樣設計的理由是:
1,把privilege的許可權id和許可權值做成一個資料字典,這樣我可以用許可權的ID來代表這個許可權,每次檢查許可權秩序檢測這個角色是否有這個許可權id,就可以判斷該角色是否可以訪問,方便程式開發。
2,如果是選擇自動產生ID,那麼這個ID我們可能會不能確定,這樣就不能利用許可權的ID來確定角色的許可權了。
或許存在比這種設計更好的設計,但目前我只發現這種設計比較適合。可能是我學藝不精,沒找到更好的辦法,希望有大牛可以指出我的錯誤,讓我這個菜鳥能找到更好的辦法。