1. 程式人生 > >許可權管理系統實現思路(SpringCloud+Thymeleaf)(二)

許可權管理系統實現思路(SpringCloud+Thymeleaf)(二)

許可權分配

   下面主要來說說Thymeleaf模板使用和許可權分配的實現思路。
   先看效果圖:
在這裡插入圖片描述
在這裡插入圖片描述
   實現該功能的思路是:傳往前端的資料為Map,該Map以columnName(許可權分欄名)為key,以該分欄下的所有許可權為value。因為要回顯許可權是否選中,這裡為許可權實體類(Perm)定義了一個屬性checkedFlag(預設為false)

private boolean checkedFlag = false;

   角色管理功能中,首先將得到columnList,遍歷columnList,然後以columnId查詢屬於該分欄下的所有許可權得到permList,根據roleId查詢許可權對映表(permmapping)得到mappingList,如果某個permId既在permList中又在mappingList中,說明該許可權為選中狀態。

@GetMapping("/assignPerm")
    public ModelAndView assignPerm(@RequestParam int roleId,@RequestParam String roleName){
        //許可權分欄集合
        List<Column> columnList = columnService.findColumnList();
        Role role = roleService.findRoleById(roleId);
        ResultEntity resultEntity = new ResultEntity();
        //獲取當前的方法名
        String methodName = new Exception().getStackTrace()[0].getMethodName();
        resultEntity.setResultCode("200");
        resultEntity.setOperMessage(CLASS_NAME+"---"+methodName);
        resultEntity.setResultObject(role);
        resultEntity.setResultList(columnList);
        HashMap<String, List<?>> map = new HashMap<>();
        List<PermMapping> mappingList = permMappingService.findMappingListByRole(roleId);
        for(Column column:columnList){
            //獲取該分欄下的所有許可權(permList)
            List<Perm> permList= permService.findPermByColumn(column.getColumnId());

            //遍歷permList
            for(Perm perm:permList){
                for(PermMapping permMapping:mappingList){
                    if(permMapping.getPermId()==perm.getPermId()){
                        //當對映關係集合mappingList中物件的permId與permList中物件permId相同時,將permChecked的狀態設定為true
                        perm.setCheckedFlag(true);
                    }
                }
            }

            //以許可權所屬的columnName(分欄名)為key,以該columnName下的permList(許可權勾選物件集合)為value
            map.put(column.getColumnName(),permList);
        }
        resultEntity.setResultListMap(map);
        ModelAndView modelAndView = new ModelAndView();
        modelAndView.addObject("resultEntity",resultEntity);
        modelAndView.setViewName("/roleOper");
        return modelAndView;
    }

   看這部分對應的前端:

<div class="step clearfix" th:each="column:${resultEntity.resultList}">
                <div class="classify">
                    <div class="checkbox_item">
                        <input type="checkbox" name="checkGroup" th:name="'checkGroup_'+${column.columnId}" value="checkbox" th:value="${column.columnName}" class="ui-checkbox" id="user" th:id="${column.columnName}">
                        <label for="user" th:for="${column.columnName}" class="ui-label blod" th:text="${column.columnName}">文章管理</label>
                    </div>
                </div>
                <div class="qx_item">
                    <div class="checkbox_item" th:each="perm:${resultEntity.resultListMap['__${column.columnName}__']}">
                        <input type="checkbox" value="ckeck_item" id="ckeck_item" th:checked="${perm.checkedFlag}" name="ckeck_item" th:name="'checkItem_'+${perm.columnId}" th:value="${perm.permId}" th:id="${perm.permId}" class="ui-checkbox" date="cms_manage" th:title="${perm.checkedFlag}">
                        <label for="ckeck_item" th:for="${perm.permId}" th:text="${perm.permName}" class="ui-label">文章分類管理</label>
                    </div>
                </div>
            </div>

   從上面的程式碼中可以看出,許可權分欄下的所有checkbox的值為該許可權的id。Thymeleaf能夠接收Map型別的值,Map的取值方式為
map['key'],如果key是變數的話,取值方式為map['__${variable}__']。
   其中,許可權分欄的checkbox的name屬性是以checkGroup為字首,以columnId為字尾,以下劃線分隔。許可權的checkbox的name屬性是以checkItem為字首,以它所屬的columnId為字尾,以下劃線分隔。全選的checkbox的name屬性的值為checkAll

th:name="'checkGroup_'+${column.columnId}"
th:name="'checkItem_'+${perm.columnId}"
name="checkAll"

下面就是js中checkbox全選和反選的邏輯:

