简单的记录下菜单前后端实现,比较基础,仅供参考
vue请求需要根据情况自行封装,代码中的请求需要自行实现
效果
数据库结构
CREATE TABLE `menus` (
`id` INT(11) NOT NULL AUTO_INCREMENT COMMENT '主键,菜单id',
`name` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单名称' COLLATE 'utf8_general_ci',
`icon` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单图标' COLLATE 'utf8_general_ci',
`route` VARCHAR(50) NOT NULL DEFAULT '' COMMENT '菜单路由' COLLATE 'utf8_general_ci',
`superior_menu` INT(11) NOT NULL DEFAULT '0' COMMENT '上级菜单',
`sort_number` INT(11) NOT NULL DEFAULT '0' COMMENT '排序',
`show_level` INT(11) NOT NULL DEFAULT '0' COMMENT '权限级别',
`create_time` TIMESTAMP NULL DEFAULT '1970-01-01 08:00:01' COMMENT '创建时间',
`update_time` TIMESTAMP NULL DEFAULT '1970-01-01 08:00:01' ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',
`status` INT(11) NOT NULL DEFAULT '0' COMMENT '是否启用,0:启用,1禁用',
PRIMARY KEY (`id`) USING BTREE,
UNIQUE INDEX `u_key_s_n` (`superior_menu`, `name`) USING BTREE,
UNIQUE INDEX `u_key_s_s` (`superior_menu`, `sort_number`) USING BTREE
)
COMMENT='侧边栏菜单'
COLLATE='utf8_general_ci'
ENGINE=InnoDB
;
Java对象
package com.xiaobai.test;
import java.util.Date;
import java.util.List;
public class Menu {
private Integer id;
private String name;
private String icon;
private String route;
private Integer superior_menu;
private Integer sort_number;
private Integer show_level;
private Date create_time;
private Date update_time;
private Integer status;
private List<Menu> subMenus;
public Menu() {
}
public Menu(Integer id, String name, String icon, String route, Integer superior_menu, Integer sort_number, Integer show_level, Integer status) {
this.id = id;
this.name = name;
this.icon = icon;
this.route = route;
this.superior_menu = superior_menu;
this.sort_number = sort_number;
this.show_level = show_level;
this.status = status;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getIcon() {
return icon;
}
public void setIcon(String icon) {
this.icon = icon;
}
public String getRoute() {
return route;
}
public void setRoute(String route) {
this.route = route;
}
public Integer getSuperior_menu() {
return superior_menu;
}
public void setSuperior_menu(Integer superior_menu) {
this.superior_menu = superior_menu;
}
public Integer getSort_number() {
return sort_number;
}
public void setSort_number(Integer sort_number) {
this.sort_number = sort_number;
}
public Integer getShow_level() {
return show_level;
}
public void setShow_level(Integer show_level) {
this.show_level = show_level;
}
public Date getCreate_time() {
return create_time;
}
public void setCreate_time(Date create_time) {
this.create_time = create_time;
}
public Date getUpdate_time() {
return update_time;
}
public void setUpdate_time(Date update_time) {
this.update_time = update_time;
}
public Integer getStatus() {
return status;
}
public void setStatus(Integer status) {
this.status = status;
}
public List<Menu> getSubMenus() {
return subMenus;
}
public void setSubMenus(List<Menu> subMenus) {
this.subMenus = subMenus;
}
}
Controller
@Controller
@RequestMapping("/menu")
public class MenuController {
@Autowired
MenuService menuService;
@RequestMapping("/queryMenus")
@ResponseBody
public ResponseEntity queryMenus(@RequestParam(value = "id", required = false) Integer id,
@RequestParam(value = "level", required = false, defaultValue = "0") Integer level,
@RequestParam(value = "status", required = false) Integer status,
@RequestParam(value = "querySubMenus", required = false, defaultValue = "true") Boolean querySubMenus) {
// 如果为系统管理员,不受菜单禁用限制,枚举类型,请根据情况自行定义,如无特殊要求注释掉该条件判断
if (level == LevelType.TYPE.SYSTEM.getCode()) {
status = null;
}
List<Menu> menus = menuService.queryMenus(null, id, level, status);
menus.sort(Comparator.comparingInt(Menu::getSort_number));
// 判断是否查询子菜单
if (querySubMenus != null && querySubMenus == true) for (Menu menu : menus) {
List<Menu> subMenus = querySubMenus(menu, level, status);
menu.setSubMenus(subMenus);
}
Map<String, Object> response = new HashMap<>();
response.put("msg", "查询成功");
response.put("code", 200);
response.put("data", menus);
return new ResponseEntity(response, HttpStatus.OK);
}
private List<Menu> querySubMenus(Menu menu, Integer level, Integer status) {
List<Menu> subMenus = menuService.queryMenus(menu, null, level, status);
if (subMenus.size() > 0) {
subMenus.sort(Comparator.comparingInt(Menu::getSort_number));
menu.setSubMenus(subMenus);
for (Menu subMenu : subMenus) {
List<Menu> menus = querySubMenus(subMenu, level, status);
subMenu.setSubMenus(menus);
}
}
return subMenus;
}
@RequestMapping("/queryMenuById")
@ResponseBody
public ResponseEntity queryMenuById(@RequestParam(value = "id", required = false) Integer id,
@RequestParam(value = "level", required = false, defaultValue = "0") Integer level) {
Menu menu = menuService.queryMenuById(id);
Map<String, Object> response = new HashMap<>();
response.put("msg", "查询成功");
response.put("code", 200);
response.put("data", menu);
return new ResponseEntity(response, HttpStatus.OK);
}
@RequestMapping("/addMenu")
@ResponseBody
public ResponseEntity addMenu(@RequestParam(value = "name", required = false) String name,
@RequestParam(value = "icon", required = false) String icon,
@RequestParam(value = "route", required = false) String route,
@RequestParam(value = "superior_menu", required = false) Integer superior_menu,
@RequestParam(value = "sort_number", required = false) Integer sort_number,
@RequestParam(value = "level", required = false) Integer level,
@RequestParam(value = "status", required = false) Integer status) {
// 修改当前菜单状态
Menu menu = new Menu(null, name, icon, route, superior_menu, sort_number, level, status);
menuService.insertMenu(menu);
Map<String, Object> response = new HashMap<>();
response.put("msg", "添加成功");
response.put("code", 200);
return new ResponseEntity(response, HttpStatus.OK);
}
}
mapper
public interface MenuMapper {
List<Menu> queryMenus(@Param("menu") Menu menu, @Param("id") Integer id, @Param("level") Integer level, @Param("status") Integer status);
Integer insertMenu(Menu menu);
Integer updateMenu(Menu menu);
Menu queryMenuById(@Param("id") Integer id);
}
service
public interface MenuService {
List<Menu> queryMenus(Menu menu, Integer id, Integer level, Integer status);
Integer updateMenu(Menu menu);
Integer insertMenu(Menu menu);
Menu queryMenuById(Integer id);
}
serviceImpl
@Service("MenuService")
public class MenuServiceImpl implements MenuService {
@Resource
private MenuMapper menuMapper;
@Override
public List<Menu> queryMenus(Menu menu, Integer id, Integer level, Integer status) {
return menuMapper.queryMenus(menu, id, level, status);
}
@Override
public Integer insertMenu(Menu menu) {
return menuMapper.insertMenu(menu);
}
@Override
public Integer updateMenu(Menu menu) {
return menuMapper.updateMenu(menu);
}
@Override
public Menu queryMenuById(Integer id) {
return menuMapper.queryMenuById(id);
}
}
mybatis.xml
自行修改对应的namespace和resultType等参数
<!DOCTYPE mapper
PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="xxx.MenuMapper">
<insert id="insertMenu" keyColumn="id" keyProperty="id"
parameterType="xxx.Menu"
useGeneratedKeys="true">
insert into menus(`name`, `icon`, `route`, `superior_menu`, `sort_number`, `show_level`, `create_time`, `update_time`, `status`) values
(#{name}, #{icon}, #{route}, #{superior_menu}, #{sort_number}, #{show_level}, now(), now(), #{status})
</insert>
<select id="queryMenus" resultType="xxx.Menu">
select `id`, `name`, `icon`, `route`, `superior_menu`,`sort_number`, `show_level`, `status`, `create_time`, `update_time`
from `menus`
<where>
show_level <![CDATA[ <= ]]> #{level}
<if test="menu!=null and menu.id!=null">
and `superior_menu`= #{menu.id}
</if>
<if test="id != null">
and `id`= #{id}
</if>
<if test="menu==null or menu.superior_menu==null">
and `superior_menu`= 0
</if>
<if test="status!=null">
and `status`= #{status}
</if>
</where>
</select>
<select id="queryMenuById" resultType="xxx.Menu">
select * from menus where id = #{id}
</select>
<update id="updateMenu">
update menus
<set>
<if test="name != null">
`name`=#{name,jdbcType=VARCHAR},
</if>
<if test="icon != null">
icon=#{icon,jdbcType=VARCHAR},
</if>
<if test="route != null">
route=#{route,jdbcType=VARCHAR},
</if>
<if test="superior_menu != null">
superior_menu=#{superior_menu,jdbcType=INTEGER},
</if>
<if test="sort_number != null">
sort_number=#{sort_number,jdbcType=INTEGER},
</if>
<if test="show_level != null">
show_level=#{show_level,jdbcType=INTEGER},
</if>
<if test="status != null">
status=#{status,jdbcType=INTEGER},
</if>
</set>
where id = #{id,jdbcType=INTEGER}
</update>
</mapper>
VUE前端
<template>
<div>
<div class="div-padding">
<el-row :gutter="10" class="mgt20">
<el-col>
<i class="el-icon-menu" style="line-height: 30px; width: 30px; color:blue; font-size: 20px;"></i>
<span class="span-page-title">菜单管理</span>
</el-col>
</el-row>
<el-row :gutter="10">
<el-col :span="2">
<el-button style="width: 90px; line-height: 13px;" type="primary"
@click="onOpenAddMenuDialogButtonClick()">新增</el-button>
</el-col>
</el-row>
<el-row :gutter="10" class="mgt20">
<el-col>
<el-table border :data="menuList" class="table" border row-key="id"
:tree-props="{children: 'subMenus'}" header-cell-class-name="table-header">
<el-table-column prop="id" :show-overflow-tooltip="true" label="菜单编号"
width="100px"></el-table-column>
<el-table-column prop="name" :show-overflow-tooltip="true" label="菜单名称"></el-table-column>
<el-table-column prop="icon" :show-overflow-tooltip="true" align="center" label="菜单图标">
<template slot-scope="scope">
<i :class="scope.row.icon"></i>
</template>
</el-table-column>
<el-table-column prop="route" :show-overflow-tooltip="true" label="路由"
width="130px"></el-table-column>
<el-table-column prop="superior_menu" :show-overflow-tooltip="true" label="父菜单编号" width="90px">
</el-table-column>
<el-table-column prop="sort_number" :show-overflow-tooltip="true" label="菜单排序">
</el-table-column>
<el-table-column prop="show_level" :show-overflow-tooltip="true" label="显示级别">
</el-table-column>
<el-table-column prop="update_time" :show-overflow-tooltip="true" label="更新时间" width="160px">
<template slot-scope="scope">
{{$moment(scope.row.update_time).format("YYYY-MM-DD HH:mm:ss")}}
</template>
</el-table-column>
<el-table-column prop="status" :show-overflow-tooltip="true" label="状态">
<template slot-scope="scope">
<el-tag type="success" v-if="scope.row.status == 0">已启用</el-tag>
<el-tag type="danger" v-if="scope.row.status == 1">已禁用</el-tag>
</template>
</el-table-column>
<el-table-column label="操作" width="200px">
<template slot-scope="scope">
<el-button v-if="scope.row.status==1" icon="el-icon-check" type="primary" plain
size="mini" @click="enabledMenu(scope)">
启用
</el-button>
<el-button v-if="scope.row.status==0" icon="el-icon-delete" type="danger" plain
size="mini" @click="disabledMenu(scope)">
禁用
</el-button>
<el-button icon="el-icon-edit" type="success" plain size="mini"
@click="onOpenModifyMenuDialogButtonClick(scope)">
编辑
</el-button>
</template>
</el-table-column>
</el-table>
</el-col>
</el-row>
</div>
<!-- ========================================================== 新增、修改对话框 ========================================================== -->
<el-dialog width="30%" :title="menuDialog.title" :close-on-click-modal="false"
@close="onCloseMenuDialogButtonClick()" :close-on-press-escape="false" :visible.sync="menuDialog.visible">
<el-form :rules="rules" ref="ruleForm" :model="menuDialog.ruleForm" label-width="100px"
class="demo-ruleForm">
<el-row>
<el-col :span="24">
<el-form-item label="菜单名称" prop="name">
<el-input style="width: 80%;" v-model="menuDialog.ruleForm.name"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单图标" prop="icon">
<el-input style="width: 80%;" v-model="menuDialog.ruleForm.icon"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单路由" prop="route">
<el-input style="width: 80%;" v-model="menuDialog.ruleForm.route"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="上级菜单" prop="superior_menu">
<el-input style="width: 80%;" v-model="menuDialog.ruleForm.superior_menu"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单排序" prop="sort_number">
<el-input style="width: 80%;" v-model="menuDialog.ruleForm.sort_number"></el-input>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="菜单权限" prop="show_level">
<el-select style="width: 80%;" v-model="menuDialog.ruleForm.show_level" placeholder="请选择">
<el-option v-for="data in authorityOption" :key="data.key" :label="data.label"
:value="data.value"></el-option>
</el-select>
</el-form-item>
</el-col>
<el-col :span="24">
<el-form-item label="是否启用" prop="status">
<el-radio-group v-model="menuDialog.ruleForm.status">
<el-radio :label="0">启用</el-radio>
<el-radio :label="1">禁用</el-radio>
</el-radio-group>
</el-form-item>
</el-col>
</el-row>
<el-row>
<el-col :span="10">
<el-form-item>
<el-button v-if="menuDialog.title == '菜单修改'" type="primary"
@click="onModifyMenuButtonClick()">确定</el-button>
<el-button v-if="menuDialog.title == '菜单新增'" type="primary"
@click="onSubmitAddMenuButtonClick()">新增</el-button>
</el-form-item>
</el-col>
</el-row>
</el-form>
</el-dialog>
</div>
</template>
<script>
import {
addMenu,
getMenus,
updateMenus,
enabledMenus,
disableMenus
} from '../../assets/js/api.js'
export default {
data() {
return {
id: this.$route.query.id, // 传入的路由id
user: JSON.parse(sessionStorage.getItem("user")), // 用户信息,请自定义
authorityOption: this.$globle.authorityOption, // 权限列表,如[{key:"0",label:"游客",value:0},{key:"1",label:"普通用户",value:1},{key:"2",label:"系统管理员",value:2},{key:"3",label:"超级管理员",value:3}]
menuList: [],
// 菜单弹窗
menuDialog: {
visible: false,
title: "",
ruleForm: {
id: "",
name: "",
icon: "1",
route: "",
superior_menu: "",
sort_number: "1",
show_level: "",
status: 0
}
},
rules: {
name: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
icon: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
route: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
superior_menu: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
sort_number: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
show_level: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}],
status: [{
required: true,
message: '请输入完整信息',
trigger: 'blur'
}]
}
};
},
created() {
this.getMenuList();
},
methods: {
getMenuList() {
let params = {
level: this.user.level,
querySubMenus: true
}
getMenus(params).then((res) => {
this.menuList = res.data
});
},
//启用菜单
enabledMenu(scope) {
this.$confirm('确定启用该菜单吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let param = {
id: scope.row.id,
status: 0,
syncSubMenus: true
}
enabledMenus(param).then((res) => {
this.getMenuList();
})
}).catch(() => {
})
},
//禁用菜单
disabledMenu(scope) {
this.$confirm('确定禁用该菜单吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let param = {
id: scope.row.id,
status: 1,
syncSubMenus: true
}
enabledMenus(param).then((res) => {
this.getMenuList();
})
}).catch(() => {
})
},
// 修改
onOpenModifyMenuDialogButtonClick(scope) {
this.menuDialog.title = "菜单修改";
this.menuDialog.visible = true;
this.menuDialog.ruleForm.id = scope.row.id;
this.menuDialog.ruleForm.name = scope.row.name;
this.menuDialog.ruleForm.icon = scope.row.icon;
this.menuDialog.ruleForm.route = scope.row.route;
this.menuDialog.ruleForm.superior_menu = scope.row.superior_menu;
this.menuDialog.ruleForm.sort_number = scope.row.sort_number;
this.menuDialog.ruleForm.show_level = scope.row.show_level;
this.menuDialog.ruleForm.status = scope.row.status;
},
onModifyMenuButtonClick() {
this.$refs["ruleForm"].validate((valid) => {
if (valid) {
this.$confirm('确定修改菜单吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let param = {
id: this.menuDialog.ruleForm.id,
name: this.menuDialog.ruleForm.name,
icon: this.menuDialog.ruleForm.icon,
route: this.menuDialog.ruleForm.route,
superior_menu: this.menuDialog.ruleForm.superior_menu,
sort_number: this.menuDialog.ruleForm.sort_number,
level: this.menuDialog.ruleForm.show_level,
status: this.menuDialog.ruleForm.status
}
updateMenus(param).then((res) => {
if (res.code == "200") {
this.$message({
message: res.msg,
type: "success",
});
this.getMenuList();
this.closeMenuDialog();
} else {
this.$message({
message: res.msg,
type: "warning"
});
}
})
}).catch(() => {
// 添加错误捕获
})
} else {
return false;
}
});
},
// 新增
onOpenAddMenuDialogButtonClick() {
this.menuDialog.title = "菜单新增";
this.menuDialog.visible = true;
this.menuDialog.ruleForm.id = "";
this.menuDialog.ruleForm.name = "";
this.menuDialog.ruleForm.icon = "";
this.menuDialog.ruleForm.route = "";
this.menuDialog.ruleForm.superior_menu = "";
this.menuDialog.ruleForm.sort_number = "";
this.menuDialog.ruleForm.show_level = "";
this.menuDialog.ruleForm.status = 0;
},
onSubmitAddMenuButtonClick() {
this.$refs["ruleForm"].validate((valid) => {
if (valid) {
this.$confirm('确定新增菜单吗, 是否继续?', '提示', {
confirmButtonText: '确定',
cancelButtonText: '取消',
type: 'warning'
}).then(() => {
let param = {
name: this.menuDialog.ruleForm.name,
icon: this.menuDialog.ruleForm.icon,
route: this.menuDialog.ruleForm.route,
superior_menu: this.menuDialog.ruleForm.superior_menu,
sort_number: this.menuDialog.ruleForm.sort_number,
level: this.menuDialog.ruleForm.show_level,
status: this.menuDialog.ruleForm.status
}
addMenu(param).then((res) => {
if (res.code == "200") {
this.$message({
message: res.msg,
type: "success",
});
this.getMenuList();
this.closeMenuDialog();
} else {
this.$message({
message: res.msg,
type: "warning"
});
}
})
}).catch(() => {
// 添加错误捕获
})
} else {
return false;
}
});
},
onCloseMenuDialogButtonClick() {
this.closeMenuDialog();
},
closeMenuDialog() {
this.$refs['ruleForm'].resetFields();
this.menuDialog.title = "";
this.menuDialog.visible = false;
this.menuDialog.ruleForm.id = "";
this.menuDialog.ruleForm.name = "";
this.menuDialog.ruleForm.icon = "";
this.menuDialog.ruleForm.route = "";
this.menuDialog.ruleForm.superior_menu = "";
this.menuDialog.ruleForm.sort_number = "";
this.menuDialog.ruleForm.show_level = "";
this.menuDialog.ruleForm.status = 0;
},
handleSizeChange(val) {
},
handlePageChange(val) {
}
},
}
</script>
<style>
</style>