权限系统控制

权限系统控制概述

权限管理基于角色访问控制(RBAC:Role Based Access Control),这种模型的基本概念是把权限(Permission)与角色(Role)联系在一起,用户通过充当合适角色从而获得该角色所拥有的权限

PageHelper 插件

  1. 添加依赖

    <dependency>
        <groupId>com.github.pagehelper</groupId>
        <artifactId>pagehelper-spring-boot-starter</artifactId>
        <version>1.3.0</version>
    </dependency>
    
  2. 配置分页插件
    #在application.properties中配置
    pagehelper.reasonable=true
    pagehelper.page-size-zero=true
    
  3. 使用分页插件提供的 PageInfo 类进行分页7要素的封装,替换掉我们自己写的PageResult类,在需要进行分页的查询方法前调用PageHelper.startPage 静态方法即可,紧跟在这个方法后的第一个查询方法会进行分页

    @Override
    public PageInfo<Department> query(QueryObject qo) {
         
        PageHelper.startPage(qo.getCurrentPage(),qo.getPageSize());
        List<Department> departments = departmentMapper.selectForList(qo);
        return new PageInfo<>(departments);
    }
    

前端 twbs-pagination 分页插件

  1. 导入相关js文件

  2. 在想要进行分页条显示的地方添加以下代码

    <ul id="pagination" class="pagination"></ul>
    <script th:inline="javascript">
        //分页
        $(function(){
           
            var totalPages = /*[[${pageInfo.pages}]]*/ 1; //如果${pageInfo.pages}为空,就把1赋给totalPages
            var startPage = /*[[${pageInfo.pageNum}]]*/ 1;//如果${pageInfo.pageNum}为空,就把1赋给startPage
            $('#pagination').twbsPagination({
           
                totalPages: totalPages,
                startPage:startPage,
                first:'首页',
                prev:'上一页',
                next:'下一页',
                last:'尾页',
                visiblePages: 5,
                onPageClick: function (event, page) {
           
                    console.log(page);//点击哪一页,就打印当前点击的页码
                    //给隐藏按钮的value属性赋值
                    $('#currentPage').val(page);
                    //提交表单
                    $('#searchForm').submit();
                }
            });
        })
    </script>
    
    • 如果有多个页面也需要分页功能,可以通过Thymeleaf 的fragment 方式进行抽取

      //要抽取的代码放入下面的标签中
      <div th:fragment="page" style="text-align: center;">
      ............
      </div>
      
      //页面通过Thymeleaf的th:replace对以上抽取的代码块进行引用
      <div th:replace="common/fragment :: page"></div>
      

Bootstrap 模态框

部门添加

请添加图片描述
请添加图片描述

  1. 将模态框放在页面 body 元素的直接子元素中即可
<div 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>
                <form action="/department/saveOrUpdate" method="post">
                    <input type="hidden" name="id">
                    <div class="modal-body">
                        <div class="form-group">
                            <label for="name">名称</label>
                            <input type="text" class="form-control" name="name" id="name" placeholder="名称">
                        </div>
                        <div class="form-group">
                            <label for="sn">缩写</label>
                            <input type="text" class="form-control" name="sn" id="sn" placeholder="缩写">
                        </div>
                    </div>
                    <div class="modal-footer">
                        <button type="submit" class="btn btn-primary">保存</button>
                        <button type="button" class="btn btn-default" data-dismiss="modal">关闭</button>
                    </div>
                </form>
            </div>
        </div>
    </div>
  1. 通过给添加按钮绑定点击事件,点击之后弹出模态框
<script>
    $(function () {
   
        $('.btn-input').click(function () {
   
            $('.modal').modal('show');
        })
    })
</script>

<a href="#" class="btn btn-success btn-input">添加</a>

部门修改

请添加图片描述

编辑回显,当用户点击编辑按钮的时候,在模态框中回显要编辑的数据

  1. 使用jquery的API实现

  2. 用AJAX,通过获取被修改数据的id值,处理方法中根据id查询部门数据返回JSON

  3. 把数据统一藏在编辑按钮上的data-json属性,点击编辑按钮后,在事件中获取该按钮 data-json 属性中的值,并使用 DOM 操作回显在模态框中

  4. 在对应的实体类中添加一个 get 方法,用于返回 JSON 字符串数据

