动态显式功能菜单
编写通过用户Id获取功能列表的SQL语句
-- 如何获取编号为1的用户拥有哪些功能?
SELECT DISTINCT n.*
FROM
sys_role_user ru , sys_role_node rn , sys_node n
WHERE
ru.role_id = rn.role_id AND user_id = 1
AND rn.node_id = n.node_id
ORDER BY n.node_code
在com.ql.oa.entity包下创建Nose.java实体类
package com.ql.oa.entity;
public class Node {
private Long nodeId;
private Integer nodeType;
private String nodeName;
private String url;
private Integer nodeCode;
private Long parentId;
public Long getNodeId() {
return nodeId;
}
public void setNodeId(Long nodeId) {
this.nodeId = nodeId;
}
public Integer getNodeType() {
return nodeType;
}
public void setNodeType(Integer nodeType) {
this.nodeType = nodeType;
}
public String getNodeName() {
return nodeName;
}
public void setNodeName(String nodeName) {
this.nodeName = nodeName;
}
public String getUrl() {
return url;
}
public void setUrl(String url) {
this.url = url;
}
public Integer getNodeCode() {
return nodeCode;
}
public void setNodeCode(Integer nodeCode) {
this.nodeCode = nodeCode;
}
public Long getParentId() {
return parentId;
}
public void setParentId(Long parentId) {
this.parentId = parentId;
}
}
在resources/mappers目录下新建rbac.xml文件,然后在mybatis-config.xml的mappers标签中配置下
<?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="rbacmapper">
<!--获取用户编号对应的功能列表-->
<select id="selectNodeByUserId" parameterType="Long" resultType="com.ql.oa.entity.Node">
SELECT DISTINCT n.*
FROM
sys_role_user ru , sys_role_node rn , sys_node n
WHERE
ru.role_id = rn.role_id AND user_id = #{value}
AND rn.node_id = n.node_id
ORDER BY n.node_code
</select>
</mapper>
<!--mybatis-config.xml中的配置-->
<mappers>
<mapper resource="mappers/user.xml"/>
<mapper resource="mappers/rbac.xml"/>
</mappers>
在com.ql.oa.dao包下新建RbacDao.java文件
package com.ql.oa.dao;
import com.ql.oa.entity.Node;
import com.ql.oa.utils.MyBatisUtils;
import java.util.List;
public class RbacDao {
public List<Node> selectNodeByUserId(Long userId){
return (List) MyBatisUtils.executeQuery(sqlSession -> sqlSession.selectList("rbacmapper.selectNodeByUserId", userId));
}
}
在UserService.java中添加方法
public List<Node> selectNodeByUserId(Long userId){
List<Node> nodeList = rbacDao.selectNodeByUserId(userId);
return nodeList;
}
修改登录成功的逻辑,登录成功后跳转index页面,所以修改LoginServlet.java和login.html的登录成功逻辑。
//调用业务逻辑
User user = userService.checkLogin(username, password);
HttpSession session = request.getSession();
//向session存入登录用户信息,属性名:login_user
session.setAttribute("login_user",user);
result.put("code", "0");
result.put("message", "success");
result.put("redirect_url", "/index");
if(json.code == "0"){ //登录校验成功
//layui.layer.msg("登录成功");
//跳转url
window.location.href=json.redirect_url;
}
然后编写请求路径为/index的servlet,在controller包下创建IndexServlet.java
package com.ql.oa.controller;
import com.ql.oa.entity.Node;
import com.ql.oa.entity.User;
import com.ql.oa.service.UserService;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
import java.util.List;
@WebServlet(name = "IndexServlet",urlPatterns = "/index")
public class IndexServlet extends HttpServlet {
private UserService userService = new UserService();
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//得到当前登录用户对象
User user = (User)session.getAttribute("login_user");
//获取登录用户可用功能模块列表
List<Node> nodeList = userService.selectNodeByUserId(user.getUserId());
//放入请求属性
request.setAttribute("node_list" , nodeList);
//请求派发至ftl进行展现
request.getRequestDispatcher("/index.ftl").forward(request,response);
}
}
然后在webapp/WEB-INF/ftl目录下创建insex.ftl
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>办公OA系统</title>
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<link rel="stylesheet" href="/resources/layui/css/layui.css">
</head>
<body class="layui-layout-body">
<!-- Layui后台布局CSS -->
<div class="layui-layout layui-layout-admin">
<!--头部导航栏-->
<div class="layui-header">
<!--系统标题-->
<div class="layui-logo" style="font-size:18px">办公OA系统</div>
<!--右侧当前用户信息-->
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:void(0)">
<!--图标-->
<span class="layui-icon layui-icon-user" style="font-size: 20px">
</span>
<!--用户信息-->
姓名[部门-职务]
</a>
</li>
<!--注销按钮-->
<li class="layui-nav-item"><a href="#">注销</a></li>
</ul>
</div>
<!--左侧菜单栏-->
<div class="layui-side layui-bg-black">
<!--可滚动菜单-->
<div class="layui-side-scroll">
<!--可折叠导航栏-->
<ul class="layui-nav layui-nav-tree">
<#list node_list as node>
<#if node.nodeType == 1>
<!--父节点-->
<li class="layui-nav-item layui-nav-itemed">
<a href="javascript:void(0)">${node.nodeName}</a>
<dl class="layui-nav-child module" data-node-id="${node.nodeId}"></dl>
</li>
</#if>
<#if node.nodeType == 2>
<!--子节点-->
<dd class="function" data-parent-id="${node.parentId}">
<a href="javascript:void(0)" target="ifmMain">${node.nodeName}</a>
</dd>
</#if>
</#list>
</ul>
</div>
</div>
<!--主体部分采用iframe嵌入其他页面-->
<div class="layui-body" style="overflow-y: hidden">
<iframe name="ifmMain" style="border: 0px;width: 100%;height: 100%"></iframe>
</div>
<!--版权信息-->
<div class="layui-footer">
Copyright © imooc. All Rights Reserved.
</div>
</div>
<!--LayUI JS文件-->
<script src="/resources/layui/layui.js"></script>
<script>
//将所有功能根据parent_id移动到指定模块下
layui.$(".function").each(function () {
var func = layui.$(this);
var parentId = func.data("parent-id");
layui.$("dl[data-node-id=" + parentId + "]").append(func);
})
//刷新折叠菜单
layui.element.render('nav');
</script>
</body>
</html>
运行项目测试,登录成功后跳转到index页并且动态带出菜单
Xml配置下实现Mapper接口
在com.ql.oa.entity包下创建Employee.java和Department.java实体类
package com.ql.oa.entity;
public class Employee {
private Long employeeId;
private String name;
private Long departmentId;
private String title;
private Integer level;
public Long getEmployeeId() {
return employeeId;
}
public void setEmployeeId(Long employeeId) {
this.employeeId = employeeId;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Long getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Long departmentId) {
this.departmentId = departmentId;
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public Integer getLevel() {
return level;
}
public void setLevel(Integer level) {
this.level = level;
}
}
package com.ql.oa.entity;
public class Department {
private Long departmentId;
private String departmentName;
public Long getDepartmentId() {
return departmentId;
}
public void setDepartmentId(Long departmentId) {
this.departmentId = departmentId;
}
public String getDepartmentName() {
return departmentName;
}
public void setDepartmentName(String departmentName) {
this.departmentName = departmentName;
}
}
在com.ql.oa.dao包下创建EmployeeDao.java和DepartmentDao接口
package com.ql.oa.dao;
import com.ql.oa.entity.Employee;
public interface EmployeeDao {
public Employee selectById(Long employeeId);
}
package com.ql.oa.dao;
import com.ql.oa.entity.Department;
public interface DepartmentDao {
public Department selectById(Long departmentId);
}
然后在resources/mappers目录创建employee.xml和department.xml编写接口实现
<?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">
<!--namespace与包名类名一致-->
<mapper namespace="com.ql.oa.dao.EmployeeDao">
<!--id与方法名对应
parameterType与方法参数类型对应
resultType与方法返回类型对应-->
<select id="selectById" parameterType="Long" resultType="com.ql.oa.entity.Employee">
select * from adm_employee where employee_id = #{value}
</select>
</mapper>
<?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">
<!--namespace与包名类名一致-->
<mapper namespace="com.ql.oa.dao.DepartmentDao">
<!--id与方法名对应
parameterType与方法参数类型对应
resultType与方法返回类型对应-->
<select id="selectById" parameterType="Long" resultType="com.ql.oa.entity.Department">
select * from adm_department where department_id = #{value}
</select>
</mapper>
并在mybatis-config.xml中配置mapper
<mappers>
<mapper resource="mappers/user.xml"/>
<mapper resource="mappers/rbac.xml"/>
<mapper resource="mappers/employee.xml"/>
<mapper resource="mappers/department.xml"/>
</mappers>
然后在com.ql.oa.service包下新增EmployeeService.java和DepartmentService.java
package com.ql.oa.service;
import com.ql.oa.dao.EmployeeDao;
import com.ql.oa.entity.Employee;
import com.ql.oa.utils.MyBatisUtils;
/**
* 员工服务
*/
public class EmployeeService {
/**
* 按编号查找员工
* @param employeeId 员工编号
* @return 员工对象,不存在时返回null
*/
public Employee selectById(Long employeeId){
return (Employee)MyBatisUtils.executeQuery(sqlSession -> {
EmployeeDao employeeDao = sqlSession.getMapper(EmployeeDao.class);
return employeeDao.selectById(employeeId);
});
}
}
package com.ql.oa.service;
import com.ql.oa.dao.DepartmentDao;
import com.ql.oa.entity.Department;
import com.ql.oa.utils.MyBatisUtils;
/**
* 部门服务
*/
public class DepartmentService {
/**
* 按编号得到部门对象
* @param departmentId 部门编号
* @return 部门对象,null代表部门不存在
*/
public Department selectById(Long departmentId){
return (Department) MyBatisUtils.executeQuery(
sqlSession -> sqlSession.getMapper(DepartmentDao.class).selectById(departmentId)
);
}
}
修改IndexServlet根据用户Id获取员工信息和部门信息,并放在会话当中
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
HttpSession session = request.getSession();
//得到当前登录用户对象
User user = (User)session.getAttribute("login_user");
//获取当前登录的员工对象
Employee employee = employeeService.selectById(user.getEmployeeId());
//获取员工对应的部门
Department department = departmentService.selectById(employee.getDepartmentId());
//获取登录用户可用功能模块列表
List<Node> nodeList = userService.selectNodeByUserId(user.getUserId());
//放入请求属性
request.setAttribute("node_list" , nodeList);
session.setAttribute("current_employee" , employee);
session.setAttribute("current_department", department);
//请求派发至ftl进行展现
request.getRequestDispatcher("/index.ftl").forward(request,response);
}
最后,在index.ftl中添加员工和部门信息
<!--右侧当前用户信息-->
<ul class="layui-nav layui-layout-right">
<li class="layui-nav-item">
<a href="javascript:void(0)">
<!--图标-->
<span class="layui-icon layui-icon-user" style="font-size: 20px">
</span>
<!--用户信息-->
${current_employee.name}[${current_department.departmentName}-${current_employee.title}]
</a>
</li>
<!--注销按钮-->
<li class="layui-nav-item"><a href="#">注销</a></li>
</ul>
运行项目登录成功后展示员工和部门名称