SSM框架实现后台管理系统权限管理(用户、菜单、角色)

后台管理系统开发

功能模块:用户登录、权限管理(用户管理、菜单管理、角色管理)

技术应用:SSM框架+Mysql5.7+jsp+前端layui和EasyUI框架

项目工具:Maven+tomcat9.0+jdk1.8+GIT

开发工具:IDEA

测试环境:window7+搜狗浏览器10.0

 

一、数据库表结构设计

基础权限管理需要五张表:菜单、用户、角色、角色权限、用户角色

创建数据库

CREATE DATABASE IF NOT EXISTS exam;
1、菜单表menu
描述 字段 类型 约束
菜单id id int 主键自增
菜单名 name varchar 不能为空
链接页面 url varchar
父菜单id parent_id int
菜单排序 sort int
icon varchar
perms varchar
菜单类型 type smallint

建表sql:

CREATE TABLE menu (
	id int PRIMARY KEY AUTO_INCREMENT,
	name varchar(50) NOT NULL,
    parent_id int,
	url varchar(500),
	icon varchar(30),
	perms varchar(100),
	type smallint(6),
    sort int
);

插入数据:

insert into menu(name,icon,type,sort) value("权限管理","fa fa-bug",0,1);
insert into menu(name,parent_id,url,icon,perms,type,sort) value("菜单管理",2,"/sys/menu.html","fa fa-th-list","svs:menu:list",1,1000);
insert into menu(name,parent_id,url,icon,perms,type,sort) value("角色管理",2,"/sys/role.html","fa fa-key","svs:role:list",1,1000);
insert into menu(name,parent_id,url,icon,perms,type,sort) value("用户管理",2,"/sys/user.html","fa fa-user","svs:user:list",1,1000);

