后台管理(二)

1、权限控制

        如果没有权限控制,系统的功能完全不设防,全部暴露在所有用户面前。用户登录以后可以使用系统中的所有功能。这是实际运行中不能接受的,所以权限控制系统的目标就是管理用户行为,保护系统功能。

1.1定义资源

        资源就是系统中需要保护起来的功能。具体形式很多:URL 地址、controller方法、service 方法、页面元素等等都可以定义为资源使用权限控制系统保护起来。

1.2创建权限

        一个功能复杂的项目会包含很多具体资源,成千上万都有可能。这么多资源逐个进行操作太麻烦了。为了简化操作,可以将相关的几个资源封装到一起,打包成一个“权限”同时分配给有需要的人。

1.3、 创建角色

        对于一个庞大系统来说,一方面需要保护的资源非常多,另一方面操作系统的人也非常多。把资源打包为权限是对操作的简化,同样把用户划分为不同角色也是对操作的简化。否则直接针对一个个用户进行管理就会很繁琐。所以角色就是用户的分组、分类。先给角色分配权限,然后再把角色分配给用户,用户以这个角色的身份操作系统就享有角色对应的权限了。

1.4 管理用户

        系统中的用户其实是人操作系统时用来登录系统的账号、密码。

1.5、 建立关联关系

权限→资源:单向多对多

  1. Java 类之间单向:从权限实体类可以获取到资源对象的集合,但是通过资源获取不到权限

  2. 数据库表之间多对多:

    • 一个权限可以包含多个资源

    • 一个资源可以被分配给多个不同权限

角色→权限:单向多对多

  1. Java 类之间单向:从角色实体类可以获取到权限对象的集合,但是通过权限获取不到角色

  2. 数据库表之间多对多:

    • 一个角色可以包含多个权限

    • 一个权限可以被分配给多个不同角色

用户→角色:双向多对多

  1. Java 类之间双向:可以通过用户获取它具备的角色,也可以看一个角色下包含哪些用户

  2. 数据库表之间:

    • 一个角色可以包含多个用户

    • 一个用户可以身兼数职

2、RBAC 权限模型

2.1 概念

        鉴于权限控制的核心是用户通过角色权限进行关联,所以前面描述的权限控制系统可以提炼为一个模型:RBAC(Role-Based Access Control,基于角色的访问控制)。在 RBAC 模型中,一个用户可以对应多个角色,一个角色拥有多个权限,权限具体定义用户可以做哪些事情。

2.2.1 RBAC0

        最基本的 RBAC 模型,RBAC 模型的核心部分,后面三种升级版 RBAC 模型也都是建立在 RBAC0 的基础上。

2.2.2 RBAC1

        在 RBAC0 的基础上增加了角色之间的继承关系。角色 A 继承角色 B 之后将具备 B 的权限再增加自己独有的其他权限。比如:付费会员角色继承普通会员角色,那么付费会员除了普通会员的权限外还具备浏览付费内容的权限

2.2.3 RBAC2

        在 RBAC0 的基础上进一步增加了角色责任分离关系。责任分离关系包含静态责任分离和动态责任分离两部分。

  1. 静态责任分离:给用户分配角色时生效

    • 互斥角色:权限上相互制约的两个或多个角色就是互斥角色。用户只能被分配到一组互斥角色中的一个角色。例如:一个用户不能既有会计师角色又有审计师角色。

    • 基数约束:

      • 一个角色对应的访问权限数量应该是受限的

      • 一个角色中用户的数量应该是受限的

      • 一个用户拥有的角色数量应该是受限的

    • 先决条件角色:用户想拥有 A 角色就必须先拥有 B 角色,从而保证用户拥有 X 权限的前提是拥有 Y 权限。

  2. 动态责任分离:用户登录系统时生效

    • 一个用户身兼数职,在特定场景下激活特定角色

2.2.4 RBAC3

        RBAC3 是在 RBAC0 的基础上同时添加 RBAC2 和 RBAC3 的约束,最全面、最复杂

3、角色维护:

3.1、创建角色表

/*
 Navicat Premium Data Transfer

 Source Server         : localhost
 Source Server Type    : MySQL
 Source Server Version : 80034
 Source Host           : localhost:3306
 Source Schema         : project_crowd

 Target Server Type    : MySQL
 Target Server Version : 80034
 File Encoding         : 65001

 Date: 01/11/2023 11:36:13
*/

