【JavaWeb】權限管理系統


前言

前面我們做的小項目都是一個表的,業務代碼也相對簡單。現在我們來做一個權限管理系統,體驗一下多表的業務邏輯,順便鞏固一下過濾器的知識。!


目的

現在我有一個管理商品、訂單的頁面。當用戶點擊某個超鏈接時,過濾器會檢測該用戶是否有權限!

 

這里寫圖片描述

 


需求分析

按照面向對象的思想,我們至少應該有權限(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:我不知道在這我理解得對不對,如果有錯的地方希望能指出!


開發BusinessService

UserService


	public class UserService { UserDao userDao = new UserDao(); //添加用戶 public void addUser(User user) { userDao.addUser(user); } //根據id查找用戶 public User findUser(String id) { return userDao.find(id); } //得到所有的用戶 public List<User> getAllUser() { return userDao.getAll(); } //獲取用戶所有的角色 public List<Role> getUserRole(String user_id) { return userDao.getRoles(user_id); } //修改用戶的角色 public void updateUserRole(User user, List<Role> roles) { userDao.updateRole(user, roles); } } 

RoleService


	public class RoleService { RoleDao roleDao = new RoleDao(); //添加角色 public void addRole(Role role) { roleDao.add(role); } //根據id查找角色 public Role findRole(String id) { return roleDao.find(id); } //獲取所有的角色 public List<Role> getAllRole() { return roleDao.getAll(); } //獲取角色所有的權限 public List<Privilege> getRolePrivilege(String role_id) { return roleDao.getPrivileges(role_id); } //修改角色的權限 public void updateRolePrivilege(Role role, List<Privilege> privileges) { roleDao.addPrivilege2Role(role, privileges); } } 

PrivilegeService


	public class PrivilegeService { PrivilegeDao privilegeDao = new PrivilegeDao(); //添加權限 public void addPrivilege(Privilege privilege) { privilegeDao.addPrivilege(privilege); } //根據id獲得權限 public Privilege findPrivilege(String id) { return privilegeDao.findPrivilege(id); } //獲取所有的權限 public List<Privilege> getAllPrivileges() { return privilegeDao.getAllPrivileges(); } } 

開發Web

用戶模塊

添加用戶

  • 提供頁面界面的Servlet
        //直接跳轉到顯示添加用戶的界面 request.getRequestDispatcher("/WEB-INF/jsp/addUser.jsp").forward(request, response); 
  • 顯示頁面的JSP

	<form action="AddUserController" method="post"> <table> <tr> <td>用戶名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td><input type="submit" value="添加用戶"></td> <td><input type="reset" value="重置"></td> </tr> </table> </form> 
  • 處理表單數據的Servlet

        //得到客戶端傳遞進來的參數 String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new User(); user.setId(WebUtils.makeId()); user.setUsername(username); user.setPassword(password); try { UserService userService = new UserService(); userService.addUser(user); request.setAttribute("message","添加用戶成功!"); } catch (Exception e) { request.setAttribute("message", "添加用戶失敗!"); throw new RuntimeException("在Controller添加客戶失敗"); } request.getRequestDispatcher("/message.jsp").forward(request,response); } 
  • 效果:

 

這里寫圖片描述

 


顯示用戶

  • 提供頁面界面的Servlet

        UserService userService = new UserService(); List<User> list = userService.getAllUser(); request.setAttribute("list", list); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookUser.jsp").forward(request, response); 
  • 顯示頁面JSP


<c:if test="${empty(list)}">
    對不起,暫時沒有任何客戶
</c:if>

<c:if test="${!empty(list)}">
    <table border="1px">
        <tr>
            <td>用戶名</td>
            <td>密碼</td>
        </tr>
        <c:forEach items="${list}" var="user">
            <tr>
                <td>${user.username}</td>
                <td>${user.password}</td>
            </tr>
        </c:forEach>
    </table>

</c:if>


  • 效果:

 

這里寫圖片描述

 


為用戶添加角色

在顯示用戶的基礎上,應該添加為用戶授權角色的超鏈接。



    <table border="1px">
        <tr>
            <td>用戶名</td>
            <td>密碼</td>
            <td>操作</td>
        </tr>
        <c:forEach items="${list}" var="user">
            <tr>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>
                    <a href="${pageContext.request.contextPath}/LookUserRole?user_id=${user.id}">
                        為用戶授權角色
                    </a>
                    <a href="#">修改用戶</a>
                    <a href="#">刪除用戶</a>

                </td>
            </tr>
        </c:forEach>
    </table>
  • 效果:

 

這里寫圖片描述

 

  • 處理顯示授權頁面的Servlet


        //得到客戶端傳遞過來的user_id String user_id = request.getParameter("user_id"); //獲取該用戶所有的角色 UserService userService = new UserService(); List<Role> userRoles = userService.getUserRole(user_id); //得到全部的角色 RoleService roleService = new RoleService(); List<Role> allRoles = roleService.getAllRole(); //為用戶授權的JSP頁面也應該顯示用戶的信息,所以把User對象也傳遞過去給JSP頁面 User user = userService.findUser(user_id); request.setAttribute("user", user); request.setAttribute("userRoles", userRoles); request.setAttribute("allRoles", allRoles); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookUserRole.jsp").forward(request, response); 
  • 授權頁面JSP



<table border="1px"> <tr> <td>當前用戶名稱</td> <td>${user.username}</td> </tr> <tr> <td>當前用戶所擁有的角色</td> <td> <c:forEach items="${userRoles}" var="userRole"> ${userRole.name} </c:forEach> </td> </tr> <tr> <td>當前系統所擁有的角色</td> <td> <form method="post" action="${pageContext.request.contextPath}/AddUserRole"> <%--要為用戶添加角色,需要知道是哪一個用戶,通過hidden傳遞過去用戶的id--%> <input type="hidden" name="user_id" value="${user.id}"> <c:forEach items="${allRoles}" var="roles"> <input type="checkbox" name="role_id" value="${roles.id}">${roles.name} </c:forEach> <input type="submit" value="添加角色!"> </form> </td> </tr> </table> 
  • 效果:

 

這里寫圖片描述

 

  • 處理表單數據並為用戶添加角色的Servlet


        //得到傳遞進來的role_id String[] ids = request.getParameterValues("role_id"); try { //得到想要修改哪個用戶的id String user_id = request.getParameter("user_id"); //通過id獲取得到User對象 UserService userService = new UserService(); User user = userService.findUser(user_id); //通過id獲取得到Role對象,再把對象用List集合裝載起來 RoleService roleService = new RoleService(); List<Role> list = new ArrayList<>(); for (String id : ids) { Role role = roleService.findRole(id); list.add(role); } //更新用戶所擁有的角色 userService.updateUserRole(user, list); request.setAttribute("message","添加角色成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message","添加角色失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request,response); 
  • 效果:

 

這里寫圖片描述

 


角色模塊

添加角色

  • 提供添加角色頁面的Servlet

        //直接跳轉到jsp頁面即可 request.getRequestDispatcher("WEB-INF/jsp/AddRole.jsp").forward(request, response); 
  • 顯示頁面JSP


	<form action="${pageContext.request.contextPath}/AddRoleController" method="post"> <table border="1px"> <tr> <td>角色名稱</td> <td><input type="text" name="name"></td> </tr> <tr> <td>詳細描述</td> <td><textarea name="description" cols="30" rows="10"></textarea></td> </tr> <tr> <td> <input type="submit" value="添加角色"> </td> </tr> </table> </form> 
  • 處理表單數據並添加角色的Servlet


        //得到客戶端帶過來的數據 String name = request.getParameter("name"); String description = request.getParameter("description"); try { //創建對象並封裝數據 Role role = new Role(); role.setId(WebUtils.makeId()); role.setName(name); role.setDescription(description); //調用Service方法,完成功能 RoleService roleService = new RoleService(); roleService.addRole(role); request.setAttribute("message","添加角色成功!"); } catch (Exception e) { request.setAttribute("message","添加角色失敗!"); e.printStackTrace(); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


查看所有的角色

  • 提供頁面的Servlet


        //得到所有的角色 RoleService roleService = new RoleService(); List<Role> list = roleService.getAllRole(); request.setAttribute("list", list); request.getRequestDispatcher("/WEB-INF/jsp/LookRoles.jsp").forward(request, response); 
  • 顯示頁面JSP

	<c:if test="${empty(list)}"> 您還沒有任何角色,請添加! </c:if> <c:if test="${!empty(list)}"> <table border="1px"> <tr> <td>角色名稱</td> <td>描述</td> </tr> <c:forEach items="${list}" var="role"> <tr> <td>${role.name}</td> <td>${role.description}</td> </tr> </c:forEach> </table> </c:if> 
  • 效果

 

這里寫圖片描述

 


為角色授權

與上面是類似的,我們要在查看角色的時候,添加授權的功能!


        <c:forEach items="${list}" var="role"> <tr> <td>${role.name}</td> <td>${role.description}</td> <td> <a href="${pageContext.request.contextPath}/LookRolePrivilege?role_id=${role.id}"> 為角色授權 </a> <a href="#">刪除角色</a> <a href="#">修改角色</a> </td> </tr> </c:forEach> 
  • 效果:

 

這里寫圖片描述

 


  • 提供顯示權利頁面的Servlet

        //得到瀏覽器想要查看的角色id String role_id = request.getParameter("role_id"); RoleService roleService = new RoleService(); //根據id獲取得到Role對象 Role role = roleService.findRole(role_id); //得到當前角色所有的權利 List<Privilege> rolePrivilege = roleService.getRolePrivilege(role_id); //得到系統所有的權利 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> allPrivilege = privilegeService.getAllPrivileges(); request.setAttribute("role", role); request.setAttribute("rolePrivilege", rolePrivilege); request.setAttribute("allPrivilege", allPrivilege); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookRolePrivilege.jsp").forward(request, response); 
  • 顯示頁面JSP


	<table border="1px"> <tr> <td>角色名稱</td> <td>${role.name}</td> </tr> <tr> <td>當前角色擁有的權利</td> <td> <c:forEach items="${rolePrivilege}" var="privi"> ${privi.name} </c:forEach> </td> </tr> <tr> <td>系統擁有的所有權利</td> <td> <form action="${pageContext.request.contextPath}/AddRolePrivilegeController" method="post"> <%--讓服務器知道要修改哪一個用戶,就要把用戶的id傳遞過去--%> <input type="hidden" name="role_id" value="${role.id}"> <c:forEach items="${allPrivilege}" var="privileges"> <input type="checkbox" name="privilege" value="${privileges.id}">${privileges.name} </c:forEach> <input type="submit" value="添加權利"> </form> </td> </tr> </table> 
  • 效果:

 

這里寫圖片描述

 


  • 處理表單數據並添加角色權利的Servlet


        //得到瀏覽器想要添加權利的id String[] ids = request.getParameterValues("privilege_id"); //獲取角色id String role_id = request.getParameter("role_id"); try { //得到想要添加權利的角色 RoleService roleService = new RoleService(); Role role = roleService.findRole(role_id); //得到權利對象,用List對象裝載起來 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> privileges_list = new ArrayList<>(); for (String id : ids) { Privilege privilege = privilegeService.findPrivilege(id); privileges_list.add(privilege); } roleService.updateRolePrivilege(role, privileges_list); request.setAttribute("message","為角色添加權利成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message","為角色添加權利失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


權限模塊

添加權限

  • 提供添加權限頁面的Servlet

        //直接跳轉到jsp頁面 request.getRequestDispatcher("/WEB-INF/jsp/AddPrivilege.jsp").forward(request, response); 
  • 顯示頁面JSP


	<form action="${pageContext.request.contextPath}/AddPrivilegeController" method="post"> <table border="1px"> <tr> <td>權限名字</td> <td><input type="text" name="name"></td> </tr> <tr> <td>權限描述</td> <td><textarea name="description" cols="30" rows="10"></textarea></td> </tr> <tr> <td><input type="submit" value="添加權限"></td> <td><input type="reset" value="重置"></td> </tr> </table> </form> 
  • 效果:

 

這里寫圖片描述

 


  • 處理表單數據,並添加權限的Servlet

        //得到瀏覽器帶過來的數據 String name = request.getParameter("name"); String description = request.getParameter("description"); //封裝數據到Privilege對象 Privilege privilege = new Privilege(); privilege.setId(WebUtils.makeId().substring(3,10)); privilege.setName(name); privilege.setDescription(name); try { PrivilegeService privilegeService = new PrivilegeService(); privilegeService.addPrivilege(privilege); request.setAttribute("message","添加權限成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message", "添加權限失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


查看所有權限

  • 提供頁面的Servlet



        //得到所有的權限 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> list = privilegeService.getAllPrivileges(); request.setAttribute("list", list); request.getRequestDispatcher("/WEB-INF/jsp/LookPrivileges.jsp").forward(request, response); 
  • 顯示權限頁面的JSP


	<c:if test="${empty(list)}"> 您還沒添加任何的權限 </c:if> <c:if test="${!empty(list)}"> <table border="1px"> <tr> <td>權限名稱</td> <td>描述</td> <td>操作</td> </tr> <c:forEach items="${list}" var="privilege"> <tr> <td>${privilege.name}</td> <td>${privilege.description}</td> <td> <a href="#">刪除權限</a> <a href="#">修改權限</a> </td> </tr> </c:forEach> </table> </c:if> 
  • 效果:

 

這里寫圖片描述

 


用分幀把功能拼接

  • head頁面

	<body style="text-align: center"> <h1>XX管理系統</h1> </body> 
  • left頁面

	
	<body> <a href="${pageContext.request.contextPath}/LookUserUI" target="body">用戶管理</a><br><br><br><br> <a href="${pageContext.request.contextPath}/LookRolesUI" target="body">角色管理</a><br><br><br><br> <a href="${pageContext.request.contextPath}/LookPrivileges" target="body">權限管理</a><br><br><br><br> </body> 
  • body頁面是空白的!

  • index頁面:



	<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <frameset rows="25%,*"> <frame src="head.jsp" name="head"> <frameset cols="15%,*"> <frame src="left.jsp" name="left"> <frame src="body.jsp" name="body"> </frameset> </frameset> </html> 
  • 效果:

 

這里寫圖片描述

 


過濾器

過濾器主要的工作就是:點擊超鏈接時,過濾器會檢測該點擊者是否有權限進入頁面進行操作(CURD)。

 

這里寫圖片描述

 

這里我們是這樣子做的:uri作為key,權限作為value,構成一個Map集合。當用戶請求資源的時候,判斷該資源是否需要權限,如果需要權限,就判斷該用戶是否登陸了,如果登陸了,就判斷該用戶有沒有權限去訪問該資源!

  • 在UserDao和UserService中需要添加login方法:

補充的代碼



    public User login(String username, String password) { try { QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "SELECT * FROM user WHERE username=? AND password=?"; User user = (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{username, password}); return user; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("登陸失敗了!!"); } } 
  • 登陸界面的JSP


	<form action="${pageContext.request.contextPath}/LoginController" method="post"> 用戶名:<input type="text" name="username"><br> 密碼:<input type="password" name="password"><br> <input type="submit" value="登陸"><br> </form> 
  • 處理登陸的Servlet


        //獲取表單數據 String username = request.getParameter("username"); String password = request.getParameter("password"); UserService userService = new UserService(); User user = userService.login(username, password); if (user != null) { request.setAttribute("message", "恭喜你,登陸成功了!"); request.getSession().setAttribute("user", user); } else { request.setAttribute("message","用戶名或密碼出錯了!!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 

Filter代碼

  • 完整代碼:

    private Map<String, Privilege> map = new HashMap<>(); public void init(FilterConfig config) throws ServletException { map.put("/addServlet", new Privilege("增加")); map.put("/deleteServlet", new Privilege("刪除")); map.put("/updateServlet", new Privilege("修改")); map.put("/findServlet", new Privilege("查賬單")); } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //得到用戶請求的資源地址 String uri = request.getRequestURI(); System.out.println(uri); //通過key獲取值,看看能不能獲取得到值【為空,就是不需要權限了】 if (map.get(uri) == null) { chain.doFilter(request, response); System.out.println("放行了"); return ; } //如果不為空,就是需要權限。需要權限的話,就判斷請求者是否登陸了! if (request.getSession().getAttribute("user") == null) { request.setAttribute("message", "您登陸了再來操作把!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } //如果登陸了,就查一下用戶的權限是否和訪問資源的權限匹配 User user = (User) request.getSession().getAttribute("user"); UserService userService = new UserService(); RoleService roleService = new RoleService(); //得到用戶所有的角色 List<Role> roles = userService.getUserRole(user.getId()); //通過角色,得到所有的權限【一個角色有多個權限,如果用戶角色很多,那么權限也就很多了】 //此時,我們又要用集合來裝載每一個角色的權限了! Set privileges = new HashSet(); for (Role role : roles) { List<Privilege> list = roleService.getRolePrivilege(role.getId()); privileges.addAll(list); } //得到的Set集合就是用戶所有的權限了!!!!! //集合的contains方法比較的是默認對象,而我們想要比較的是字符串名稱,所以我們要在Privilege對象中重寫equals和hashCode方法! if (!privileges.contains(map.get(uri))) { request.setAttribute("message", "你沒有權限喲"); request.getRequestDispatcher("/message.jsp").forward(request, response); return ; } //到這里,就是有權限了 chain.doFilter(request, response); } public void destroy() { } 

測試

 

這里寫圖片描述

 


總結要點

①:用戶和權限的關系,由於添加用戶的權限和修改用戶權限的不足【在權限很多的情況下,這種情況是不好處理的】,所以我們引入了角色這個概念

②:用戶與角色,角色與權限都是多對多的關系

③:按照數據庫范式,我們會創建5張實體表,其中兩張是代表着:用戶與角色、角色與權限的關系表。角色這個字段在外鍵中,不能同名!

④:無論是角色、用戶、權限都有這三個方法:得到所有的權限(角色、用戶)、添加權限(角色、用戶)、權限的id得到權限(角色、用戶)對象

⑤:根據id得到具體的對象方法的意義:在web顯示層只能通過id來標識着這個對象,然而在后端常常使用的是對象,於是就有了這個方法。

⑥:多對多之間的關系,在程序中並不是都要在其類上定義一個集合來記住對方。當顯示用戶時,需要顯示角色,但是顯示角色時,一般我們是不需要顯示用戶的信息的。因此在角色上,並不需要維護一個集合來記住所有的用戶

⑦:得到用戶的所有角色:傳入的參數必定有具體的用戶或角色,所以id必須是外界傳遞進來的。【得到角色的所有權限是同理】

⑧:修改用戶的角色:我們先把用戶的角色全部刪除了,再通過外界勾選的角色進行添加(這是一個折中的辦法)【修改角色的權限是同理】

⑨:在添加用戶角色的時候,要把用戶的id通過隱藏域傳遞進去給服務器端,不然是不知道要修改的是哪一個用戶的角色的。【修改角色的權限是同理】

⑩:frameset和frame來實現前台的分幀,target指定在哪里顯示具體的數據

①①:在init()方法中用一個Map集合,以uri作為key,以具體的權限作為值來實現過濾

①②:如果uri不需要權限,直接放行。需要權限,那么判斷該用戶是否登錄了。沒有登錄就讓用戶去登錄

①③:如果登錄了,就得到用戶所有的權限,權限用一個Set集合裝載,遍歷Set集合,使用contains()方法就可以查看出有沒有對應的權限了。

①④:使用contains()方法需要在權限類上重寫hashCode()和equals()方法的。因為我們比較的是字符串。


如果文章有錯的地方歡迎指正,大家互相交流。


作者:Java3y
鏈接:https://juejin.im/post/5a93b9e66fb9a0634e6cb2de
來源:掘金
著作權歸作者所有。商業轉載請聯系作者獲得授權,非商業轉載請注明出處。

前言

前面我們做的小項目都是一個表的,業務代碼也相對簡單。現在我們來做一個權限管理系統,體驗一下多表的業務邏輯,順便鞏固一下過濾器的知識。!


目的

現在我有一個管理商品、訂單的頁面。當用戶點擊某個超鏈接時,過濾器會檢測該用戶是否有權限!

 

這里寫圖片描述

 


需求分析

按照面向對象的思想,我們至少應該有權限(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:我不知道在這我理解得對不對,如果有錯的地方希望能指出!


開發BusinessService

UserService


	public class UserService { UserDao userDao = new UserDao(); //添加用戶 public void addUser(User user) { userDao.addUser(user); } //根據id查找用戶 public User findUser(String id) { return userDao.find(id); } //得到所有的用戶 public List<User> getAllUser() { return userDao.getAll(); } //獲取用戶所有的角色 public List<Role> getUserRole(String user_id) { return userDao.getRoles(user_id); } //修改用戶的角色 public void updateUserRole(User user, List<Role> roles) { userDao.updateRole(user, roles); } } 

RoleService


	public class RoleService { RoleDao roleDao = new RoleDao(); //添加角色 public void addRole(Role role) { roleDao.add(role); } //根據id查找角色 public Role findRole(String id) { return roleDao.find(id); } //獲取所有的角色 public List<Role> getAllRole() { return roleDao.getAll(); } //獲取角色所有的權限 public List<Privilege> getRolePrivilege(String role_id) { return roleDao.getPrivileges(role_id); } //修改角色的權限 public void updateRolePrivilege(Role role, List<Privilege> privileges) { roleDao.addPrivilege2Role(role, privileges); } } 

PrivilegeService


	public class PrivilegeService { PrivilegeDao privilegeDao = new PrivilegeDao(); //添加權限 public void addPrivilege(Privilege privilege) { privilegeDao.addPrivilege(privilege); } //根據id獲得權限 public Privilege findPrivilege(String id) { return privilegeDao.findPrivilege(id); } //獲取所有的權限 public List<Privilege> getAllPrivileges() { return privilegeDao.getAllPrivileges(); } } 

開發Web

用戶模塊

添加用戶

  • 提供頁面界面的Servlet
        //直接跳轉到顯示添加用戶的界面 request.getRequestDispatcher("/WEB-INF/jsp/addUser.jsp").forward(request, response); 
  • 顯示頁面的JSP

	<form action="AddUserController" method="post"> <table> <tr> <td>用戶名:</td> <td><input type="text" name="username"></td> </tr> <tr> <td>密碼:</td> <td><input type="password" name="password"></td> </tr> <tr> <td><input type="submit" value="添加用戶"></td> <td><input type="reset" value="重置"></td> </tr> </table> </form> 
  • 處理表單數據的Servlet

        //得到客戶端傳遞進來的參數 String username = request.getParameter("username"); String password = request.getParameter("password"); User user = new User(); user.setId(WebUtils.makeId()); user.setUsername(username); user.setPassword(password); try { UserService userService = new UserService(); userService.addUser(user); request.setAttribute("message","添加用戶成功!"); } catch (Exception e) { request.setAttribute("message", "添加用戶失敗!"); throw new RuntimeException("在Controller添加客戶失敗"); } request.getRequestDispatcher("/message.jsp").forward(request,response); } 
  • 效果:

 

這里寫圖片描述

 


顯示用戶

  • 提供頁面界面的Servlet

        UserService userService = new UserService(); List<User> list = userService.getAllUser(); request.setAttribute("list", list); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookUser.jsp").forward(request, response); 
  • 顯示頁面JSP


<c:if test="${empty(list)}">
    對不起,暫時沒有任何客戶
</c:if>

<c:if test="${!empty(list)}">
    <table border="1px">
        <tr>
            <td>用戶名</td>
            <td>密碼</td>
        </tr>
        <c:forEach items="${list}" var="user">
            <tr>
                <td>${user.username}</td>
                <td>${user.password}</td>
            </tr>
        </c:forEach>
    </table>

</c:if>


  • 效果:

 

這里寫圖片描述

 


為用戶添加角色

在顯示用戶的基礎上,應該添加為用戶授權角色的超鏈接。



    <table border="1px">
        <tr>
            <td>用戶名</td>
            <td>密碼</td>
            <td>操作</td>
        </tr>
        <c:forEach items="${list}" var="user">
            <tr>
                <td>${user.username}</td>
                <td>${user.password}</td>
                <td>
                    <a href="${pageContext.request.contextPath}/LookUserRole?user_id=${user.id}">
                        為用戶授權角色
                    </a>
                    <a href="#">修改用戶</a>
                    <a href="#">刪除用戶</a>

                </td>
            </tr>
        </c:forEach>
    </table>
  • 效果:

 

這里寫圖片描述

 

  • 處理顯示授權頁面的Servlet


        //得到客戶端傳遞過來的user_id String user_id = request.getParameter("user_id"); //獲取該用戶所有的角色 UserService userService = new UserService(); List<Role> userRoles = userService.getUserRole(user_id); //得到全部的角色 RoleService roleService = new RoleService(); List<Role> allRoles = roleService.getAllRole(); //為用戶授權的JSP頁面也應該顯示用戶的信息,所以把User對象也傳遞過去給JSP頁面 User user = userService.findUser(user_id); request.setAttribute("user", user); request.setAttribute("userRoles", userRoles); request.setAttribute("allRoles", allRoles); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookUserRole.jsp").forward(request, response); 
  • 授權頁面JSP



<table border="1px"> <tr> <td>當前用戶名稱</td> <td>${user.username}</td> </tr> <tr> <td>當前用戶所擁有的角色</td> <td> <c:forEach items="${userRoles}" var="userRole"> ${userRole.name} </c:forEach> </td> </tr> <tr> <td>當前系統所擁有的角色</td> <td> <form method="post" action="${pageContext.request.contextPath}/AddUserRole"> <%--要為用戶添加角色,需要知道是哪一個用戶,通過hidden傳遞過去用戶的id--%> <input type="hidden" name="user_id" value="${user.id}"> <c:forEach items="${allRoles}" var="roles"> <input type="checkbox" name="role_id" value="${roles.id}">${roles.name} </c:forEach> <input type="submit" value="添加角色!"> </form> </td> </tr> </table> 
  • 效果:

 

這里寫圖片描述

 

  • 處理表單數據並為用戶添加角色的Servlet


        //得到傳遞進來的role_id String[] ids = request.getParameterValues("role_id"); try { //得到想要修改哪個用戶的id String user_id = request.getParameter("user_id"); //通過id獲取得到User對象 UserService userService = new UserService(); User user = userService.findUser(user_id); //通過id獲取得到Role對象,再把對象用List集合裝載起來 RoleService roleService = new RoleService(); List<Role> list = new ArrayList<>(); for (String id : ids) { Role role = roleService.findRole(id); list.add(role); } //更新用戶所擁有的角色 userService.updateUserRole(user, list); request.setAttribute("message","添加角色成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message","添加角色失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request,response); 
  • 效果:

 

這里寫圖片描述

 


角色模塊

添加角色

  • 提供添加角色頁面的Servlet

        //直接跳轉到jsp頁面即可 request.getRequestDispatcher("WEB-INF/jsp/AddRole.jsp").forward(request, response); 
  • 顯示頁面JSP


	<form action="${pageContext.request.contextPath}/AddRoleController" method="post"> <table border="1px"> <tr> <td>角色名稱</td> <td><input type="text" name="name"></td> </tr> <tr> <td>詳細描述</td> <td><textarea name="description" cols="30" rows="10"></textarea></td> </tr> <tr> <td> <input type="submit" value="添加角色"> </td> </tr> </table> </form> 
  • 處理表單數據並添加角色的Servlet


        //得到客戶端帶過來的數據 String name = request.getParameter("name"); String description = request.getParameter("description"); try { //創建對象並封裝數據 Role role = new Role(); role.setId(WebUtils.makeId()); role.setName(name); role.setDescription(description); //調用Service方法,完成功能 RoleService roleService = new RoleService(); roleService.addRole(role); request.setAttribute("message","添加角色成功!"); } catch (Exception e) { request.setAttribute("message","添加角色失敗!"); e.printStackTrace(); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


查看所有的角色

  • 提供頁面的Servlet


        //得到所有的角色 RoleService roleService = new RoleService(); List<Role> list = roleService.getAllRole(); request.setAttribute("list", list); request.getRequestDispatcher("/WEB-INF/jsp/LookRoles.jsp").forward(request, response); 
  • 顯示頁面JSP

	<c:if test="${empty(list)}"> 您還沒有任何角色,請添加! </c:if> <c:if test="${!empty(list)}"> <table border="1px"> <tr> <td>角色名稱</td> <td>描述</td> </tr> <c:forEach items="${list}" var="role"> <tr> <td>${role.name}</td> <td>${role.description}</td> </tr> </c:forEach> </table> </c:if> 
  • 效果

 

這里寫圖片描述

 


為角色授權

與上面是類似的,我們要在查看角色的時候,添加授權的功能!


        <c:forEach items="${list}" var="role"> <tr> <td>${role.name}</td> <td>${role.description}</td> <td> <a href="${pageContext.request.contextPath}/LookRolePrivilege?role_id=${role.id}"> 為角色授權 </a> <a href="#">刪除角色</a> <a href="#">修改角色</a> </td> </tr> </c:forEach> 
  • 效果:

 

這里寫圖片描述

 


  • 提供顯示權利頁面的Servlet

        //得到瀏覽器想要查看的角色id String role_id = request.getParameter("role_id"); RoleService roleService = new RoleService(); //根據id獲取得到Role對象 Role role = roleService.findRole(role_id); //得到當前角色所有的權利 List<Privilege> rolePrivilege = roleService.getRolePrivilege(role_id); //得到系統所有的權利 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> allPrivilege = privilegeService.getAllPrivileges(); request.setAttribute("role", role); request.setAttribute("rolePrivilege", rolePrivilege); request.setAttribute("allPrivilege", allPrivilege); //跳轉到顯示頁面 request.getRequestDispatcher("/WEB-INF/jsp/LookRolePrivilege.jsp").forward(request, response); 
  • 顯示頁面JSP


	<table border="1px"> <tr> <td>角色名稱</td> <td>${role.name}</td> </tr> <tr> <td>當前角色擁有的權利</td> <td> <c:forEach items="${rolePrivilege}" var="privi"> ${privi.name} </c:forEach> </td> </tr> <tr> <td>系統擁有的所有權利</td> <td> <form action="${pageContext.request.contextPath}/AddRolePrivilegeController" method="post"> <%--讓服務器知道要修改哪一個用戶,就要把用戶的id傳遞過去--%> <input type="hidden" name="role_id" value="${role.id}"> <c:forEach items="${allPrivilege}" var="privileges"> <input type="checkbox" name="privilege" value="${privileges.id}">${privileges.name} </c:forEach> <input type="submit" value="添加權利"> </form> </td> </tr> </table> 
  • 效果:

 

這里寫圖片描述

 


  • 處理表單數據並添加角色權利的Servlet


        //得到瀏覽器想要添加權利的id String[] ids = request.getParameterValues("privilege_id"); //獲取角色id String role_id = request.getParameter("role_id"); try { //得到想要添加權利的角色 RoleService roleService = new RoleService(); Role role = roleService.findRole(role_id); //得到權利對象,用List對象裝載起來 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> privileges_list = new ArrayList<>(); for (String id : ids) { Privilege privilege = privilegeService.findPrivilege(id); privileges_list.add(privilege); } roleService.updateRolePrivilege(role, privileges_list); request.setAttribute("message","為角色添加權利成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message","為角色添加權利失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


權限模塊

添加權限

  • 提供添加權限頁面的Servlet

        //直接跳轉到jsp頁面 request.getRequestDispatcher("/WEB-INF/jsp/AddPrivilege.jsp").forward(request, response); 
  • 顯示頁面JSP


	<form action="${pageContext.request.contextPath}/AddPrivilegeController" method="post"> <table border="1px"> <tr> <td>權限名字</td> <td><input type="text" name="name"></td> </tr> <tr> <td>權限描述</td> <td><textarea name="description" cols="30" rows="10"></textarea></td> </tr> <tr> <td><input type="submit" value="添加權限"></td> <td><input type="reset" value="重置"></td> </tr> </table> </form> 
  • 效果:

 

這里寫圖片描述

 


  • 處理表單數據,並添加權限的Servlet

        //得到瀏覽器帶過來的數據 String name = request.getParameter("name"); String description = request.getParameter("description"); //封裝數據到Privilege對象 Privilege privilege = new Privilege(); privilege.setId(WebUtils.makeId().substring(3,10)); privilege.setName(name); privilege.setDescription(name); try { PrivilegeService privilegeService = new PrivilegeService(); privilegeService.addPrivilege(privilege); request.setAttribute("message","添加權限成功!"); } catch (Exception e) { e.printStackTrace(); request.setAttribute("message", "添加權限失敗!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 
  • 效果:

 

這里寫圖片描述

 


查看所有權限

  • 提供頁面的Servlet



        //得到所有的權限 PrivilegeService privilegeService = new PrivilegeService(); List<Privilege> list = privilegeService.getAllPrivileges(); request.setAttribute("list", list); request.getRequestDispatcher("/WEB-INF/jsp/LookPrivileges.jsp").forward(request, response); 
  • 顯示權限頁面的JSP


	<c:if test="${empty(list)}"> 您還沒添加任何的權限 </c:if> <c:if test="${!empty(list)}"> <table border="1px"> <tr> <td>權限名稱</td> <td>描述</td> <td>操作</td> </tr> <c:forEach items="${list}" var="privilege"> <tr> <td>${privilege.name}</td> <td>${privilege.description}</td> <td> <a href="#">刪除權限</a> <a href="#">修改權限</a> </td> </tr> </c:forEach> </table> </c:if> 
  • 效果:

 

這里寫圖片描述

 


用分幀把功能拼接

  • head頁面

	<body style="text-align: center"> <h1>XX管理系統</h1> </body> 
  • left頁面

	
	<body> <a href="${pageContext.request.contextPath}/LookUserUI" target="body">用戶管理</a><br><br><br><br> <a href="${pageContext.request.contextPath}/LookRolesUI" target="body">角色管理</a><br><br><br><br> <a href="${pageContext.request.contextPath}/LookPrivileges" target="body">權限管理</a><br><br><br><br> </body> 
  • body頁面是空白的!

  • index頁面:



	<%@ page contentType="text/html;charset=UTF-8" language="java" %> <html> <head> <title>$Title$</title> </head> <frameset rows="25%,*"> <frame src="head.jsp" name="head"> <frameset cols="15%,*"> <frame src="left.jsp" name="left"> <frame src="body.jsp" name="body"> </frameset> </frameset> </html> 
  • 效果:

 

這里寫圖片描述

 


過濾器

過濾器主要的工作就是:點擊超鏈接時,過濾器會檢測該點擊者是否有權限進入頁面進行操作(CURD)。

 

這里寫圖片描述

 

這里我們是這樣子做的:uri作為key,權限作為value,構成一個Map集合。當用戶請求資源的時候,判斷該資源是否需要權限,如果需要權限,就判斷該用戶是否登陸了,如果登陸了,就判斷該用戶有沒有權限去訪問該資源!

  • 在UserDao和UserService中需要添加login方法:

補充的代碼



    public User login(String username, String password) { try { QueryRunner queryRunner = new QueryRunner(JdbcUtils.getDataSource()); String sql = "SELECT * FROM user WHERE username=? AND password=?"; User user = (User) queryRunner.query(sql, new BeanHandler(User.class), new Object[]{username, password}); return user; } catch (Exception e) { e.printStackTrace(); throw new RuntimeException("登陸失敗了!!"); } } 
  • 登陸界面的JSP


	<form action="${pageContext.request.contextPath}/LoginController" method="post"> 用戶名:<input type="text" name="username"><br> 密碼:<input type="password" name="password"><br> <input type="submit" value="登陸"><br> </form> 
  • 處理登陸的Servlet


        //獲取表單數據 String username = request.getParameter("username"); String password = request.getParameter("password"); UserService userService = new UserService(); User user = userService.login(username, password); if (user != null) { request.setAttribute("message", "恭喜你,登陸成功了!"); request.getSession().setAttribute("user", user); } else { request.setAttribute("message","用戶名或密碼出錯了!!"); } request.getRequestDispatcher("/message.jsp").forward(request, response); 

Filter代碼

  • 完整代碼:

    private Map<String, Privilege> map = new HashMap<>(); public void init(FilterConfig config) throws ServletException { map.put("/addServlet", new Privilege("增加")); map.put("/deleteServlet", new Privilege("刪除")); map.put("/updateServlet", new Privilege("修改")); map.put("/findServlet", new Privilege("查賬單")); } public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws ServletException, IOException { HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) resp; //得到用戶請求的資源地址 String uri = request.getRequestURI(); System.out.println(uri); //通過key獲取值,看看能不能獲取得到值【為空,就是不需要權限了】 if (map.get(uri) == null) { chain.doFilter(request, response); System.out.println("放行了"); return ; } //如果不為空,就是需要權限。需要權限的話,就判斷請求者是否登陸了! if (request.getSession().getAttribute("user") == null) { request.setAttribute("message", "您登陸了再來操作把!"); request.getRequestDispatcher("/message.jsp").forward(request, response); return; } //如果登陸了,就查一下用戶的權限是否和訪問資源的權限匹配 User user = (User) request.getSession().getAttribute("user"); UserService userService = new UserService(); RoleService roleService = new RoleService(); //得到用戶所有的角色 List<Role> roles = userService.getUserRole(user.getId()); //通過角色,得到所有的權限【一個角色有多個權限,如果用戶角色很多,那么權限也就很多了】 //此時,我們又要用集合來裝載每一個角色的權限了! Set privileges = new HashSet(); for (Role role : roles) { List<Privilege> list = roleService.getRolePrivilege(role.getId()); privileges.addAll(list); } //得到的Set集合就是用戶所有的權限了!!!!! //集合的contains方法比較的是默認對象,而我們想要比較的是字符串名稱,所以我們要在Privilege對象中重寫equals和hashCode方法! if (!privileges.contains(map.get(uri))) { request.setAttribute("message", "你沒有權限喲"); request.getRequestDispatcher("/message.jsp").forward(request, response); return ; } //到這里,就是有權限了 chain.doFilter(request, response); } public void destroy() { } 

測試

 

這里寫圖片描述

 


總結要點

①:用戶和權限的關系,由於添加用戶的權限和修改用戶權限的不足【在權限很多的情況下,這種情況是不好處理的】,所以我們引入了角色這個概念

②:用戶與角色,角色與權限都是多對多的關系

③:按照數據庫范式,我們會創建5張實體表,其中兩張是代表着:用戶與角色、角色與權限的關系表。角色這個字段在外鍵中,不能同名!

④:無論是角色、用戶、權限都有這三個方法:得到所有的權限(角色、用戶)、添加權限(角色、用戶)、權限的id得到權限(角色、用戶)對象

⑤:根據id得到具體的對象方法的意義:在web顯示層只能通過id來標識着這個對象,然而在后端常常使用的是對象,於是就有了這個方法。

⑥:多對多之間的關系,在程序中並不是都要在其類上定義一個集合來記住對方。當顯示用戶時,需要顯示角色,但是顯示角色時,一般我們是不需要顯示用戶的信息的。因此在角色上,並不需要維護一個集合來記住所有的用戶

⑦:得到用戶的所有角色:傳入的參數必定有具體的用戶或角色,所以id必須是外界傳遞進來的。【得到角色的所有權限是同理】

⑧:修改用戶的角色:我們先把用戶的角色全部刪除了,再通過外界勾選的角色進行添加(這是一個折中的辦法)【修改角色的權限是同理】

⑨:在添加用戶角色的時候,要把用戶的id通過隱藏域傳遞進去給服務器端,不然是不知道要修改的是哪一個用戶的角色的。【修改角色的權限是同理】

⑩:frameset和frame來實現前台的分幀,target指定在哪里顯示具體的數據

①①:在init()方法中用一個Map集合,以uri作為key,以具體的權限作為值來實現過濾

①②:如果uri不需要權限,直接放行。需要權限,那么判斷該用戶是否登錄了。沒有登錄就讓用戶去登錄

①③:如果登錄了,就得到用戶所有的權限,權限用一個Set集合裝載,遍歷Set集合,使用contains()方法就可以查看出有沒有對應的權限了。

①④:使用contains()方法需要在權限類上重寫hashCode()和equals()方法的。因為我們比較的是字符串。


如果文章有錯的地方歡迎指正,大家互相交流。學習Java和想學java的朋友如果需要交流和學習資 料這里介紹一個Java技術交流群:318261748 有免費的 學習資料提供給大家,群里都是學習Java的朋友,有什 么問題都可以一起交流互相學習進步!




免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM