• springboot2.x+security+vue2.x后台管理框架---菜单管理(五)


    菜单管理

    一、数据库构建

    -- longzy.sys_menu definition
    
    CREATE TABLE `sys_menu` (
      `menuid` int(20) NOT NULL AUTO_INCREMENT COMMENT '菜单id',
      `name` varchar(200) NOT NULL COMMENT '菜单名称',
      `parentid` int(20) NOT NULL COMMENT '父菜单id',
      `path` varchar(255) DEFAULT NULL COMMENT '菜单url',
      `perms` longtext COMMENT '权限',
      `menutype` varchar(1) NOT NULL COMMENT '菜单类型(0目录,1菜单,2按钮)',
      `icon` varchar(100) DEFAULT NULL COMMENT '菜单图标',
      `orderno` int(20) DEFAULT NULL COMMENT '排序号',
      `createuser` int(20) NOT NULL COMMENT '创建人',
      `createtime` date NOT NULL COMMENT '创建时间',
      `effective` varchar(1) NOT NULL COMMENT '有效状态',
      `destory` varchar(1) NOT NULL COMMENT '注销状态',
      PRIMARY KEY (`menuid`)
    ) ENGINE=InnoDB AUTO_INCREMENT=1000000007 DEFAULT CHARSET=utf8mb4 COMMENT='菜单表';
    

    在这里插入图片描述

    二、前端与后台实现

    1、前端效果

    在这里插入图片描述

    2、自定义tag

    效果:
    在这里插入图片描述
    自定义tag:

    <template>
        <div class="tag">
            <span class="title">{{title}}span>
            <el-tag :size="size"
                v-for="tag in tagData"
                :key="tag.code"
                :class="{active: tag.code == active}"
                @click="handleTag(tag)"
            >
            {{tag.label}}
            el-tag>
    
        div>
    
    template>
    
    <script>
    export default {
        name: 'myTag',
        props: {
            title: {
                type: String,
                default: ''
            },
            size: {
                type: String,
                default: ''
            },
            tagData: {
                type: Array,
                default: () => []
            }
        },
        data(){
            return{
                active: ''
            }
        },
        methods: {
            handleTag(tag){
                if (this.active != tag.code){
                    this.active = tag.code
                    this.$emit('handleTag', tag)
                }else {
                    this.active = ''
                    this.$emit('handleTag')
                }
                
            }
        }
        
    }
    script>
    <style lang="less" scoped>
        .tag{
            font-size: 12px;
            .title {
                margin-right: 10px;
            }
            .el-tag{
                margin-right: 8px;
            }
            .active {
                background-color: #66b1ff;
                color: #fff;
            }
        }
    style>
    

    调用代码:

    <my-tag title="有效状态: " size="small" 
    	 :tagData="$store.getters.getDictList('EFFECTIVE')" 
    	 @handleTag="handleTag">
     my-tag>
    

    3、页面实现代码

    <template>
        <div class="app-content">
            <div class="search">
                <el-input v-model="searchInfo" placeholder="请输入菜单名称"/>
                <el-button type="primary" icon="el-icon-search" @click="queryMenuByCondition">搜索el-button>
            div>
            <div class="op-btn">
                <div class="op-btn-left">
                    <my-tag title="有效状态: " size="small" 
                        :tagData="$store.getters.getDictList('EFFECTIVE')" 
                        @handleTag="handleTag">
                    my-tag>
                div>
            div>
            <my-table :data="menuTreeData" 
                :columns="columns" 
                height="600px" 
                :selection="true" 
                tooltipEffect="dark"
                :highlightCurrentRow="true"
                rowKey="menuId"
            >
                
                <template slot="menuType" slot-scope="{scope}">
                    <el-tag
                        :type="scope.row.menuType === '0' ? '' : (scope.row.menuType == '1' ? 'success' : 'danger')"
                        disable-transitions>{{$store.getters.getDictLabelByType('MENUTYPE', scope.row.menuType)}}el-tag>
                template>
                
                <template slot="effective" slot-scope="{scope}">
                    <el-tag
                        :type="scope.row.effective === '1' ? 'success' : 'danger'"
                        disable-transitions>{{$store.getters.getDictLabelByType('EFFECTIVE', scope.row.effective)}}el-tag>
                template>
                
                <template slot="operate" slot-scope="{scope}">
                    <el-button type="text" size="small" 
                        @click="handleAddMenu(scope.row)" :disabled="scope.row.effective == 0 ? true : false">添加下级el-button>
                    <el-button type="text" size="small" 
                        @click="handleEditMenu(scope.row)" :disabled="scope.row.effective == 0 ? true : false">编辑el-button>
                    <el-dropdown>
                        <el-dropdown-menu slot="dropdown">
                            <el-dropdown-item @click.native="handleEffective('1', scope.row)" >启用el-dropdown-item>
                            <el-dropdown-item @click.native="handleEffective('2', scope.row)" divided >禁用el-dropdown-item>
                            <el-dropdown-item @click.native="handleDelete(scope.row)" divided>删除el-dropdown-item>
                        el-dropdown-menu>
                        <span class="el-dropdown-link">
                            更多<i class="el-icon-arrow-down el-icon--right">i>
                        span>
                    el-dropdown>
                template>
            my-table>
    
            
            <edit-menu :visible="editVisible" :rowData="rowData" @close="editVisible = false" @queryMenuByCondition="queryMenuByCondition">edit-menu>
        div>
    template>
    <script>
    import myTag from '@/components/tag/myTag'
    import $api from './api/index'
    import editMenu from './part/editMenu';
    
    const columns = [
        {label: '菜单名称', prop: 'name'},
        {label: '菜单路径', prop: 'path', align: 'center'},
        {label: '菜单类型', prop: 'menuType', align: 'center', slot: 'menuType'},
        {label: '有效状态', prop: 'effective', align: 'center', slot: 'effective'},
        {label: '操作', prop: 'operate', align: 'center', slot: 'operate'}
    ]
    export default{
        components: { myTag, editMenu },
        name: 'menuManagement',
        data() {
            return{
                editVisible: false,
                columns,
                searchInfo: '',
                menuTreeData: [],
                rowData: {},
                effectiveTag: '',
            }
        },
        mounted() {
            this.queryMenuByCondition()
        },
        methods: {
            // 添加下级菜单
            handleAddMenu(val){
                this.rowData = {}
                this.editVisible = true
                this.rowData.parentName = val.name
                this.rowData.editType = '1'
                this.rowData.parentId = val.menuId
            },
            // 编辑菜单
            handleEditMenu(val){
                this.rowData = {}
                this.editVisible = true
                this.rowData = val
                this.rowData.editType = '2'
            },
            // 有效状态条件
            handleTag(val){
                this.effectiveTag = ''
                if (val != undefined){
                    this.effectiveTag = val.code
                }
                this.queryMenuByCondition()
            },
        
            // 填充表格数据
            queryMenuByCondition(){
                let param = {
                    searchInfo: this.searchInfo,
                    effective: this.effectiveTag
                }
                $api.queryMenuByCondition(param).then(res => {
                    if (res.data.code == 200){
                        this.menuTreeData = res.data.data
                    }
                })
            },
            // 更新有效状态: 1启用 2禁用
            handleEffective(type, row){
                if (type == "1"){
                    if (row.effective == "1"){
                        this.$message({
                            showClose: true,
                            message: '该记录已启用,请勿重复操作.',
                            type: 'error',
                        })
                        return
                    }
                }else {
                    if (row.effective != "1"){
                        this.$message({
                            showClose: true,
                            message: '该记录已禁用,请勿重复操作.',
                            type: 'error',
                        })
                        return
                    }
                }
                $api.updateEffective({type: type, menuId: row.menuId}).then(res => {
                    if (res.data.code == 200){
                        this.queryMenuByCondition()
                        this.$message({
                            showClose: true,
                            message: type == '1' ? '启用成功.' : '禁用成功.',
                            type: 'success',
                        })
                    }
                })
            },
            // 删除
            handleDelete(row){
                this.$confirm('确认删除该记录?',{
                    confirmButtonText: '确定',
                    cancelButtonText: '取消',
                    type: 'warning'
                }).then(() => {
                    $api.deleteMenuByMenuId({menuId: row.menuId}).then(res => {
                        if (res.data.code == 200){
                            this.queryMenuByCondition()
                            this.$message({
                                showClose: true,
                                message: '删除成功.',
                                type: 'success',
                            })
                        }
                    })
                })
            }
        }
    }
    
    script>
    <style lang="less" scoped>
        .search {
            text-align: center; 
            margin-bottom: 40px;
            .el-input{
                width: 300px;
            }
        }
        .op-btn{
            display: flex;
            align-content: center;
            justify-content: space-between;
            padding: 2px 5px;
        }
        .el-button{
            margin-right: 10px;
        }
        .el-dropdown-link {
            cursor: pointer;
            color: #409EFF;
        }
        .el-icon-arrow-down {
            font-size: 12px;
        }
    style>
    

    4、编辑实现效果及代码

    在这里插入图片描述

    <template>
        <el-drawer
            :title="rowData.editType == '2' ? '编辑菜单' : '添加下级菜单'"
            :visible="visible"
            size="25%"
            :before-close="closeDrawer"
            :destroy-on-close="true"
        >
            <el-form ref="formData" :rules="formRules" :model="formData" class="drawer__content" label-width="120px">
                <el-form-item label="上级菜单" prop="parentName">
                    <el-input v-model="formData.parentName" autocomplete="off" :disabled="true">el-input>
                el-form-item>
                <el-form-item label="菜单名称" prop="name">
                    <el-input v-model="formData.name" autocomplete="off">el-input>
                el-form-item>
                <el-form-item label="菜单路径" prop="path">
                    <el-input v-model="formData.path" autocomplete="off" placeholder="如:/home">el-input>
                el-form-item>
                <el-form-item label="菜单权限" prop="perms">
                    <el-input v-model="formData.perms" autocomplete="off" placeholder="如:sys:system">el-input>
                el-form-item>
                <el-form-item label="菜单图标" prop="icon">
                    <icon-select :iconName="formData.icon" @selected="selected">icon-select>
                el-form-item>
                <el-form-item label="菜单类型" prop="menuType">
                    <el-radio-group v-model="formData.menuType">
                        <el-radio
                            v-for="item in $store.getters.getDictList('MENUTYPE')"
                            :key="item.code" 
                            :label="item.code">
                        {{item.label}}
                        el-radio>
                    el-radio-group>
                el-form-item>
                <el-form-item label="排序号" prop="orderNo">
                    <el-input-number v-model="formData.orderNo" controls-position="right" :min="1">el-input-number>
                el-form-item>
                <el-form-item label="有效状态" prop="effective" >
                    <el-switch  v-model="formData.effective">el-switch>
                el-form-item>
            el-form>
            <div class="drawer__footer">
                <el-button @click="resetForm('formData')">重 置el-button>
                <el-button type="primary" @click="submitForm('formData')">确 定el-button>
            div>
        el-drawer>
    template>
    
    <script>
    import iconSelect from '@/components/iconSelect/iconSelect'
    import $api from '../api/index'
    
    export default {
      components: { iconSelect },
        name: 'editMenu',
        props: ['visible', 'rowData'],
        data(){
            return {
                drawer: false,
                formData: {},
                formRules: {
                    parentName: [
                        { required: true, message: '请输入上级菜单', trigger: 'blur'}
                    ],
                    name: [
                        { required: true, message: '请输入菜单名称', trigger: 'blur'}
                    ],
                    menuType: [
                        { required: true, message: '请输入菜单类型', trigger: 'blur'}
                    ]
                }
            }
        },
        watch: {
            visible(val){
                if (val){
                    this.setFormValue()
                }
            }
        },
        methods: {
            // 表单数据
            setFormValue(){
                const {menuId, menuType, name, path, perms, component, icon, editType, orderNo, effective, parentName, parentId} = this.rowData
                if(editType == '1'){
                    this.formData = {
                        parentName: parentName,
                        parentId: parentId,
                        effective: true,
                        orderNo: orderNo ? orderNo : 1
                    }
                }else {
                    this.formData = {
                        menuId: menuId,
                        menuType: menuType,
                        name: name,
                        path: path,
                        perms: perms,
                        component: component,
                        icon: icon,
                        orderNo: orderNo,
                        parentName: parentName,
                        effective: effective == '1' ? true : false
                    }
                }
            },
            // 图标选择
            selected(icon){
                this.formData.icon = icon
            },
            // 编辑/新增保存
            submitForm(formName){
                this.$refs[formName].validate((valid) => {
                    if (valid){
                        this.formData.effective = this.formData.effective ? '1' : '0'
                        // 新增
                        if(this.rowData.editType == '1'){
                            $api.addMenu(this.formData).then(res => {
                                if (res.data.code == 200){
                                    this.closeDrawer()
                                    this.$emit('queryMenuByCondition')
                                    this.$message({
                                        showClose: true,
                                        message: '新增菜单成功.',
                                        type: 'success',
                                    })
                                }
                            })
                        }else { // 编辑
                            $api.editMenu(this.formData).then(res => {
                                if (res.data.code == 200){
                                    this.$emit('queryMenuByCondition')
                                    this.closeDrawer()
                                    this.$message({
                                        showClose: true,
                                        message: '编辑菜单成功..',
                                        type: 'success',
                                    })
                                }
                            })
                        }
                    }
                })
            },
            // 重置表单
            resetForm(formName){
                this.$refs[formName].resetFields();
                this.setFormValue()
            },
            // 关闭
            closeDrawer(){
                this.formData = {}
                this.resetForm('formData')
                this.$emit('close')
            }
        }
        
    }
    script>
    <style lang="less" scoped>
        /deep/ .el-drawer__header{
            padding: 20px;
            border-bottom: 1px solid rgba(0,21,41,0.08);
        }
        .drawer__content {
            width: 90%;
        }
        .drawer__footer{
            position: absolute;
            bottom: 20px;
            left: 25px;
            .el-button{
                width: 150px;
                margin-right: 15px;
            }
        }
    style>
    
    

    5、调用js方法

    import request from '@/axios/request';
    
    const api = {
        // 填充树形数据
        queryMenuByCondition(data){
            return request.post("/menu/queryMenuByCondition", data, true)
        },
    
        // 新增菜单
        addMenu(data){
            return request.post('/menu/addMenu', data)
        },
    
        // 编辑菜单
        editMenu(data){
            return request.post('/menu/editMenu', data)
        },
    
        // 更新菜单有效状态
        updateEffective(data){
            return request.post("/menu/updateEffectiveByMenuId", data)
        },
    
        // 删除菜单
        deleteMenuByMenuId(data){
            return request.post("/menu/deleteMenuByMenuId", data)
        }
    }
    
    export default api
      
    

    6、后台实现

    (1)、结构

    在这里插入图片描述

    (2)、自定义构建树形结构工具类
    package com.longzy.common.bean;
    
    
    import java.util.List;
    
    /**
     * @Desc: 构建树形结构接口
     * @Packge: com.longzy.common.bean
     * @Author: longzy
     * @Date: 2022/9/24 22:41
     */
    
    public interface TreeBean<T> {
    
        public Object getId();
    
        public Object getParentId();
    
        // 子节点
        public void setChildren(List<T> children);
    
    }
    
    
    package com.longzy.common.utils;
    
    import com.longzy.common.bean.TreeBean;
    import com.longzy.component.menu.vo.SysMenuVo;
    import org.apache.commons.lang3.ObjectUtils;
    
    import java.util.*;
    
    /**
     * @Desc: 树形数据结构工具类
     * @Packge: com.longzy.common.utils
     * @Author: longzy
     * @Date: 2022/9/24 21:31
     */
    public class TreeUtils {
    
        /**
         * 构建树形结构数据
         * @param lists 数据
         * @param topId 顶级id
         * @return
         */
        public static <T extends TreeBean<T>> List<T> buildTree(List<T> lists, Object topId) {
            List<T> finalNodes = new ArrayList();
            if (ObjectUtils.isEmpty(topId) && ObjectUtils.isEmpty(lists)){
                return  finalNodes;
            }
    
            // 获取顶级节点集合
            for (T bean: lists) {
                Object parentId = bean.getParentId();
                if (parentId == null || topId.equals(parentId)){
                    finalNodes.add(bean);
                }
            }
    
            // 获取顶级节点的子节点集合
            for (T bean : finalNodes){
                bean.setChildren(getChildren(bean.getId(), lists));
            }
            // 没有顶级元素择返回搜索结果(0为顶级元素)
            if (finalNodes.size() < 1){
                return lists;
            }
    
            return finalNodes;
        }
    
        private static <T extends TreeBean<T>> List<T> getChildren(Object id, List<T> nodeList){
            List<T> childrenNodes = new ArrayList();
            if (ObjectUtils.isEmpty(id)){
                return childrenNodes;
            }
            // 获取顶级节点集合
            for (T bean: nodeList) {
                Object parentId = bean.getParentId();
                if (id.equals(parentId)){
                    childrenNodes.add(bean);
                }
            }
    
            // 获取顶级节点的子节点集合
            for (T bean : childrenNodes){
                bean.setChildren(getChildren(bean.getId(), nodeList));
            }
            return childrenNodes;
        }
    
        public static void main(String[] args) {
            List list = new ArrayList();
            SysMenuVo map = new SysMenuVo();
            map.setMenuId(1);
            map.setName("系統管理");
            map.setParentId(0);
            map.setOrderNo(10);
            SysMenuVo map1 = new SysMenuVo();
            map1.setMenuId(2);
            map1.setName("用户管理");
            map1.setParentId(1);
            map1.setOrderNo(10);
            SysMenuVo map3 = new SysMenuVo();
            map3.setMenuId(3);
            map3.setName("菜单管理");
            map3.setParentId(1);
            map3.setOrderNo(5);
            SysMenuVo map2 = new SysMenuVo();
            map2.setMenuId(4);
            map2.setName("资源管理");
            map2.setParentId(0);
            map2.setOrderNo(5);
            SysMenuVo map4 = new SysMenuVo();
            map4.setMenuId(5);
            map4.setName("字典管理");
            map4.setParentId(4);
            map4.setOrderNo(10);
    
            list.add(map);
            list.add(map1);
            list.add(map2);
            list.add(map3);
    //        list.add(map4);
    
            System.out.println(buildTree(list, 0));
    
            List<SysMenuVo> menuList = buildTree(list, 0);
            Collections.sort(menuList, new Comparator<SysMenuVo>() {
    
                @Override
                public int compare(SysMenuVo o1, SysMenuVo o2) {
                    return o1.getOrderNo() - o2.getOrderNo();
                }
            });
            System.out.println(menuList);
        }
    
    }
    
    
    (3)、实体类po与vo
    package com.longzy.component.menu.entity;
    
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    import java.util.Date;
    
    /**
     * @Desc: 菜单实体类
     * @Packge: com.longzy.component.menu.entity
     * @Author: longzy
     * @Date: 2022/9/24 21:05
     */
    @ApiModel
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class SysMenuPo implements Serializable {
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty(value = "菜单id")
        private Integer menuId;
    
        @ApiModelProperty(value = "菜单名称")
        private String name;
    
        @ApiModelProperty(value = "父菜单id")
        private Integer parentId;
    
        @ApiModelProperty(value = "菜单url")
        private String path;
    
        @ApiModelProperty(value = "权限")
        private String perms;
    
        @ApiModelProperty(value = "菜单类型")
        private String menuType;
    
        @ApiModelProperty(value = "菜单图标")
        private String icon;
    
        @ApiModelProperty(value = "排序号")
        private Integer orderNo;
    
        @ApiModelProperty(value = "创建人")
        private Integer createUser;
    
        @ApiModelProperty(value = "创建时间")
        private Date createTime;
    
        @ApiModelProperty(value = "有效状态")
        private String effective;
    
        @ApiModelProperty(value = "销毁状态")
        private String destory;
    
    }
    
    
    package com.longzy.component.menu.vo;
    
    import com.longzy.common.bean.TreeBean;
    import io.swagger.annotations.ApiModel;
    import io.swagger.annotations.ApiModelProperty;
    import lombok.AllArgsConstructor;
    import lombok.Builder;
    import lombok.Data;
    import lombok.NoArgsConstructor;
    
    import java.io.Serializable;
    import java.util.Date;
    import java.util.List;
    
    /**
     * @Desc: 菜单实体类
     * @Packge: com.longzy.component.menu.entity
     * @Author: longzy
     * @Date: 2022/9/24 21:05
     */
    @ApiModel
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    @Builder
    public class SysMenuVo implements Serializable, TreeBean<SysMenuVo> {
    
        private static final long serialVersionUID = 1L;
    
        @ApiModelProperty(value = "菜单id")
        private Integer menuId;
    
        @ApiModelProperty(value = "菜单名称")
        private String name;
    
        @ApiModelProperty(value = "父菜单id")
        private Integer parentId;
    
        @ApiModelProperty(value = "父菜单名称")
        private String parentName;
    
        @ApiModelProperty(value = "菜单url")
        private String path;
    
        @ApiModelProperty(value = "权限")
        private String perms;
    
        @ApiModelProperty(value = "菜单类型")
        private String menuType;
    
        @ApiModelProperty(value = "菜单图标")
        private String icon;
    
        @ApiModelProperty(value = "排序号")
        private Integer orderNo;
    
        @ApiModelProperty(value = "创建人")
        private Integer createUser;
    
        @ApiModelProperty(value = "创建时间")
        private Date createTime;
    
        @ApiModelProperty(value = "有效状态")
        private String effective;
    
        @ApiModelProperty(value = "销毁状态")
        private String destory;
    
        @ApiModelProperty(value = "子节点")
        private List<SysMenuVo> children;
    
        @Override
        public Integer getId() {
            return this.menuId;
        }
    }
    
    
    (4)、控制层(controller)实现
    package com.longzy.component.menu.controller;
    
    import com.longzy.common.response.CommonReturnType;
    import com.longzy.component.menu.service.read.SysMenuReadService;
    import com.longzy.component.menu.service.write.SysMenuWriteService;
    import com.longzy.component.menu.vo.SysMenuVo;
    import com.longzy.component.user.service.read.SysUserReadService;
    import io.swagger.annotations.Api;
    import io.swagger.annotations.ApiOperation;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.PostMapping;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RestController;
    
    import java.security.Principal;
    import java.util.List;
    
    /**
     * @Desc: 菜单
     * @Packge: com.longzy.component.menu.controller
     * @Author: longzy
     * @Date: 2022/9/24 21:03
     */
    @Api(value = "菜单模块")
    @RestController
    @RequestMapping("menu")
    public class SysMenuController {
    
        @Autowired
        private SysMenuReadService sysMenuReadService;
    
        @Autowired
        private SysMenuWriteService sysMenuWriteService;
    
        @Autowired
        private SysUserReadService sysUserReadService;
    
        @ApiOperation(value = "菜单查询", notes = "根据条件查询树形菜单列表")
        @PostMapping("queryMenuByCondition")
        public CommonReturnType queryMenuByCondition(String effective, String searchInfo){
            List<SysMenuVo> treeMenu = sysMenuReadService.queryMenuByCondition(effective, searchInfo);
            return CommonReturnType.success("操作成功", treeMenu);
        }
    
        @ApiOperation(value = "添加菜单")
        @PostMapping("addMenu")
        public CommonReturnType addMenu(Principal principal, SysMenuVo sysMenuVo){
            // 获取当前操作人员id
            int currentUserId = sysUserReadService.getUserIdByLoginId(principal.getName());
            sysMenuWriteService.addMenu(currentUserId, sysMenuVo);
            return CommonReturnType.success("操作成功.");
        }
    
        @ApiOperation(value = "编辑菜单")
        @PostMapping("editMenu")
        public CommonReturnType editMenu(SysMenuVo menuVo){
            sysMenuWriteService.editMenu(menuVo);
            return CommonReturnType.success("操作成功.");
        }
    
        @ApiOperation(value = "更新菜单状态")
        @PostMapping("updateEffectiveByMenuId")
        public CommonReturnType updateEffectiveByMenuId(String type, int menuId){
            sysMenuWriteService.updateEffective(type, menuId);
            return CommonReturnType.success("操作成功.");
        }
    
        @ApiOperation(value = "删除菜单", notes = "根据菜单id删除菜单项")
        @PostMapping("deleteMenuByMenuId")
        public CommonReturnType deleteMenuByMenuId(int menuId){
            sysMenuWriteService.deleteMenuByMenuId(menuId);
            return CommonReturnType.success("操作成功.");
        }
    
    
    
    }
    
    
    (5)、服务层(service)实现

    read:

    package com.longzy.component.menu.service.read;
    
    import com.longzy.component.menu.vo.SysMenuVo;
    
    import java.util.List;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.service.read
     * @Author: longzy
     * @Date: 2022/9/24 21:19
     */
    public interface SysMenuReadService {
        List<SysMenuVo> queryMenuByCondition(String effective, String searchInfo);
    }
    
    
    package com.longzy.component.menu.service.read.impl;
    
    import com.longzy.common.utils.TreeUtils;
    import com.longzy.component.menu.mapper.read.SysMenuReadMapper;
    import com.longzy.component.menu.service.read.SysMenuReadService;
    import com.longzy.component.menu.vo.SysMenuVo;
    import org.springframework.stereotype.Service;
    
    import javax.annotation.Resource;
    import java.util.Collections;
    import java.util.Comparator;
    import java.util.List;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.service.read.impl
     * @Author: longzy
     * @Date: 2022/9/24 21:19
     */
    @Service
    public class SysMenuReadServiceImpl implements SysMenuReadService {
    
        @Resource
        private SysMenuReadMapper sysMenuReadMapper;
    
        @Override
        public List<SysMenuVo> queryMenuByCondition(String effective, String searchInfo) {
            List<SysMenuVo> menuList = sysMenuReadMapper.queryMenuByCondition(effective, searchInfo, "0");
            // 构建树形结构数据
            List<SysMenuVo> menuTree = TreeUtils.buildTree(menuList, 0);
            // 节点排序(升序)
            compareTo(menuTree);
            return menuTree;
        }
    
        /**
         * 排序
         * @param menuList 需排序的集合
         */
        private static void compareTo(List<SysMenuVo> menuList) {
            Collections.sort(menuList, new Comparator<SysMenuVo>() {
                @Override
                public int compare(SysMenuVo o1, SysMenuVo o2) {
                    return o1.getOrderNo() - o2.getOrderNo();
                }
            });
            for (SysMenuVo menuVo : menuList){
                if (menuVo.getChildren() != null && menuVo.getChildren().size() > 0){
                    compareTo(menuVo.getChildren());
                }
            }
        }
    }
    
    

    write:

    package com.longzy.component.menu.service.write;
    
    import com.longzy.component.menu.vo.SysMenuVo;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.service.write
     * @Author: longzy
     * @Date: 2022/9/26 16:27
     */
    public interface SysMenuWriteService {
        void addMenu(int currentUserId, SysMenuVo sysMenuVo);
    
        void editMenu(SysMenuVo menuVo);
    
        void updateEffective(String type, int menuId);
    
        void deleteMenuByMenuId(int menuId);
    }
    
    
    package com.longzy.component.menu.service.write.impl;
    
    import com.longzy.common.utils.ConvertUtils;
    import com.longzy.component.menu.entity.SysMenuPo;
    import com.longzy.component.menu.mapper.read.SysMenuReadMapper;
    import com.longzy.component.menu.mapper.write.SysMenuWriteMapper;
    import com.longzy.component.menu.service.write.SysMenuWriteService;
    import com.longzy.component.menu.vo.SysMenuVo;
    import com.longzy.error.BusinessException;
    import org.springframework.stereotype.Service;
    import org.springframework.transaction.annotation.Transactional;
    
    import javax.annotation.Resource;
    import java.util.Date;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.service.write.impl
     * @Author: longzy
     * @Date: 2022/9/26 16:27
     */
    @Service
    @Transactional
    public class SysMenuWriteServiceImpl implements SysMenuWriteService {
    
        @Resource
        private SysMenuWriteMapper sysMenuWriteMapper;
    
        @Resource
        private SysMenuReadMapper sysMenuReadMapper;
    
        @Override
        public void addMenu(int currentUser, SysMenuVo sysMenuVo) {
            SysMenuPo menuPo = ConvertUtils.convert(sysMenuVo, new SysMenuPo());
            menuPo.setCreateUser(currentUser);
            menuPo.setCreateTime(new Date());
            menuPo.setDestory("0");
            int count = sysMenuWriteMapper.addMenu(menuPo);
            if (count < 1){
                throw new BusinessException("新增菜单失败.");
            }
        }
    
        @Override
        public void editMenu(SysMenuVo menuVo) {
            SysMenuPo menuPo = ConvertUtils.convert(menuVo, new SysMenuPo());
            int count = sysMenuWriteMapper.editMenu(menuPo);
            if (count < 1){
                throw new BusinessException("编辑菜单失败.");
            }
        }
    
        /**
         * 更新菜单状态
         * @param type 1启用 2禁用
         * @param menuId 菜单id
         */
        @Override
        public void updateEffective(String type, int menuId) {
            String effective = null;
            if ("1".equals(type)){
                effective = "1";
                // 查询该记录是否还有父记录为禁用状态
                int countMenu = sysMenuReadMapper.countEnableByMenuId(menuId, "0");
                if (countMenu > 0){
                    throw new BusinessException("该记录还有父记录的状态为无效,不可以操作该记录.");
                }
            }else {
                effective = "0";
                // 查询该记录是否还有子记录为启用状态
                int countMenu = sysMenuReadMapper.countDisableByParentId(menuId, "0");
                if (countMenu > 0){
                    throw new BusinessException("该记录还有子记录的状态为有效,不可以操作该记录.");
                }
            }
            int count = sysMenuWriteMapper.updateEffective(menuId, effective);
            if (count < 1){
                throw new BusinessException(type== "1" ? "该记录启用失败." : "该记录禁用失败.");
            }
        }
    
        @Override
        public void deleteMenuByMenuId(int menuId) {
            // 统计删除菜单是否还有子元素
            int countMenu = sysMenuReadMapper.countDeleteByChildren(menuId, "0");
            if (countMenu > 0){
                throw new BusinessException("该记录还有子记录,不可以操作该记录.");
            }
            int count = sysMenuWriteMapper.deleteMenuByMenuId(menuId, "1");
            if (count < 1){
                throw new BusinessException("改记录删除失败.");
            }
        }
    }
    
    
    (6)、持久层(mapper)实现

    read:

    package com.longzy.component.menu.mapper.read;
    
    import com.longzy.component.menu.vo.SysMenuVo;
    import org.apache.ibatis.annotations.Param;
    
    import java.util.List;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.mapper.read
     * @Author: longzy
     * @Date: 2022/9/24 21:22
     */
    public interface SysMenuReadMapper {
        /**
         * 查询菜单列表
         * @param effective 有效状态
         * @param searchInfo 菜单名称
         * @param destory 销毁状态
         * @return
         */
        List<SysMenuVo> queryMenuByCondition(@Param("effective") String effective, @Param("searchInfo") String searchInfo, @Param("destory") String destory);
    
        /**
         * 启用:根据父菜单id统计
         * @param menuId 菜单id
         * @param destory 销毁状态
         * @return
         */
        int countEnableByMenuId(@Param("menuId")int menuId, @Param("destory") String destory);
    
        /**
         * 禁用: 根据菜单id统计
         * @param parentId 父菜单id
         * @param destory 销毁状态
         * @return
         */
        int countDisableByParentId(@Param("parentId") int parentId, @Param("destory") String destory);
    
        /**
         * 删除: 根据父菜单id统计
         * @param parentId
         * @param destory
         * @return
         */
        int countDeleteByChildren(@Param("parentId") int parentId, @Param("destory") String destory);
    }
    
    

    write:

    package com.longzy.component.menu.mapper.write;
    
    import com.longzy.component.menu.entity.SysMenuPo;
    import org.apache.ibatis.annotations.Param;
    
    /**
     * @Desc:
     * @Packge: com.longzy.component.menu.mapper.write
     * @Author: longzy
     * @Date: 2022/9/26 16:29
     */
    public interface SysMenuWriteMapper {
        /**
         * 新增菜单
         * @param menuPo 入参
         * @return
         */
        int addMenu(SysMenuPo menuPo);
    
        /**
         * 编辑菜单
         * @param menuPo 入参
         * @return
         */
        int editMenu(SysMenuPo menuPo);
    
        /**
         * 更新状态
         * @param menuId 菜单id
         * @param effective 状态值
         * @return
         */
        int updateEffective(@Param("menuId") int menuId, @Param("effective") String effective);
    
        /**
         * 逻辑删除菜单
         * @param menuId 菜单id
         * @param destory 1销毁 0正常
         * @return
         */
        int deleteMenuByMenuId(@Param("menuId") int menuId, @Param("destory") String destory);
    }
    
    
    (7)、sql实现

    read:

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.longzy.component.menu.mapper.read.SysMenuReadMapper">
    
        <sql id="Base_Column_List">
            m.menuid,
            m.name,
            m.parentid,
            m.path,
            m.perms,
            m.menutype,
            m.icon,
            m.orderno,
            m.createuser,
            m.createtime,
            m.effective,
            m.destory
        sql>
    
        <select id="queryMenuByCondition" resultType="com.longzy.component.menu.vo.SysMenuVo">
            SELECT <include refid="Base_Column_List">include>,
            ifnull((SELECT n.name from sys_menu n where n.menuid  = m.parentid), '0') as parentname
            FROM sys_menu m
            WHERE m.destory = #{destory,jdbcType=VARCHAR}
            <if test="searchInfo != '' and searchInfo != null">
                AND m.name like concat('%', #{searchInfo,jdbcType=VARCHAR}, '%')
            if>
            <if test="effective != '' and effective != null">
                AND m.effective = #{effective,jdbcType=VARCHAR}
            if>
        select>
    
        <select id="countEnableByMenuId" resultType="int">
            SELECT count(1)
            FROM sys_menu
            WHERE destory = #{destory,jdbcType=VARCHAR}
            AND effective = '0'
            AND menuid = (select parentid from sys_menu where menuid = #{menuId,jdbcType=INTEGER})
        select>
    
        <select id="countDisableByParentId" resultType="int">
            SELECT count(1)
            FROM sys_menu
            WHERE destory = #{destory,jdbcType=VARCHAR}
            AND effective = '1'
            AND parentid = #{parentId,jdbcType=INTEGER}
        select>
    
        <select id="countDeleteByChildren" resultType="int">
            SELECT count(1)
            FROM sys_menu
            WHERE destory = #{destory,jdbcType=VARCHAR}
            AND parentid = #{parentId,jdbcType=INTEGER}
        select>
    mapper>
    

    write:

    
    DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.longzy.component.menu.mapper.write.SysMenuWriteMapper">
    
        <insert id="addMenu" parameterType="com.longzy.component.menu.entity.SysMenuPo">
            INSERT INTO sys_menu
            (name, parentid, `path`, perms, menutype, icon, orderno, createuser, createtime, effective, destory)
            VALUES(#{name,jdbcType=VARCHAR},
                   #{parentId,jdbcType=INTEGER},
                   #{path,jdbcType=VARCHAR},
                   #{perms,jdbcType=VARCHAR},
                   #{menuType,jdbcType=VARCHAR},
                   #{icon,jdbcType=VARCHAR},
                   #{orderNo,jdbcType=INTEGER},
                   #{createUser,jdbcType=INTEGER},
                   #{createTime,jdbcType=DATE},
                   #{effective,jdbcType=VARCHAR},
                   #{destory,jdbcType=VARCHAR})
        insert>
    
        <update id="editMenu" parameterType="com.longzy.component.menu.entity.SysMenuPo">
            UPDATE sys_menu
            <set>
                <if test="name != null">
                    name = #{name,jdbcType=VARCHAR},
                if>
                <if test="path != null">
                    path = #{path,jdbcType=VARCHAR},
                if>
                <if test="perms != null">
                    perms = #{perms,jdbcType=VARCHAR},
                if>
                <if test="menuType != null">
                    menutype = #{menuType,jdbcType=VARCHAR},
                if>
                <if test="icon != null">
                    icon = #{icon,jdbcType=VARCHAR},
                if>
                <if test="orderNo != null">
                    orderno = #{orderNo,jdbcType=INTEGER},
                if>
                <if test="effective != null">
                    effective = #{effective,jdbcType=VARCHAR}
                if>
            set>
            WHERE menuid = #{menuId,jdbcType=INTEGER}
        update>
    
        <update id="updateEffective" >
            UPDATE sys_menu SET effective = #{effective,jdbcType=VARCHAR} WHERE menuid = #{menuId,jdbcType=INTEGER}
        update>
    
        <update id="deleteMenuByMenuId">
            UPDATE sys_menu SET destory = #{destory,jdbcType=VARCHAR} WHERE menuid = #{menuId,jdbcType=INTEGER}
        update>
    
    mapper>
    

    代码地址:

    后端: https://gitee.com/longzyl/longzy-admin
    前端: https://gitee.com/longzyl/longzy-vue2

  • 相关阅读:
    全新升级的AOP框架Dora.Interception[4]: 基于Lambda表达式的拦截器注册方式
    STM32WB55开发(6)----FUS更新
    python基础小知识【基础+进阶】
    代码随想录学习记录——栈与队列篇
    嵌入式分享合集104
    简明SQL截断和偏移指南:掌握 LIMIT 和 OFFSET 实现数据筛选
    Jmeter接口测试---随机数、加密、cookie鉴权、断言、CSV参数化
    git命令 本地
    C#解析Markdown文档,实现替换图片链接操作
    若依框架解读(微服务版)——2.模块间的调用逻辑(ruoyi-api模块)(OpenFeign)
  • 原文地址:https://blog.csdn.net/longzhengyong1314/article/details/127120190