首页 > 代码库 > Hibernate单向多对多
Hibernate单向多对多
最近做一个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(); } /** * 初始化系统,权限由系统初始化的时候插入数据库 */ @Test public 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的权限 */ @Test public 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() ; } /** * 测试刚添加的角色有什么权限 */ @Test public 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 Role Hibernate: 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来确定角色的权限了。
或许存在比这种设计更好的设计,但目前我只发现这种设计比较适合。可能是我学艺不精,没找到更好的办法,希望有大牛可以指出我的错误,让我这个菜鸟能找到更好的办法。