CMS客户关系管理系统【上】
发布于 4 年前 作者 fang06 4816 次浏览 来自 分享

引言
本文介绍了最近刚做的一个cms小项目,如有不足请各位及时指正,不胜感激!

因受社区文章限制,故将此项目分为上、中、下三部分进行发表

CMS客户关系管理系统【上】

简介

CMS客户关系管理系统,是一套用于管理业务员与客户的拜访记录的一套系统。在这套系统中:

业务员:

  1. 查询查看客户
  2. 新增客户
  3. 业务删除客户
  4. 变更客户信息

管理员:

  1. 新增业务员
  2. 重置业务员密码
  3. 删除业务员(业务删除)
  4. 查看拜访记录

当前用户:

  1. 修改密码
  2. 修改自己头像

注意:

不同的角色登录,显示的菜单和功能按钮不相同

数据库设计

在开发中,需要根据需求和原型进行数据库==概要设计。设计完成后,进行会议讨论==。每个人负责的模块不尽相同,站的考虑问题的角度也不同,设计者的设计很大可能存在偏向性。需要在会议中进行思想的碰撞,完善设计。

用户表(user):分角色

类型 说明
id int
username varchar(20)
password varchar(20)
realname varchar(5)
role int(1) 1:管理员 2:业务员
delete int(1) 1:有效 2:无效
img varchar(50) 用户头像
create_time varchar(19) 创建时间:yyyy-MM-dd HH:mm:ss
modify_time varchar(19) 修改时间:yyyy-MM-dd HH:mm:ss
delete_time varchar(19) 删除时间:yyyy-MM-dd HH:mm:ss

客户表(customer)

类型 说明
id int 客户ID
name varchar(20) 客户名称
sex int(1) 1 : 男 2 : 女
phone varchar(11) 手机号
salary int(10) 工资
addresss varchar(50) 地址
birth varchar(10) 生日:yyyy-MM-dd
delete int(1) 1:有效 2:无效
user_id int 业务员ID
create_time varchar(19) 创建时间:yyyy-MM-dd HH:mm:ss
modify_time varchar(19) 修改时间:yyyy-MM-dd HH:mm:ss
delete_time varchar(19) 删除时间:yyyy-MM-dd HH:mm:ss

拜访记录表(visit_log)

类型 说明
cust_id int 客户ID
cust_name varchar(20) 客户名称
user_id int 业务员ID
user_name varchar(20) 业务员真实姓名
visit_time varchar(19) 拜访时间:yyyy-MM-dd HH:mm
create_time varchar(19) 创建时间:yyyy-MM-dd HH:mm:ss

相关SQL