$(function () {
        $('.btn-input').click(function () {
            var $data = $(this);
            //{name: '人力部', id: 1, sn: 'hr'}
            var data = $data.data('json');
            //console.log(data);
            //清除模板框中的value
            $('.modal input').val('');
            if(data){//如果有数据才进行回显
                $('input[name=id]').val(data.id);
                $('input[name=name]').val(data.name);
                $('input[name=sn]').val(data.sn);
            }
            $('.modal').modal('show');//官方文档中表示通过该方法即可弹出模态框
        })
})

<a href="#" th:data-json="${d.json}" class="btn btn-info btn-xs btn-input">编辑</a>
public String getJson() throws JsonProcessingException {
   
    Map<String,Object> map = new HashMap<>();
    map.put("id",id);
    map.put("name",name);
    map.put("sn",sn);
    return new ObjectMapper().writeValueAsString(map);
}

部门删除

软删除:

(del字段为bit类型,如果被删除了,就为true,没有被删除,就为false)

通过给数据库表中增加一列字段,类型为boolean,如果点击了删除按钮,执行操作时sql语句的编写为:

<update id="delete">  update department set del = 1 where id = #{
   id}</update>

在查询时,由于页面不再显示被删除的数据,因此在查询时需要加过滤条件,只查询del字段为false的数据:

<select id="selectForList" resultType="cn.kjcoder.domain.Department">  select id,name,sn from department where del = false</select>

硬删除:

使用弹框框架,引入弹框依赖文件,使用官方提供的案例进行修改

<a th:url="|/department/delete?id=${d.id}|" class="btn btn-danger btn-xs btn-delete"> 删除 </a>
$('.btn-delete').click(function () {
          //获取删除按钮的url属性
          var url = $(this).attr('url');
          Swal.fire({
                title: '您确定要删除吗?',
                text: "此操作不可撤销!",
                icon: 'warning',
                showCancelButton: true,
                confirmButtonColor: '#3085d6',
                cancelButtonColor: '#d33',
                confirmButtonText: '确定',
                cancelButtonText: '取消'
           }).then((result) => {
                console.log(result.value);//是否删除,是输出true,否则输出未定义
                if(result.value) {
                    // 点了确定做什么,由开发者决定
                    location.href = url;
                }
           });
})

如果多个页面也需要进行删除操作,可以把删除的操作代码单独抽取到一个js文件中

权限加载

请添加图片描述

  • 通过点击权限加载按钮发送异步请求
  • 后台处理方法对请求进行处理,通过反射获取所有控制器对象的处理方法(可以通过应用上下文获取到容器中的所有bean对象|控制器对象|),获取每个控制器字节码对象,反射获取其中的方法,并且拿到方法上的自定义注解,把注解里面属性值取出并封装到Permission对象中之后批量保存到数据库权限表中,并返回json数据
  • 若贴有自定义注解,则从注解中获取权限名称和权限表达式,还要判断这个方法的权限表达式是否已经存在数据库中,若该权限表达式不存在数据库,则创建 Permission 对象,封装数据并存入数据库中,若已存在,则不进行保存操作(实体类需重写hashCode和equals方法)
  • 前端通过回调函数获取后端返回的json数据,若成功跳转查询所有,若加载失败,提示友好信息
<!--html-->
<script>
    $(function () {
     
        $('.btn-reload').click(function () {
     
            Swal.fire({
     
                title: '您确定要加载权限吗?',
                text: "此操作不可撤销!",
                icon: 'warning',
                showCancelButton: true,
                confirmButtonColor: '#3085d6',
                cancelButtonColor: '#d33',
                confirmButtonText: '确定',
                cancelButtonText: '取消'
            }).then((result) => {
     
                //console.log(1);
                if(result.value){
     
                    $.post('/permission/load',function (data) {
     
                        //console.log(data);
                        if(data.success){
     
                            location.href = '/permission/list';
                        }else{
     
                            alert(data.msg);
                        }
                    })
                }
            });
        })
    })
