首页 > 代码库 > 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来确定角色的权限了。

或许存在比这种设计更好的设计,但目前我只发现这种设计比较适合。可能是我学艺不精,没找到更好的办法,希望有大牛可以指出我的错误,让我这个菜鸟能找到更好的办法。