CREATE TABLE `user` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '业务员ID',
  `username` varchar(20) NOT NULL COMMENT '用户名',
  `password` varchar(20) NOT NULL COMMENT '用户密码',
  `realname` varchar(5) NOT NULL COMMENT '真名',
  `role` int(1) NOT NULL COMMENT '角色:1.管理员 2.业务员',
  `delete` int(1) NOT NULL COMMENT '业务删除:1.有效 2.无效',
  `img` varchar(50) DEFAULT NULL COMMENT '图片路径',
  `create_time` varchar(19) NOT NULL COMMENT '创建时间:yyyy-MM-dd HH:mm:ss',
  `modify_time` varchar(19) NOT NULL COMMENT '修改时间:yyyy-MM-dd HH:mm:ss',
  `delete_time` varchar(19) DEFAULT NULL COMMENT '删除时间:yyyy-MM-dd HH:mm:ss',
  PRIMARY KEY (`id`),
  UNIQUE KEY `username_uni_key` (`username`) COMMENT '用户名唯一不能重复'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `customer` (
  `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '客户ID',
  `name` varchar(20) NOT NULL COMMENT '客户名称',
  `sex` int(1) NOT NULL COMMENT '性别:1.男 2.女',
  `phone` varchar(11) NOT NULL COMMENT '手机号',
  `salary` int(10) NOT NULL COMMENT '工资',
  `address` varchar(50) NOT NULL COMMENT '地址',
  `birth` varchar(10) NOT NULL COMMENT '生日:yyyy-MM-dd',
  `delete` int(1) NOT NULL COMMENT '业务删除:1.有效 2.无效',
  `user_id` int(11) NOT NULL COMMENT '业务员ID',
  `create_time` varchar(19) NOT NULL COMMENT '创建时间:yyyy-MM-dd HH:mm:ss',
  `modify_time` varchar(19) NOT NULL COMMENT '修改时间:yyyy-MM-dd HH:mm:ss',
  `delete_time` varchar(19) DEFAULT NULL COMMENT '删除时间:yyyy-MM-dd HH:mm:ss',
  PRIMARY KEY (`id`),
  UNIQUE KEY `phone_uni_key` (`phone`) COMMENT '手机号不能重复'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

CREATE TABLE `visit_log` (
  `cust_id` int(11) NOT NULL COMMENT '客户ID',
  `cust_name` varchar(20) NOT NULL COMMENT '客户名称',
  `user_id` int(11) NOT NULL COMMENT '业务员ID',
  `user_name` varchar(20) NOT NULL COMMENT '业务员真实姓名',
  `visit_time` varchar(19) NOT NULL COMMENT '拜访时间:yyyy-MM-dd HH:mm',
  `create_time` varchar(19) NOT NULL COMMENT '创建时间:yyyy-MM-dd HH:mm:ss'
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;

项目架构

前端

在JavaWeb中静态资源文件是直接放在web目录下面,非静态文件是不允许客户端直接访问(jsp文件),基于安全的考虑,需要放在WEB-INF目录下。

静态资源文件,要放在web目录下面,考虑所有的静态资源文件不能被拦截。此时需要设置统一访问路径。一般使用一个统一的文件夹,将所有的静态资源文件装起来,然后判断请求路径前缀是否是这个统一的文件夹名称即可。<mark>__resources__</mark>
所有非静态资源(jsp)页面要放在WEB-INF,基于这样情况,WEB-INF文件相对较乱较杂,创建文件夹进行分类管理。view文件,表示下面是页面,然后基于每个模块,创建相应的文件夹。例如==:==



<mark>__用户模块:view/user/list.jsp__</mark>

main.jsp

main.jsp是管理界面的框架,由于需要从session获取当前用户所以使用jsp。

注意:

在web项目中,存在资源路径出现多重路径,使用相对路径会因为URL变化,导致URL请求发生404。所以在使用时使用绝对路径。在URL前面拼接:${pageContext.request.contextPath}

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/resources/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">CMS管理系统</div>
        <!-- 头部区域(可配合layui已有的水平导航) -->
        <ul class="layui-nav layui-layout-left">
        </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="page.do?service=userList" target="content">员工管理</a></dd>
                        <dd><a href="index2.html" target="content">客户管理</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>
                    </dl>
                </li>
                <li class="layui-nav-item"><a href="javascript:;">数据分析</a>
                    <dl class="layui-nav-child">
                        <dd><a href="javascript:;">拜访占比</a></dd>
                    </dl>

                </li>
            </ul>
        </div>
    </div>

    <div class="layui-body">
        <!-- 内容主体区域 -->
        <div style="padding: 15px;">
            <iframe name="content" style="width: 100%;height: 100%;border: 0px"></iframe>
        </div>
    </div>

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

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

控制页面跳转的Servlet

package com.sxt.controller;

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 java.io.IOException;
import java.lang.reflect.Method;

/**
 * [@Description](/user/Description): 专门用于进行页面跳转
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 10:48
 */
[@WebServlet](/user/WebServlet)("/page.do")
public class PageController extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String service = req.getParameter("service");
        try {
            Method method = this.getClass().getDeclaredMethod(service, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void main(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/WEB-INF/view/main.jsp").forward(req,resp);
    }

}

注意点:

  1. 在网页中,每多一个iframe就多一个window对象
  2. 子iframe 访问父iframe使用window.parent访问父窗口的window对象,根据window对象获取其他对象
  3. 父iframe访问子iframe
*   使用name直接访问: iframeName.window
*   使用iframe的id,frames\[‘id值’\]
*   使用索引iframes\[索引\]

后台

在JavaWeb开发中,基本都是基于MVC思想进行开发。Web后台框架,主要负责:M层和C层。

C层:使用Servlet技术。

M层主要分为:

  1. 实体类
  2. 数据操作层。

但是,在具体的实际开发中,发现:Controller层和M层耦合性极高,代码复用性极差。

按照之前的结构:Controller直接访问Dao层。如果类似以下场景:

用户注册场景:controller层只负责接收View层数据,将数据传递给M层中的Dao层,发现在Dao层,



*   
    
    查询注册用户名是否存在
    
    
*   
    
    插入一个数据
修改用户信息场景:



*   
    
    查询用户名是否已存在
    
    
*   
    
    修改数据
    
    




发现查询用户是否存在是重复操作,并且Dao层并不是单纯只是进行数据库的数据操作。也存在各种业务判断,违背了设计原则:单一职责。并且代码的复用不高,维护性也差。



所以基于这样的情况,在M层加上了service,service只进行业务判断,dao层只做数据操作。controller访问==__service__==层。

相关包如下:

  1. pojo : 所有的实体类
  2. dao : 数据操作类
  3. service :业务处理类
  4. controller :控制器
  5. util : 工具类
  6. common :公共类
  7. filter : web拦截器

相关jar包

fastjson-1.1.22.jar
hutool-all-5.4.1.jar
jstl-1.2.jar
mysql-connector-java-5.1.47.jar
standard-1.1.2.jar

相关类:

工具类
数据库连接配置文件
#jdbc连接配置文件
jdbc.driver=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/cms?useUnicode=true&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
数据库连接工具类
package com.sxt.util;

import java.io.IOException;
import java.io.InputStream;
import java.sql.*;
import java.util.Properties;

/**
 * [@Description](/user/Description):Jdbc连接工具类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-02 15:55
 */
public abstract class JdbcUtil {

    private  static final String DRIVER;

    private static final String URL;

    private static final  String USERNAME;

    private static final String PASSWORD;
    //静态块 加载 配置文件
    static {
        /**
         * 类加载器
         *  三种类加载器 :     Bootstrap  加载 JDK中核心类库
         *      扩展类加载器   加载扩展类库
         *      应用类加载器   加载应用程序自定义的类
         *  双亲委派加载
         *      1. 首先使用 Bootstrap 类加载器加载类 只加载JDK 核心类库
         *      2. 扩展类加载器 加载ext文件夹下的类
         *      3. 使用应用类加载器加载类 默认加载src源码目录下类
         *  为什么Java使用双亲委派加载机制 类一旦被加载 其他类加载器将不会加载这个类
         *  类的区分方式,包名+类名
         *  如果用户自定义一个类,且类包名,类名与系统类一致。虽然一致,但是由于类加载器不同,所以依然使用系统类。
         *  如果不是使用双亲委派机制,如果使用同一个类加载器,可能出现类覆盖。自定义的类覆盖系统类。
         *  改写了JDK源代码。容易出现安全问题。
         */
        InputStream in = JdbcUtil.class.getClassLoader().getResourceAsStream("jdbc.properties");
        //读入到properties对象中
        Properties prop = new Properties();
        if (in == null){
            throw new RuntimeException("配置文件没有找到");
        }
        try {
            prop.load(in);
        } catch (IOException e) {
            e.printStackTrace();
        }
        DRIVER = prop.getProperty("jdbc.driver");
        URL = prop.getProperty("jdbc.url");
        USERNAME = prop.getProperty("jdbc.username");
        PASSWORD = prop.getProperty("jdbc.password");
        try {
            //加载驱动
            Class.forName(DRIVER);
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

    /**
     * 获取连接
     * @return
     */
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = DriverManager.getConnection(URL, USERNAME, PASSWORD);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }

    /**
     * 关闭连接
     * @param conn
     * @param prep
     */
    public static void close(Connection conn, PreparedStatement prep){
        if (prep != null){
            try {
                prep.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        if (conn != null){
            try {
                conn.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 关闭连接
     * @param conn
     * @param prep
     * @param rs
     */
    public static void close(Connection conn, PreparedStatement prep, ResultSet rs){
        if (rs != null){
            try {
                rs.close();
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
        close(conn,prep);
    }

}
JSON结果数据工具类
package com.sxt.util;

import com.alibaba.fastjson.JSON;
import com.sxt.common.Result;

import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.PrintWriter;

/**
 * [@Description](/user/Description): 响应数据工具类
 *              将返回的数据转化为JSON字符串 返回给客户端
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-14 15:19
 */
public abstract class RespUtil {
    /**
     * 将返回的数据转化为JSON字符串返回给客户端
     * @param rs  需要返回的数据
     * @param resp  响应对象
     * @throws IOException
     */
    public static void writer(Result rs, HttpServletResponse resp) throws IOException {
        resp.setCharacterEncoding("UTF-8");
        //设置返回数据的类型
        resp.setContentType("text/json;charset=utf-8");
        PrintWriter writer = resp.getWriter();
        //将需要返回的数据转化为JSON字符串
        String s = JSON.toJSONString(rs);
        writer.write(s);
        writer.flush();
        writer.close();
    }
}
公共类
通用数据操作类
package com.sxt.common;

import com.sxt.common.PageInfo;
import com.sxt.util.JdbcUtil;

import java.lang.reflect.Field;
import java.sql.*;
import java.util.ArrayList;
import java.util.List;

/**
 * [@Description](/user/Description): 数据通用的操作类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-08 09:17
 */
public class BaseDao {

    /**
     * 数据更新操作
     * @param sql
     * @param params
     * @return
     */
    public boolean update(String sql,Object... params){
        //获取连接
        Connection conn = JdbcUtil.getConnection();
        //获取数据操作对象
        PreparedStatement prep = null;
        try {
            prep = conn.prepareStatement(sql);
            //校验是否有传输参数
            if (params != null && params.length > 0){
                //根据for循环设置sql中的参数
                for (int i = 1; i <= params.length; i++) {
                    prep.setObject(i,params[i-1]);
                }
            }
            int count = prep.executeUpdate();
            return  count == 1 ?true : false;
        } catch (Exception throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtil.close(conn,prep);
        }
        return  false;
    }

    /**
     * 根据条件查询数据列表
     * @param sql
     * @param cls
     * @param params
     * @param <T>
     * @return
     */
    public <T> List<T> selectList(String sql,Class<T> cls,Object... params){
        //获取连接
        Connection conn = JdbcUtil.getConnection();
        //获取数据操作对象
        PreparedStatement prep = null;
        //数据结果集
        ResultSet rs = null;
        List<T> data = new ArrayList<>();
        try {
            prep = conn.prepareStatement(sql);
            int length = params.length;
            //循环处理sql参数
            if (params != null && length > 0){
                //根据for循环设置sql中的参数
                for (int i = 1; i <= length; i++) {
                    prep.setObject(i,params[i-1]);
                }
            }
            //查询  获取结果集
            rs = prep.executeQuery();
            //获取数据元信息
            ResultSetMetaData metaData = rs.getMetaData();
            //获取列数
            int count = metaData.getColumnCount();
            while (rs.next()){
                //创建对象
                T obj = cls.newInstance();
                //对象属性封装
                for (int i = 1; i <= count ; i++) {
                    //根据序列获取列别名
                    String label = metaData.getColumnLabel(i);
                    //根据列别名获取数据
                    Object value = rs.getObject(label);
                    //进行对象属性设置
                    //获取属性
                    try {
                        Field field = cls.getDeclaredField(label);
                        //设置属性的访问标识
                        field.setAccessible(true);
                        //设置属性值
                        field.set(obj,value);
                    }catch (Exception exception){
                        exception.printStackTrace();
                        //如果属性不存在 则跳过这个属性的设置
                        continue;
                    }
                }
                data.add(obj);
            }
        } catch (Exception throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtil.close(conn,prep,rs);
        }
        return  data;
    }

    /**
     * 查询一个
     * @param sql
     * @param cls
     * @param params
     * @param <T>
     * @return
     */
    public <T> T selectOne(String sql,Class<T> cls,Object... params){
        List<T> data = this.selectList(sql, cls, params);
        if (!data.isEmpty() && data.size() > 1){
            throw new RuntimeException("查询结果不是一个!!!");
        }
        if (data.size() == 1){
            return data.get(0);
        }
        return  null;
    }

    /**
     *  分页查询
     * @param sql 查询的基础sql
     * @param cls 封装的类
     * @param page 页码
     * @param limit 每页数据条数
     * @param params 查询的参数
     * @param <T>
     * @return
     */
    public <T> PageInfo<T> selectPage(String sql,Class<T> cls,Integer page,Integer limit,Object... params){
        //查询符合条件的总数据条数
        int total = selectCount(sql,params);
        //根据总数据条数获取总页数
        //总数据条数 除以每页条数  如果能除断 说明刚好 则直接 除以
        //如果有余数 则使用新一页装剩余的数据  所以加1
        int totalPage = total%limit == 0? total/limit : total/limit + 1;
        //页码不能大于总页数
        //页码的最大值是总页数
        if (page > totalPage ){
            page = totalPage;
        }
        //页码的最小值是  1
        if (page < 1){
            page  = 1;
        }
        //拼接分页查询数据的sql语句
        int startRow = (page-1)*limit;
        sql = sql +"   limit "+ startRow +","+limit;
        //获取数据
        List<T> data = this.selectList(sql, cls, params);
        PageInfo<T> pageInfo = new PageInfo<>(data,total,totalPage,page,limit);
        return  pageInfo;
    }

    /**
     * 符合条件的总数据条数
     * @param sql
     * @param params
     * @return
     */
    private int selectCount(String sql,Object... params){
        //组装查询总数据条数的sql语句
        StringBuffer sb = new StringBuffer("select count(1) from ");
        sb.append("(").append(sql).append(")").append(" as rs");
        //获取连接
        Connection conn = JdbcUtil.getConnection();
        //获取数据操作对象
        PreparedStatement prep = null;
        //数据结果集
        ResultSet rs = null;
        try {
            prep = conn.prepareStatement(sb.toString());
            //循环设置参数
            if (params != null && params.length > 0){
                for (int i = 1; i <= params.length ; i++) {
                    prep.setObject(i,params[i-1]);
                }
            }
            //获取查询结果集
            rs = prep.executeQuery();
            //默认指在元信息
            rs.next();
            return  rs.getInt(1);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }finally {
            JdbcUtil.close(conn,prep,rs);
        }
        return  0;
    }
}

通用分页封装实体类
package com.sxt.common;

import java.util.List;

/**
 * [@Description](/user/Description): 分页数据实体类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-08 10:48
 */
public class PageInfo<T> {

    private List<T> data; //具体数据

    private int total;//总数据条数

    private int pages;//总页数

    private int page;//当前页码

    private int limit;//每页显示的条数

    public PageInfo(List<T> data, int total, int pages, int page, int limit) {
        this.data = data;
        this.total = total;
        this.pages = pages;
        this.page = page;
        this.limit = limit;
    }

    public List<T> getData() {
        return data;
    }

    public void setData(List<T> data) {
        this.data = data;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    public int getPages() {
        return pages;
    }

    public void setPages(int pages) {
        this.pages = pages;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getLimit() {
        return limit;
    }

    public void setLimit(int limit) {
        this.limit = limit;
    }

    @Override
    public String toString() {
        return "PageInfo{" +
                "data=" + data +
                ", total=" + total +
                ", pages=" + pages +
                ", page=" + page +
                ", limit=" + limit +
                '}';
    }
}

通用的业务结果类
package com.sxt.common;

/**
 * [@Description](/user/Description): 数据结果类
 *              所有返回给页面的JSON数据 通过该类进行包装
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-14 15:13
 */
public class Result {

    private Integer code;//业务码

    private String msg;//业务消息  默认操作成功

    private Object data; //业务数据

    public Result(){
        this.code = CodeMsg.SUCCESS.code;
        this.msg = CodeMsg.SUCCESS.msg;
    }

    /**
     * 成功的构造方法
     * @param data
     */
    public Result(Object data) {
        this();
        this.data = data;
    }

    /**
     * 业务异常的构造方法
     * @param codeMsg
     */
    public Result(CodeMsg codeMsg) {
        this.code = codeMsg.code;
        this.msg = codeMsg.msg;
    }

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public Object getData() {
        return data;
    }

    public void setData(Object data) {
        this.data = data;
    }
}
业务码和消息枚举
package com.sxt.common;

/**
 * [@Description](/user/Description): 系统的业务码和业务消息枚举
 *              存放整个系统需要用到业务码和对应的业务消息
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 14:47
 */
public enum CodeMsg {
    //操作成功枚举
    SUCCESS(200,"操作成功");
    /*
    *   由于系统使用时 模块会逐渐增多
    *       当业务失败时  所有的业务码 使用 4 开头
    *       紧邻的3位是模块编号
    *       模块编号后紧邻3位 业务编号
    *       例如:用户模块是 1   4001001, 表示用户业务模块 第一个异常编码
    *       如果直接:411  随着错误码增多: 4110   此时表示  用户模块 第 10种业务异常
    *       如果模块超过了10个  第11个模块第1个业务异常 4111
    *       随着模块增多,异常情况增多  可以出现重复业务码 基于这样的情况,才采用4001001格式。
    *       业务码不容易重复  其次 格式统一。
    */
    public  Integer code;
    public  String msg;

    CodeMsg(Integer code, String msg) {
        this.code = code;
        this.msg = msg;
    }
}
常量接口
package com.sxt.common;

/**
 * [@Description](/user/Description): 所有常量
 *              存储系统中需要使用到的所有常量
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:39
 */
public interface Constant {
}

filter
编码过滤器
package com.sxt.filter;

import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import java.io.IOException;

/**
 * [@Description](/user/Description): 编码过滤器
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-14 15:38
 */
[@WebFilter](/user/WebFilter)("*.do")
public class CharsetEncodingFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
        request.setCharacterEncoding("UTF-8");
        response.setCharacterEncoding("UTF-8");
        chain.doFilter(request,response);
    }

    @Override
    public void destroy() {

    }
}

登录过滤器
package com.sxt.filter;

import javax.servlet.*;
import java.io.IOException;

/**
 * [@Description](/user/Description): 登录过滤器
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:19
 */
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {

    }

    @Override
    public void destroy() {

    }
}

M层
用户实体类
package com.sxt.pojo;

/**
 * [@Description](/user/Description): 用户实体类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:21
 */
public class User {
    //用户ID
    private Integer id;
    //用户名
    private  String username;
    //用户密码
    private String password;
    //用户真实姓名
    private String realname;
    //用户角色  1 管理员  2 业务员
    private Integer role;
    //是否删除  1 未删除  2 已删除
    private Integer delete;
    //用户头像
    private String img;
    //创建时间
    private String createTime;
    //修改时间
    private String modifyTime;
    //删除时间
    private String deleteTime;

    public User(){}

    public User(Integer id, String username, String password, String realname, Integer role, Integer delete, String img, String createTime, String modifyTime, String deleteTime) {
        this.id = id;
        this.username = username;
        this.password = password;
        this.realname = realname;
        this.role = role;
        this.delete = delete;
        this.img = img;
        this.createTime = createTime;
        this.modifyTime = modifyTime;
        this.deleteTime = deleteTime;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public String getRealname() {
        return realname;
    }

    public void setRealname(String realname) {
        this.realname = realname;
    }

    public Integer getRole() {
        return role;
    }

    public void setRole(Integer role) {
        this.role = role;
    }

    public Integer getDelete() {
        return delete;
    }

    public void setDelete(Integer delete) {
        this.delete = delete;
    }

    public String getImg() {
        return img;
    }

    public void setImg(String img) {
        this.img = img;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public String getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(String modifyTime) {
        this.modifyTime = modifyTime;
    }

    public String getDeleteTime() {
        return deleteTime;
    }

    public void setDeleteTime(String deleteTime) {
        this.deleteTime = deleteTime;
    }
}

客户实体类
package com.sxt.pojo;

/**
 * [@Description](/user/Description): 客户类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:21
 */
public class Customer {
    //客户ID
    private Integer id;
    //客户名称
    private String name;
    //客户性别  1 男  2 女
    private Integer sex;
    //客户电话
    private String phone;
    //客户工资
    private Integer salary;
    //客户地址
    private String address;
    //客户生日
    private String birth;
    //是否有效  1 有效  2 无效
    private Integer delete;
    //业务员ID
    private Integer userId;
    //创建时间
    private String createTime;
    //修改时间
    private String modifyTime;
    //删除时间
    private String deleteTime;

    public Customer(){}

    public Customer(Integer id, String name, Integer sex, String phone, Integer salary, String address, String birth, Integer delete, Integer userId, String createTime, String modifyTime, String deleteTime) {
        this.id = id;
        this.name = name;
        this.sex = sex;
        this.phone = phone;
        this.salary = salary;
        this.address = address;
        this.birth = birth;
        this.delete = delete;
        this.userId = userId;
        this.createTime = createTime;
        this.modifyTime = modifyTime;
        this.deleteTime = deleteTime;
    }

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getSex() {
        return sex;
    }

    public void setSex(Integer sex) {
        this.sex = sex;
    }

    public String getPhone() {
        return phone;
    }

    public void setPhone(String phone) {
        this.phone = phone;
    }

    public Integer getSalary() {
        return salary;
    }

    public void setSalary(Integer salary) {
        this.salary = salary;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getBirth() {
        return birth;
    }

    public void setBirth(String birth) {
        this.birth = birth;
    }

    public Integer getDelete() {
        return delete;
    }

    public void setDelete(Integer delete) {
        this.delete = delete;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }

    public String getModifyTime() {
        return modifyTime;
    }

    public void setModifyTime(String modifyTime) {
        this.modifyTime = modifyTime;
    }

    public String getDeleteTime() {
        return deleteTime;
    }

    public void setDeleteTime(String deleteTime) {
        this.deleteTime = deleteTime;
    }
}

拜访记录实体类
package com.sxt.pojo;

/**
 * [@Description](/user/Description): 拜访记录
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:21
 */
public class VisitLog {
    //客户ID
    private Integer custId;
    //客户名称
    private String custName;
    //用户ID
    private Integer userId;
    //用户名称
    private String userName;
    //拜访时间
    private String visitTime;
    //创建时间
    private String createTime;

    public VisitLog(){}

    public VisitLog(Integer custId, String custName, Integer userId, String userName, String visitTime, String createTime) {
        this.custId = custId;
        this.custName = custName;
        this.userId = userId;
        this.userName = userName;
        this.visitTime = visitTime;
        this.createTime = createTime;
    }

    public Integer getCustId() {
        return custId;
    }

    public void setCustId(Integer custId) {
        this.custId = custId;
    }

    public String getCustName() {
        return custName;
    }

    public void setCustName(String custName) {
        this.custName = custName;
    }

    public Integer getUserId() {
        return userId;
    }

    public void setUserId(Integer userId) {
        this.userId = userId;
    }

    public String getUserName() {
        return userName;
    }

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public String getVisitTime() {
        return visitTime;
    }

    public void setVisitTime(String visitTime) {
        this.visitTime = visitTime;
    }

    public String getCreateTime() {
        return createTime;
    }

    public void setCreateTime(String createTime) {
        this.createTime = createTime;
    }
}

用户数据操作类
package com.sxt.dao;

import com.sxt.common.BaseDao;

/**
 * [@Description](/user/Description): 用户数据操作类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:41
 */
public class UserDao extends BaseDao {
}

客户数据操作类
package com.sxt.dao;

import com.sxt.common.BaseDao;

/**
 * [@Description](/user/Description): 客户数据操作类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:42
 */
public class CustomerDao extends BaseDao {
}

拜访记录数据操作类
package com.sxt.dao;

import com.sxt.common.BaseDao;

/**
 * [@Description](/user/Description): 拜访记录数据操作类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:42
 */
public class VisitLogDao extends BaseDao {
}
用户业务接口
package com.sxt.service;

/**
 * [@Description](/user/Description): 用户业务接口
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:43
 */
public interface IUserService {
}

客户业务接口
package com.sxt.service;

/**
 * [@Description](/user/Description): 客户业务类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:44
 */
public interface ICustomerService {
}

拜访记录业务接口
package com.sxt.service;

/**
 * [@Description](/user/Description): 拜访记录业务类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:44
 */
public interface IVisitLogService {
}

用户业务实现类
package com.sxt.service.impl;

import com.sxt.service.IUserService;

/**
 * [@Description](/user/Description): 用户业务实现类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:44
 */
public class UserServiceImpl implements IUserService {
}

客户业务实现类
package com.sxt.service.impl;

import com.sxt.service.ICustomerService;

/**
 * [@Description](/user/Description): 客户业务实现类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:45
 */
public class CustomerServiceImpl implements ICustomerService {
}

拜访记录业务实现类
package com.sxt.service.impl;

import com.sxt.service.IVisitLogService;

/**
 * [@Description](/user/Description): 拜访记录业务实现类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:45
 */
public class VisitLogServiceImpl implements IVisitLogService {
}

C层
控制页面跳转类
package com.sxt.controller;

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 java.io.IOException;
import java.lang.reflect.Method;

/**
 * [@Description](/user/Description): 专门用于进行页面跳转
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 10:48
 */
[@WebServlet](/user/WebServlet)("/page.do")
public class PageController extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String service = req.getParameter("service");
        try {
            Method method = this.getClass().getDeclaredMethod(service, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    protected void main(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/WEB-INF/view/main.jsp").forward(req,resp);
    }

}

用户控制类
package com.sxt.controller;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

/**
 * [@Description](/user/Description): 用户控制类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:48
 */
[@WebServlet](/user/WebServlet)("/user.do")
public class UserController extends HttpServlet {
}

客户控制类
package com.sxt.controller;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

/**
 * [@Description](/user/Description): 客户控制类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:49
 */
[@WebServlet](/user/WebServlet)("/customer.do")
public class CustomerController extends HttpServlet {
}

拜访记录控制类
package com.sxt.controller;

import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;

/**
 * [@Description](/user/Description): 拜访记录控制类
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 15:50
 */
[@WebServlet](/user/WebServlet)("/log.do")
public class VisitLogController extends HttpServlet {
}

登录功能

登录逻辑

  1. 获取表单数据
  2. 使用ajax将数据进行提交
  3. 处理响应码
*   如果响应码不是200 则将异常业务消息进行提示
*   如果响应码是200,说明成功,则跳转到==__main.jsp__==

1.登录页面

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
    <link rel="stylesheet" href="resources/layui/css/layui.css">
    <style>
        .content{
            width: 330px;
            height: 330px;
            position: absolute;
            left: 50%;
            top: 50%;
            margin-top: -165px;
            margin-left: -165px;
            box-shadow:2px 2px 10px #909090;
        }
    </style>
</head>
<body>

<div class="content">
    <form class="layui-form layui-form-pane" style="margin:10px">
        <h1 style="text-align: center;margin-bottom: 20px;color: rgb(0,150,136);font-weight: bold">用户·登录</h1>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 80px">用户名:</label>
            <div class="layui-input-inline">
                <input type="text" name="username"  autocomplete="off" class="layui-input" placeholder="用户名" lay-verify="required" lay-reqText="请输入用户名" >
            </div>
        </div>
        <div class="layui-form-item">
            <label class="layui-form-label" style="width: 80px">密码:</label>
            <div class="layui-input-inline">
                <input type="text" name="password" autocomplete="off" class="layui-input" placeholder="密码" lay-verify="required" lay-reqText="请输入密码" >
            </div>
        </div>
        <div class="layui-form-item">
            <div class="layui-inline">
                <label class="layui-form-label" style="width: 80px">验证码:</label>
                <div class="layui-input-inline" style="width: 90px">
                    <input type="text" name="checkCode" autocomplete="off" class="layui-input" placeholder="验证码" lay-verify="required" lay-reqText="请输入验证码" >
                </div>
                <img src="code.do" style="height: 38px;margin-left: 10px" id="checkCodeImg">
            </div>
        </div>
        <div class="layui-form-item" style="margin-top: 30px">
            <button style="width: 300px" type="button" class="layui-btn" lay-submit lay-filter="subBtnFilter">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;</button>
        </div>
    </form>
</div>
<script src="resources/layui/layui.js"></script>
<script>
    layui.use(['form','layer','jquery'],function () {
        let form = layui.form;
        let layer = layui.layer;
        let $ = layui.jquery;
        //更新验证码
        $("#checkCodeImg").click(function () {
            $(this).attr("src","code.do?"+new Date());
        });

        //表单提交
        form.on("submit(subBtnFilter)",function (d) {
            let data = d.field;//获取表单数据
            // 使用ajax提交数据
            $.post("user.do?service=login",data,function (rs) {
                //rs 是返回的数据  校验业务码
                if (rs.code != 200 ){
                    //当业务码不是200  说明业务操作失败  将失败的原因进行展示
                    layer.msg(rs.msg);
                    return false;
                }
                //操作成功则跳转到list.jsp
                location.href = "page.do?service=main";
            })
            return false;//阻止表单默认提交行为
        });

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

2.新增验证码Servlet

package com.sxt.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.CircleCaptcha;
import com.sxt.common.Constant;

import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * [@Description](/user/Description): 验证码Servlet
 * [@author](/user/author): Mr.T
 * [@date](/user/date) 2020-09-15 16:25
 */
[@WebServlet](/user/WebServlet)("/code.do")
public class CheckCodeServlet extends HttpServlet {

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //使用工具产生验证码对象
        CircleCaptcha captcha = CaptchaUtil.createCircleCaptcha(100, 50, 4, 0);
        //获取验证码字符串
        String code = captcha.getCode();
        //将验证码放入session
        req.getSession().setAttribute(Constant.CHECK_CODE_KEY,code);
        //将验证码使用流输出
        ServletOutputStream outputStream = resp.getOutputStream();
        captcha.write(outputStream);
        //释放资源
        outputStream.close();
    }
}

3.修改UserController

    private IUserService userService;

    @Override
    public void init() throws ServletException {
        userService = new UserServiceImpl();
    }

    @Override
    protected void service(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String service = req.getParameter("service");
        try {
            Method method = this.getClass().getDeclaredMethod(service, HttpServletRequest.class, HttpServletResponse.class);
            method.invoke(this,req,resp);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 处理用户登录请求
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void login(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //获取前端参数
        String username = req.getParameter("username");
        String password = req.getParameter("password");
        String checkCode = req.getParameter("checkCode");
        //获取验证码
        Object o = req.getSession().getAttribute(Constant.CHECK_CODE_KEY);
        //校验验证码
        if (o == null || !StrUtil.equals(checkCode,o.toString())){
            Result rs = new Result(CodeMsg.USER_CHECK_CODE_ERROR);
            RespUtil.writer(rs,resp);
            return;
        }
        //校验账号密码
        //根据用户名 和 密码查询用户
        Result rs = userService.login(username,password);
        //登录成功
        if (rs.getCode().equals(CodeMsg.SUCCESS.code)){
            req.getSession().setAttribute(Constant.CURRENT_USER_KEY,rs.getData());
            rs.setData(null);
        }
        RespUtil.writer(rs,resp);
    }

4.修改IUserService

    /**
     * 用户登录方法
     * @param username
     * @param password
     * @return
     */
    Result login(String username, String password);

5.修改UserServiceImpl

  	UserDao userDao = new UserDao();

    @Override
    public Result login(String username, String password) {
        //根据用户名查询用户
        User user = userDao.selectOneByName(username);
        //校验账号是否存在
        if (user == null){
            return  new Result(CodeMsg.USER_USERNAME_NOT_EXIST_ERROR);
        }
        //校验密码是否一致
        if (!StrUtil.equals(user.getPassword(),password)){
            return  new Result(CodeMsg.USER_USERNAME_PASSWORD_ERROR);
        }
        //校验用户状态是否有效
        if (user.getDelete().equals(Constant.USER_STATE_INVALID)){
            return  new Result(CodeMsg.USER_INVALID_ERROR);
        }
        return new Result(user);
    }

6.修改UserDao

    /**
     * 根据用户名查询用户
     * @param username
     * @return
     */
    public User selectOneByName(String username) {
        String sql = "select id,username,password,realname,role,`delete`,img from user where username=?";
        return super.selectOne(sql,User.class,username);
    }

7.修改常量

   /**
     * 验证码 session中的key
     */
    String CHECK_CODE_KEY = "code";
    /**
     * 用户状态  1  有效
     */
    Integer USER_STATE_VALID = 1;
    /**
     * 用户状态  2 无效
     */
    Integer USER_STATE_INVALID = 2;
    /**
     * 当前存放在session中的用户的key
     */
    String CURRENT_USER_KEY = "user";

8.修改CodeMsg枚举

	USER_CHECK_CODE_ERROR(4002001,"用户验证码不正确"),
    USER_USERNAME_NOT_EXIST_ERROR(4002002,"用户名不存在"),
    USER_USERNAME_PASSWORD_ERROR(4002003,"用户名密码不匹配"),
    USER_INVALID_ERROR(4002004,"用户账号已失效"),

退出功能

退出功能逻辑

  1. 点击退出
  2. 服务器删除session中当前用户
  3. 跳转到登录页面

修改main.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/resources/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">CMS管理系统</div>
        <!-- 头部区域(可配合layui已有的水平导航) -->
        <ul class="layui-nav layui-layout-left">
        </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>
            </li>
            <li class="layui-nav-item"><a href="user.do?service=loginOut">退了</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="page.do?service=userList" target="content">员工管理</a></dd>
                        <dd><a href="index2.html" target="content">客户管理</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>
                    </dl>
                </li>
                <li class="layui-nav-item"><a href="javascript:;">数据分析</a>
                    <dl class="layui-nav-child">
                        <dd><a href="javascript:;">拜访占比</a></dd>
                    </dl>

                </li>
            </ul>
        </div>
    </div>

    <div class="layui-body">
        <!-- 内容主体区域 -->
        <div style="padding: 15px;">
            <iframe name="content" style="width: 100%;height: 100%;border: 0px"></iframe>
        </div>
    </div>

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

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

修改UserController

/**
     * 退出
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void loginOut(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        //删除当前session中用户
        req.getSession().removeAttribute(Constant.CURRENT_USER_KEY);
        //解除session绑定
        req.getSession().invalidate();
        //跳转到登录页面
        resp.sendRedirect("index.html");
    }

显示当前登录用户及头像

修改main.jsp

从session获取当前登录的用户名称

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
    <title>Title</title>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/resources/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">CMS管理系统</div>
        <!-- 头部区域(可配合layui已有的水平导航) -->
        <ul class="layui-nav layui-layout-left">
        </ul>
        <ul class="layui-nav layui-layout-right">
            <li class="layui-nav-item">
                <a href="javascript:;">
                    <img onerror="javascript:this.src='${pageContext.request.contextPath}/imgs/default.jpg';" src="${pageContext.request.contextPath}/${user.img}" class="layui-nav-img">
                    ${user.realname}
                </a>
            </li>
            <li class="layui-nav-item"><a href="user.do?service=loginOut">退了</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="page.do?service=userList" target="content">员工管理</a></dd>
                        <dd><a href="index2.html" target="content">客户管理</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>
                    </dl>
                </li>
                <li class="layui-nav-item"><a href="javascript:;">数据分析</a>
                    <dl class="layui-nav-child">
                        <dd><a href="javascript:;">拜访占比</a></dd>
                    </dl>

                </li>
            </ul>
        </div>
    </div>

    <div class="layui-body">
        <!-- 内容主体区域 -->
        <div style="padding: 15px;">
            <iframe name="content" style="width: 100%;height: 100%;border: 0px"></iframe>
        </div>
    </div>

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

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

新建imgs文件夹

新建imgs文件夹

将default.jpg放入

员工列表

员工列表

  1. 点击左侧菜单跳转到员工列表页面
  2. 员工列表页面请求员工列表数据
  3. 将员工列表数据进行渲染成列表

1.在view文件夹中新建user文件夹,在user文件夹中新建list.jsp

2.list.jsp

<%@ page contentType="text/html;charset=UTF-8" pageEncoding="UTF-8" isELIgnored="false" language="java" %>
<html>
<head>
    <title>Title</title>
    <%-- 引入layui --%>
    <link rel="stylesheet" href="${pageContext.request.contextPath}/resources/layui/css/layui.css">
</head>
<body>
    <div>
        <form  class="layui-form layui-form-pane">
            <div class="layui-form-item">
                <div class="layui-inline">
                    <label class="layui-form-label">员工名称</label>
                    <div class="layui-input-inline">
                        <input class="layui-input" type="text" id="realname" placeholder="员工名称" autocomplete="off">
                    </div>
                </div>
                <div class="layui-inline">
                    <label class="layui-form-label">角色</label>
                    <div class="layui-input-inline">
                        <select id="role">
                            <option value="">请选择角色</option>
                            <option value="1">管理员</option>
                            <option value="2">业务员</option>
                        </select>
                    </div>
                </div>
                <div class="layui-inline">
                    <label class="layui-form-label">状态</label>
                    <div class="layui-input-inline">
                        <select id="delete">
                            <option value="">状态</option>
                            <option value="1">在职</option>
                            <option value="2">离职</option>
                        </select>
                    </div>
                </div>
                <div class="layui-inline">
                    <button type="button" id="searchBtn" class="layui-btn">查询</button>
                </div>
            </div>
        </form>
        <hr>
        <table id="dataTable" lay-filter="dataTableFilter"></table>
    </div>

<script src="${pageContext.request.contextPath}/resources/layui/layui.js"></script>
<script>
    layui.use(['form','table','jquery','layer'],function () {
        let form = layui.form;
        let table = layui.table;
        let $ = layui.jquery;
        let layer = layui.layer;

        //渲染表格
        let opt = {
            id:"dataTableId",
            elem:"#dataTable",
            url:"${pageContext.request.contextPath}/user.do?service=page",
            cols:[[
                {type:"checkbox"},
                {field:"username",title:"用户名"},
                {field:"password",title:"密码"},
                {field:"realname",title:"用户名"},
                {field:"role",title:"角色",templet:function (d) {
                    let role = d.role;
                    if (role == 1){
                        return "<b style='color: #5FB878'>管理员</b>"
                    }else if (role == 2){
                        return "<b style='color: red'>业务员</b>"
                    }
                }},
                {field:"delete",title:"状态",templet:function (d) {
                        let del = d.delete;
                        if (del == 1){
                            return "<b style='color: #5FB878'>在职</b>"
                        }else if (del == 2){
                            return "<b style='color: red'>离职</b>"
                        }
                    }},
                {field:"createTime",title:"创建时间"},
                {title:"操作"},
            ]],
            page:true,
            parseData:function (rs) {
                return {
                    "code" : rs.code,
                    "msg":rs.msg,
                    "count":rs.data.total,
                    "data":rs.data.data
                }
            },
            response:{
                statusCode:200
            }

        };
        let tabIns = table.render(opt);
        //表格查询
        $("#searchBtn").click(function () {
            let realname = $("#realname").val();
            let role = $("#role").val();
            let del = $("#delete").val();

            tabIns.reload({
                where:{
                    realname:realname,
                    role:role,
                    "delete":del
                }
            })
        });
    });
</script>
</body>
</html>

3.修改PageController

    /**
     * 员工列表
     * @param req
     * @param resp
     * @throws ServletException
     * @throws IOException
     */
    protected void userList(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        req.getRequestDispatcher("/WEB-INF/view/user/list.jsp").forward(req,resp);
    }
回到顶部