</script>
//自定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RequiredPermission {
   
    String name();
    String expression();
}

@Autowired
private ApplicationContext ac;

@RequestMapping("/load")
@ResponseBody
public JsonResult load(){
   
    List<Permission> permissions = permissionService.listAll();
    //存要被保存的权限对象
    Set<Permission> savePermissions = new LinkedHashSet<>();
    try {
   
        Map<String, Object> map = ac.getBeansWithAnnotation(Controller.class);
        Collection<Object> controllers = map.values();
        //遍历所有控制器对象
        for (Object controller : controllers) {
   
            //获取每个控制器字节码对象,反射获取其中的方法
            Method[] methods = controller.getClass().getDeclaredMethods();
            for (Method method : methods){
   
                //获取方法上的自定义注解
                RequiredPermission annotation = method.getAnnotation(RequiredPermission.class);
                //若方法贴了注解,获取注解属性值封装到permission对象中
                if(annotation != null){
   
                    Permission permission = new Permission();
                    permission.setName(annotation.name());
                    permission.setExpression(annotation.expression());

                    //不存在,才往集合中添加
                    if(!permissions.contains(permission)){
   
                        savePermissions.add(permission);
                    }

                }
            }
        }

        /*if(savePermissions.size() > 0){
                //批量保存
                permissionService.batchSave(savePermissions);
            }*/
        permissionService.batchSave(savePermissions);
    } catch (Exception e) {
   
        return new JsonResult(false,"权限加载失败");
    }
    return new JsonResult(true,"权限加载成功");
}
//映射配置文件中进行批量保存操作
<insert id="insertPermission">
  insert into permission (name, expression)  values
  <foreach collection="savePermissions" item="p" separator=",">
    (#{p.name},#{p.expression})
  </foreach>
</insert>

角色保存

请添加图片描述

  1. 应前端页面需要权限数据,可以在controller将所有权限查询出来存入model,页面通过Thymeleaf 将所有权限显示在左边下拉框中
@RequestMapping("/input")
@RequiredPermission(name="角色新增或修改",expression="role:saveOrUpdate")
public String input(Long id, Model model){
   
    if (id != null) {
    // 表示去修改
        Role role = roleService.get(id);
        model.addAttribute("role", role);
    }
    List<Permission> permissions = permissionService.listAll();
    model.addAttribute("permissions",permissions);
    return "role/input";
}
  1. 点击保存按钮,提交表单,在这之前要选中右边下拉框中的所有option,因为下拉框只会提交选中的数据,若没有选中的数据是不会提交的,这样会导致右边没有被选中就提交不了要保存的权限信息

(修改按钮为普通按钮,通过绑定点击事件,在事件中把右边的 select 元素中的 option 设置为选中后,再提交表单)

$(function () {
   
    //点击保存按钮,提交表单
    $('.btn-submit').click(function () {
   
        //把右边的所有复选框的selected属性都设为true
        $('.selfPermissions > option').prop('selected',true);
        //提交表单
        $('#editForm').submit();
    })
})
  1. 接收对应参数,调用业务方法,业务方法中除了往role表插入数据外,还需要往中间表插入关系数据
//controller层
@RequestMapping("/saveOrUpdate")
@RequiredPermission(name="角色新增或修改",expression="role:saveOrUpdate")
public String saveOrUpdate(Role role,Long[] permissionIds){
   
    if(role.getId()  == null){
   
        roleService.save(role,permissionIds);
    }else {
   
        roleService.update(role,permissionIds);
    }
    return "redirect:/role/list";
}
//service
@Override
public void save(Role role, Long[] permissionIds) {
   
    roleMapper.insert(role);
    //除了录入角色表的数据外,还要往中间表中录入数据
    if(permissionIds != null && permissionIds.length > 0){
   
        for (Long permissionId : permissionIds) {
   
       
  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值