基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【七】【菜单维护模块】

       大家在阅读本章的时候大家一定要把上一章的代码从GitHub上拿下来先,因此本章的以及后续章节的所有的Java代码都是基于上一章节的代码因此大家一定要记得把上一章的代码全部给clone下来,否则本章的代码大家将无法运行起来。

       通过上一章节我们已经完成了我们的基本架构的开发工作,那么这一章我们将开发我们的菜单维护模块,实现对菜单的增删改查的功能,该模块的菜单树使用的是ztree的前端js的代码,首先在我们开发该模块的时候我们需要到WebMvcConfig中增加如下配置:


接着我们开始编写我们的菜单模块的代码首先建如下的文件路径,同时我们实现我们的菜单维护的业务逻辑:


首先是treeList.html的页面的代码(该页面使用了bootstrap和ztree)

<html xmlns:th="http://www.thymeleaf.org"
>
<head th:include="include/includebase"></head>
<body>
<div id="content" class="row-fluid">
    <div class="col-md-3 " style="margin-top: 10px;">
        <ul id="menu_tree" class="ztree" style="width:560px; overflow:auto;"></ul>
    </div>
</div>
<script th:inline="javascript">
    var zTree;
    var demoIframe;
    var selectNode;

    function addHoverDom(treeId, treeNode) {
        var sObj = $("#" + treeNode.tId + "_span");
        if (treeNode.editNameFlag || $("#addBtn_"+treeNode.tId).length>0) return;
        var addStr = "<span class='button remove' id='removeBtn_" + treeNode.tId + "' title='add node' οnfοcus='this.blur();'></span>";
        addStr += "<span class='button add' id='addBtn_" + treeNode.tId + "'></span>";
        addStr += "<span class='button edit' id='editBtn_" + treeNode.tId + "'></span>";
        if(treeNode.isParent){
            addStr += "<span class='button add' id='addParentBtn_" + treeNode.tId + "'></span>";
        }
        sObj.after(addStr);
        var btn = $("#addBtn_"+treeNode.tId);
        if (btn) btn.bind("click", function(){
            zTree = $.fn.zTree.getZTreeObj("menu_tree");
            selectNode = treeNode;
            window.Ewin.dialog({title:"添加",url:"tree/addTreePage?id="+treeNode.id,width:400,height:650})
            return false;
        });
        var remove_btn = $("#removeBtn_"+treeNode.tId);
        if (remove_btn) remove_btn.bind("click", function() {
            zTree = $.fn.zTree.getZTreeObj("menu_tree");
            if (treeNode.isParent) {
                window.Ewin.alert({message:"请先删除当前菜单节点底下的子菜单!"});
            }else{
                window.Ewin.confirm({title: '提示', message: '是否要删除您当前选中的菜单节点?', width: 500}).on(function (e) {
                    if (e) {
                        $.post("tree/remove",{id:treeNode.id},function(e){
                            if(e.result){
                                zTree.removeNode(treeNode);
                                window.Ewin.alert({message:e.msg});
                            }else{
                                window.Ewin.alert({message:e.msg});
                            }
                        })
                    }
                });
            }
            return false;
        });
        var edit_btn = $("#editBtn_"+treeNode.tId);
        if (edit_btn) edit_btn.bind("click", function(){
            zTree = $.fn.zTree.getZTreeObj("menu_tree");
            selectNode = treeNode;
            window.Ewin.dialog({title:"修改",url:"tree/updateTreePage?id="+treeNode.id,width:400,height:650})
            return false;
        });
        var add_parent_btn = $("#addParentBtn_"+treeNode.tId);
        if (add_parent_btn) add_parent_btn.bind("click", function(){
            zTree = $.fn.zTree.getZTreeObj("menu_tree");
            selectNode = null;
            window.Ewin.dialog({title:"添加",url:"tree/addTreePage",width:400,height:650})
            return false;
        })
    };

    function removeHoverDom(treeId, treeNode) {
        $("#addBtn_"+treeNode.tId).unbind().remove();
        $("#removeBtn_"+treeNode.tId).unbind().remove();
        $("#editBtn_"+treeNode.tId).unbind().remove();
        $("#addParentBtn_"+treeNode.tId).unbind().remove();
    };

    var setting = {
        check: {
            enable: false
        },
        view: {
            addHoverDom: addHoverDom,
            removeHoverDom: removeHoverDom,
            dblClickExpand: false,
            showLine: true,
            selectedMulti: false
        },
        data: {
            simpleData: {
                enable:true,
                idKey: "id",
                pIdKey: "pId",
                rootPId: "0"
            }
        },
        callback: {
            beforeClick: function(treeId, treeNode) {
                var zTree = $.fn.zTree.getZTreeObj('menu_tree');
                if (treeNode.isParent) {
                    zTree.expandNode(treeNode);
                    return false;
                } else {
                    return true;
                }
            }
        }
    };

    function loadReady() {
        var bodyH = demoIframe.contents().find("body").get(0).scrollHeight,
            htmlH = demoIframe.contents().find("html").get(0).scrollHeight,
            maxH = Math.max(bodyH, htmlH), minH = Math.min(bodyH, htmlH),
            h = demoIframe.height() >= maxH ? minH:maxH;
        if (h < 530){
            h = 530;
        }
        demoIframe.height(h);
    }

    $(function() {
        $.post("/tree/loadUserTree",function(info){
            var t = $("#menu_tree");
            t = $.fn.zTree.init(t, setting,info.data);
        })
    });