SET NAMES utf8mb4;
SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------
-- Table structure for t_role
-- ----------------------------
DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role`  (
  `id` int NOT NULL AUTO_INCREMENT,
  `name` char(100) CHARACTER SET utf8mb3 COLLATE utf8mb3_general_ci NULL DEFAULT NULL,
  PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDB CHARACTER SET = utf8mb3 COLLATE = utf8mb3_general_ci ROW_FORMAT = Dynamic;

SET FOREIGN_KEY_CHECKS = 1;

3.2、使用插件逆向工程

这个就不说啦!

3.3、分页查询:

3.3.1、关键字查询

展示

 <div class="table-responsive">
     <table class="table  table-bordered">
       <thead>
           <tr>
              <th width="30"><input type="checkbox"></th>
              <th width="50">编号</th>
              <th>名称</th>
              <th width="100">操作</th>
           </tr>
       </thead>
     <tbody id="rolePageBody">
     </tbody>
       <tfoot>
          <tr>
              <td colspan="6" align="center">
                 <div id="Pagination" class="pagination"><!-- 这里显示分页 --></div>
              </td>
          </tr>
       </tfoot>
    </table>
</div>

js

// 声明专门的函数显示确认模态框
function showConfirmModal(roleArray) {

    // 打开模态框
    $("#confirmModal").modal("show");

    // 清除旧的数据
    $("#roleNameDiv").empty();

    // 在全局变量范围创建数组用来存放角色id
    window.roleIdArray = [];

    // 遍历roleArray数组
    for(var i = 0; i < roleArray.length; i++) {
        var role = roleArray[i];
        var roleName = role.roleName;
        $("#roleNameDiv").append(roleName+"<br/>");

        var roleId = role.roleId;

        // 调用数组对象的push()方法存入新元素
        window.roleIdArray.push(roleId);
    }

}

// 执行分页,生成页面效果,任何时候调用这个函数都会重新加载页面
function generatePage() {

    // 1.获取分页数据
    var pageInfo = getPageInfoRemote();

    // 2.填充表格
    fillTableBody(pageInfo);

}

// 远程访问服务器端程序获取pageInfo数据
function getPageInfoRemote() {

    // 调用$.ajax()函数发送请求并接受$.ajax()函数的返回值
    var ajaxResult = $.ajax({
        "url": "role/get/page/info.json",
        "type":"post",
        "data": {
            "pageNum": window.pageNum,
            "pageSize": window.pageSize,
            "keyword": window.keyword
        },
        "async":false,
        "dataType":"json"
    });

    console.log(ajaxResult);

    // 判断当前响应状态码是否为200
    var statusCode = ajaxResult.status;

    // 如果当前响应状态码不是200,说明发生了错误或其他意外情况,显示提示消息,让当前函数停止执行
    if(statusCode != 200) {
        layer.msg("失败!响应状态码="+statusCode+" 说明信息="+ajaxResult.statusText);
        return null;
    }

    // 如果响应状态码是200,说明请求处理成功,获取pageInfo
    var resultEntity = ajaxResult.responseJSON;

    // 从resultEntity中获取result属性
    var result = resultEntity.result;

    // 判断result是否成功
    if(result == "FAILED") {
        layer.msg(resultEntity.message);
        return null;
    }

    // 确认result为成功后获取pageInfo
    var pageInfo = resultEntity.data;

    // 返回pageInfo
    return pageInfo;
}

// 填充表格
function fillTableBody(pageInfo) {

    // 清除tbody中的旧的内容
    $("#rolePageBody").empty();

    // 这里清空是为了让没有搜索结果时不显示页码导航条
    $("#Pagination").empty();

    // 判断pageInfo对象是否有效
    if(pageInfo == null || pageInfo == undefined || pageInfo.list == null || pageInfo.list.length == 0) {
        $("#rolePageBody").append("<tr><td colspan='4' align='center'>抱歉!没有查询到您搜索的数据!</td></tr>");

        return ;
    }

    // 使用pageInfo的list属性填充tbody
    for(var i = 0; i < pageInfo.list.length; i++) {

        var role = pageInfo.list[i];

        var roleId = role.id;

        var roleName = role.name;

        var checkboxTd = "<td><input id='"+roleId+"' class='itemBox' type='checkbox'></td>";
        var numberTd = "<td>"+(i+1)+"</td>";
        var roleNameTd = "<td>"+roleName+"</td>";

        var checkBtn = "<button type='button' class='btn btn-success btn-xs'><i class=' glyphicon glyphicon-check'></i></button>";

        // 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
        var pencilBtn = "<button id='"+roleId+"' type='button' class='btn btn-primary btn-xs pencilBtn'><i class=' glyphicon glyphicon-pencil'></i></button>";

        // 通过button标签的id属性(别的属性其实也可以)把roleId值传递到button按钮的单击响应函数中,在单击响应函数中使用this.id
        var removeBtn = "<button id='"+roleId+"' type='button' class='btn btn-danger btn-xs removeBtn'><i class=' glyphicon glyphicon-remove'></i></button>";

        var buttonTd = "<td>"+checkBtn+" "+pencilBtn+" "+removeBtn+"</td>";

        var tr = "<tr>"+numberTd+checkboxTd+roleNameTd+buttonTd+"</tr>";

        $("#rolePageBody").append(tr);
    }

    // 生成分页导航条
    generateNavigator(pageInfo);
}

// 生成分页页码导航条
function generateNavigator(pageInfo) {

    // 获取总记录数
    var totalRecord = pageInfo.total;

    // 声明相关属性
    var properties = {
        "num_edge_entries": 3,
        "num_display_entries": 5,
        "callback": paginationCallBack,
        "items_per_page": pageInfo.pageSize,
        "current_page": pageInfo.pageNum - 1,
        "prev_text": "上一页",
        "next_text": "下一页"
    }

    // 调用pagination()函数
    $("#Pagination").pagination(totalRecord, properties);
}

// 翻页时的回调函数
function paginationCallBack(pageIndex, jQuery) {

    // 修改window对象的pageNum属性
    window.pageNum = pageIndex + 1;

    // 调用分页函数
    generatePage();

    // 取消页码超链接的默认行为
    return false;

}

展示调用的分页函数  

    $(function () {
        //初始化数据
        window.pageNum = 1;
        window.pageSize = 5;
        window.keyword = "";

        //调用分页函数
        generatePage();

        $("#searchBtn").click(function () {
            //获取关键字数据
            window.keyword = $("#keywordInput").val();
            //调用函数
            generatePage();
        });
    })
3.3.2、添加角色

创建模态框jsp:默认是放在最后的位置

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<div id="addModal" class="modal fade" tabindex="-1" role="dialog">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal" aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">创筹网系统弹窗</h4>
            </div>
            <div class="modal-body">
                <form class="form-signin" role="form">
                    <div class="form-group has-success has-feedback">
                        <input
                                type="text" name="roleName"
                                class="form-control" id="inputSuccess4" placeholder="请输入角色名称" autofocus>
                    </div>
                </form>
            </div>
            <div class="modal-footer">
                <button id="saveRoleBtn" type="button" class="btn btn-primary"> 保存
                </button>
            </div>
        </div>
    </div>
</div>

点击添加展示模态框


        //点击添加打开模态框
        $("#showAddModalBtn").click(function () {
            $("#addModal").modal("show");

        });

前端操作:


        //获取模态框中的数据,然后发送请求
        $("#saveRoleBtn").click(function () {
            let roleName = $.trim($("#addModal [name=roleName]").val());

            // 发送异步请求
            $.ajax({
                "url": "role/save.json",
                "type": "post",
                "data": {
                    "name": roleName
                },
                "dataType":"json",
                "success":function (response) {
                    let result = response.result;
                    if (result=="SUCCESS"){
                        layer.msg("操作成功!");
                        //重新加载分页
                        window.pageNum=999999;
                        generatePage();
                    }
                    if (result=="FAILED"){
                        layer.msg("操作失败!"+response.message)
                    }
                },
                "error":function (response) {
                    layer.msg(response.status+"" +response.statusText)
                }
            });

            //关闭模态框
            $("#addModal").modal("hide");

            //清理模态框
            $("#addModal [name=roleName]").val("")

        });

controller

 @ResponseBody
    @RequestMapping(value = "/role/save.json")
    public ResultEntity<String> saveRole(Role role){
        roleService.saveRole(role);
        return ResultEntity.successWithoutData();
    }

service

    /**
     * @description: 添加角色
     * @author: 斗痘侠
     * @date: 2023/11/1 19:21
     * @param: role
     **/
    @Override
    public void saveRole(Role role) {
        roleMapper.insertSelective(role);
    }
3.3.3、修改角色

前端:


        //给更新按钮绑定事件

        $("#updateRoleBtn").click(function () {
            if(confirm("确定更新嘛")){
                //获取角色名称
                let roleName = $("#editModal [name=roleName]").val();

                $.ajax({
                    "url": "role/update.json",
                    "type":"post",
                    "data":{
                        "id":window.roleId,
                        "name":roleName
                    },
                    "dataType":"json",
                    "success": function (response) {
                        let result = response.result;
                        if (result == "SUCCESS") {
                            layer.msg("操作成功!");
                            //重新加载分页
                            generatePage();
                        }
                        if (result == "FAILED") {
                            layer.msg("操作失败!" + response.message)
                        }
                    },
                    "error": function (response) {
                        layer.msg(response.status + "" + response.statusText)
                    }

                });
                $("#editModal").modal("hide");
            }
        });

controller

    @ResponseBody
    @RequestMapping(value = "/role/update.json")
    public ResultEntity<String> updateRole(Role role){
        roleService.updateRole(role);
        return ResultEntity.successWithoutData();
    }

service

/**
     * @description: 更新操作
     * @author: 斗痘侠
     * @date: 2023/11/2 8:15
     * @param: role
     **/
    @Override
    public void updateRole(Role role) {
        roleMapper.updateByPrimaryKey(role);
    }
3.3.4、删除角色:

模态框:

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html lang="zh-CN">
<div id="confirmModal" class="modal fade" tabindex="-1" role="dialog">
    <div class="modal-dialog" role="document">
        <div class="modal-content">
            <div class="modal-header">
                <button type="button" class="close" data-dismiss="modal"
                        aria-label="Close">
                    <span aria-hidden="true">&times;</span>
                </button>
                <h4 class="modal-title">创筹网系统弹窗</h4>
            </div>
            <div class="modal-body">
                <h4>请确认是否要删除下列角色:</h4>
                <div id="roleNameDiv" style="text-align: center;"></div>
            </div>
            <div class="modal-footer">
                <button id="removeRoleBtn" type="button" class="btn btn-primary">确认删除</button>
            </div>
        </div>
    </div>
</div>
3.3.4.1、单选删除:
//点击模态框删除
        $("#removeRoleBtn").click(function () {
            var requestBody=JSON.stringify(window.roleIdArray);

            $.ajax({
                "url":"role/remove/by/role/id/array.json",
                "type":"psot",
                "data":requestBody,
                "contentType":"application/json;charset=UTF-8",
                "dataTpe":"json",
                "success": function (response) {
                    let result = response.result;
                    if (result == "SUCCESS") {
                        layer.msg("操作成功!");
                        //重新加载分页
                        generatePage();
                    }
                    if (result == "FAILED") {
                        layer.msg("操作失败!" + response.message)
                    }
                },
                "error": function (response) {
                    layer.msg(response.status + "" + response.statusText)
                }
            });
            //关闭模态框
            $("#confirmModal").modal("hide");
        });
        
        
        //单挑删除
        $("#rolePageBody").on("click", ".removeBtn", function () {
            let roleName = $(this).parent().prev().text();

            //创建rile对象
            var roleArray=[{
                roleId:this.id,
                roleName:roleName
            }];
            showConfirmModal(roleArray);
        });
3.3.4.2、多选删除:
    //全选全不选
        $("#summaryBox").click(function () {
            //获取当前的状态
            let checkedStatus = this.checked;

            //改变属性值
            $(".itemBox").prop("checked",checkedStatus);


        });



        $("#rolePageBody").on("click",".itemBox",function () {
            //获取当前已经选中的itemBox的数量

            let checkedBoxCount = $(".itemBox:checked").length;

            //总的
            let totalBoxCount = $(".itemBox").length;

            //使用二者来比较结果设置总的checkbox
            $("#summaryBox").prop("checked",checkedBoxCount == totalBoxCount);

        });


        // 12.给批量删除的按钮绑定单击响应函数
        $("#batchRemoveBtn").click(function(){

            // 创建一个数组对象用来存放后面获取到的角色对象
            var roleArray = [];

            // 遍历当前选中的多选框
            $(".itemBox:checked").each(function(){

                // 使用this引用当前遍历得到的多选框
                var roleId = this.id;

                // 通过DOM操作获取角色名称
                var roleName = $(this).parent().next().text();

                roleArray.push({
                    "roleId":roleId,
                    "roleName":roleName
                });
            });

            // 检查roleArray的长度是否为0
            if(roleArray.length == 0) {
                layer.msg("请至少选择一个执行删除");
                return ;
            }

            // 调用专门的函数打开模态框
            showConfirmModal(roleArray);
            location.reload();
        });

        因为实现单选删除和多选删除的操作,可以实现使用一个操作,从前端获取的数据是一个数组,如果是传递一个参数就是单选删除,如果是多个参数的话就是多选删除。

controller:

 @ResponseBody
    @RequestMapping(value = "/role/remove/by/role/id/array.json")
    public ResultEntity<String> removeByRoleIdArray(@RequestBody List<Integer> roleIdList){

        roleService.removeRole(roleIdList);
        return ResultEntity.successWithoutData();
    }

service

  /**
     * @description:  批量删除
     * @author: 斗痘侠
     * @date: 2023/11/2 8:16
     * @param: roleList
     **/
    @Override
    public void removeRole(List<Integer> roleList) {

        RoleExample roleExample = new RoleExample();
        RoleExample.Criteria criteria = roleExample.createCriteria();
        criteria.andIdIn(roleList);
        roleMapper.deleteByExample(roleExample);
    }

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值