var totalLength = $(":checkbox[name!='checkAll']").length;
            var checkedLength = 0;

            $(":checkbox[name^='checkGroup']").each(
                function(){
                    var perffix = 'checkItem';
                    var suffix = $(this).attr('name').split('_')[1];
                    var itemLength = $(":checkbox[name^='"+perffix+"'][name$='"+suffix+"']").length;
                    var itemCheckedLength = $(":checkbox[name^='"+perffix+"'][name$='"+suffix+"']:checked").length;
                    if(itemCheckedLength == itemLength){
                        this.checked = true;
                        checkedLength+=itemLength+1;
                    }
                    var flag = this.checked;
                    $(":checkbox[name^='"+perffix+"'][name$='"+suffix+"']").each(
                        function(){
                            this.checked = flag;
                        }
                    );
                    if(checkedLength==totalLength){
                        $(":checkbox[name='checkAll']").attr("checked",true);
                    }
                }
            );

            $(":checkbox[name^='checkGroup']").click(
                function(){
                    var perffix = 'checkItem';
                    var suffix = $(this).attr('name').split('_')[1];

                    var flag = this.checked;
                    $(":checkbox[name^='"+perffix+"'][name$='"+suffix+"']").each(
                        function(){
                            this.checked = flag;
                        }
                    );

                }
            );

            $(":checkbox[name^='checkItem']").click(function(){
                var suffix = $(this).attr('name').split('_')[1];
                var itemLength = $(":checkbox[name^='checkItem'][name$='"+suffix+"']").length;
                var itemCheckedLength = $(":checkbox[name^='checkItem'][name$='"+suffix+"']:checked").length;
                if(itemCheckedLength == itemLength){
                    $(":checkbox[name^='checkGroup'][name$='"+suffix+"']").attr("checked",true);
                }else{
                    $(":checkbox[name^='checkGroup'][name$='"+suffix+"']").attr("checked",false);
                }
            });


            $(":checkbox[name!='checkAll']").click(function () {
                var checkedLength = $(":checkbox[name!='checkAll']:checked").length;
                if(checkedLength == totalLength){
                    $(":checkbox[name='checkAll']").attr("checked",true);
                }else{
                    $(":checkbox[name='checkAll']").attr("checked",false);
                }
            });

            /*全選*/
            $(":checkbox[name^='checkAll']").click(
                function () {
                    var flag = this.checked;
                    $(":checkbox").each(
                        function () {
                            this.checked = flag;
                        }
                    )
                }

            );

   如果某個許可權被選中,就將該許可權Id加入permIdArray(許可權陣列)

var permIdArray = new Array();
            $("#submitBtn").click(
                function () {
                    var roleId = $("#roleId").val().trim();
                    var roleName = $("#roleName").val().trim();
                    var roleInfo = $("#roleInfo").val().trim();
                    var creatorName = 'admin';
                    console.info("date: "+getNowFormatDate());
                    console.info("roleId: "+roleId);
                    $(":checkbox[name^='checkItem']:checked").each(
                        function () {
                            permIdArray.push($(this).val());
                            console.info("permIdArray: "+$(this).val());

                        }
                    );

   為方便描述對映關係,這裡定義了一個MappingEntity(對映實體類)

public class MappingEntity {

    private int primeMapId;//主對映(一對多的一方)
    private int[] minorMapIdArray;//從對映(一對多的多方)
    private String primeMapName;
    private String primeMapInfo;
    private String creatorName;
    private Date createTime;


    public int getPrimeMapId() {
        return primeMapId;
    }

    public void setPrimeMapId(int primeMapId) {
        this.primeMapId = primeMapId;
    }

    public int[] getMinorMapIdArray() {
        return minorMapIdArray;
    }

    public void setMinorMapIdArray(int[] minorMapIdArray) {
        this.minorMapIdArray = minorMapIdArray;
    }

    public String getPrimeMapName() {
        return primeMapName;
    }

    public void setPrimeMapName(String primeMapName) {
        this.primeMapName = primeMapName;
    }

    public String getPrimeMapInfo() {
        return primeMapInfo;
    }

    public void setPrimeMapInfo(String primeMapInfo) {
        this.primeMapInfo = primeMapInfo;
    }

    public String getCreatorName() {
        return creatorName;
    }

    public void setCreatorName(String creatorName) {
        this.creatorName = creatorName;
    }

    public Date getCreateTime() {
        return createTime;
    }

    public void setCreateTime(Date createTime) {
        this.createTime = createTime;
    }
}

勾選中後提交的請求

$.ajax({
                        url: [[@{/admin/assignPerm.asy}]],
                        type: 'post',
                        dataType: 'json',
                        contentType: 'application/json',
                        data: JSON.stringify({primeMapId:roleId,minorMapIdArray : permIdArray,primeMapName : roleName,primeMapInfo : roleInfo,creatorName : creatorName}),
                        async: true,
                        success: function(data){
                            if(data != null){
                                alert(data.hintMsg);
                                if(data.operFlag == true){
                                    window.location.reload();
                                }else{
                                    $(".role_box").hide();
                                }

                        }

                        }
                    });
                });

   在分配許可權的實現過程中,涉及到多次分配許可權的問題。首先看看對映表是否存在該對映,如果不存在,說明是第一次分配許可權,直接插入即可;如果存在,說明是不是第一次分配許可權,要獲取上一次許可權Id的list,比較前端傳過來的陣列,將多餘的刪除,缺少的插入。通過ArrayCompare這個工具來實現