</script>
</body>
</html>
接着是add.html增加菜单的页面的代码:

<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<body>
<form id="treeForm"  role="form" method="post" action="tree/save">
    <input type="hidden" name="pId" th:value="${entity.id}" />
    <div class="form-group" >
        <label >父菜单名称:</label>
        <input type="text" class="form-control" th:value="${entity.name}" readonly="readonly"  />
    </div>
    <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="url">菜单地址:</label>
        <input type="text" class="form-control" name="url" id="url"  placeholder="请输入菜单地址" />
    </div>
    <div class="form-group">
        <label for="icon">菜单样式:</label>
        <input type="text" class="form-control" name="icon" id="icon"  placeholder="请输入菜单样式" />
    </div>
    <div class="form-group">
        <label for="url">菜单编码:</label>
        <input type="text" class="form-control" name="code" id="code"  placeholder="请输入菜单编码" />
    </div>
    <div class="form-group">
        <label for="treeOrder">菜单顺序:</label>
        <input type="text" class="form-control" name="treeOrder" id="treeOrder"  placeholder="请输入菜单顺序" />
    </div>
    <div class="form-group">
        <label >菜单状态:</label>
        <label  class='radio-inline'><input type='radio' name='state' value='1'  checked="checked"  />可用</label>
        <label  class='radio-inline'><input type='radio' name='state' value='0'   />禁用</label>
    </div>
</form>
<script th:inline="javascript">
    <![CDATA[
    $(function () {
        $('#treeForm').bootstrapValidator({
            message: 'This value is not valid',
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                name: {
                    message: '菜单名称验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单名称不能为空'
                        }
                    }
                },
                url: {
                    message: '菜单地址验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单地址不能为空'
                        }
                    }
                },
                code: {
                    message: '菜单编码验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单编码不能为空'
                        }
                    }
                },
                treeOrder: {
                    message: '菜单顺序验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单顺序不能为空'
                        },
                        regexp: {
                            regexp: /^[0-9_]+$/,
                            message: '菜单顺序必须为数字'
                        },
                        stringLength: {
                            min: 1,
                            max: 18,
                            message: '菜单顺序必须在1到18位之间'
                        }
                    }
                }
            }
        })

        // 绑定dialog的确定按钮的监听事件
        $("#btnOk",window.top.document).click(function() {

            var bootstrapValidator = $("#treeForm", window.top.document).data('bootstrapValidator');
            bootstrapValidator.validate();
            if(bootstrapValidator.isValid()){
                var zTree = $(window.parent.document).contents().find(".tab-pane.fade.active.in iframe")[0].contentWindow.zTree;
                var selectNode = $(window.parent.document).contents().find(".tab-pane.fade.active.in iframe")[0].contentWindow.selectNode;
                $.post($("#treeForm",window.top.document).attr('action'),$("#treeForm",window.top.document).serialize(),function(e){
                    if(e.result){
                        $('.modal-dialog', window.top.document).parent('div').remove()
                        $('body', window.top.document).find('.modal-backdrop').remove();
                        var entity = e.entity;
                        zTree.addNodes(selectNode, {id:entity.id, pId:entity.pId, name:entity.name});
                        window.Ewin.alert({message:'增加数据成功!'});
                    }else{
                        window.Ewin.alert({message:'增加数据失败!'});
                    }
                })
            }
        });

    })
    ]]>
</script>
</body>
</html>

最后是update.html修改菜单页面的代码:

<html xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity4">
<body>
<form id="treeForm"  role="form" method="post" action="tree/update">
    <input type="hidden" name="pId" th:value="${entity.tree.id}" />
    <input type="hidden" name="id" th:value="${entity.id}" />
    <div class="form-group" >
        <label >父菜单名称:</label>
        <input type="text" class="form-control" th:value="${entity.tree.name}" readonly="readonly"  />
    </div>
    <div class="form-group">
        <label for="name">菜单名称:</label>
        <input type="text" class="form-control" name="name" id="name"  th:value="${entity.name}" placeholder="请输入菜单名称" />
    </div>
    <div class="form-group">
        <label for="url">菜单地址:</label>
        <input type="text" class="form-control" name="url" id="url" th:value="${entity.url}" placeholder="请输入菜单地址" />
    </div>
    <div class="form-group">
        <label for="icon">菜单样式:</label>
        <input type="text" class="form-control" name="icon" id="icon" th:value="${entity.icon}"  placeholder="请输入菜单样式" />
    </div>
    <div class="form-group">
        <label for="url">菜单编码:</label>
        <input type="text" class="form-control" name="code" id="code" th:value="${entity.code}"  placeholder="请输入菜单编码" />
    </div>
    <div class="form-group">
        <label for="treeOrder">菜单顺序:</label>
        <input type="text" class="form-control" name="treeOrder" id="treeOrder" th:value="${entity.treeOrder}" placeholder="请输入菜单顺序" />
    </div>
    <div class="form-group">
        <label for="treeOrder">菜单状态:</label>
        <label  class='radio-inline'><input type='radio' name='state' value='1' th:checked="${entity.state} == 1?true:false"   />可用</label>
        <label  class='radio-inline'><input type='radio' name='state' value='0' th:checked="${entity.state} == 0?true:false"   />禁用</label>
    </div>
</form>
<script th:inline="javascript">
    <![CDATA[
    $(function () {
        $('#treeForm').bootstrapValidator({
            message: 'This value is not valid',
            feedbackIcons: {
                valid: 'glyphicon glyphicon-ok',
                invalid: 'glyphicon glyphicon-remove',
                validating: 'glyphicon glyphicon-refresh'
            },
            fields: {
                name: {
                    message: '菜单名称验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单名称不能为空'
                        }
                    }
                },
                url: {
                    message: '菜单地址验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单地址不能为空'
                        }
                    }
                },
                code: {
                    message: '菜单编码验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单编码不能为空'
                        }
                    }
                },
                treeOrder: {
                    message: '菜单顺序验证失败',
                    validators: {
                        notEmpty: {
                            message: '菜单顺序不能为空'
                        },
                        regexp: {
                            regexp: /^[0-9_]+$/,
                            message: '菜单顺序必须为数字'
                        },
                        stringLength: {
                            min: 1,
                            max: 18,
                            message: '菜单顺序必须在1到18位之间'
                        }
                    }
                }
            }
        })

        // 绑定dialog的确定按钮的监听事件
        $("#btnOk",window.top.document).click(function() {
            var bootstrapValidator = $("#treeForm", window.top.document).data('bootstrapValidator');
            bootstrapValidator.validate();
            if(bootstrapValidator.isValid()){
                var zTree = $(window.parent.document).contents().find(".tab-pane.fade.active.in iframe")[0].contentWindow.zTree;
                var selectNode = $(window.parent.document).contents().find(".tab-pane.fade.active.in iframe")[0].contentWindow.selectNode;
                $.post($("#treeForm",window.top.document).attr('action'),$("#treeForm",window.top.document).serialize(),function(e){
                    if(e.result){
                        $('.modal-dialog', window.top.document).parent('div').remove()
                        $('body', window.top.document).find('.modal-backdrop').remove();
                        var entity = e.entity;
                        selectNode.name = entity.name;
                        zTree.updateNode(selectNode);
                        window.Ewin.alert({message:'修改数据成功!'});
                    }else{
                        window.Ewin.alert({message:'修改数据失败!'});
                    }
                })
            }
        });
    })
    ]]>
</script>
</body>
</html>

到此我们完成了菜单模块的开发工作,由于java代码我们在上一章已经完成了全部的开发因此此处就不再继续陈述了,开发完成以后大家可以直接运行程序查看结果如下:

本章代码的GitHub地址:https://github.com/185594-5-27/csdndemo/tree/master-base-tree


上一篇文章地址:基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【六】【引入bootstrap前端框架】


下一篇文章地址:基于springboot+bootstrap+mysql+redis搭建一套完整的权限架构【八】【完善整个项目】


QQ交流群:578746866



课程简介: 历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring Boot、Spring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:
©️2020 CSDN 皮肤主题: 数字20 设计师:CSDN官方博客 返回首页