【JavaWeb】許可權管理系統

Java3y發表於2018-02-26

前言

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


目的

現在我有一個管理商品、訂單的頁面。當使用者點選某個超連結時,過濾器會檢測該使用者是否有許可權!

這裡寫圖片描述


需求分析

按照物件導向的思想,我們至少應該有許可權(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資源的同學,可以關注微信公眾號:Java3y

相關文章