最近做一个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来确定角色的权限了。
或许存在比这种设计更好的设计,但目前我只发现这种设计比较适合。可能是我学艺不精,没找到更好的办法,希望有大牛可以指出我的错误,让我这个菜鸟能找到更好的办法。