insert into menu(name,parent_id,perms,type,sort) value("添加",5,"sys:user:add",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("修改",5,"sys:user:update",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("删除",5,"sys:user:delete",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("授权",5,"sys:user:assign",2,1000);

insert into menu(name,parent_id,perms,type,sort) value("添加",3,"sys:menu:add",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("修改",3,"sys:menu:update",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("删除",3,"sys:menu:delete",2,1000);

insert into menu(name,parent_id,perms,type,sort) value("添加",4,"sys:role:add",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("修改",4,"sys:role:update",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("删除",4,"sys:role:delete",2,1000);
insert into menu(name,parent_id,perms,type,sort) value("授权",4,"sys:role:assign",2,1000);

2、用户表user
描述 字段 类型 约束
用户id id int 主键自增
用户名 account varchar 唯一、不能为空
用户密码 password varchar
暱称 nickname varchar
动态盐(用户名md5) salt varchar
用户状态 status int 为1正常,为0表示停用

建表sql:

CREATE TABLE user (
	id int PRIMARY KEY AUTO_INCREMENT,
	account varchar(50) NOT NULL UNIQUE,
	password varchar(50),
	nickname varchar(50),
	salt varchar(50),
    STATUS int DEFAULT '1'
);

插入数据:

insert into user(account, password, nickname)
VALUES ("a000001", "123456", "瞪谁谁怀孕"),
       ("a000002", "123456", "骑猪上高速"),
       ("a000003", "123456", "朕要去幼儿园深造了"),
       ("a000004", "123456", "帅到拖网速"),
       ("a000005", "123456", "遇蛇撑伞装许仙"),
       ("a000006", "123456", "谈情不如逗狗"),
       ("a000007", "123456", "地球是哥捏圆的"),
       ("a000008", "123456", "不贱不散"),
       ("a000009", "123456", "跳进海里躲雨"),
       ("a000010", "123456", "此用户下落不明")
       ("a000011", "123456", "软妹轰炸机"),
       ("a000012", "123456", "怡红院掌柜"),
       ("a000013", "123456", "被丢弃的小盆友"),
       ("a000014", "123456", "近猪者吃"),
       ("a000015", "123456", "跪是种美德"),
       ("a000016", "123456", "老衲逛青楼"),
       ("a000017", "123456", "武功再高也怕菜刀"),
       ("a000018", "123456", "镜子你又胖了"),
       ("a000019", "123456", "骑猪总裁"),
       ("a000020", "123456", "抢我辣条还想跑"),
       ("a000021", "123456", "骗子被骗子骗了"),
       ("a000022", "123456", "农夫三拳"),
       ("a000023", "123456", "夜以深,适宜私奔"),
       ("a000024", "123456", "卖女孩的小火柴"),
       ("a000025", "123456", "唐伯虎点蚊香"),
       ("a000026", "123456", "贱男春"),
       ("a000027", "123456", "老鼠上了猫"),
       ("a000028", "123456", "穷人的孩子早出家"),
       ("a000029", "123456", "车到山前是死路"),
       ("a000030", "123456", "我在马路边丢了一分钱"),
       ("a000031", "123456", "卖身葬楼主"),
       ("a000032", "123456", "人贱人爱"),
       ("a000033", "123456", "看野花一朵朵");
3、角色表role
描述 字段 类型 约束
角色id id int 主键自增
角色名 name varchar
角色备注 remark varchar
角色状态 status int

建表sql:

CREATE TABLE role (
	id int PRIMARY KEY AUTO_INCREMENT,
	name varchar(50) NOT NULL,
	remark varchar(50) NOT NULL,
	status int NOT NULL
);

插入数据:

INSERT INTO role (NAME, REMARK, STATUS) VALUES ('admin', '超级管理员', 1),
('test1', 'remark', 1),
('aa3', '3333', 0),
('asd', 'sadsa', 0),
('sa', 'asd', 0);
4、角色权限表role_menu
描述 字段 类型 约束
角色id role_id int 不能为空
菜单名 menu_id int 不能为空

建表sql:

CREATE TABLE role_menu (
	role_id int NOT NULL,
	menu_id int NOT NULL,
	CONSTRAINT `PRIMARY` PRIMARY KEY (role_id, menu_id)
);

插入数据:

INSERT INTO role_menu (role_id, menu_id) 
VALUES(1, 2),(1, 3),(1, 4),(1, 5),(1, 6),(1, 7),(1, 8),(1, 9),(1, 10),(1, 11),(1, 12),(1, 13),(1, 14),(1, 15);
INSERT INTO role_menu (role_id, menu_id) 
VALUES(2, 4),(2, 12),(2, 13),(2, 14),(2, 15);
5、用户角色表user_role
描述 字段 类型 约束
用户id user_id int 不能为空
角色id role_id int 不能为空

建表sql:

CREATE TABLE user_role (
	user_id int NOT NULL,
	role_id int NOT NULL,
	CONSTRAINT `PRIMARY` PRIMARY KEY (user_id, role_id)
);

插入数据:

INSERT INTO user_role (USER_ID, ROLE_ID) VALUES (1, 1),(2, 2);

二、项目准备

1、创建maven项目

建包

主包:com.booy.ssm.exam

子包:实体类包pojo、dao包、service包、controller包、utils包

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-h63d5ung-1592834137816)(\img\1.jpg)]

2、创建实体类

User类

package com.booy.ssm.exam.pojo;

import lombok.Data;

@Data
public class User {
    private Integer id;
    private String account;
    private String password;
    private String nickname;
    private Integer status;
}

Menu类:

package com.booy.ssm.exam.pojo;

import lombok.Data;

@Data
public class Menu {
    private Integer id;
    private String name;//菜单名
    private String url;
    private Integer parentId;//父id
    private Integer sort;//排序
}
3、添加依赖

在pom.xml添加项目所需要用到的依赖包

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.example</groupId>
    <artifactId>ssmdemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>war</packaging>
    <properties>
        <spring.version>5.1.3.RELEASE</spring.version>
    </properties>

    <dependencies>
        <!-- mybatis核心包 -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.4.1</version>
        </dependency>
        <!-- mysql驱动包 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.29</version>
        </dependency>
        <!--日志包-->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.6.1</version>
        </dependency>
        <!--spring数据库-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--aop-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring核心包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--spring-mybatis整合包-->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.1</version>
        </dependency>
        <!--spring相关包-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>${spring.version}</version>
        </dependency>
        <!--实体类注解-->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.16.22</version>
        </dependency>
        <!--分页插件-->
        <dependency>
            <groupId>com.github.pagehelper</groupId>
            <artifactId>pagehelper</artifactId>
            <version>4.2.1</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>3.1.0</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <!--配置资源文件扫描,否则Mapper-->
    <build>
        <resources>
            <resource>
                <directory>src/main/java</directory>
                <includes>
                    <include>**/*.xml</include>
                </includes>
                <filtering>true</filtering>
            </resource>
            <resource>
                <directory>src/main/resources</directory>
                <includes>
                    <include>**/*.xml</include>
                    <include>**/*.properties</include>
                </includes>
            </resource>
        </resources>
    </build>
</project>

三、登录功能简单实现

1、dao层

创建UserDAO接口:

package com.booy.ssm.exam.dao;

import com.booy.ssm.exam.pojo.User;

public interface UserDAO {
    User getUserByAccount(String account);
}

创建UserMapper.xml映射sql查询:

<?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.booy.ssm.exam.dao.UserDAO">
    <!--<![CDATA[你的注释]]>-->
    <select id="getUserByAccount" resultType="User" parameterType="String">
        select id, account, password,status
        from user
        where account=#{account}
    </select>
</mapper>
2、service层

创建UserService接口:

package com.booy.ssm.exam.service;

import com.booy.ssm.exam.pojo.User;

public interface UserService {
    //用户登录
    User dologin(String account,String password);
}

UserService接口实现类:

package com.booy.ssm.exam.service.impl;

import com.booy.ssm.exam.dao.UserDAO;
import com.booy.ssm.exam.pojo.User;
import com.booy.ssm.exam.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserDAO userDAO;

    @Override
    public User dologin(String account, String password) {
        User user = userDAO.getUserByAccount(account);
        if(user==null || !user.getPassword().equals(password)|| user.getStatus().equals(ExamConstants.USER_STATUS_DELETE)){
            return null;//账号或密码错误
        }
        return user;
    }
}
3、controller层

创建SystemController

package com.booy.ssm.exam.controller;

import com.booy.ssm.exam.pojo.User;
import com.booy.ssm.exam.service.UserService;
import com.booy.ssm.exam.utils.ExamConstants;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpSession;

@Controller
public class SystemController {
    @Autowired
    UserService userService;

    @RequestMapping("login.html")
    public String login(){
        return "login";
    }
    
    @RequestMapping("dologin.html")
    public String dologin(String account, String password, Model model, HttpSession session){
        User user = userService.dologin(account, password);
        if(user==null){
            model.addAttribute("message","用户名或密码错误!");
            return "login";
        }
        model.addAttribute("message","登录成功!");
        session.setAttribute(ExamConstants.SESSION_USER,user.getAccount());
        return "redirect:index.html";
    }
}
4、utils工具类
package com.booy.ssm.exam.utils;

public interface ExamConstants {
    String SESSION_USER="SESSION_USER";
    int USER_STATUS_DELETE=0;
}
5、引入配置文件

1)、jdbc配置文件jdbc.properties

jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/exam?characterEncoding=utf8
jdbc.username=root
jdbc.password=123456

2)、日志文件log4j.properties

log4j.rootLogger=DEBUG,stdout
log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m%n
#begin
#for normal test, delete when online
log4j.logger.com.ibatis=DEBUG
1og4j.logger.com.ibatis.common.jdbc.SimpleDataSource=DEBUG
log4j.logger.com.ibatis.common.jdbc.ScriptRunner=DEBUG
1og4j.logger.com.ibatis.sqlmap.engine.impl.SqlMapClientDelegate=DEBUG
1og4j.logger.java.sql.Connection=DEBUG
1og4j.logger.java.sql.Statement=DEBUG
1og4j.logger.java.sql.PreparedStatement=DEBUG
1og4j.1ogger.java.sq1.ResultSet=DEBUG

3)、spring配置文件spring-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--数据源管理-->
    <context:property-placeholder location="classpath:jdbc.properties" ignore-unresolvable="true"/>
    <bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--管理session工厂-->
    <bean id="sessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
        <!--指定数据源-->
        <property name="dataSource" ref="dataSource"/>
        <!--扫描pojo包,给包下所有pojo对象起别名-->
        <property name="typeAliasesPackage" value="com.booy.ssm.exam.pojo"/>
        <property name="mapperLocations" value="classpath:com/booy/ssm/exam/dao/mapper/*.xml"/>
        <!--配置PageHelper分页插件-->
        <property name="plugins">
            <array>
                <bean class="com.github.pagehelper.PageHelper">
                    <property name="properties">
                        <value>
                            dialect=mysql
                            reasonable=true
                        </value>
                    </property>
                </bean>
            </array>
        </property>
    </bean>

    <!--扫描接口包路径,生成包下所有接口的代理对象,并且放入spring容器中-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="com.booy.ssm.exam.dao" />
    </bean>
    <!--扫描指定包-->
    <context:component-scan base-package="com.booy.ssm.exam.service" >
        <!--指定扫描的是Service注解-->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    </context:component-scan>

    <!-- 事务管理器-->
    <bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>
    <!--定义事务规则-->
    <tx:advice id="txAdvice" transaction-manager="transactionManager">
        <!--对方法的增强-->
        <tx:attributes>
            <!--有异常时回滚事务-->
            <tx:method name="add*" rollback-for="Exception"/>
            <tx:method name="update*" rollback-for="Exception"/>
            <tx:method name="delete*" rollback-for="Exception"/>
            <tx:method name="get*" read-only="true"/>
        </tx:attributes>
    </tx:advice>
    <!--配置aop切入点-->
    <aop:config>
        <aop:pointcut id="point" expression="execution(* com.booy.ssm.exam.service..*(..))"/>
        <aop:advisor advice-ref="txAdvice" pointcut-ref="point"/>
    </aop:config>
</beans>

4)、springMvc配置文件springMvc-servlet.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:mvc="http://www.springframework.org/schema/mvc"
       xsi:schemaLocation=" http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context-4.2.xsd
       http://www.springframework.org/schema/mvc
       http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd">
    <!-- 启动注解,注册服务-->
    <mvc:annotation-driven/>
    <!--视图解析器-->
    <bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
        <property name="prefix" value="/WEB-INF/pages/"/>
        <property name="suffix" value=".jsp"/>
    </bean>
    <!-- 启动自动扫描-->
    <!-- 制定扫包规则 ,扫描controller包下面的类-->
    <context:component-scan base-package="com.booy.ssm.exam.controller">
        <!-- 扫描使用@Controller注解的JAVA 类 -->
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>
</beans>

5)、web配置文件web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
         http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         version="3.0">
    <!--将欢迎页设置成  index.html-->
    <welcome-file-list>
        <welcome-file>login.html</welcome-file>
    </welcome-file-list>
    <!--指定listener读取文件-->
    <context-param>
        <param-name>contextConfigLocation</param-name>
        <param-value>classpath:spring-config.xml</param-value>
    </context-param>
    <!--默认读取WEB-INF下的applicationContext.xml-->
    <listener>
        <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
    </listener>
    <!--配置  DispatcherServlet -->
    <servlet>
        <servlet-name>springMVC</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>springMVC</servlet-name>
        <url-pattern>*.html</url-pattern>
    </servlet-mapping>
    <!--解决编码乱码-->
    <filter>
        <filter-name>EncodingFilter</filter-name>
        <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>
        <init-param>
            <param-name>encoding</param-name>
            <param-value>UTF-8</param-value>
        </init-param>
    </filter>
    <filter-mapping>
        <filter-name>EncodingFilter</filter-name>
        <url-pattern>*.html</url-pattern>
    </filter-mapping>
</web-app>
6、layui创建登录页与后台主页

1)、在webapp下创建文件夹media引入layui文件和jquery文件

2)、创建jsp页面引入layui表单组件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>后台登录页面</title>
    <link rel="stylesheet" href="<%=request.getContextPath()%>/media/layui/css/layui.css">
</head>
<body>
<div class="layui-container">
    <div class="layui-row">
        <div class="layui-col-md9">
            <form class="layui-form" action="<%=request.getContextPath()%>/dologin.html" method="post">
                <div class="layui-form-item">
                    <label class="layui-form-label">用户名:</label>
                    <div class="layui-input-inline">
                        <input type="text" name="account" required lay-verify="required" placeholder="请输入用户名"
                               autocomplete="off"
                               class="layui-input">
                    </div>
                </div>
                <div class="layui-form-item">
                    <label class="layui-form-label">&nbsp;&nbsp;&nbsp;&nbsp;码:</label>
                    <div class="layui-input-inline">
                        <input type="password" name="password" required lay-verify="required" placeholder="请输入密码"
                               autocomplete="off" class="layui-input">
                    </div>
                    <div class="layui-form-mid layui-word-aux">${message}</div>
                </div>
                <div class="layui-form-item">
                    <div class="layui-input-block">
                        <button class="layui-btn" lay-submit lay-filter="formDemo">立即提交</button>
                        <button type="reset" class="layui-btn layui-btn-primary">重置</button>
                    </div>
                </div>
            </form>
        </div>
    </div>
</div>
</body>
</html>

3)、创建jsp后台主页面引入layui后台组件

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
    <title>考试管理系统</title>
    <link rel="stylesheet" href="<%=request.getContextPath()%>/media/layui/css/layui.css">
</head>
<body class="layui-layout-body">
<div class="layui-layout layui-layout-admin">
    <div class="layui-header">
        <div class="layui-logo">考试管理系统</div>
        <!-- 头部区域(可配合layui已有的水平导航) -->
        <ul class="layui-nav layui-layout-left">
            <li class="layui-nav-item"><a href="">控制台</a></li>
            <li class="layui-nav-item"><a href="">商品管理</a></li>
            <li class="layui-nav-item"><a href="">用户</a></li>
            <li class="layui-nav-item">
                <a href="javascript:;">其它系统</a>
                <dl class="layui-nav-child">
                    <dd><a href="">邮件管理</a></dd>
                    <dd><a href="">消息管理</a></dd>
                    <dd><a href="">授权管理</a></dd>
                </dl>
            </li>
        </ul>
        <ul class="layui-nav layui-layout-right">
            <li class="layui-nav-item">
                <a href="javascript:;">
                    <img src="http://t.cn/RCzsdCq" class="layui-nav-img">
                    贤心
                </a>
                <dl class="layui-nav-child">
                    <dd><a href="">基本资料</a></dd>
                    <dd><a href="">安全设置</a></dd>
                </dl>
            </li>
            <li class="layui-nav-item"><a href="">退了</a></li>
        </ul>
    </div>

    <div class="layui-side layui-bg-black">
        <div class="layui-side-scroll">
            <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
            <ul class="layui-nav layui-nav-tree"  lay-filter="test">
                <li class="layui-nav-item layui-nav-itemed">
                    <a class="" href="javascript:;">所有商品</a>
                    <dl class="layui-nav-child">
                        <dd><a href="javascript:;">列表一</a></dd>
                        <dd><a href="javascript:;">列表二</a></dd>
                        <dd><a href="javascript:;">列表三</a></dd>
                        <dd><a href="">超链接</a></dd>
                    </dl>
                </li>
                <li class="layui-nav-item">
                    <a href="javascript:;">解决方案</a>
                    <dl class="layui-nav-child">
                        <dd><a href="javascript:;">列表一</a></dd>
                        <dd><a href="javascript:;">列表二</a></dd>
                        <dd><a href="">超链接</a></dd>
                    </dl>
                </li>
                <li class="layui-nav-item"><a href="">云市场</a></li>
                <li class="layui-nav-item"><a href="">发布商品</a></li>
            </ul>
        </div>
    </div>

    <div class="layui-body">
        <!-- 内容主体区域 -->
        <div style="padding: 15px;">内容主体区域</div>
    </div>

    <div class="layui-footer">
        <!-- 底部固定区域 -->
        © layui.com - 底部固定区域
    </div>
</div>
<script src="<%=request.getContextPath()%>/media/layui/layui.js"></script>
<script>
    //JavaScript代码区域
    layui.use('element', function(){
        var element = layui.element;

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

登录页面效果
在这里插入图片描述

7、Tomcat配置与运行

配置tomcat并运行代码,在浏览器打开http://localhost:8080/login.html能打开并且可登录,表示初运行成功。

四、用户登录完善

1、配置拦截器

1)、创建interceptor包,创建拦截器类实现HandlerInterceptorAdapter接口的preHandle方法

package com.booy.ssm.exam.interceptor;

import com.booy.ssm.exam.utils.ExamConstants;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

public class LoginInterceptor extends HandlerInterceptorAdapter {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        if(request.getSession().getAttribute(ExamConstants.SESSION_USER)==null){
            response.sendRedirect("/login.html");
            return false;
        }
        return true;
    }
}

2)、springMVC-servlet.xml中配置拦截器规则

<!--拦截器配置-->
<mvc:interceptors>
    <mvc:interceptor>
        <mvc:mapping path="/*"/>
        <mvc:exclude-mapping path="/login.html"/>
        <mvc:exclude-mapping path="/dologin.html"/>
        <bean class="com.booy.ssm.exam.interceptor.LoginInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
2、登录退出实现

SystemController添加登录退出方法

//用户注销
@RequestMapping("logout.html")
public String logout(HttpSession session){
    session.invalidate();
    return "login";
}
3、展示登录暱称

在index.jsp中找到暱称位置修改为:

${sessionScope.SESSION_USER.nickname}
4、动态盐加密处理

创建MD5Utils工具类

package com.booy.ssm.exam.utils;

import org.springframework.util.DigestUtils;

public class MD5Utils {
    //添加时生成密码
    public static String getDigestMD5(String account, String password){
        String salt = DigestUtils.md5DigestAsHex(account.getBytes());
        return DigestUtils.md5DigestAsHex((salt + password).getBytes());
    }
    //登录时的密码
    public static String getLoginMD5(String salt, String password){
        return DigestUtils.md5DigestAsHex((salt + password).getBytes());
    }
}

UserServiceImpl实现类

@Override
public User dologin(String account, String password) {
    User user = userDAO.getUserByAccount(account);
    String loginMD5 = MD5Utils.getLoginMD5(user.getSalt(), password);
    System.out.println("加密后密码为"+loginMD5);
    System.out.println("加密后密码为"+user.getPassword());
    if(user==null || !user.getPassword().equals(loginMD5) || user.getStatus().equals(ExamConstants.USER_STATUS_DELETE)){
        return null;//账号或密码错误
    }
    return user;
}

五、导航展示

1、dao层

1)、创建MenuDAO接口

package com.booy.ssm.exam.dao;

import com.booy.ssm.exam.pojo.Menu;

import java.util.List;

public interface MenuDAO {
    List<Menu> getAllMenu();
}

2)、创建MenuMapper.xml映射sql查询:

<?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.booy.ssm.exam.dao.MenuDAO">
    <select id="getAllMenu" resultType="Menu">
        select id,name,parent_id parentId,url,sort from menu
    </select>
</mapper>

新增Menu实体类属性

private List<Menu> children=new ArrayList<>();
2、service层

创建MenuService接口:

package com.booy.ssm.exam.service;

import com.booy.ssm.exam.pojo.Menu;

import java.util.List;

public interface MenuService {
    List<Menu> getMenuTree();
}

创建MenuServiceInpl实现类:

package com.booy.ssm.exam.service.impl;

import com.booy.ssm.exam.dao.MenuDAO;
import com.booy.ssm.exam.pojo.Menu;
import com.booy.ssm.exam.service.MenuService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

@Service
public class MenuServiceImpl implements MenuService {
    @Autowired
    MenuDAO menuDAO;

    @Override
    public List<Menu> getMenuTree() {
        //所有菜单对象
        List<Menu> menus = menuDAO.getAllMenu();
        //一级菜单
        List<Menu> fistMenus=new ArrayList<>();
        //所有菜单键值对存储
        HashMap<Integer, Menu> menuMap = new HashMap<>();
        //遍历所有菜单对象,没有父节点存储到一级菜单列表,并且将所有菜单对象存储到map中
        for (Menu menu : menus) {
            if (menu.getParentId() == null) {
                fistMenus.add(menu);
            }
            menuMap.put(menu.getId(), menu);
        }
        //填充拼接菜单树,遍历所有菜单对象,有父节点存储到属性子节点列表
        for (Menu menu : menus){
            //不是一级菜单,并且map中有父节点,把当前菜单对象设置给父节点列表中
            if(menu.getParentId()!=null && menuMap.containsKey(menu.getParentId())){
                menuMap.get(menu.getParentId()).getChildren().add(menu);
            }
        }
        return fistMenus;
    }
}
3、controller层

新增SystemController方法

    @Autowired
    MenuService menuService;
//主页
@RequestMapping("index.html")
public String index(Model model){
    List<Menu> menuList = menuService.getMenuTree();
    model.addAttribute("menuList",menuList);
    return "index";
}

菜单树显示效果

在这里插入图片描述

4、jsp页面配置

pom.xml中添加jstl依赖

<dependency>
    <groupId>jstl</groupId>
    <artifactId>jstl</artifactId>
    <version>1.2</version>
</dependency>

index.jsp页面

<div class="layui-side layui-bg-black">
    <div class="layui-side-scroll">
        <!-- 左侧导航区域(可配合layui已有的垂直导航) -->
        <ul class="layui-nav layui-nav-tree" lay-filter="test">
            <c:forEach items="${requestScope.menuList}" var="parent">
                <li class="layui-nav-item layui-nav-itemed">
                    <a class="" href="javascript:;">${parent.name}</a>
                    <c:if test="${not empty parent.children}">
                        <dl class="layui-nav-child">
                            <c:forEach items="${parent.children}" var="c">
                                <dd><a href="javascript:;" >${c.name}</a></dd>
                            </c:forEach>
                        </dl>
                    </c:if>
                </li>
            </c:forEach>
        </ul>
    </div>
</div>
5、页面局部加载

1)、创建UserController

package com.booy.ssm.exam.controller;

import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;

@Controller
@RequestMapping("/sys/user.html")
public class UserController {
    @RequestMapping
    public String user(){
        return "User";
    }
}

2)、创建user.jsp页面

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
我是用户管理页面

3)、新增index.jsp页面加载局部js

<dd><a href="javascript:;" οnclick="$('#main-content').load('${c.url}')">${c.name}</a></dd>

六、实现用户管理功能

用户管理功能:新增用户、修改用户,删除用户,条件查询用户

1、dao层

新增UserDAO接口删除用户、添加用户、修改用户和查询用户列表方法

    void addUser(User user);
    void updateUser(User user);
    List<User> getUserList(User user);
    void deleteUser(int id);

新增UserMapper.xml映射sql查询:

    <insert id="addUser" parameterType="User" >
        insert into user(account, password,nickname) values(#{account},#{password},#{nickname})
    </insert>
    <update id="updateUser" parameterType="User">
        update user <set>
        <if test="password!=null and password!=''">password=#{password},</if>
        <if test="nickname!=null and nickname!=''">nickname=#{nickname},</if>
        <if test="status!=null">status=#{status}</if>
    </set>
    where id=#{id}
    </update>
    <update id="deleteUser" parameterType="int">
        update user set status=0 where id=#{id}
    </update>
    <select id="getUserList" parameterType="User" resultType="User">
        select id, account, password,nickname,status
        from user
        <where>
            <if test="account!=null and account!=''">and account like concat('%',#{account},'%')</if>
            <if test="nickname!=null and nickname!=''">
                <bind name="temp" value="'%'+nickname+'%'"/>
                and nickname like #{temp}
            </if>
        </where>
    </select>
2、返回状态工具类

AjaxResult,新增、修改和删除时给前端的返回状态值

package com.booy.ssm.exam.utils;

import lombok.Data;

@Data
public class AjaxResult {
    private boolean status;//是否成功
    private String message;//提示信息
    private Object result;//成功信息

    public AjaxResult() {
    }

    public AjaxResult(boolean status, String message, Object result) {
        this.status = status;
        this.message = message;
        this.result = result;
    }
}
3、service层

新增UserService接口方法:

    AjaxResult addUser(User user);
    AjaxResult updateUser(User user);
    PageInfo<User> getUserList(User user,int pageNum,int pageSize);
    AjaxResult deleteUser(int[] ids);

新增UserServiceImpl实现类方法:

    @Override
    public AjaxResult addUser(User user) {
        AjaxResult result = new AjaxResult();
        if(userDAO.getUserByAccount(user.getAccount())==null ){
            userDAO.addUser(user);
            result.setStatus(true);
            return result;
        }
        result.setStatus(false);
        result.setMessage("用户名已存在!");
        return result;
    }

    @Override
    public AjaxResult updateUser(User user) {
        AjaxResult result = new AjaxResult();
        try {
            System.out.println("user="+user);
            userDAO.updateUser(user);
            result.setStatus(true);
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus(false);
            result.setMessage("更新失败!");
        }
        return result;
    }

    @Override
    public PageInfo<User> getUserList(User user, int pageNum, int pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        PageInfo<User> users = new PageInfo<>(userDAO.getUserList(user));
        return users;
    }

    @Override
    public AjaxResult deleteUser(int[] ids) {
        AjaxResult result = new AjaxResult();
        for(int id:ids){
            userDAO.deleteUser(id);
        }
        result.setStatus(true);
        return result;
    }
4、controller层

新增UserController数据操作功能

@RequestMapping(params = "act=edit")
@ResponseBody
public AjaxResult edit(User user){
    //添加
    if(user.getId()==null){
        AjaxResult result = userService.addUser(user);
        return result;
    }else{//修改
        AjaxResult result = userService.updateUser(user);
        return result;
    }
}
@RequestMapping(params = "act=delete")
@ResponseBody
public AjaxResult deleteUser(int[] ids){
    try {
        AjaxResult result = userService.deleteUser(ids);
        result.setStatus(true);
        return result;
    } catch (Exception e) {
        e.printStackTrace();
        AjaxResult result = new AjaxResult();
        result.setStatus(false);
        result.setMessage("删除失败!");
        return result;
    }
}
5、动态表格数据渲染

1)、新增user.jsp页面动态表格

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<table id="userTable" lay-filter="test"></table>

<script>
    layui.use('table', function(){
       //初始化table对象,当前页面所有table都归lay管理,以id区分
        var table = layui.table;

        table.render({
            elem: '#userTable'//渲染的table
            ,height: 668
            ,url: '/sys/user.html?act=table' //数据接口
            ,page: true //开启分页
            ,limit:15
            ,limits:[15,30,45,60,75,90]
            ,cols: [[ //表头
                {field: 'id', title: 'ID', width:80,  fixed: 'left'}
                ,{field: 'account', title: '用户名'}
                ,{field: 'nickname', title: '暱称'}
            ]]
        });

    });
</script>

2)、创建封装返回数据的工具类TableData

import lombok.Data;

import java.util.List;

//数据封装
@Data
public class TableData<T> {
    private int code=0;
    private String msg="";
    private long count;
    private List<T> data;

    public TableData() {
    }

    public TableData(long count, List<T> data) {
        this.count = count;
        this.data = data;
    }
}

3)、新增返回的数据接口

import com.booy.ssm.exam.pojo.User;
import com.booy.ssm.exam.service.UserService;
import com.booy.ssm.exam.utils.TableData;
import com.github.pagehelper.PageInfo;
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;

@Controller
@RequestMapping("/sys/user.html")
public class UserController {
    @Autowired
    private UserService userService;

    @RequestMapping
    public String user(){
        return "user";
    }

    @RequestMapping(params = "act=table")
    @ResponseBody
    public TableData table(User user,int page,int limit){
        PageInfo<User> pageInfo = userService.getUserList(user, page, limit);
        TableData tableData = new TableData(pageInfo.getTotal(), pageInfo.getList());
        return tableData;
    }
}

4)、在pom中添加json依赖

注意json版本和spring版本的匹配

<!--json依赖-->
<dependency>
    <groupId>com.fasterxml.jackson.core</groupId>
    <artifactId>jackson-databind</artifactId>
    <version>2.11.0</version>
</dependency>

5)、在springMVC中配置json数据转换

<!--配置返回值转换器-->
<bean id="contentNegotiationManagerFactoryBean"
      class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <!--是否支持后缀匹配-->
    <property name="favorPathExtension" value="false"/>
    <!--是否支持参数匹配-->
    <property name="favorParameter" value="false"/>
    <!--是否 accept-header 匹配-->
    <property name="ignoreAcceptHeader" value="false"/>
    <property name="mediaTypes">
        <map>
            <!--表示.json 结尾的请求返回 json-->
            <entry key="json" value="application/json"/>
        </map>
    </property>
</bean>

启用json

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManagerFactoryBean"/>

用户数据显示效果:
在这里插入图片描述

6、条件检索功能实现

新增user.jsp中搜索框,表格重载渲染

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%--顶部搜索--%>
<div class="layui-form-item">
    <form class="layui-form">
        <div class="layui-inline">
            <label class="layui-form-label">用户名:</label>
            <div class="layui-input-inline" style="width: 200px;">
                <input type="text" name="account" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-inline">
            <label class="layui-form-label">暱称:</label>
            <div class="layui-input-inline" style="width: 200px;">
                <input type="text" name="nickname" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-inline">
            <button class="layui-btn" lay-submit  lay-filter="searchForm">查询</button>
        </div>
    </form>

</div>
<%--动态表格--%>
<table id="userTable" lay-filter="test"></table>

<script>
    layui.use(['table','form'], function(){
        //初始化table对象,当前页面所有table都归lay管理,以id区分
        var table = layui.table;
        var form = layui.form;

        table.render({
            id:'userTable'//渲染后的table
            ,elem: '#userTable'//渲染的table
            ,height: 668
            ,url: '/sys/user.html?act=table' //数据接口
            ,page: true //开启分页
            ,limit:15
            ,limits:[15,30,45,60,75,90]
            ,cols: [[ //表头
                {field: 'id', title: 'ID', width:80,  fixed: 'left'}
                ,{field: 'account', title: '用户名'}
                ,{field: 'nickname', title: '暱称'}
            ]]
        });
        form.on('submit(searchForm)', function(data){
            console.log(data.field);//当前容器的全部表单字段,名值对形式:{name: value}
            table.reload('userTable', {
                where: data.field //设定异步数据接口的额外参数
                //,height: 300
            });
            return false;
        });
    });
</script>

条件搜索效果:
在这里插入图片描述

7、页面头部工具栏实现

新增User.jsp代码

1)、添加复选框

table.render里的表头第一行添加如下代码:

{type: 'checkbox', fixed: 'left'}

2)、添加头部工具栏

<script type="text/html" id="headtool">
    <div class="layui-btn-container">
       <button class="layui-btn layui-btn-sm " lay-event="add"><i class="layui-icon">&#xe654;</i>添加</button>
        <button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="update"><i class="layui-icon">&#xe642;</i>编辑</button>
        <button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="delete"><i class="layui-icon">&#xe640;</i>删除</button>
    </div>
</script>

在table.render中调用以上代码

//JS 调用:
table.render({
elem: '#demo'
,toolbar: '#headtool'
//,…… //其他参数
});

复选框及工具栏显示效果
在这里插入图片描述

3)、弹出层代码块

<%--添加功能弹出层--%>
<script type="text/html" id="editFormlayer">
    <form class="layui-form" style="width:80%;padding-top: 20px" id="editForm" lay-filter="editForm">
        <input type="hidden" name="id">
        <div class="layui-form-item">
            <label class="layui-form-label">用户名:</label>
            <div class="layui-input-block">
                <input type="text" name="account" required lay-verify="required" placeholder="请输入用户名" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">密码:</label>
            <div class="layui-input-inline">
                <input type="password" name="password" required lay-verify="required" placeholder="请输入密码"
                       autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">暱称:</label>
            <div class="layui-input-block">
                <input type="text" name="nickname" required lay-verify="required" placeholder="请输入暱称" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">状态</label>
            <div class="layui-input-block">
                <input type="radio" name="status" value="1" title="有效">
                <input type="radio" name="status" value="0" title="无效">
            </div>
        </div>
    </form>
</script>

4)、头部工具条js

头部工具条具体实现的js,主要为事件监听、打开弹出层及json传输数据

<%--工具条--%>
<script>
    layui.use(['table', 'form'], function () {
        //初始化table对象,当前页面所有table都归lay管理,以id区分
        var table = layui.table;
        var form = layui.form;

        table.render({
            id: 'userTable'//设置渲染后的table
            , elem: '#userTable'//根据id取首次渲染的table
            , toolbar: '#headtool'//头部工具条
            , height: 600
            , url: '/sys/user.html?act=table' //数据接口
            , page: true //开启分页
            , cols: [[ //表头
                {type: 'checkbox', fixed: 'left'}
                , {field: 'id', title: 'ID', width: 80}
                , {field: 'account', title: '用户名'}
                , {field: 'nickname', title: '暱称'}
                , {field: 'status', title: '状态' ,templet: function(d){
                        return d.status==1?'<span class="layui-badge layui-bg-green">正常</span>':'<span class="layui-badge layui-bg-gray">停用</span>'
                    }}
                ,{fixed: 'right', width:150, align:'center', toolbar: '#rowtool'}
            ]]
        });
        //添加搜索渲染
        form.on('submit(searchForm)', function (data) {
            console.log(data.field);//当前容器的全部表单字段,名值对形式:{name: value}
            table.reload('userTable', {//渲染后的tableid
                where: data.field //设定异步数据接口的额外参数
                //,height: 300
            });
            return false;
        });
        //监听头部工具条事件
        table.on('toolbar(userTable)', function (obj) {
            var checkStatus = table.checkStatus(obj.config.id);
            var data = checkStatus.data;//获取选中行数据
            switch (obj.event) {
                case 'add':
                    if (data.length>0) {
                        return;
                    }
                    openidielayer(data);//null
                    break;
                case 'delete':
                    if (data.length<1) {
                        return;
                    }
                    layer.confirm('你确定要删除吗?', {
                        btn: ['确定','取消'] //按钮
                    }, function(index){
                        var ids = new Array();
                        for (var i = 0; i < data.length; i++) {
                            ids.push(data[i].id)
                        }
                        $.ajax({
                            url: "/sys/user.html?act=delete",
                            method: "post",
                            data: "ids="+ids,//jquery获取表单内容
                            success: function (res) {
                                if (res.status) {
                                    table.reload('userTable', {});//删除数据后刷新table
                                } else {
                                    layer.msg(res.message);
                                }
                            }
                        })
                        layer.close(index)
                    })

                    break;
                case 'update':
                    if (data.length != 1) {
                        layer.msg('请选中一行数据');
                        return;
                    }
                    openidielayer(data[0]);
                    break;
            }
            ;
        });
        //打开弹出层,添加编辑共用
        function openidielayer(data) {//打开后往表单里添加数据
            layer.open({
                type: 1
                , area: '500px'
                , content: $("#editFormlayer").html()
                , btn: ['确认', '取消']
                , yes: function (index, layero) {
                    $.ajax({
                        url: "/sys/user.html?act=edit",
                        method: "post",
                        data: $("#editForm").serialize(),//jquery获取表单内容
                        success: function (res) {
                            if (res.status) {
                                table.reload('userTable', {});//添加数据后刷新table
                                layer.close(index);
                            } else {
                                layer.msg(res.message);
                            }
                        }
                    })
                }
                , btn2: function (index, layero) {
                    layer.close(index)
                }, success: function (layero, index) {
                    console.log(data);
                    form.render();//重新渲染table
                    form.val("editForm",data);//获取array的第0个元素渲染表单
                    form.val("editForm",{status:data.status+""});//数字转字符串才能被渲染
                }
            });
        }
    });
</script>
8、页面数据行工具条实现

新增User.jsp代码

1)、页面展示

<%--行工具条--%>
<script type="text/html" id="rowtool">
    <a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">编辑</a>
    <a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>

2)、新增js片段

//监听行工具条
table.on('tool(userTable)', function(obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
    var data = obj.data; //获得当前行数据
    var layEvent = obj.event; //获得 lay-event 对应的值
    switch (layEvent) {
        case 'del':
            layer.confirm('你确定要删除吗?', {
                btn: ['确定','取消'] //按钮
            }, function(index){
                $.ajax({
                    url: "/sys/user.html?act=delete",
                    method: "post",
                    data: "ids="+data.id,//获取当前行的id
                    success: function (res) {
                        if (res.status) {
                            table.reload('userTable', {});//删除数据后刷新table
                        } else {
                            layer.msg(res.message);
                        }
                    }
                })
                layer.close(index)
            })

            break;
        case 'edit':
            openidielayer(data);
            break;
    }
})
9、页面效果

页面全局效果

在这里插入图片描述

添加功能

复选框没有选中的情况才能打开

在这里插入图片描述

头部修改功能

只能选中一行且必须选中一行才能修改,多选或不选给提示,右侧则直接弹出层

在这里插入图片描述

删除功能

头部工具条多条批量删除,右侧工具条删除当前条

在这里插入图片描述

七、实现菜单管理功能

1、菜单树显示

1)、MenuController向页面返回菜单树

@RequestMapping(params = "act=tree")
@ResponseBody
public List<Menu> MenuTree(Boolean needButton){
    return menuService.getMenuTree(true);
}

此处更改了MenuService接口和实现类的菜单树方法重载,当方法为true需要按钮菜单,index页面不需要按钮菜单,而菜单管理页面需要

List<Menu> getMenuTree(Boolean needButton);

2)、引入EasyUI的js和css文件

<script src="media/jquery.easyui.min.js"/>
<link rel="stylesheet" href="media/easyui.css">

3)、页面标签:

<button class="layui-btn layui-btn-sm" id="addMenu"><i class="layui-icon">&#xe654;</i>添加</button>
<button class="layui-btn layui-btn-sm layui-btn-danger" id="delMenu"><i class="layui-icon">&#xe640;</i>删除</button>
<ul id="menu-tree" class="easyui-tree">
</ul>

4)、菜单树显示js

<script>
    layui.use(['form'], function () {
        $('#menu-tree').tree({
            url: "sys/menu.html?act=tree&needButton=true",//数据接口
            checkbox: true,
            formatter: function (node) {
                return node.name;//获取节点的内容
            }
        })
      })

显示效果:
在这里插入图片描述

2、dao层

新增MenuDAO接口增删改方法

void addMenu(Menu menu);
void updateMenu(Menu menu);
void deleteMenu(Integer id);

新增MenuMapper.xml增删改映射sql:

<insert id="addMenu" parameterType="Menu">
    insert into menu(name, parent_id, url, type) VALUES(#{name},#{parentId},#{url},#{type})
</insert>
<update id="updateMenu" parameterType="Menu">
    update menu set
        <if test="name!=null and name!=''">name=#{name},</if>
        <if test="parentId!=null and parentId!=''">parent_id=#{parentId},</if>
        <if test="url!=null and url!=''">url=#{url},</if>
        <if test="type!=null">type=#{type}</if>
         where id=#{id}
</update>
<delete id="deleteMenu" parameterType="int">
    delete from menu where id=#{id}
</delete>
3、service层

新增MenuService接口增删改方法

void addMenu(Menu menu);
void updateMenu(Menu menu);
void deleteMenu(int[] ids);

新增MenuServiceImpl实现类增删改方法

@Override
public void addMenu(Menu menu) {
    menuDAO.addMenu(menu);
}

@Override
public void updateMenu(Menu menu) {
    menuDAO.updateMenu(menu);
}

@Override
public void deleteMenu(int[] ids) {
    for(int id:ids){
        menuDAO.deleteMenu(id);
    }
}
4、controller层

新增MenuController增删改方法

@RequestMapping(params = "act=edit")
@ResponseBody
public AjaxResult edit(Menu menu){
    AjaxResult result = new AjaxResult();
    //添加功能
    try {
        if(menu.getId()==null){
            menuService.addMenu(menu);
        }else{
            menuService.updateMenu(menu);
        }
        result.setStatus(true);
    } catch (Exception e) {
        e.printStackTrace();
        result.setStatus(false);
        result.setMessage("编辑失败!");
    }
    return result;
}
@RequestMapping(params = "act=delete")
@ResponseBody
public AjaxResult deleteMenu(int[] ids){
    AjaxResult result = new AjaxResult();
    try {
        menuService.deleteMenu(ids);
        result.setStatus(true);
    } catch (Exception e) {
        e.printStackTrace();
        result.setStatus(false);
        result.setMessage("删除失败!");
    }
    return result;
}

5、页面处理

1)、添加功能弹出层代码块

<%--添加功能弹出层--%>
<script type="text/html" id="editFormlayer">
    <form class="layui-form" style="width:80%;padding-top: 20px" id="editForm" lay-filter="editForm">
        <input type="hidden" name="id">
        <div class="layui-form-item">
            <label class="layui-form-label">菜单名</label>
            <div class="layui-input-block">
                <input type="text" name="name" required lay-verify="required" placeholder="请输入菜单名" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">父节点</label>
            <div class="layui-input-block">
                <input type="text" name="parentId" id="parentId">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">url</label>
            <div class="layui-input-block">
                <input type="text" name="url" placeholder="请输入url" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">状态</label>
            <div class="layui-input-block">
                <input type="radio" name="type" value="0" checked title="目录">
                <input type="radio" name="type" value="1" title="链接">
                <input type="radio" name="type" value="2" title="按钮">
            </div>
        </div>
    </form>
</script>

2)、菜单管理模块js

<script>
    layui.use(['form'], function () {
        var form = layui.form;//初始化form
        $('#menu-tree').tree({
            url: "sys/menu.html?act=tree&needButton=true",//数据接口
            checkbox: true,
            formatter: function (node) {
                return node.name;//获取节点的内容
            }, onClick: function (node) {
                openidielayer(node)
            }
        })
        $('#addMenu').click(function () {
            openidielayer(null)
        })
        $('#delMenu').click(function () {
            layer.confirm('你确定要删除吗?', {
                btn: ['确定','取消'] //按钮
            }, function(index){
                var nodes = $('#menu-tree').tree('getChecked');
                var ids=new Array();
                for (var i = 0; i <nodes.length ; i++) {
                    ids.push(nodes[i].id);
                }
                $.ajax({
                    url: "/sys/menu.html?act=delete",
                    method: "post",
                    data: "ids="+ids,
                    success: function (res) {
                        if (res.status) {
                            $('#menu-tree').tree('reload');
                        } else {
                            layer.msg(res.message);
                        }
                    }
                })
                layer.close(index)
            })
        })

        //打开弹出层,添加编辑共用
        function openidielayer(data) {//打开后往表单里添加数据
            layer.open({
                type: 1
                , zIndex: 10000
                , area: '500px'
                , content: $("#editFormlayer").html()
                , btn: ['确认', '取消']
                , yes: function (index, layero) {
                    $.ajax({
                        url: "/sys/menu.html?act=edit",
                        method: "post",
                        data: $("#editForm").serialize(),//jquery获取表单内容
                        success: function (res) {
                            if (res.status) {
                                $('#menu-tree').tree('reload');
                                layer.close(index);
                            } else {
                                layer.msg(res.message);
                            }
                        }
                    })
                }
                , btn2: function (index, layero) {
                    layer.close(index)
                }, success: function (layero, index) {
                    console.log(data);
                    form.render();//重新渲染table
                    if (data != null) {
                        form.val("editForm", data);//获取array的元素渲染表单
                        form.val("editForm", {type: data.type + '',});//数字转字符串才能被渲染
                    }
                    //表单初始化完成后初始化input
                    $('#parentId').combotree({
                        url: 'sys/menu.html?act=tree&needButton=false',
                        required: true
                    });
                }
            });
        }
    })
</script>
5、页面效果

添加菜单

在这里插入图片描述

删除菜单

在这里插入图片描述

编辑菜单

在这里插入图片描述

八、实现角色管理功能

1、dao层

创建Role实体类

package com.booy.ssm.exam.pojo;

import lombok.Data;

@Data
public class Role {
    private Integer id;
    private String name;
    private String remark;
    private Integer status;
}

创建RoleDAO接口

package com.booy.ssm.exam.dao;

import com.booy.ssm.exam.pojo.Role;

import java.util.List;

public interface RoleDAO {
    List<Role>  getRoleList();
    List<Role> getRoleListByIF(Role role);
    void addRole(Role role);
    void updateRole(Role role);
    void deleteRole(Integer id);
}

创建RoleMapper映射sql

<?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.booy.ssm.exam.dao.RoleDAO">
    <select id="getRoleList" resultType="Role">
        select id, name, remark, status
        from role
    </select>
    <select id="getRoleListByIF" parameterType="Role" resultType="Role">
        select id,name,remark,status from role
        <where>
            <if test="name!=null and name!=''">and name like concat('%',#{name},'%')</if>
            <if test="remark!=null and remark!=''">and remark like concat('%',#{remark},'%')</if>
        </where>
    </select>
    <insert id="addRole" parameterType="Role">
        insert into role (name, remark, status)
        VALUES (#{name}, #{remark}, #{status})
    </insert>
    <update id="updateRole" parameterType="Role">
        update role set
        <if test="name!=null and name!=''">name=#{name},</if>
        <if test="remark!=null and remark!=''">remark=#{remark},</if>
        <if test="status!=null">status=#{status}</if>
        where id=#{id}
    </update>
    <delete id="deleteRole" parameterType="int">
        delete from role where id=#{id}
    </delete>
</mapper>
2、service层

创建RoleService接口

package com.booy.ssm.exam.service;

import com.booy.ssm.exam.pojo.Role;
import com.github.pagehelper.PageInfo;

import java.util.List;

public interface RoleService {
    //角色列表
    PageInfo<Role> getRoleList(Role role, int pageNum,int pageSize);
    //获取所有角色,角色树用
    List<Role> getRoleList();
    //增删改
    void addRole(Role role);
    void updateRole(Role role);
    void deleteRole(Integer[] roleIds);
    //角色菜单功能
    void addRoleMenu(Integer roleId,Integer[] MenuIds);
    List<Integer> getMenuByRoleId(Integer roleId);
}

创建RoleServiceImpl实现类

package com.booy.ssm.exam.service.impl;

import com.booy.ssm.exam.dao.PremissionDAO;
import com.booy.ssm.exam.dao.RoleDAO;
import com.booy.ssm.exam.pojo.Menu;
import com.booy.ssm.exam.pojo.Role;
import com.booy.ssm.exam.service.RoleService;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.Arrays;
import java.util.List;

@Service
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleDAO roleDAO;

    @Autowired
    private PremissionDAO premissionDAO;

    @Override
    public PageInfo<Role> getRoleList(Role role,int pageNum,int pageSize) {
        PageHelper.startPage(pageNum,pageSize);
        PageInfo<Role> roles = new PageInfo<>(roleDAO.getRoleListByIF(role));
        return roles;
    }
//重改方法名
    @Override
    public List<Role> getRoleList() {
       return roleDAO.getRoleList();
    }
//增删改查

    @Override
    public void addRole(Role role) {
        roleDAO.addRole(role);
    }

    @Override
    public void updateRole(Role role) {
        roleDAO.updateRole(role);
    }

    @Override
    public void deleteRole(Integer[] roleIds) {
        for(Integer roleId:roleIds){
            roleDAO.deleteRole(roleId);
        }
    }

    @Override
    public void addRoleMenu(Integer roleId, Integer[] MenuIds) {
        premissionDAO.deleteRoleMenuByRoleId(roleId);
        for(int menu:MenuIds){
            premissionDAO.addRoleMenu(roleId,menu);
        }
    }

    @Override
    public List<Integer> getMenuByRoleId(Integer roleId) {
        List<Integer> menuIds = premissionDAO.getMenuByRoleId(roleId);
        return menuIds;
    }
}
3、controller
package com.booy.ssm.exam.controller;

import com.booy.ssm.exam.pojo.Menu;
import com.booy.ssm.exam.pojo.Role;
import com.booy.ssm.exam.service.MenuService;
import com.booy.ssm.exam.service.RoleService;
import com.booy.ssm.exam.utils.AjaxResult;
import com.booy.ssm.exam.utils.TableData;
import com.github.pagehelper.PageInfo;
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
@RequestMapping("/sys/role.html")
public class RoleController {
    @Autowired
    private RoleService roleService;

    @Autowired
    private MenuService menuService;
    @RequestMapping
    public String user(){
        return "role";
    }

    @RequestMapping(params = "act=table")
    @ResponseBody
    public TableData<Role> role(Role role, int page,int limit){
        PageInfo<Role> roleList = roleService.getRoleList(role,page, limit);
        TableData<Role> tableData = new TableData<>(roleList.getTotal(), roleList.getList());
        return tableData;
    }

    @RequestMapping(params = "act=tree")
    @ResponseBody
    public List<Menu> MenuTree(){
        return menuService.getMenuTree(true);
    }

    @RequestMapping(params = "act=assign")
    @ResponseBody
    public AjaxResult assign(Integer roleId, Integer[] menuIds){
        AjaxResult result = new AjaxResult();
        try {
            roleService.addRoleMenu(roleId,menuIds);
            result.setStatus(true);
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus(false);
            result.setMessage("授权失败!");
        }
        return result;
    }
    @RequestMapping(params = "act=menuIds")
    @ResponseBody
    public List<Integer> menuIds(Integer roleId){
        List<Integer> menuIds = roleService.getMenuByRoleId(roleId);
        return menuIds;
    }
    @RequestMapping(params = "act=edit")
    @ResponseBody
    public AjaxResult edit(Role role){
        AjaxResult result = new AjaxResult();
        try {
            if(role.getId()==null){
                roleService.addRole(role);
                result.setStatus(true);
            }else{
                roleService.updateRole(role);
                result.setStatus(true);
            }
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus(false);
            result.setMessage("编辑失败!");
            return result;
        }
    }

    @RequestMapping(params = "act=delete")
    @ResponseBody
    public AjaxResult deleteRole(Integer[] roleIds){
        AjaxResult result = new AjaxResult();
        try {
            roleService.deleteRole(roleIds);
            result.setStatus(true);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
            result.setStatus(false);
            result.setMessage("删除失败!");
            return result;
        }
    }
}
4、role.jsp页面
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<script src="media/jquery.easyui.min.js"/>
<link rel="stylesheet" href="media/easyui.css">
<%--顶部搜索--%>
<div class="layui-form-item">
    <form class="layui-form" >
        <div class="layui-inline">
            <label class="layui-form-label">角色名:</label>
            <div class="layui-input-inline" style="width: 200px;">
                <input type="text" name="name" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-inline">
            <label class="layui-form-label">别名:</label>
            <div class="layui-input-inline" style="width: 200px;">
                <input type="text" name="remark" autocomplete="off" class="layui-input">
            </div>
        </div>
        <div class="layui-inline">
            <button class="layui-btn" lay-submit lay-filter="searchForm">查询</button>
        </div>
    </form>

</div>
<%--动态表格--%>
<table id="roleTable" lay-filter="roleTable"></table>
<%--表格头部工具条--%>
<script type="text/html" id="headtool">
    <div class="layui-btn-container">
        <button class="layui-btn layui-btn-sm " lay-event="add"><i class="layui-icon">&#xe654;</i>添加</button>
        <button class="layui-btn layui-btn-sm layui-btn-normal" lay-event="update"><i class="layui-icon">&#xe642;</i>编辑
        </button>
        <button class="layui-btn layui-btn-sm layui-btn-danger" lay-event="delete"><i class="layui-icon">&#xe640;</i>删除
        </button>
    </div>
</script>
<%--行工具条--%>
<script type="text/html" id="rowtool">
    <a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="assign">授权</a>
    <a class="layui-btn layui-btn-xs layui-btn-normal" lay-event="edit">编辑</a>
    <a class="layui-btn layui-btn-xs layui-btn-danger" lay-event="del">删除</a>
</script>

<%--工具条--%>
<script>
    layui.use(['table', 'form'], function () {
        //初始化table对象,当前页面所有table都归lay管理,以id区分
        var table = layui.table;
        var form = layui.form;

        table.render({
            id: 'roleTable'//设置渲染后的table
            , elem: '#roleTable'//根据id取首次渲染的table
            , toolbar: '#headtool'//头部工具条
            , height: 523
            , url: '/sys/role.html?act=table' //数据接口
            , page: true //开启分页
            , cols: [[ //表头
                {type: 'checkbox', fixed: 'left'}
                , {field: 'id', title: 'ID', width: 80}
                , {field: 'name', title: '角色名'}
                , {field: 'remark', title: '别名'}
                , {field: 'status', title: '状态' ,templet: function(d){
                        return d.status==1?'<span class="layui-badge layui-bg-green">正常</span>':'<span class="layui-badge layui-bg-gray">停用</span>'
                    }}
                ,{fixed: 'right', width:200, align:'center', toolbar: '#rowtool'}
            ]]
        });
        //添加搜索渲染
        form.on('submit(searchForm)', function (data) {
            console.log(data.field);//当前容器的全部表单字段,名值对形式:{name: value}
            table.reload('roleTable', {//渲染后的tableid
                where: data.field //设定异步数据接口的额外参数
                //,height: 300
            });
            return false;
        });
        //监听头部工具条事件
        table.on('toolbar(roleTable)', function (obj) {
            var checkStatus = table.checkStatus(obj.config.id);
            var data = checkStatus.data;//获取选中行数据
            switch (obj.event) {
                case 'add':
                    if (data.length>0) {
                        return;
                    }
                    openidielayer(data);//null
                    break;
                case 'delete':
                    if (data.length<1) {
                        return;
                    }
                    layer.confirm('你确定要删除吗?', {
                        btn: ['确定','取消'] //按钮
                    }, function(index){
                        var ids = new Array();
                        for (var i = 0; i < data.length; i++) {
                            ids.push(data[i].id)
                        }
                        $.ajax({
                            url: "/sys/role.html?act=delete",
                            method: "post",
                            data: "roleIds="+ids,//jquery获取表单内容
                            success: function (res) {
                                if (res.status) {
                                    table.reload('roleTable', {});//删除数据后刷新table
                                } else {
                                    layer.msg(res.message);
                                }
                            }
                        })
                        layer.close(index)
                    })

                    break;
                case 'update':
                    if (data.length != 1) {
                        layer.msg('请选中一行数据');
                        return;
                    }
                    openidielayer(data[0]);
                    break;
            }
            ;
        });
        //监听行工具条
        table.on('tool(roleTable)', function(obj) { //注:tool 是工具条事件名,test 是 table 原始容器的属性 lay-filter="对应的值"
            var data = obj.data; //获得当前行数据
            var layEvent = obj.event; //获得 lay-event 对应的值
            switch (layEvent) {
                case 'del':
                    layer.confirm('你确定要删除吗?', {
                        btn: ['确定','取消'] //按钮
                    }, function(index){
                        $.ajax({
                            url: "/sys/role.html?act=delete",
                            method: "post",
                            data: "roleIds="+data.id,//获取当前行的id
                            success: function (res) {
                                if (res.status) {
                                    table.reload('roleTable', {});//删除数据后刷新table
                                } else {
                                    layer.msg(res.message);
                                }
                            }
                        })
                        layer.close(index)
                    })
                    break;
                case 'edit':
                    openidielayer(data);
                    break;
                case 'assign':
                    openMenulayer(data.id);
                    break;
            }
        })
        //打开弹出层,添加编辑共用
        function openidielayer(data) {//打开后往表单里添加数据
            layer.open({
                type: 1
                , area: '500px'
                , content: $("#editFormlayer").html()
                , btn: ['确认', '取消']
                , yes: function (index, layero) {
                    $.ajax({
                        url: "/sys/role.html?act=edit",
                        method: "post",
                        data: $("#editForm").serialize(),//jquery获取表单内容
                        success: function (res) {
                            if (res.status) {
                                table.reload('roleTable', {});//添加数据后刷新table
                                layer.close(index);
                            } else {
                                layer.msg(res.message);
                            }
                        }
                    })
                }
                , btn2: function (index, layero) {
                    layer.close(index)
                }, success: function (layero, index) {
                    console.log(data);
                    form.render();//重新渲染table
                    form.val("editForm",data);//获取array的第0个元素渲染表单
                    form.val("editForm",{status:data.status+''});//数字转字符串才能被渲染
                }
            });
        }

        //授权弹出层
        function openMenulayer(id) {//打开后往表单里添加数据
            layer.open({
                type: 1
                , area: '500px'
                , content: $("#menulayer").html()
                , btn: ['确认', '取消']
                , yes: function (index, layero) {
                    var nodes = $('#menu-tree').tree('getChecked', ['checked','indeterminate']);
                    var menuIds = new Array();
                    for (var i = 0; i < nodes.length; i++) {
                        menuIds.push(nodes[i].id)
                        console.log(nodes[i].id)
                    }

                    $.ajax({
                        url: "/sys/role.html?act=assign",
                        method: "post",
                        data: "roleId="+id+"&menuIds="+menuIds,
                        success: function (res) {
                            if (res.status) {
                                layer.close(index);
                            } else {
                                layer.msg(res.message);
                            }
                        }
                    })
                }
                , btn2: function (index, layero) {
                    layer.close(index)
                }, success: function (layero, index) {
                    $.ajax({
                        url: "sys/role.html?act=menuIds",
                        data:"roleId="+id,
                        success:function (res) {
                            $('#menu-tree').tree({//打开成功后加载树
                                url: "sys/role.html?act=tree",//数据接口
                                checkbox: true,
                                onLoadSuccess:function (node, data) {//选中用户已有数据res
                                    var tree = $('#menu-tree');
                                    $.each(res, function (i,obj) {
                                        var node = tree.tree('find', obj);
                                        if(node!=null&&tree.tree('isLeaf',node.target)){//只选中子节点
                                            tree.tree('check', node.target);
                                        }
                                    })

                                }
                            })
                        }
                    })


                }
            });
        }
    });
</script>
<%--添加功能弹出层--%>
<script type="text/html" id="editFormlayer">
    <form class="layui-form" style="width:80%;padding-top: 20px" id="editForm" lay-filter="editForm">
        <input type="hidden" name="id">
        <div class="layui-form-item">
            <label class="layui-form-label">角色名:</label>
            <div class="layui-input-block">
                <input type="text" name="name" required lay-verify="required" placeholder="请输入角色名" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">别名:</label>
            <div class="layui-input-block">
                <input type="text" name="remark" required lay-verify="required" placeholder="请输入别名" autocomplete="off"
                       class="layui-input">
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label">状态</label>
            <div class="layui-input-block">
                <input type="radio" name="status" value="1" title="有效">
                <input type="radio" name="status" value="0" title="无效">
            </div>
        </div>
    </form>
</script>
<%--授权功能弹出层--%>
<script type="text/html" id="menulayer">
    <ul id="menu-tree" class="easyui-tree">
    </ul>
</script>

页面效果
在这里插入图片描述
github地址:https://github.com/booy123/ssmdemo

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章