之前菜单都是写死的,现在做成可以变化的,首先创建一张menu的表
使用mybatis的生成映射文件的插件,指定我们的表
<table tableName="menu" />
我们需要修改一下menu的pojo类
public class Menu { private Integer id; private String text; private String url; private Menu parent; private Permission permission; private List<Menu> children = new ArrayList<>(); }
首先写controller层
package com.yang.web; import com.yang.domain.AjaxRes; import com.yang.domain.Menu; import com.yang.domain.PageListRes; import com.yang.domain.QueryVo; import com.yang.service.MenuService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.ResponseBody; import java.util.List; @Controller public class MenuController { /*注入*/ @Autowired private MenuService menuService; /*返回menu*/ @RequestMapping("/menu") public String menu(){ return "menu"; } /*返回menu列表*/ @RequestMapping("/menu/list") @ResponseBody public PageListRes menuList(QueryVo queryVo){ return menuService.getMenuList(queryVo); } /*返回所有的菜单*/ @RequestMapping("/menu/parent/list") @ResponseBody public List<Menu> parentList(){ return menuService.getAll(); } /*增加一个菜单*/ @RequestMapping("/menu/add") @ResponseBody public AjaxRes menuAdd(Menu menu){ return menuService.addMenu(menu); } /*更新菜单*/ @RequestMapping("/menu/edit") @ResponseBody public AjaxRes menuUpdate(Menu menu){ return menuService.updateMenu(menu); } /*删除菜单*/ @RequestMapping("/menu/delete") @ResponseBody public AjaxRes menuUpdate(Integer id){ return menuService.deleteMenu(id); } /*获取菜单结构树*/ @RequestMapping("/menu/tree") @ResponseBody public List<Menu> menuTree(){ return menuService.getMenuTree(); } }
接下来直接看业务层的实现类
package com.yang.service.impl; import com.github.pagehelper.Page; import com.github.pagehelper.PageHelper; import com.yang.domain.*; import com.yang.mapper.MenuMapper; import com.yang.service.MenuService; import org.apache.shiro.SecurityUtils; import org.apache.shiro.subject.Subject; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import java.util.Iterator; import java.util.List; @Service @Transactional public class MenuServiceImpl implements MenuService { /*注入mapper*/ @Autowired private MenuMapper menuMapper; /*返回menu列表*/ @Override public PageListRes getMenuList(QueryVo queryVo) { // 分页 Page<Object> page = PageHelper.startPage(queryVo.getPage(), queryVo.getRows()); // 查询 List<Menu> menus = menuMapper.selectAll(); // 封装返回结果 PageListRes pageListRes = new PageListRes(); pageListRes.setTotal(page.getTotal()); pageListRes.setRows(menus); return pageListRes; } /*返回所有的菜单*/ @Override public List<Menu> getAll() { return menuMapper.selectAll(); } /*增加一个菜单*/ @Override public AjaxRes addMenu(Menu menu) { AjaxRes ajaxRes = new AjaxRes(); try{ // 保存菜单 menuMapper.insert(menu); ajaxRes.setSuccess(true); ajaxRes.setMsg("保存菜单成功"); }catch (Exception e){ ajaxRes.setMsg("保存菜单失败"); ajaxRes.setSuccess(false); } return ajaxRes; } /*更新菜单*/ @Override public AjaxRes updateMenu(Menu menu) { AjaxRes ajaxRes = new AjaxRes(); try{ // 获取待更新菜单父节点 if(menu.getParent() != null){ Integer parentId = menuMapper.selectParentId(menu.getParent().getId()); if(parentId.equals(menu.getId())){ ajaxRes.setSuccess(false); ajaxRes.setMsg("自己的子菜单不能设置为父菜单"); return ajaxRes; } } // 更新菜单 menuMapper.updateByPrimaryKey(menu); ajaxRes.setSuccess(true); ajaxRes.setMsg("保存菜单成功"); }catch (Exception e){ ajaxRes.setMsg("保存菜单失败"); ajaxRes.setSuccess(false); } return ajaxRes; } /*删除菜单*/ @Override public AjaxRes deleteMenu(Integer id) { AjaxRes ajaxRes = new AjaxRes(); try{ // 保存菜单 menuMapper.deleteByPrimaryKey(id); ajaxRes.setSuccess(true); ajaxRes.setMsg("删除菜单成功"); }catch (Exception e){ ajaxRes.setMsg("删除菜单失败"); ajaxRes.setSuccess(false); } return ajaxRes; } /*获取菜单结构树*/ @Override public List<Menu> getMenuTree() { List<Menu> menus = menuMapper.getTreeMenu(); // 进行权限认证 // 首先获取当前主体 Subject subject = SecurityUtils.getSubject(); Employee employee = (Employee) subject.getPrincipal(); // 判断当前用户是否是管理员,如果是,则跳过验证 if(!employee.getAdmin()){ // 进行权限认证 checkPermission(menus); } return menus; } /*进行权限检验*/ public void checkPermission(List<Menu> menus){ // 获取主体 Subject subject = SecurityUtils.getSubject(); // 将菜单做成迭代器 Iterator<Menu> iterator = menus.iterator(); while (iterator.hasNext()){ Menu menu = iterator.next(); // 判断当前菜单是否需要进行权限校验 if(menu.getPermission() != null){ // 获取权限 String resource = menu.getPermission().getResource(); if(!subject.isPermitted(resource)){ // 将当前菜单从迭代器中删除,没有权限 iterator.remove(); continue; } } // 判断是否有子菜单 if(menu.getChildren().size() >0){ checkPermission(menu.getChildren()); } } } }
修改一下插件帮助我们自动生成的映射文件
<?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd"> <mapper namespace="com.yang.mapper.MenuMapper"> <resultMap id="BaseResultMap" type="com.yang.domain.Menu"> <id column="id" jdbcType="INTEGER" property="id" /> <result column="text" jdbcType="VARCHAR" property="text" /> <result column="url" jdbcType="VARCHAR" property="url" /> <!--封装父亲节点--> <association property="parent" javaType="com.yang.domain.Menu" columnPrefix="m_"> <result property="id" column="id" /> <result property="text" column="text" /> <result property="url" column="url" /> </association> <!--权限--> <association property="permission" javaType="com.yang.domain.Permission"> <result property="id" column="p_id" /> <result property="name" column="name" /> <result property="resource" column="resource" /> </association> <!--获取子菜单--> <collection property="children" ofType="com.yang.domain.Menu" select="listChildren" column="id"/> </resultMap> <delete id="deleteByPrimaryKey" parameterType="java.lang.Integer"> delete from menu where id = #{id,jdbcType=INTEGER} </delete> <insert id="insert" parameterType="com.yang.domain.Menu"> insert into menu (id, text, url, parent_id) values (#{id,jdbcType=INTEGER}, #{text,jdbcType=VARCHAR}, #{url,jdbcType=VARCHAR}, #{parent.id}) </insert> <update id="updateByPrimaryKey" parameterType="com.yang.domain.Menu"> update menu set text = #{text,jdbcType=VARCHAR}, url = #{url,jdbcType=VARCHAR}, parent_id = #{parent.id} where id = #{id,jdbcType=INTEGER} </update> <select id="selectAll" resultMap="BaseResultMap"> select m1.id, m1.text, m1.url, m2.id as m_id, m2.text as m_text, m2.url as m_url from `menu` as m1 left join `menu` as m2 on m1.parent_id = m2.id order by m1.id desc </select> <!--获取传入节点的父节点--> <select id="selectParentId" resultType="java.lang.Integer"> select parent_id from `menu` where id=#{id} </select> <select id="getTreeMenu" resultMap="BaseResultMap"> select m.id, m.text, m.url, m.parent_id, p.id as p_id, p.resource, p.name from `menu` as m left join `permission` as p on m.permission_id = p.id where m.parent_id is null; </select> <select id="listChildren" resultMap="BaseResultMap"> select m.id, m.text, m.url, m.parent_id, p.id as p_id, p.resource, p.name from `menu` as m left join `permission` as p on m.permission_id = p.id where m.parent_id =#{id}; </select> </mapper>
接下来看一下前端页面的js代码
首先修改一下index.js的代码
$('#tree').tree({ // 发送请求获取文件 url:"menu/tree", 。。。 }
menu.js文件
$(function () { // 数据表格 $('#dg').datagrid({ url: "menu/list", columns: [[ {field: "text", title: "名称", 100, align: "center"}, {field: "url", title: "跳转地址", 100, align: "center"}, { field: "parent", title: "父菜单", 100, align: "center", formatter: function (value, row, index) { return value ? value.text : ""; } }, ]], fit: true, rownumbers: true, singleSelect: true, striped: true, pagination: true, fitColumns: true, toolbar: "#tb", }); // 初始化增加/编辑对话框 $('#dialog').dialog({ 300, height: 240, closed: true, buttons: "#menu_dialog_bt", }); // 加载父级菜单 $('#parentMenu').combobox({ 150, panelHeight: "auto", editable: false, url: "menu/parent/list", textField: "text", // 显示内容 valueField: "id", // 传递内容 onLoadSuccess: function () { /*数据加载完成之后的回调*/ $('#parentMenu').each(function (i) { let span = $(this).siblings("span")[i]; let targetInput = $(span).find("input:first"); if (targetInput) { $(targetInput).attr("placeholder", $(this).attr("placeholder")) } }) } }); /*添加功能*/ $('#add').click(function () { $('#dialog').dialog("setTitle", "增加菜单"); $('#menuForm').form("clear"); $('#dialog').dialog("open") }); /*编辑功能*/ $('#edit').click(function () { // 清空表格内容 $('#menuForm').form("clear"); let rowData = $("#dg").datagrid("getSelected"); if (!rowData) { $.messager.alert("温馨提示", "至少需要选择一条数据"); return false; } else { /*回显的placeholder*/ $("#parentMenu").each(function (i) { let span = $(this).siblings("span")[i]; let targetInput = $(span).find("input:first"); if (targetInput) { $(targetInput).attr("placeholder", $(this).attr("placeholder")); } }); } // 设置菜单回显 if (rowData.parent) { rowData["parent.id"] = rowData.parent.id; } $("#dialog").dialog("setTitle", "编辑菜单"); $('#dialog').dialog("open"); $('#menuForm').form("load", rowData) }) /*点击保存按钮*/ $('#save').click(function () { let id = $("[name='id']").val(); let url; if (id) { // 判断父级菜单是否等于本季点 let parentId = $("[name='parent.id']").val(); if (parentId === id) { $.messager.alert("温馨提示", "父菜单是自身!") return false; } url = "menu/edit" } else { url = "menu/add" } // 提交表单 $('#menuForm').form("submit", { url: url, success: function (data) { data = $.parseJSON(data); if (data.success) { $.messager.alert("温馨提示", data.msg); /*关闭对话框 */ $("#dialog").dialog("close"); $("#parentMenu").combobox("reload"); $("#dg").datagrid("reload"); } else { $.messager.alert("温馨提示", data.msg); } } }) }); /*取消操作*/ $('#cancel').click(function () { $('#dialog').dialog("close"); }) /*删除操作*/ $('#delete').click(function () { // 清空表格内容 let rowData = $("#dg").datagrid("getSelected"); if (!rowData) { $.messager.alert("温馨提示", "至少需要选择一条数据"); return false; } // 提醒用户,是否做删除操作 $.messager.confirm("确认","是否做删除操作",function (res) { if(res){ /*做离职操作*/ $.get("/menu/delete?id="+rowData.id,function (data) { if (data.success){ $.messager.alert("温馨提示",data.msg); /*重新加载下拉列表数据*/ $("#parentMenu").combobox("reload"); /*重新加载数据表格*/ $("#dg").datagrid("reload"); } else { $.messager.alert("温馨提示",data.msg); } }); } }); }) });