前面我们做的小项目都是一个表的,业务代码也相对简单。现在我们来做一个权限管理系统,体验一下多表的业务逻辑,顺便巩固一下过滤器的知识。!
目的
现在我有一个管理商品、订单的页面。当用户点击某个超链接时,过滤器会检测该用户是否有权限!
需求分析
按照面向对象的思想,我们至少应该有权限(Privilege)和用户(User)实体。两个实体足够了吗?细想一下,如果我们有多个用户,多个用户也有多个权限,当要为用户授权的时候,这样子就会非常麻烦!所以我们应该引入角色(Role)这个实体!
引入角色(Role)这个实体方便在哪呢??把权限赋给角色(比如:把删除、修改的权限给管理员这个角色),管理员这个角色再赋给用户,那么该用户就有了修改、删除的权限了!
权限和角色是多对多的关系,角色和用户也是多对多的关系!
开发实体 用户实体
public class User {
private String id;
private String username;
private String password;
//记住角色
private Set<Role> roles = new HashSet<>();
//各种getter和setter.....
}
角色实体
public class Role {
private String id;
private String name;
private String description;
//记住所有的用户
private Set<User> users = new HashSet<>();
//记住所有的权限
private Set<Privilege> privileges = new HashSet<>();
//各种getter和setter.....
}
权限实体
public class Privilege {
private String id;
private String name;
private String description;
//记住所有的角色
private Set<Role> roles = new HashSet<>();
//各种getter和setter.....
}
改良
用户和角色、角色和权限都是多对多的关系,这是毋庸置疑的!我们也按照面向对象的方法来设计,用集合来记住另一方的数据!
但是呢,我们想想:
- 在权限的Dao中,在查看权限的时候,有必要列出相对应的角色吗??
- 在角色的Dao中,在查看角色的时候,有必要列出相对应的用户吗??
答案是没有的,一般我们都不会显示出来。所以,权限的实体没必要使用Set集合来记住角色,角色实体没必要使用Set集合来记住用户!
改良后的权限实体
public class Privilege {
private String id;
private String name;
private String description;
//各种setter和getter方法
}
改良后的角色实体
public class Role {
private String id;
private String name;
private String description;
//记住所有的权限
private Set<Privilege> privileges = new HashSet<>();
//各种setter和getter方法
}
在数据库中建表 user表
CREATE TABLE user (
id VARCHAR(20) PRIMARY KEY,
username VARCHAR(20) NOT NULL,
password VARCHAR(20) NOT NULL
);
role表
CREATE TABLE role (
id VARCHAR(20) PRIMARY KEY,
name VARCHAR(20) NOT NULL,
description VARCHAR(255)
);
privilege表
CREATE TABLE privilege (
id VARCHAR(20) PRIMARY KEY,
name VARCHAR(20) NOT NULL,
description VARCHAR(255)
);
user和role的关系表
CREATE TABLE user_role (
user_id VARCHAR(20),
role_id VARCHAR(20),
PRIMARY KEY (user_id, role_id),
CONSTRAINT user_id_FK FOREIGN KEY (user_id) REFERENCES user (id),
CONSTRAINT role_id_FK FOREIGN KEY (role_id) REFERENCES role (id)
);
role和privilege的关系表
CREATE TABLE role_privilege (
role_id VARCHAR(20),
privilege_id VARCHAR(20),
PRIMARY KEY (role_id, privilege_id),
CONSTRAINT role_id_FK1 FOREIGN KEY (role_id) REFERENCES role (id),
CONSTRAINT privilege_id_FK FOREIGN KEY (privilege_id) REFERENCES privilege (id)
);
注意:user和role的关系表、role和privilege的关系都有role_id作为外键,外键的名称是不能一样的!
开发DAO PrivilegeDao
/**
* 权限的管理应该有以下的功能:
* 1.添加权限
* 2.查看所有权限
* 3.查找某个权限
*
* */
public class PrivilegeDao {
/*添加权限*/
public void addPrivilege(Privilege privilege) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO privilege (id, name, description) VALUE (?, ?, ?)";
queryRunner.update(sql, new Object[]{privilege.getId(), privilege.getName(), privilege.getDescription()});
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("添加权限失败了!");
}
}
/*查找权限*/
public Privilege findPrivilege(String id) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT *FROM privilege WHERE id = ?";
Privilege privilege = (Privilege) queryRunner.query(sql, new BeanHandler(Privilege.class), new Object[]{id});
return privilege;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("查找权限失败了!");
}
}
/*获取所有的权限*/
public List<Privilege> getAllPrivileges() {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT * FROM privilege ";
List<Privilege> privileges = (List<Privilege>) queryRunner.query(sql, new BeanListHandler(Privilege.class));
return privileges;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("查找权限失败了!");
}
}
}
测试PrivilegeDao的功能
为了测试方便,添加有参构造函数到Privilege对象中
public class PrivilegeDaoTest {
PrivilegeDao privilegeDao = new PrivilegeDao();
@Test
public void add() {
Privilege privilege = new Privilege("2", "修改", "修改功能");
privilegeDao.addPrivilege(privilege);
}
@Test
public void getAll() {
List<Privilege> list = privilegeDao.getAllPrivileges();
for (Privilege privilege : list) {
System.out.println(privilege.getId());
}
}
@Test
public void find() {
String id = "2";
Privilege privilege = privilegeDao.findPrivilege(id);
System.out.println(privilege.getName());
}
}
UserDao
public class UserDao {
public void addUser(User user) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "INSERT INTO user (id,username,password) VALUES(?,?,?)";
queryRunner.update(sql, new Object[]{user.getId(), user.getUsername(), user.getPassword()});
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("添加权限失败了!");
}
}
public User find(String id) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT * FROM user WHERE id=?";
User user = (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{id});
return user;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("添加权限失败了!");
}
}
public List<User> getAll() {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT * FORM user";
List<User> users = (List<User>) queryRunner.query(sql, new BeanListHandler(User.class));
return users;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("添加权限失败了!");
}
}
}
測試UserDao
public class UserDaoTest {
UserDao userDao = new UserDao();
@Test
public void add() {
User user = new User();
user.setId("2");
user.setUsername("qqq");
user.setPassword("123");
userDao.addUser(user);
}
@Test
public void find() {
String id = "1";
User user = userDao.find(id);
System.out.println(user.getUsername());
}
@Test
public void findALL() {
List<User> userList = userDao.getAll();
for (User user : userList) {
System.out.println(user.getUsername());
}
}
}
RoleDao
public void add(Role role){
try{
QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "insert into role(id,name,description) values(?,?,?)";
Object params[] = {role.getId(),role.getName(),role.getDescription()};
runner.update(sql, params);
}catch (Exception e) {
throw new RuntimeException(e);
}
}
public Role find(String id){
try{
QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select * from role where id=?";
return (Role) runner.query(sql, id, new BeanHandler(Role.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}
//得到所有角色
public List<Role> getAll(){
try{
QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "select * from role";
return (List<Role>) runner.query(sql, new BeanListHandler(Role.class));
}catch (Exception e) {
throw new RuntimeException(e);
}
}
测试RoleDao
RoleDao roleDao = new RoleDao();
@Test
public void add() {
Role role = new Role();
role.setId("1");
role.setName("manager");
role.setDescription("this is a manager");
roleDao.add(role);
}
@Test
public void find( ) {
String id = "1";
Role role = roleDao.find(id);
System.out.println(role.getName());
}
@Test
public void getAdd() {
List<Role> roleList = roleDao.getAll();
for (Role role : roleList) {
System.out.println(role.getName());
}
}
补充
上面的仅仅是单表的Dao功能,User和Role表是多对多的关系,Role和Privilege表也是多对多的关系。
前面已经分析了
- 在User对象中,需要一个Set集合来记住Role的关系。【显示用户的时候,应该把所有角色显示出来】
- 在Role对象中,需要一个Set集合来记住Privilege的关系【显示角色的时候,应该把所有权限显示很出来】。
所以应该在UserDao有获取某用户所有的角色的方法:
/*得到用戶的所有角色*/
public List<Role> getRoles(String user_id) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
//根據用戶id查詢所有角色,重點就在角色上,所以要有role表。然后查詢user_role表,就可以鎖定用戶id對應的角色了!
String sql = "SELECT r.* FROM role r, user_role ur WHERE ur.user_id = ? AND r.id = ur.role_id ";
List<Role> roles = (List<Role>) queryRunner.query(sql, new BeanListHandler(Role.class), new Object[]{user_id});
return roles;
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("得到用戶所有的角色失败了!");
}
}
在RoleDao有获取所有权限的方法:
//得到某角色的所有權限【權限表、權限和角色關系表】
public List<Privilege> getPrivileges(String role_id) {
try{
QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
String sql = "SELECT p.* FROM privilege p, role_privilege rp WHERE rp.role_id = ? AND p.id = rp.role_id";
List<Privilege> privileges = (List<Privilege>) runner.query(sql, new BeanListHandler(Privilege.class), new Object[]{role_id});
return privileges;
}catch (Exception e) {
throw new RuntimeException(e);
}
}
我们既然能获取得到用户所有的角色了,获取得到角色所有的权限了。那自然我们就应该有修改用户的角色功能,修改角色的权限的功能啦!
我们先来分析一下它怎么写:要修改用户所拥有的角色,应该知道修改用户是哪一个,所以需要用户的id或者User对象!修改的角色是什么,需要Role对象或者装载Role对象的集合!
在UserDao有修改某用户角色的方法,我们是想把所有的角色都删除了,再添加新的角色
//更新用戶的角色
public void updateRole(User user, List<Role> roles) {
try {
QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource());
//先把用戶原來的所有角色刪掉了
String delete = "DELETE FROM user_role WHERE user_id = ?";
queryRunner.update(delete, user.getId());
String add = "INSERT INTO user_role (user_id,role_id) VALUES(?,?)";
for (Role role : roles) {
queryRunner.update(add, new Object[]{user.getId(), role.getId()});
}
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException("添加权限失败了!");
}
}
在RoleDao有修改角色权限的方法,和上面是类似的。
//为某个角色授权
public void addPrivilege2Role(Role role, List<Privilege> privileges) {
try{
QueryRunner runner = new QueryRunner(JdbcUtils.getDataSource());
//先刪除該角色的所有權限
String delete = "DELETE FROM role_privilege WHERE role_id = ?";
runner.update(delete, new Object[]{role.getId()});
//賦予角色新的權限
String sql = "INSERT INTO role_privilege (role_id, privilege_id) VALUES (?, ?)";
for (Privilege privilege : privileges) {
runner.update(sql, new Object[]{role.getId(), privilege.getId()});
}
}catch (Exception e) {
throw new RuntimeException(e);
}
}
更新
刚才又思考了一下:
- 其实我们并不需要在User类用使用集合来维护Role,在Role中使用集合来维护Privilege。在原本的做法我们已经看到了,我们完全是不需要这两个变量也能完成效果的。
- 那么,现在问题就来了。什么时候我们才需要在实体中使用变量来维护多的一方的关系呢???我觉得是这样的:当我们在查询一方数据的时候,另一方的数据也同时需要展示。那么此时我们就应该使用集合来维护多的一方数据了。
- 基于上面一个例子,就比如:订单与订单项。当我们查看订单的时候,同时一定会把所有的订单项都列举出来。
- 再比如:当我们查看购物车的时候,就需要把所有的购物项都列举出来。
- 而我们使用展示用户的时候,并不需要第一时间就把角色列举出来,而是通过超链接来查看用户下的角色,基于这种情况,我觉得我们是不用使用集合变量来维护多的一方的数据的。
这就跟Hibernate的懒加载差不多。用到关联关系的数据的时候才加载,没有用到的时候就先不查询数据库。
ps:我不知道在这我理解得对不对,如果有错的地方希望能指出!