public class ArrayCompare {


    /*第一個引數list獨有的部分*/
    public static List<Integer> fristOwn(List<Integer> list,int[] array){

        int[] array1 = listToArray(list);

        List<Integer> fristOwnList=new ArrayList<>();

        for (int num:array1) {
            if (Arrays.binarySearch(array, num)<0){
                fristOwnList.add(num);
            }
        }


        return fristOwnList;
    }


    /*第二個引數list獨有的部分*/
    public static List<Integer> secondOwn(List<Integer> list,int[] array){

        int[] array1 = listToArray(list);

        List<Integer> secondOwnList=new ArrayList<>();

        for (int num:array) {
            if (Arrays.binarySearch(array1, num)<0){
                secondOwnList.add(num);
            }
        }


        return secondOwnList;
    }


    public static int[] listToArray(List<Integer> list){


        int[] array = new int[list.size()];

        for(int i=0;i<list.size();i++){
            array[i]=list.get(i);
        }
        return array;

    }

}

   許可權分配的程式碼邏輯

 @PostMapping("/assignPerm.asy")
    public void addPermMapping(@RequestBody MappingEntity mappingEntity, HttpServletResponse resp) throws Exception{

        //時間格式
        Date date=new Date();
        Timestamp timeStamp = new Timestamp(date.getTime());

        System.out.println(timeStamp.toString());
        JSONObject jsonObject = new JSONObject();
        String hintMsg = null;
        boolean operFlag = false;

        //查詢之前是否存在對映關係
        List<Integer> permIdList = permMappingService.permIdList(mappingEntity.getPrimeMapId());


        int[] minorMapIdArray = mappingEntity.getMinorMapIdArray();
        if(minorMapIdArray == null){
            hintMsg = "前端傳遞的資料為空!!!";
        }else{
            if(permIdList.size()==0){
                //將role-perm對映關係插入permmapping表
                List<PermMapping> permMappingList = new ArrayList<>();

                for(int i=0;i<minorMapIdArray.length;i++){
                    //建立PermMapping物件,存放 role-perm 的對映資訊
                    PermMapping permMapping = new PermMapping();
                    permMapping.setRoleId(mappingEntity.getPrimeMapId());
                    permMapping.setPermId(minorMapIdArray[i]);
                    permMapping.setCreatorName(mappingEntity.getCreatorName());
                    permMapping.setCreateTime(timeStamp);

                    //將role-perm 的對映資訊存入permMappingList
                    permMappingList.add(permMapping);
                }
                permMappingService.addPermMappingList(permMappingList);

                hintMsg = "插入資料成功!!!";
                operFlag = true;
            }else{

                //需要刪除的部分
                List<Integer> deleteList = ArrayCompare.fristOwn(permIdList, minorMapIdArray);
                //需要新增的部分
                List<Integer> insertList = ArrayCompare.secondOwn(permIdList, minorMapIdArray);


                if(deleteList.size()>0){
                    ArrayList<PermMapping> permMappingList = new ArrayList<>();
                    for(Integer permId:deleteList){
                        PermMapping permMapping = new PermMapping();
                        permMapping.setPermId(permId);
                        permMapping.setRoleId(mappingEntity.getPrimeMapId());
                        permMappingList.add(permMapping);
                    }
                    permMappingService.deletePermMappingList(permMappingList);
                }


                if(insertList.size()>0){
                    List<PermMapping> permMappingList = new ArrayList<>();
                    for(int permId:insertList){
                        //建立PermMapping物件,存放 role-perm 的對映資訊
                        PermMapping permMapping = new PermMapping();
                        permMapping.setRoleId(mappingEntity.getPrimeMapId());
                        permMapping.setPermId(permId);
                        permMapping.setCreatorName(mappingEntity.getCreatorName());
                        permMapping.setCreateTime(timeStamp);

                        //將role-perm 的對映資訊存入permMappingList
                        permMappingList.add(permMapping);
                    }

                    permMappingService.addPermMappingList(permMappingList);
                }


                hintMsg = "插入資料成功!!!";
                operFlag = true;

            }

        }

        jsonObject.put("hintMsg",hintMsg);
        jsonObject.put("operFlag",operFlag);
        System.out.println(jsonObject.toJSONString());
        resp.setContentType("text/html;charset=UTF-8");
        resp.getWriter().println(jsonObject.toJSONString());
        resp.getWriter().close();

    }

   如果系統中的使用者與角色的關係也是1對N的話,給使用者分配角色的思路也是一樣的。

許可權校驗

   系統中除了登入,註冊,退出操作以外的所有請求都要進行攔截(這裡我在考慮能否用閘道器攔截)。根據請求攜帶的session或cookie得到當前的使用者資訊。去資料庫查詢該使用者的所有許可權(建議將許可權資訊存入redis中),看看使用者是否有當前操作的許可權,如果沒有,進行提示。