30-JavaWeb-《卖淘乐》后台管理系统

30-JavaWeb-《卖淘乐》后台管理系统-qianfeng-笔记


文章目录


学以致⽤:将所学习的技术转换成企业⽣产⼒


一、《卖淘乐》后台管理系统介绍

《卖淘乐》后台管理系统 是一个管理系统,管理系统是对数据进行管理和维护的。

1.1 《卖淘乐》系统

电商:京东(B2C& C2B2C)、淘宝(C2B2C) — 买东⻄

卖淘乐 —— 非传统电商,用户如果有闲置的手机可以通过此平台进行估价和交易 (二手手机回收系统)

在这里插入图片描述

1.2 《卖淘乐》后台管理系统

《卖淘乐》后台管理系统就是对卖淘乐系统的数据进行管理的一个系统

在这里插入图片描述
在这里插入图片描述

二、软件系统的开发流程

软件开发生命周期——一个软件系统从无到有的z 过程

2.1 软件开发生命周期

  • 问题定义: 明确要开发一个什么样的软件系统 完成《卖淘乐》后台管理系统

  • 可行性分析: 从技术、经济、社会因素等多个方面综合考虑这个项目是否可以做 技术训练

  • 需求分析: 从细节上探讨这个项目要完成的功能 《卖淘乐》后台管理系统包含的具体功能

  • 概要设计: 系统结果、技术栈、数据库

  • 详细设计: 针对一个具体功能实现的详细步骤 《卖淘乐》管理员登录功能实现的流程图

  • 编码: 按照功能实现的项目步骤进行代码的编写 DAO---service---servlet---JSP

  • 测试: 检测软件系统功能实现及性能 (黑盒测试、白盒测试)

  • 项目部署(交付): 将项目部署运行到甲方的生产环境

2.2 通俗的开发流程

  • 做什么

  • 怎么做

  • 动手做

三、《卖淘乐》后台管理系统功能需求

3.1 卖淘乐二手手机回收业务流程

在这里插入图片描述

3.2 《卖淘乐》后台管理系统功能清单

https://www.processon.com/view/link/61a6de825653bb586f8a832b

在这里插入图片描述

四、《卖淘乐》后台管理系统业务流程设计

4.0概要设计:

  • 系统的业务流程

  • 系统的数据库设计

  • 系统的UI设计

4.1 HIPO图

项目功能的层次结构图:列出系统的功能,并建立起功能之间的层次关系

在这里插入图片描述

4.2 功能流程分析

针对HIPO图中的每个功能进行详细的业务流程分析

以管理员登录为例:

  • 流程图:

  • 功能说明:
功能名称管理员登录
功能说明管理员通过登录⻚面输入登录信息之后,验证登录信息是否合法
输入项管理员登录账号,字符串类型
管理员登录密码,字符串类型
登录验证码
处理接收账号、密码、验证码,首先验证验证码是否正确;
如果验证码正确则继续校验账号和密码,如果…
输出项如果登录成功则进入到系统管理的首⻚,如果登录失败则进入到登录⻚面并进行提示

五、《卖淘乐》后台管理系统数据库设计

5.1 数据库设计流程

  • 根据系统的功能需求分析涉及到的数据实体(系统中需要对哪些数据进行存储和处理)

  • 提取数据实体的数据项(数据实体的属性)

  • 根据数据库设计范式规范和约束实体的数据项是否合理

  • 数据库建模:整理项目中涉及的数据实体的关系

    • E-R图

    • PD

    • PDMan

  • 建库建表:sql脚本、建模工具导出数据表

5.2 《卖淘乐》数据库分析

《卖淘乐》后台管理系统和 用户系统公用同一个数据库,在此我们主要对已经设计好的 数据库/数据表进行分析,理清楚各个数据表的作用以及表与表之间的关系

5.2.1 相关数据表的归类说明

系统 相关数据表
在这里插入图片描述
产品业务 相关的数据表
在这里插入图片描述
用户 相关的数据表
在这里插入图片描述

5.2.2 系统的数据库的E-R图

https://www.processon.com/view/link/61a6f59c6376897a4d2c082c

数据库E-R图
在这里插入图片描述

5.3 《卖淘乐》数据库创建

5.3.1 运行SQL脚本创建数据表

  • 脚本文件:

在这里插入图片描述

  • 创建数据库: db_mtl

在这里插入图片描述

  • 选择创建的db_mtl数据库,运行SQL脚本文件
    在这里插入图片描述
    在这里插入图片描述

5.3.2 使用PDMan逆向生成数据库模型

  • 下载安装PDMan (我没有下载用的是Navicat自带的表逆向模型)

  • 打开PDMan,创建一个新项目

  • 建立PDMan与数据库连接
    在这里插入图片描述

  • 逆向解析数据库
    在这里插入图片描述

  • 通过PDMan建立、分离数据表关系

(我使用的是Navicat自带的表逆向模型)
在这里插入图片描述

六、《卖淘乐》后台管理系统UI设计

  • 在企业开发中,web前端的HTML模板通常是由UI团队设计并完成静态网⻚的创建;

  • 系统的UI界面也是根据系统的功能需求进行设计的。

七、《卖淘乐》后台管理系统技术选型与项目搭建

7.1 技术选型

  • 前端静态网⻚ HTML/CSS/JS+jQuery

  • Servlet/JSP

  • JDBC:Druid + apache commons DBUtil

7.2 创建Java web工程

  • mtlms (卖淘乐Management System) 卖淘乐管理系统

    • 视图层:JSP

    • 控制层:Servlet

    • 业务层:Service

    • 持久层:DAO
      在这里插入图片描述

7.3 项目开发环境搭建

7.3.1 JDBC开发环境

  • druid

  • apache commons dbutil

  • 导入依赖坐标: mysql驱动、druid、apache commons dbutil


<dependency>
          <groupId>mysql</groupId>
          <artifactId>mysql-connector-java</artifactId>
          <version>8.0.28</version>
      </dependency>

      <dependency>
          <groupId>commons-dbutils</groupId>
          <artifactId>commons-dbutils</artifactId>
          <version>1.6</version>
      </dependency>

      <dependency>
          <groupId>com.alibaba</groupId>
          <artifactId>druid</artifactId>
          <version>1.1.12</version>
      </dependency>
  • 在resources包中创建druid.properties配置文件,并完成参数的配置:

在这里插入图片描述

driverClassName=com.mysql.cj.jdbc.Driver
#URL连接数据库的URL,其中travel(以下面例子来说)为连接的数据库,后面的参数可不改但不删
url=jdbc:mysql://localhost:3306/db_mtl?serverTimezone=GMT&useSSL=false&allowPublicKeyRetrieval=true
characterEncoding=utf-8
#安装mysql时候设置的用户与密码
username=root
password=root
#初始化物理连接的个数
initialSize=5
#最大连接池数量
maxActive=10
#获取连接时最大等待时间
maxWait=3000
#用来检测连接是否有效的sql
validationQuery=SELECT 1
#保证安全性!
testWhileIdle=true
  • 在utils包中创建Druid的工具类
    在这里插入图片描述
package com.example.d9_mtl.utils;

import com.alibaba.druid.pool.DruidDataSource;
import com.alibaba.druid.pool.DruidDataSourceFactory;

import javax.sql.DataSource;
import java.io.IOException;
import java.io.InputStream;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;

public class DruidUtils {

    // 定义Druid数据库连接池对象
    private static DruidDataSource druidDataSource;

    /**
     * 初始化数据库连接池
     */
    static {
        InputStream inputStream = DruidUtils.class.getResourceAsStream("druid.properties");
        Properties pros = new Properties();
        try {
            pros.load(inputStream);
            druidDataSource = (DruidDataSource) DruidDataSourceFactory.createDataSource(pros);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        }

    }

    /**
     * 返回 DataSource 数据库连接池对象
     * @return
     */
    public static DataSource getDataSource(){
        return druidDataSource;
    }


    /**
     * 从连接池中获取获取数据库连接
     * @return
     */
    public static Connection getConnection(){
        Connection connection = null;
        try {
            connection = druidDataSource.getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return connection;
    }
}

7.3.2 JSTL

  • 添加JSTL标签库的坐标

  • jstl

  • standard

 <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
      <dependency>
          <groupId>javax.servlet</groupId>
          <artifactId>jstl</artifactId>
          <version>1.2</version>
      </dependency>
      <!-- https://mvnrepository.com/artifact/taglibs/standard -->
      <dependency>
          <groupId>taglibs</groupId>
          <artifactId>standard</artifactId>
          <version>1.1.2</version>
      </dependency>

7.3.3 JUNIT 单元测试

  • 添加junit的坐标
      <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.13</version>
          <scope>test</scope>
      </dependency>

八、管理员登录功能的设计与实现

  • 设计:分析系统功能具体的实现流程与步骤

  • 实现:使用代码按照设计的步骤进行编码、完成功能

8.1 管理员登录—实现流程设计

在这里插入图片描述

1:进入系统显示登录⻚面,管理员输入账号、密码点击登录按钮进行提交;

2: 账号和密码提交到ManagerLoginServlet类,在ManagerLoginServlet中接收账号和密码,调用ManagerService验证账号和密码是否正确;

3:ManagerService先调用ManagerDAO中的方法,根据管理员名称查询管理员信息,将查询结果返回给ManagerService;

4:在ManagerService中:

  • 如果ManagerDAO返回的信息为空,则表示根据用户输入的管理员登录账号没有查询到管理员信息(账号不存在),就返回给ManagerLoginServlet一个null值;

  • 如果ManagerDAO返回的信息不为空,表示管理员账号是正确的,然后校验输入的密码与查询的管理员信息密码是否一致:

    • 如果密码不一致,则返回给ManagerLoginServlet一个null值;

    • 如果密码一致,则返回给ManagerLoginServlet管理员对象;

5: ManagerLoginServlet接收ManagerService返回的验证结果:如果返回的是null,则表示账号或者密码错误,转发到login.jsp并提示如果返回的管理员对象,则表示账号和密码都正确,将管理员信息存放到session中,跳转到index.jsp

8.2 管理员登录—功能代码实现

  • 数据库操作

  • 业务逻辑层

  • 功能流程

8.2.1 数据库操作实现

根据管理员账号查询管理员信息

1: 数据表

  • tb_managers 管理员信息表
    在这里插入图片描述

2: 创建实体类 Manager

public class Manager {
    private String mgrId;
    private String loginName;
    private String loginPwd;
    private String mgrName;
    private String mgrGender;
    private String mgrTel;
    private String mgrEmail;
    private String mgrQQ;
    private Date createTime;

    //无参构造器
    //全参构造器
}

3:创建DAO类 ManagerDAO

public class ManagerDAO {

    private static Manager manager =null;

    /**
     * 根据管理员登录名查询管理员信息
     * @param loginName 管理员登录名
     * @return 如果查询成功则返回管理员对象,如果查询没有结果则返回null
     */
    public Manager selectManagerByLoginName(String loginName){

        try {
            String sql = "SELECT mgr_id mgrId,login_name loginName,login_pwd loginPwd,mgr_name mgrName,mgr_gender mgrGender,mgr_tel mgrTel,mgr_email mgrEmail,mgr_qq mgrQQ,create_time createTime FROM tb_managers WHERE login_name = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            manager = queryRunner.query(sql, new BeanHandler<Manager>(Manager.class), loginName);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return manager;
    }

8.2.2 业务层实现

public class ManagerService {

    public Manager checkLogin(String loginName, String loginPwd){
        // 1.根据loginName查询管理员信息
        ManagerDAO managerDAO = new ManagerDAO();
        Manager manager = managerDAO.selectManagerByLoginName(loginName);
        // 2.如果查询的结果不为null,则登录名正确
        if (manager != null){
            // 3.判断密码,输入密码与数据库密码相等则正确,否则返回null
            if (manager.getLoginPwd().equals(loginPwd)){
                return manager;
            }
        }
        return null;
    }
}

8.2.3 视图层和控制层的实现

1.视图层

  • 将HTML模版整合到java web工程

  • 将对应的HTML网⻚,修改为jsp⻚面

  • login.html —> login.jsp

  • index.html–>index.jsp

修改java web工程的默认欢迎⻚面: 在web.xml文件设置欢迎界面
在这里插入图片描述
2.控制层
在servlets包中创建ManagerLoginServlet类
在这里插入图片描述
在login.jsp⻚面点击登录之后,将帐号和密码提交到ManagerLoginServlet类
在这里插入图片描述
在这里插入图片描述

ManagerLoginServlet类接收账号和密码,然后调用ManagerService进行数据校验

@WebServlet(name = "ManagerLoginServlet", value = "/ManagerLoginServlet")
public class ManagerLoginServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ①:接收账号、密码、验证码
        String loginName = request.getParameter("loginName");
        String loginPwd = request.getParameter("loginPwd");
        String checkCode = request.getParameter("checkCode");
        // ②:调用ManagerService进行校验
        ManagerService managerService = new ManagerService();
        Manager manager = managerService.checkLogin(loginName, loginPwd);
        // ③:判断验证结果
        if (manager == null){
            // ④:登录失败:跳转到登录页面并进行提示
            request.setAttribute("tips","<label style='color:red'>登录失败,账号或密码错误!</label>");
            request.getRequestDispatcher("login.jsp").forward(request,response);
        }else {
            // ⑤:登录成功:跳转到管理系统的页面
            response.sendRedirect("index.jsp");
        }
    }
}
在登录⻚面显示提示信息
login.jsp
在这里插入图片描述

8.3 验证码功能—实现流程设计

在这里插入图片描述

8.4 验证码功能—代码实现

1. 在登录⻚面对应的位置添加一个验证码图片的img标签,同时将图片的src设置为CheckCodeServlet类路径;
login.jsp
在这里插入图片描述
2. 创建CheckCodeServlet类,用于生成验证码
@WebServlet(name = "CheckCodeServlet", value = "/CheckCodeServlet")
public class CheckCodeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 通过 awt提供的类绘制验证码图片
        //1.创建一张图片
        int width = 300; //验证码宽度
        int height = 90; //验证码高度
        BufferedImage image = new
                BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        //2.绘制图片 , 从图片对象中获取绘制图片的 “笔”
        Graphics2D pen = image.createGraphics();
        //a.绘制背景
        pen.setColor(getRandomColor());
        //fillRect: 绘制实心矩形
        pen.fillRect(0, 0, width, height);

        //b.绘制验证码字符串
        int letterNum = 4; //验证码图片上的字符的个数
        int space = 20; // 验证码图片上两个字母之间的空隙
        int letterWidth = (width - (letterNum + 1) * space) / letterNum;
        //计算每个字母占据的宽度

        //for循环每循环一次,绘制一个字母 (小写字母的ascii码 97-122)
        Random random = new Random();
        for (int i = 0; i < letterNum; i++) {
            //随机生成一个小写字母:
            int ascii = random.nextInt(26) + 97; //97-122
            byte[] bs = {(byte) ascii};
            String letter = new String(bs);
            //drawString: 绘制字母
            pen.setColor(getRandomColor());
            pen.setFont(new Font("Gulim", Font.BOLD, 70));
            pen.drawString(letter, space +
                    (letterWidth + space) * i, height - space);
        }
        // 为了让图片不是那么容易被程序识别,可以绘制干扰线、干扰图形
        //图片绘制完成之后,将图片通过 response的输出流响应到客户端
        ImageIO.write(image, "png", response.getOutputStream());
    }
	// 随机生成一个颜色
    private Color getRandomColor() {
        Random random = new Random();
        int r = random.nextInt(256);
        int g = random.nextInt(256);
        int b = random.nextInt(256);
        Color color = new Color(r, g, b);
        return color;
    }
}

3. 在登录⻚面实现验证码图片的刷新
在这里插入图片描述
4. 校验验证码
在CheckCodeServlet中生成验证码之后,要将正确的验证码存储到session中;
在这里插入图片描述
5.在ManagerLoginServlet中接收用户输入的验证码,和session中存储的正确的验证码进行对比
在这里插入图片描述

8.5 用户认证校验(登录过滤器)

对于系统中的受限资源必须在管理员登录之后才能访问(例如管理系统首⻚),如何实现未经登录不允许访问受限资源呢?—— 登录认证过滤器

8.5.1 用户认证校验—流程设计

在这里插入图片描述

8.5.2 用户认证校验—代码实现

ManagerLoginServlet
1. 用户登录成功,将管理员信息存放到session中
在这里插入图片描述
2. 创建登录过滤器拦截所有用户请求
在这里插入图片描述
3. 在登录过滤器中实现拦截及校验规则
package com.example.d9_mtl.filter;

import com.example.d9_mtl.dto.Manager;

import javax.servlet.*;

import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@WebFilter("/*")
public class LoginFilter implements Filter {
    @Override
    public void init(FilterConfig filterConfig) throws ServletException {

    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
       // ①:获取用户请求资源的url(用户请求的可能是非受限资源,也可能是受限资源)
        HttpServletRequest  request = (HttpServletRequest)servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        String url = request.getRequestURL().toString();
        // ②:从url中截取请求的资源名称(url 字符串中最后一个/后面的部分)
        String path = url.substring(url.lastIndexOf("/") + 1);
        if ("login.jsp".equals(path) || "ManagerLoginServlet".equals(path) || "CheckCodeServlet".equals(path)
            || path.endsWith(".js") || path.endsWith(".css") || path.endsWith(".jpg")
            || path.endsWith(".png") || path.endsWith(".bmp")){
            // ③:如果url中的资源是非受限资源(不登录也可以访问) 则放行
            // 非受限资源:登录页面,登录页面的静态资源(js\css\image),验证码的Servlet类路径,对登录进行校验的servlet类
            filterChain.doFilter(servletRequest, servletResponse);
        }else {
            // ④:如果url中的是受限资源,需要验证管理员是否登录(检查Session中是否有管理员信息)
            HttpSession session = request.getSession();
            Manager mgr = (Manager) session.getAttribute("mgr");
            if (mgr == null){
                // ⑤:跳转到登录页面,提示登录
                request.setAttribute("tips","<label style='color:red'>您还未登录,请先登录!</label>");
                request.getRequestDispatcher("login.jsp").forward(request,response);
            }else {
                // 管理员已登录 放行
                filterChain.doFilter(servletRequest, servletResponse);
            }

        }
    }

    @Override
    public void destroy() {
    }
}

8.6 密码的加密加盐存储业务

密码的加密加盐存储背景——为了保证用户信息的安全性
①: 在用户系统用户注册时或者管理系统添加管理员时,用户或管理员的密码都需要加密存储
**②:**存储在数据库中的密码进行加密之后,即使出现数据泄露也可以保证用户信息的安全性

8.6.1 加密方式

  • 对称加密: 明文按照一定的规则加密成密文,这个密文可以按照对应的规则解密成明文对称加密也存在安全隐患:当不速之客知道了加密规则以后,可以进行解密)

    • Base64
  • 非对称加密: 明文按照一定的规则加密成密文,密文没有对应的规则解密成明文(加密后的密文是不能解密的)

    • MD5

8.6.2 加盐

即使非对称加密的加密方式依然存在安全隐患:穷举法破解

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

8.6.3 密码加密校验实现

1.创建MD5加密帮助类
public class MD5Utils {
    public static String md5Encode(String pwd){
        String str =null;
        try {
            MessageDigest md5 = MessageDigest.getInstance("MD5");
            md5.update(pwd.getBytes());
            byte[] bs = md5.digest();
             // 将字节数组转换成十六进制字符串表示
            // toString(16) 参数16:代表16进制
            str = new BigInteger(1, bs).toString(16);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return str;
    }
}
2.在登录校验的逻辑中对密码加密校验
ManagerService
在这里插入图片描述

九、系统权限管理功能的设计与实现

9.1 权限管理介绍

9.1.1 什么是权限管理?

在一个系统中通常会存在不同身份的用户,不同身份的用户都可以登录系统,但是进入到系统之后所能够完成的操作是不同的。

  • 教务管理系统(教师、学生)
    • 教师:录入学生成绩、修改成绩
    • 学生:查看成绩
  • 企业OA系统(总监、主管、员工)
    • 员工:查看个人信息、请假申请、加班申请
    • 主管:批准请求、批准加班
    • 总监:管理员工信息(新增、删除、查看)
  • 《卖淘乐》后台管理系统(超级管理员、普通管理员、业务员、客服...)
    • 超级管理员(商品管理、评估管理、订单管理、评价管理、会员管理、工单管理、消息管理、系统管理、授权管理)
    • 普通管理员(商品管理、评估管理、订单管理、评价管理、会员管理、工单管理、消息管理)
    • 业务员(订单管理、评价管理、会员管理、工单管理、消息管理)
      在这里插入图片描述

9.1.2 如何实现权限管理?

  • 基于菜单的权限管理:不同身份的用户登录到系统之后所能够操作的菜单是不同的,当前用户没有权限操作的菜单对此用户是不可⻅的。

  • 基于功能的权限管理:所有用户都可以看到完整的菜单,但是当进行没有权限的操作时,RBAC数据库设计系统提示“权限不足”并阻止下一步的操作。

9.2 RBAC权限管理实现流程

9.2.1 RBAC概念

RBAC (Role-Based Access Control)基于⻆色的访问控制:

  • 我们将一组权限绑定到某个用户⻆色之上:

    • 超级管理员(商品管理、评估管理、订单管理、评价管理、会员管理、工单管理、消息管理、系统管理、授权管理)
    • 普通管理员(商品管理、评估管理、订单管理、评价管理、会员管理、工单管理、消息管理)
    • 业务员(订单管理、评价管理、会员管理、工单管理、消息管理)
  • 当创建一个新的用户时(wangwu),我们只需要给这个用户指定对应的⻆色,此用户 就拥有这个⻆色对应的功能/菜单。

9.2.2 RBAC数据库设计

在这里插入图片描述

9.2.3 RBAC实现流程

1.基于菜单实现
  • 在创建系统用户时,为用户绑定对应的⻆色(⻆色对应着一组权限)

  • 当用登录成功进入到主⻚面时,根据用户查询⻆色、再根据⻆色关联查询到当前用户的权限列表(菜单列表)并传递、显示到主⻚。

2.基于功能实现
  • 在创建系统用户时,为用户绑定对应的⻆色(⻆色对应着一组权限)

  • 当用户登录成功,系统首⻚显示所有菜单

  • 当用户点击菜单进行操作时,在操作之前先根据当前用户名查询此用户有没有这个功能的操作权限,如果有则进行操作,如果没有则提示“权限不足”。

9.3 主⻚菜单的加载显示功能

根据不同的管理员身份加载并显示当前管理员可以进行操作的菜单

9.3.1 实现流程设计

9.3.2 数据库操作代码实现

操作:根据管理员的ID查询当前管理员的菜单

1.涉及的数据表
  • 管理员信息表 : tb_managers

  • 管理员⻆色关联表:tb_mgr_role

  • ⻆色表:tb_roles

  • ⻆色菜单关联表:tb_role_menu

  • 菜单表:tb_menus

在这里插入图片描述

2.查询SQL
  • 使用子查询:
 -- 根据管理员ID查询当前管理员拥有的权限的菜单( 5 表关联)
select menu_id,menu_code,menu_name,menu_order,menu_level,menu_icon,parent_menu_
code,menu_url from tb_menus where menu_id in(
-- 根据⻆色ID查询当前管理员的权限ID
select menu_id from tb_role_menu where role_id in(
-- 根据管理员ID查询管理员的⻆色ID
select role_id from tb_mgr_role where mgr_id='10000002'
)
);
  • 使用连接查询:
select c.menu_id,menu_code,menu_name,menu_order,menu_level,menu_icon,parent_men
u_code,menu_url 
from tb_mgr_role a 
inner join tb_role_menu b 
inner join tb_menus c 
on a.role_id = b.role_id and b.menu_id = c.menu_id 
where a.mgr_id='10000002';
3.创建实体类

创建实体类封装查询的菜单信息

  • 一级菜单实体类Menu1:

  • 二级菜单实体类Menu2:

package com.qfedu.mtlms.dto;
/**
* @Description 二级菜单
*/
public class Menu2 {
private int menuId;
private String menuCode;
private String menuName;
private int menuOrder;
private int menuLevel;
private String parentMenuCode;
private String menuUrl;

package com.qfedu.mtlms.dto;
import java.util.List;

/*
* @Description 一级菜单
*/

public class Menu1 {

private int menuId;
private String menuCode;
private String menuName;
private int menuOrder;
private int menuLevel;
private String menuIcon;
//当前一级菜单中包含的二级菜单
private List<Menu2> childMenus;
}
4. JDBC实现

如何将对应的二级菜单封装到一级菜单下:

  • 方式一:使用上述SQL一次性查询出当前管理员所有的菜单,在JDBC结果集处理时将查询出的菜单数据进行处理(优点:只需查询一次数据库;缺点:封装数据的业务比较复杂)

  • 方式二:先查询出当前管理员的一级菜单,然后再根据一级菜单的ID查询当前管理拥有的这个一级菜单下的二级菜单(优点:业务简单;缺点:需要多次查询数据库)

5. 查询SQL改造:
  • 根据管理员ID,查询当前管理员的一级菜单:

  • 根据管理员ID和一级菜单编号,查询这个一级菜单下的二级菜单:

 -- 根据管理员ID查询一级菜单
select c.menu_id menuId,menu_code menuCode,menu_name
menuName,menu_order menuOrder, menu_level menuLevel,menu_icon
menuIcon
from tb_mgr_role a inner join tb_role_menu b inner join tb_menus c
on a.role_id = b.role_id and b.menu_id = c.menu_id
where a.mgr_id='10000001' and c.menu_level= 1 order by c.menu_order;
-- 根据管理员ID和一级菜单编号,查询这个一级菜单下的二级菜单
SELECT menus.menu_id menuId, menu_code menuCode, menu_name menuName, menu_order menuOrder,menu_level menuLevel,menu_icon menuIcon,parent_menu_code parentMenuCode,menu_url menuUrl
FROM tb_mgr_role mgr INNER JOIN tb_role_menu menu INNER JOIN tb_menus menus
ON mgr.role_id = menu.role_id AND menu.menu_id = menus.menu_id
WHERE mgr.mgr_id ='10000001' AND menus.menu_level = 2 AND menus.parent_menu_code = '01' ORDER BY menus.menu_order;
6.创建MenuDAO类实现JDBC操作
package com.qfedu.mtlms.dao;

import com.qfedu.mtlms.dto.Menu1;
import com.qfedu.mtlms.dto.Menu2;
import com.qfedu.mtlms.utils.DruidUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;

/**
* @Description 实现菜单的数据库操作
*/
public class MenuDAO {

/**
* 根据管理员ID查询对应的一级菜单
*/
public List<Menu1> selectFirstLevelMenusByMgrId(String mgrId){
List<Menu1> menu1List = new ArrayList<>();
try {
String sql = "select c.menu_id menuId,menu_code
menuCode,menu_name menuName,menu_order menuOrder,menu_level
menuLevel,menu_icon menuIcon " +

"from tb_mgr_role a inner join tb_role_menu b inner
join tb_menus c " +
"on a.role_id = b.role_id and b.menu_id = c.menu_id
" +
"where a.mgr_id=? and c.menu_level=1 order by
c.menu_order";
QueryRunner queryRunner = new
QueryRunner(DruidUtils.getDataSource());
menu1List = queryRunner.query(sql,new
BeanListHandler<Menu1>(Menu1.class),mgrId);
} catch (SQLException e) {
e.printStackTrace();
}
return menu1List;
}

/**
* 根据管理员ID及一级菜单ID,查询此管理员在这个一级菜单下拥有的二级菜单
* @param mgrId
* @param parentCode
* @return
*/
public List<Menu2> selectMenu2ByMgrIdAndParentCode(String
mgrId,String parentCode){
List<Menu2> menu2List = new ArrayList<>();
try {
String sql = "select c.menu_id menuId,menu_code
menuCode,menu_name menuName,menu_order menuOrder,menu_level
menuLevel,parent_menu_code parentMenuCode,menu_url menuUrl from
tb_mgr_role a inner join tb_role_menu b inner join tb_menus c on
a.role_id = b.role_id and b.menu_id = c.menu_id where a.mgr_id=? and
c.menu_level=2 and c.parent_menu_code=? order by c.menu_order";
QueryRunner queryRunner = new
QueryRunner(DruidUtils.getDataSource());
menu2List = queryRunner.query(sql, new
BeanListHandler<Menu2>(Menu2.class),mgrId,parentCode);
} catch (SQLException e) {
e.printStackTrace();
}
return menu2List;
}
}

9.3.3 业务逻辑层代码实现

①:创建MenuService类
package com.qfedu.mtlms.service;

import com.qfedu.mtlms.dao.MenuDAO;
import com.qfedu.mtlms.dto.Menu1;
import com.qfedu.mtlms.dto.Menu2;

import java.util.List;

/**
* @Description 菜单相关业务逻辑
*/
public class MenuService {

private MenuDAO menuDAO = new MenuDAO();

/**
* 根据管理员ID查询当前管理员的菜单列表(一级菜单中需要包含对应的二级菜单)
* @param mgrId
* @return
*/
public List<Menu1> listMenusByMgrId(String mgrId){
//1.根据管理ID查询此管理员所有的一级菜单
List<Menu1> menu1List =
menuDAO.selectFirstLevelMenusByMgrId(mgrId);
//2.查询每个一次菜单中的二级菜单
for (int i = 0 ; i <menu1List.size() ; i++) {
Menu1 menu1 = menu1List.get(i);
//查询此一级菜单下的二级菜单
List<Menu2> menu2List =
menuDAO.selectMenu2ByMgrIdAndParentCode(mgrId, menu1.getMenuCode());
//将二级菜单集合,设置给一级菜单对象
menu1.setChildMenus(menu2List);
}
return menu1List;
}

9.3.4 功能流程代码实现

①: 在Servlets中创建IndexServlet
②:在ManagerLoginServlet中,登录成功之后重定向到IndexServlet
ManagerLoginServlet
在这里插入图片描述
③: 在IndexServlet根据管理员ID查询菜单集合,并传递到index.jsp
package com.example.d9_mtl.servlet;

import com.example.d9_mtl.dto.Manager;
import com.example.d9_mtl.dto.Menu1;
import com.example.d9_mtl.service.MenuService;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.util.List;

@WebServlet("/index")
public class IndexServlet extends HttpServlet {
    private MenuService menuService = new MenuService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.根据当前登录的管理员ID,查询管理员的菜单列表
        //a.从session中获取当前管理员的id
        HttpSession session = request.getSession();
        Manager manager = (Manager) session.getAttribute("mgr");
        //b.调用MenuService查询当前管理员的菜单
        String mgrId = manager.getMgrId();
        List<Menu1> menu1List = menuService.listMenusByMgrId(mgrId);
        
        //2.将菜单的集合传递到index.jsp
        request.setAttribute("menu1List",menu1List);
        request.getRequestDispatcher("index.jsp").forward(request,response);
    }
}

④: 在index.jsp通过JSTL+EL显示菜单树
index.jsp
在这里插入图片描述
在这里插入图片描述

9.4 权限(菜单)信息管理

对于一个系统而言,系统功能是由程序员进行开发和实现的,菜单相对比较固定的;如果要新增一个菜单,则需要有对应的功能支撑,因此对于菜单的添加操作不会让管理员来实现,而是由程序员实现的。因此在《卖淘乐后台管理系统》中,菜单信息管理功能只要就是对菜单的展示。

9.4.1 菜单信息列表流程设计

9.4.2 数据库操作代码实现

  • 查询所有的一级菜单

  • 查询所有的二级菜单

  • 根据一级菜单查询所有的二级菜单

①:涉及数据表
  • 菜单信息表 tb_menus
②:SQL指令
 -- 1 查询所有一级菜单
select menu_id,menu_code,menu_name,menu_order,menu_level,menu_icon from
tb_menus where menu_level= 1 order by menu_order;
-- 2 查询所有的二级菜单
select
menu_id,menu_code,menu_name,menu_order,menu_level,parent_menu_code,menu_
url from tb_menus where menu_level= 2 order by menu_order;
-- 3 根据一级菜单code查询当前一级菜单下的二级菜单
select
menu_id,menu_code,menu_name,menu_order,menu_level,parent_menu_code,menu_
url from tb_menus where parent_menu_code='01' order by menu_order;
③:在MenuDAO类中实现数据库操作
package com.example.d9_mtl.dao;

import com.example.d9_mtl.dto.Menu1;
import com.example.d9_mtl.dto.Menu2;
import com.example.d9_mtl.utils.DruidUtils;
import org.apache.commons.dbutils.QueryRunner;
import org.apache.commons.dbutils.handlers.BeanListHandler;

import java.sql.SQLException;
import java.util.List;

public class MenuDAO {

    /**
     * 根据管理员ID查询对应的一级菜单
     * @param mgrId
     * @return
     */
    public List<Menu1> selectFirstLevelMenusByMgrId(String mgrId){
    }

    /**
     * 根据管理员ID及一级菜单ID,查询此管理员在这个一级菜单下拥有的二级菜单
     * @param mgrId
     * @param parentCode
     * @return
     */
    public List<Menu2> selectMenu2ByMgrIdAndParentCode(String mgrId, String parentCode){
    }

    /**
     * 查询系统中所有的一级菜单
     * @return
     */
    public List<Menu1> selectMenu1(){
        List<Menu1> menu1List = null;
        try {
            String sql = "SELECT menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,menu_icon menuIcon " +
                    "FROM tb_menus WHERE menu_level = 1 ORDER BY menu_order";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            menu1List = queryRunner.query(sql, new BeanListHandler<Menu1>(Menu1.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return menu1List;
    }

    /**
     * 查询系统中所有的二级菜单
     * @return
     */
    public List<Menu2> selectMenu2(){
        List<Menu2> menu2List = null;
        try {
            String sql = "SELECT menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,parent_menu_code parentMenuCode,menu_url menuUrl " +
                    "FROM tb_menus WHERE menu_level = 2 ORDER BY menu_order";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            menu2List = queryRunner.query(sql, new BeanListHandler<Menu2>(Menu2.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return menu2List;
    }

    /**
     * 根据一级菜单的menuCode查询当前一级菜单下的二级菜单
     * @param parentCode
     * @return
     */
    public List<Menu2> selectMenu2ByMenu1Code(String parentCode){

        List<Menu2> menu2List = null;
        try {
            String sql = "SELECT menu_id menuId,menu_code menuCode,menu_name menuName,menu_order menuOrder,menu_level menuLevel,parent_menu_code parentMenuCode,menu_url menuUrl\n" +
                    "FROM tb_menus WHERE parent_menu_code = ? ORDER BY menu_order";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            menu2List = queryRunner.query(sql, new BeanListHandler<Menu2>(Menu2.class), parentCode);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return menu2List;
    }
}

9.4.3 业务逻辑层代码实现

在MenuService中实现两个业务
在这里插入图片描述

9.4.4 一级菜单列表显示实现

  • 1: *admin_menu_list.html修改为admin_menu_list.jsp*

  • 2: 创建MenuListServlet

  • 3:点击【菜单管理】跳转到MenuListServlet,因为菜单是从数据库加载的,修改【菜单管理】的跳转路径应该要到数据库tb_menus进行修改
    在这里插入图片描述

  • 4: MenuListServlet类查询菜单信息,传递到admin_menu_list.jsp⻚面

package com.qfedu.mtlms.servlets;

import com.qfedu.mtlms.service.MenuService;

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.util.List;
import java.util.Map;

/**
* @Description
*/
@WebServlet("/MenuListServlet")
public class MenuListServlet extends HttpServlet {

@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
doPost(request, response);
}
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
//1.查询一级菜单和二级菜单
MenuService menuService = new MenuService();
Map<String, List> menus = menuService.listMenus();
//2.将一级菜单和二级菜单传递到 admin_menu_list.jsp
request.setAttribute("menu1List",menus.get("menu1List"));
request.setAttribute("menu2List",menus.get("menu2List"));

request.getRequestDispatcher("admin_menu_list.jsp").forward(reques
t,response);
}
}
  • 5: admin_menu_list.jsp使用JSTL+EL显示菜单信息
admin_menu_list.jsp 引入JSTL标签库
在这里插入图片描述
admin_menu_list.jsp 显示一级菜单
在这里插入图片描述
admin_menu_list.jsp 显示二级菜单
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.4.5 二级菜单联动显示

当点击一级菜单列表,异步请求二级菜单并显示

①: 创建Menu2ListByMenu1Servlet
②: 点击admin_menu_list.jsp中的一级菜单,触发ajax请求,请求Menu2ListByMenu1Servlet
admin_menu_list.jsp
在这里插入图片描述
在这里插入图片描述
③: 在Menu2ListByMenu1Servlet类中接收ajax请求,并根据一级菜单查询二级菜单,然后以JSON格式响应ajax请求
package com.example.d9_mtl.servlet;

import com.example.d9_mtl.dto.Menu2;
import com.example.d9_mtl.service.MenuService;
import com.google.gson.Gson;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.servlet.annotation.*;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

/**
 * 接收ajax请求 根据一级菜单查询二级菜单
 */
@WebServlet(name = "Menu2ListByMenu1Servlet", value = "/Menu2ListByMenu1Servlet")
public class Menu2ListByMenu1Servlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // ①:接收一级菜单编号
        String parentCode = request.getParameter("parentCode");
        // ②:根据parentCode查询二级菜单
        MenuService menuService = new MenuService();
        List<Menu2> menu2List = menuService.listMenu2ByMenu1Code(parentCode);
        // ③: 将menu2List集合以Json格式响应给页面
        // 1.将集合转换成Json格式
        Gson gson = new Gson();
        String jsonStr = gson.toJson(menu2List);
        // 2.通过输入流响应ajax请求
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
4. 在admin_menu_list.jspajax得到的响应数据(二级菜单)显示出来(DOM操作)
   <!--管理员列表-->
      <div class="clearfix administrator_style" id="administrator">
        <div class="left_style">
          <div id="scrollsidebar" class="left_Treeview">
            <div class="show_btn" id="rightArrow"><span></span></div>
            <div class="widget-box side_content" >
              <div class="side_title"><a title="隐藏" class="close_btn"><span></span></a></div>
              <div class="side_list"><div class="widget-header header-color-green2"><h4 class="lighter smaller">一级菜单列表</h4></div>
                <div class="widget-body">
                  <ul class="b_P_Sort_list">
                    <li><i class="fa fa-users green"></i> <a href="#">全部</a></li>
                    <%--  遍历一级菜单 --%>
                    <c:forEach items="${menu1List}" var="menu1">
                    <li><i class="fa fa-users orange"></i>
                      <a href="#" onclick="return requestMenu2List('${menu1.menuCode}')">${menu1.menuName}</a>
                    </li>
                    </c:forEach>
                  </ul>
                </div>
              </div>
            </div>
          </div>
        </div>
        <script type="text/javascript">
          function requestMenu2List(menuCode) {
            // 发送ajax请求,获取当前一级菜单下的二级菜单
            $.post("Menu2ListByMenu1Servlet",{parentCode:menuCode},function (res){
              // 将二级菜单通过DOM操作显示在表格中
              // 1.将id=testIframe中原有的表格清楚,同时重新载入以恶搞table(id="sample_table")
              $("#testIframe").html("<table class=\"table table-striped table-bordered table-hover\" id=\"sample_table\">\n"+
              "<thead>\n"+
              "<tr>\n"+
              "<th width=\"25px\"><label><input type=\"checkbox\" class=\"ace\"><span class=\"lbl\"></span></label></th>\n"+
              "<th width=\"80px\">菜单编号</th>\n"+
              "<th width=\"250px\">菜单名称</th>\n"+
              "<th width=\"100px\">菜单排序</th>\n"+
              "<th width=\"100px\">菜单级别</th>\n"+
              "<th width=\"100px\">父级编号</th>\n"+
              "<th width=\"180px\">菜单URL</th>\n"+
              "<th width=\"70px\">状态</th>\n"+
              "<th width=\"200px\">操作</th>\n"+
              "</tr>\n"+
              "</thead>\n"+
              "<tbody></tbody></table>");

              // 2.显示二级菜单
              for (var i = 0; i < res.length; i++) {
                var menu2 = res[i];
                var trTag = "<tr>\n"+
              "<td><label><input type=\"checkbox\" class=\"ace\"><span class=\"lbl\"></span></label></td>\n"+
              "<td>"+menu2.menuCode+"</td>\n"+
              "<td>"+menu2.menuName+"</td>\n"+
              "<td>"+menu2.menuOrder+"</td>\n"+
              "<td>"+menu2.menuLevel+"</td>\n"+
              "<td>"+menu2.parentMenuCode+"</td>\n"+
              "<td>"+menu2.menuUrl+"</td>\n"+
              "<td class=\"td-status\"><span class=\"label label-success radius\">已启用</span></td>\n"+
              "<td class=\"td-manage\">\n"+
              "  <a onClick=\"member_stop(this,'10001')\"  href=\"javascript:;\" title=\"停用\"  class=\"btn btn-xs btn-success\"><i class=\"fa fa-check  bigger-120\"></i></a>\n"+
              "</td>\n"+
           "</tr>";
                $("#sample_table").append(trTag);
              }
              // 3. 表格中的数据重新渲染了,分页效果需要重新初始化
              $('#sample_table').dataTable( {
                "aaSorting": [[ 1, "desc" ]],//默认第几个排序
                "bStateSave": true,//状态保存
                "aoColumnDefs": [
                  // {"bVisible": false, "aTargets": [ 3 ]} //控制列的隐藏显示
                  {"orderable":false,"aTargets":[0,2,3,4,5,7,8,]}// 制定列不参与排序
                ] } );
            },"json");
            return false;
          }
        </script>

9.5 权限(菜单)启用和停用功能

权限/菜单的启用与停用功能,指的是当系统管理员禁用了某个菜单之后,即使拥有这个权限的用户也不能进行此操作了。

修改tb_menus数据表以支持启用停用功能
在这里插入图片描述

9.5.1 实现流程设计

在这里插入图片描述

9.5.2 显示二级菜单状态

在二级菜单列表中,显示二级菜单对应状态

①: 修改二级菜单实体类Menu2
Menu2
在这里插入图片描述
②:修改MenuDAO中查询 Menu2 的方法

在MenuDAO中,涉及到Menu2的查询方法,添加一个查询字段,menu_state

MenuDAO类
在这里插入图片描述
③:在admin_menu_list.jsp显示二级菜单时,同时显示其状态

在这里插入图片描述

<tbody>
 <c:forEach items="${menu2List}" var="menu2">
 <tr>
   <td><label><input type="checkbox" class="ace"><span class="lbl"></span></label></td>
   <td>${menu2.menuCode}</td>
   <td>${menu2.menuName}</td>
   <td>${menu2.menuOrder}</td>
   <td>${menu2.menuLevel}</td>
   <td>${menu2.parentMenuCode}</td>
   <td>${menu2.menuUrl}</td>
   <td class="td-status">
     <c:choose>
       <c:when test="${menu2.menuState == 1}">
         <span class="label label-success radius">已启用</span>
       </c:when>
       <c:otherwise>
         <span class="label label-defaunt radius">已停用</span>
       </c:otherwise>
     </c:choose>
   </td>
   <td class="td-manage">
     <c:choose>
     <c:when test="${menu2.menuState == 1}">
     <a onClick="member_stop(this,'10001')"  href="javascript:;" title="停用"  class="btn btn-xs btn-success">
       <i class="fa fa-close  bigger-120"></i></a>
     </c:when>
     <c:otherwise>
       <a style="text-decoration:none" class="btn btn-xs " onClick="member_start(this,id)" href="javascript:;" title="启用">
         <i class="fa fa-check bigger-120"></i></a>
     </c:otherwise>
     </c:choose>
   </td>
 </tr>
 </c:forEach>
 </tbody>
4. 显示根据一级菜单联动的二级菜单状态
admin_menu_list.jsp
在这里插入图片描述
<script type="text/javascript">
  function requestMenu2List(menuCode) {
    // 发送ajax请求,获取当前一级菜单下的二级菜单
    $.post("Menu2ListByMenu1Servlet",{parentCode:menuCode},function (res){
      // 将二级菜单通过DOM操作显示在表格中
      // 1.将id=testIframe中原有的表格清楚,同时重新载入以恶搞table(id="sample_table")
      $("#testIframe").html("<table class=\"table table-striped table-bordered table-hover\" id=\"sample_table\">\n"+
      "<thead>\n"+
      "<tr>\n"+
      "<th width=\"25px\"><label><input type=\"checkbox\" class=\"ace\"><span class=\"lbl\"></span></label></th>\n"+
      "<th width=\"80px\">菜单编号</th>\n"+
      "<th width=\"250px\">菜单名称</th>\n"+
      "<th width=\"100px\">菜单排序</th>\n"+
      "<th width=\"100px\">菜单级别</th>\n"+
      "<th width=\"100px\">父级编号</th>\n"+
      "<th width=\"180px\">菜单URL</th>\n"+
      "<th width=\"70px\">状态</th>\n"+
      "<th width=\"200px\">操作</th>\n"+
      "</tr>\n"+
      "</thead>\n"+
      "<tbody></tbody></table>");

      // 2.显示二级菜单
      for (var i = 0; i < res.length; i++) {
        var menu2 = res[i];
        var str1 = menu2.menuState == 1?"<span class=\"label label-success radius\">已启用</span>":"<span class=\"label label-defaunt radius\">已停用</span>";
        var str2 = menu2.menuState == 1?"<a onClick=\"member_stop(this,'10001')\"  href=\"javascript:;\" title=\"停用\"  class=\"btn btn-xs btn-success\"><i class=\"fa fa-check  bigger-120\"></i></a>"
                :"<a style=\"text-decoration:none\" class=\"btn btn-xs \" onClick=\"member_start(this,id)\" href=\"javascript:;\" title=\"启用\"><i class=\"fa fa-close bigger-120\"></i></a>";
        var trTag = "<tr>\n"+
      "<td><label><input type=\"checkbox\" class=\"ace\"><span class=\"lbl\"></span></label></td>\n"+
      "<td>"+menu2.menuCode+"</td>\n"+
      "<td>"+menu2.menuName+"</td>\n"+
      "<td>"+menu2.menuOrder+"</td>\n"+
      "<td>"+menu2.menuLevel+"</td>\n"+
      "<td>"+menu2.parentMenuCode+"</td>\n"+
      "<td>"+menu2.menuUrl+"</td>\n"+
      "<td class=\"td-status\">"+str1+"</td>\n"+
      "<td class=\"td-manage\">"+str2+"</td>\n"+
   "</tr>";
        $("#sample_table").append(trTag);
      }
      // 3. 表格中的数据重新渲染了,分页效果需要重新初始化
      $('#sample_table').dataTable( {
        "aaSorting": [[ 1, "desc" ]],//默认第几个排序
        "bStateSave": true,//状态保存
        "aoColumnDefs": [
          // {"bVisible": false, "aTargets": [ 3 ]} //控制列的隐藏显示
          {"orderable":false,"aTargets":[0,2,3,4,5,7,8,]}// 制定列不参与排序
        ] } );
    },"json");
    return false;
  }
</script>

9.5.3 实现菜单的启用和停用

①:完成数据库操作

根据菜单的ID,修改菜单的状态

public class MenuDAO {
    /**
     * 根据menuCode修改菜单状态
     * @param menuCode
     * @param state
     * @return
     */
    public int updateMenuState(String menuCode, int state){
        int i = 0;
        try {
            String sql = "UPDATE tb_menus set menu_state = ? WHERE menu_code = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, state, menuCode);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }

        return i;
    }
 }
2. 完成业务逻辑层实现
public class MenuService {
    private MenuDAO menuDAO = new MenuDAO();

    /**
     * 启用菜单
     * @param menuCode
     * @return
     */
    public boolean enableMenu(String menuCode){
        return changeMenuState(menuCode,1);
    }

    /**
     * 停用菜单
     * @param menuCode
     * @return
     */
    public boolean disableMenu(String menuCode){
        return changeMenuState(menuCode, 0);
    }

    private boolean changeMenuState(String menuCode, int state){
        int i = menuDAO.updateMenuState(menuCode, state);
        return i > 0;
    }

}
3.启用与停用功能实现
①:创建MenuStateChangeServlet
②: 在amdin_menu_list.jsp点击停用或启用按钮,通过ajax请求MenuStateChangeServlet
amdin_menu_list.jsp 点击停用/启用按钮将menuCode传递到JS函数中
在这里插入图片描述
在这里插入图片描述
③:在MenuStateChangeServlet类中接收请求,修改菜单状态
@WebServlet(name = "MenuStateChangeServlet", value = "/MenuStateChangeServlet")
public class MenuStateChangeServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    // 1.接收要修改的menuCode 和 要做的操作
        String menuCode = request.getParameter("menuCode");
        String oper = request.getParameter("oper");
        MenuService menuService = new MenuService();
        boolean b = false;
        //
        if ("stop".equals(oper)){
            // 停用
            b = menuService.disableMenu(menuCode);
        }else if ("start".equals(oper)){
            // 启用
            b = menuService.enableMenu(menuCode);
        }
        // 3. 返回操作结果(响应ajax请求)
       String jsonStr = b?"{\"code\":1000,\"msg\":\"success\"}":"{\"code\":1001,\"msg\":\"fail\"}";
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
④:在admin_menu_list.jsp中显示菜单禁用/启用的效果
admin_menu_list.jsp
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

/菜单-停用/

  function member_stop(obj,id){
    // 1. 提示确认是否要停用
    layer.confirm('确认要停用吗?',function(index){
      // 发送ajax请求到MenuStateChangeServlet, 将当前菜单停用
      $.post("MenuStateChangeServlet",{menuCode:id,oper:"stop"},function (res){
        if (res.code == 1000){
          // 启用菜单成功
          // 2. 将按钮状态修改为"已停用",按钮修改为 启用
          $(obj).parents("tr").find(".td-manage").prepend('<a style="text-decoration:none" class="btn btn-xs " ' +
                  'onClick="member_start(this,id)" href="javascript:;" title="启用"><i class="fa fa-check bigger-120"></i></a>');
          // 3.将当前菜单显示的状态修改为"已停用"
          $(obj).parents("tr").find(".td-status").html('<span class="label label-defaunt radius">已停用</span>');
          // 4.移除当前按钮
          $(obj).remove();
          layer.msg('已停用!',{icon: 5,time:1000});
        }else if (res.code == 1001){
          layer.msg('停用失败!',{icon: 5,time:1000});
        }
      },"json")
    });
  }

/菜单-启用/

  function member_start(obj,id){
    layer.confirm('确认要启用吗?',function(index){
      $.post("MenuStateChangeServlet",{menuCode:id,oper:"start"},function (res){
        if (res.code == 1000){
          // 启用菜单成功
          // 2. 将按钮状态修改为"停用按钮"
          $(obj).parents("tr").find(".td-manage").prepend('<a class="btn btn-xs btn-success " onClick="member_stop(this,id)" ' +
                  'href="javascript:;" title="停用"><i class="fa fa-close bigger-120"></i></a>');
          // 3.将当前菜单显示的状态修改为"已启用"
          $(obj).parents("tr").find(".td-status").html('<span class="label label-success radius">已启用</span>');
          // 4.移除当前按钮
          $(obj).remove();
          layer.msg('已启用!',{icon: 5,time:1000});
        }else if (res.code == 1001){
          layer.msg('启用失败!',{icon: 5,time:1000});
        }
      },"json")
    });
  }
⑤:解决同一个菜单连续停用和启用的bug
  • 在上述代码实现中,存在的问题:

    • 当一个“已停用”状态的菜单,点击“启用”按钮启用后,再次点击“停用”按钮无法停用
    • 当一个“已启用”状态的菜单,点击“停用”按钮停用后,再次点击“启用”按钮无法启用
  • 问题分析:

    • menuCode是字符串类型,当我们使用JS代码拼接“停用”/“启用”按钮时,要指定按钮点击事件触发JS方法,通过要将menuCode传递到方法中,menuCode没有添加’',导致menuCode不能传递到JS函数中
启用菜单的JS方法中 member_start()
在这里插入图片描述
停用菜单的JS方法中 member_stop()
在这里插入图片描述

9.5.4 管理员登录成功之后隐藏禁用菜单

如果一个菜单(权限)被超级管理员“禁用”之后,即使拥有该权限的管理员登录之后,此权限应当不可⻅/不可操作

  • 不可⻅(√)
  • 可⻅但不可操作(√)
index.jsp
在这里插入图片描述

9.6 ⻆色信息管理—列表

⻆色列表功能

  • 添加新⻆色(需要给⻆色指定菜单权限)
  • 删除⻆色
  • 修改⻆色信息(⻆色基本信息、⻆色菜单权限)

9.6.1 ⻆色列表功能

①:实现流程

在这里插入图片描述

②:数据库操作代码实现

从⻆色信息表查询⻆色信息

1. 涉及到的数据表 : tb_roles

2. 创建实体类

public class Role {
    private int roleId;
    private String roleName;
    private String roleDesc;
    
    // get -- set 等方法 略
}

3. 创建DAO类,完成数据库操作

public class RoleDAO {
    /**
     * 查询所有的角色信息
     * @return
     */
    public List<Role> selectRoles(){
        List<Role> roleList = new ArrayList<>();
        try {
            String sql = "select role_id roleId, role_name roleName, role_desc roleDesc from tb_roles";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            roleList = queryRunner.query(sql, new BeanListHandler<Role>(Role.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return roleList;
    }
}
③: 业务逻辑层代码实现

在service包中创建RoleService类

public class RoleService {
    /**
     * 调用RoleDAO 查询角色列表
     */
    private RoleDAO roleDAO = new RoleDAO();
    public List<Role> getRoles(){
        List<Role> roleList = roleDAO.selectRoles();
        return roleList;
    }
}
④: 视图层及控制层代码实现

创建RoleListServlet类

1. 在index.jsp中点击⻆色管理菜单,跳转到RoleListServlet类(修改数据库tb_menus)
在这里插入图片描述
2. 在RoleListServlet类调用RoleService查询⻆色列表信息**
@WebServlet(name = "RoleListServlet", value = "/RoleListServlet")
public class RoleListServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
       // 1.查询所有角色信息
        List<Role> roleList = roleService.getRoles();
      // 2. 将角色列表传递到admin_role_list.jsp
      request.setAttribute("roleList",roleList);
      request.getRequestDispatcher("admin_role_list.jsp").forward(request,response);
    }
}
3. 将admin_role_list.html修改为admin_role_list.jsp
4. 在admin_role_list.jsp使用JSTL+EL显示⻆色列表
在这里插入图片描述
在这里插入图片描述

9.6.2 使用dataTables实现列表的分⻚

①: dataTables是一个jquery的插件
1.在jsp/html⻚面中引入JS库
jquery.js (本地引入,CDN)
dataTables(本地引入,CDN)
(在线引入) //cdn.datatables.net/1.11.3/js/jquery.dataTables.min.js
admin_role_list.jsp
在这里插入图片描述
②: 对数据表格进行初始化

datatables可以支持不同的数据源,我们⻆色列表是对已经加载好数据的表格进行分⻚处理

<script type="text/javascript">
    $("#sample-table-1").DataTable();
</script>

在这里插入图片描述

③: 分⻚效果

在这里插入图片描述

9.7 角色信息管理—添加新⻆色

9.7.1 实现流程分析

在这里插入图片描述

9.7.2 显示菜单列表

当进入到admin_role_add.jsp⻚面添加新⻆色时,需要给新增的⻆色设置权限菜单,因此在这个⻚面需要先显示菜单列表

①:数据库操作实现
MenuDAO 此功能所需的两个数据库操作方法在之前的功能实现已经完成,可以复用
在这里插入图片描述
②:业务逻辑层实现
在MenuService中新增一个方法
查询一级菜单列表(一级菜单中包含其对应的二级菜单)
在这里插入图片描述
③:显示菜单列表功能实现

视图层及控制层的实现

1. 创建MenuListAllServlet
2. 在admin_role_list.jsp⻚面点击【添加新⻆色】按钮
跳转到MenuListAllServlet
在这里插入图片描述
3. 在MenuListAllServlet类,调用MenuService查询系统菜单列表
@WebServlet(name = "MenuListAllServlet", value = "/MenuListAllServlet")
public class MenuListAllServlet extends HttpServlet {
    private MenuService menuService = new MenuService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询所有的系统菜单
        List<Menu1> menu1List = menuService.listAllMenus();
        // 2. 将查询到的系统菜单集合传递到admin_role_add.jsp
        request.setAttribute("menu1List",menu1List);
        request.getRequestDispatcher("admin_role_add").forward(request,response);
    }
}
4. 将项目中的admin_role_add.html改造为admin_role_add.jsp⻚面
5. 在admin_role_add.jsp中使用JSTL+EL表达式将系统菜单显示出来
在这里插入图片描述

9.7.3 保存⻆色信息

①:数据库操作实现
  • 保存⻆色信息 tb_roles

  • 保存⻆色和菜单的关联关系 tb_role_menu

RoleDAO操作
public class RoleDAO {

    /**
     * 添加角色信息(获取添加的数据自动生成的主键)
     * @param role
     * @return
     */
    public int insertRole(Role role){
        int i = 0;
        try {
            String sql = "insert into tb_roles(role_name,role_desc) values(?,?)";
            // 返回的生成的主键存储在一个BigInteger对象中
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            BigInteger object = queryRunner.insert(sql, new ScalarHandler<>(), role.getRoleName(), role.getRoleDesc());
            // 将BigInteger转换成int类型, 赋值给i
            i = object.intValue();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 添加角色和菜单的关联关系
     * @param roleId
     * @param menuId
     * @return
     */
    public int insertRoleAndMenu(int roleId, int menuId){
        int i = 0;
        try {
            String sql = "insert into tb_role_menu(role_id, menu_id) values(?,?)";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, roleId, menuId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
}
②:业务逻辑层实现
1. 在RoleService中,定义完成添加⻆色的业务处理方法
public class RoleService {
   /**
     * 添加角色信息
     * @param role
     * @param menuIds
     * @return
     */
    public boolean addRole(Role role, String[] menuIds){
        boolean b = true;
        // 1.保存角色信息,获取生成的角色的ID
        int roleId = roleDAO.insertRole(role);
        // 2.保存角色和菜单的关联
        if (menuIds != null){
            for (int i = 0; i < menuIds.length; i++) {
                int menuId = Integer.parseInt(menuIds[i]);
                int j = roleDAO.insertRoleAndMenu(roleId, menuId);
                b = b && j > 0;
            }
        }
        return b;
    }
}
③:保存⻆色信息功能实现
1. 创建RoleAddServlet
2. 在admin_role_add.jsp⻚面提交数据到RoleAddServlet
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3. 在RoleAddServlet类接收⻆色信息、以及选择的菜单的id
@WebServlet(name = "RoleAddServlet", value = "/RoleAddServlet")
public class RoleAddServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        // 1.接收角色名称和角色描述
        String roleName = request.getParameter("roleName");
        String roleDesc = request.getParameter("roleDesc");
        Role role = new Role(0, roleName, roleDesc);
        // 2.获取选择的菜单权限id
        String[] menuIds = request.getParameterValues("menuId");
        // 3.保存角色信息
        boolean b = roleService.addRole(role, menuIds);
        // 4.角色添加成功之后,跳到 提示页面 prompt.jsp 并提示操作结果
        String tips = b? "<label style='color:green'>添加成功</label>"
                :"<label style='color:red'>添加失败</label>";
        request.setAttribute("tips",tips);
        request.getRequestDispatcher("prompt.jsp").forward(request,response);
    }
}
④: 创建prompt.jsp⻚面,显示提示信息
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
    <title>Title</title>
</head>
<body>
    <div style="background: lightyellow; padding: 25px 20px; border-radius: 10px; margin: auto;
        margin-top: 100px; width: 200px">
        ${tips}
    </div>
</body>
</html>

9.8 ⻆色信息管理—删除⻆色

从⻆色信息表中将某个⻆色删除,删除一个⻆色分为两个步骤:

  • 先删除这个⻆色绑定的与菜单的关联(从tb_role_menu表中先删除关联关系)
  • 再删除这个⻆色信息(从tb_roles表中删除)

9.8.1 实现流程分析

在这里插入图片描述

9.8.2 功能代码实现

①:数据库操作实现RoleDAO
1. 从tb_role_menu中根据⻆色ID,删除这个⻆色对应的与菜单的关联
    /**
     * 根据角色ID删除这个角色与菜单的映射
     * @param roleId
     * @return
     */
    public int deleteRoleAndMenuByRoleId(int roleId){
        int i = 0;
        try {
            String sql = "delete from tb_role_menu where role_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, roleId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
2.从tb_roles表中根据⻆色ID删除这个⻆色信息
    /**
     * 根据角色ID删除角色信息
     * @param roleId
     * @return
     */
    public int deleteRoleByRoleId(int roleId){
        int i = 0;
        try {
            String sql = "delete from tb_roles where role_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, roleId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
②:业务逻辑层实现RoleService
    /**
     * 根据角色ID删除角色信息
     * @param roleId
     * @return
     */
    public boolean deleteRole(int roleId){
        int i = roleDAO.deleteRoleAndMenuByRoleId(roleId);
        int j = roleDAO.deleteRoleByRoleId(roleId);
        return j >0;
    }
③:视图层和控制层实现
1. 创建RoleDeleteServlet
2. 在admin_role_list.jsp中,点击“删除”触发js方法发送异步请求到RoleDeleteServlet
在这里插入图片描述
在这里插入图片描述
3. 在RoleDeleteServlet类,接收⻆色ID、调用RoleService执行删除
@WebServlet(name = "RoleDeleteServlet", value = "/RoleDeleteServlet")
public class RoleDeleteServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1,接收角色Id
        int roleId = Integer.parseInt(request.getParameter("roleId"));
        // 2.调用RoleService执行删除
        boolean b = roleService.deleteRole(roleId);
        // 3.删除成功之后,响应前端的ajax请求
        String str = b?"{\"code\":1000,\"msg\":\"success\"}":"{\"code\":1001,\"msg\":\"fail\"}";
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();

9.9 ⻆色信息管理—批量删除

9.9.1 批量删除实现流程分析

在这里插入图片描述

9.9.2 批量删除代码实现(同步)

①: 创建RoleMultiDeleteServlet
②: 在admin_role_list.jsp点击批量删除,通过 表单提交 选择的⻆色id提交到RoleMultiDeleteServlet
在这里插入图片描述
在这里插入图片描述
③: 在RoleMultiDeleteServlet类中接收多个⻆色ID,执行删除,并重新查询⻆色列表传递 到admin_role_list.jsp⻚面,并且还要传递提示信息
@WebServlet(name = "RoleMultiDeleteServlet", value = "/RoleMultiDeleteServlet")
public class RoleMultiDeleteServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收点击“批量删除”提交的角色ID
        String[] roleIds = request.getParameterValues("roleId");
        // 2.遍历roleId,依次执行删除
        List<Integer> failIds = new ArrayList<>();
        for (int i = 0; i < roleIds.length; i++) {
            int roleId = Integer.parseInt(roleIds[i]);
            boolean b = roleService.deleteRole(roleId);
            if (b == false){
                failIds.add(roleId);
            }
        }
        // 3.提示信息
        String ids = "";
        for (Integer failId : failIds) {
            ids = "," + failId;
        }
        String tips = failIds.size()==0?"多个角色删除成功!":"删除失败!";
        request.setAttribute("tips",tips);
        // 4.角色列表
        List<Role> roleList = roleService.getRoles();
        request.setAttribute("roleList",roleList);
        request.getRequestDispatcher("admin_role_list.jsp").forward(request,response);
    }
}
④: 在admin_role_list.jsp⻚面显示提示信息
在这里插入图片描述

9.10 ⻆色信息管理—修改⻆色

修改⻆色除了修改⻆色名称、⻆色描述之外,还可以修改这个⻆色的权限菜单(权限分配)

9.10.1 实现流程分析

在这里插入图片描述

9.10.2 ⻆色信息的回显

①:数据库实现
  • 根据⻆色ID查询⻆色信息

  • 根据⻆色ID查询当前⻆色关联的菜单的ID

public class RoleDAO {
	// ... 其他方法略
	
    /**
     * 根据角色ID查询角色信息
     * @param roleId
     * @return
     */
    public Role selectRoleById(int roleId){
        Role role = null;
        try {
            String sql = "SELECT role_id roleId,role_name roleName,role_desc roleDesc FROM tb_roles WHERE role_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            role = queryRunner.query(sql, new BeanHandler<Role>(Role.class), roleId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return role;
    }

    /**
     * 根据角色ID查询当前角色所拥有的权限ID
     * @param roleId
     * @return
     */
    public List<Integer> selectMenuIdByRoleId(int roleId){
        List<Integer> menuIds = null;
        try {
            String sql = "SELECT menu_id FROM tb_role_menu WHERE  role_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            ResultSetHandler<List<Integer>> resultSetHandler = new ResultSetHandler<List<Integer>>() {
                @Override
                public List<Integer> handle(ResultSet resultSet) throws SQLException {
                    ArrayList<Integer> list = new ArrayList<>();
                    while (resultSet.next()){
                        int menuId = resultSet.getInt("menu_id");
                        list.add(menuId);
                    }
                    return list;
                }
            };
            menuIds = queryRunner.query(sql, resultSetHandler, roleId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return menuIds;
    }
}
②:业务逻辑层实现
RoleService
在这里插入图片描述
③:⻆色信息回显功能实现
1. 创建RoleQueryServlet
2. 在admin_role_list.jsp点击列表中的“ 修改 ”按钮
将⻆色ID提交到RoleQueryServlet
在这里插入图片描述
3. 在RoleQueryServlet类中
Menu1和Menu2实体类中添加private boolean havaMenu 属性
在这里插入图片描述
  1. 接收⻆色ID

  2. 根据⻆色ID查询当前⻆色信息

  3. 查询系统中所有的菜单列表

  4. 查询当前⻆色拥有的菜单的id的集合

  5. 【重难点】检查所有的菜单,标识当前⻆色拥有的菜单

    • Menu1和Menu2实体类中添加private boolean havaMenu 属性,标识当前色是否拥有该菜单

    • 遍历所有菜单,如果id在当前⻆色拥有的菜单ID集合中,设置havaMenu=true;

  6. 将⻆色信息及权限信息传递到修改⻚面`admin_role_modify.jsp

@WebServlet(name = "RoleQueryServlet", value = "/RoleQueryServlet")
public class RoleQueryServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    private MenuService menuService = new MenuService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 接收角色ID
        String id = request.getParameter("roleId");
        Integer roleId = id == null?0:Integer.parseInt(id);
        // 根据角色Id查询当前角色信息
        Role role = roleService.getRoleById(roleId);
        // 查询系统中所有的菜单
        List<Menu1> menu1List = menuService.listAllMenus();
        // 查询当前角色所拥有菜单的ID
        List<Integer> menuIds = roleService.getMenuIdsByRoleId(roleId);
        // 判断所有菜单中哪些是当前角色所拥有的
        for (int i = 0; i < menu1List.size(); i++) {
            Menu1 menu1 = menu1List.get(i);
            // 如果menuIds中包含当前一级菜单的id,说明当前角色具有这个一级菜单
            // 那么如何标识这个一级权限的状态呢? -- 在Menu1实体类中添加一个标识属性
            if (menuIds.contains(menu1.getMenuId())){
                menu1.setHavaMenu(true);
            }
            // 判断二级权限
            for (int j = 0; j < menu1.getChildMenus().size(); j++) {
                Menu2 menu2 = menu1.getChildMenus().get(j);
                if (menuIds.contains(menu2.getMenuId())){
                    menu2.setHavaMenu(true);
                }
            }
        }
        // 【说明】通过以上for判断及设置,menu1List中当前角色拥有的菜单haveMenu属性都为true
        // 将角色信息 及 菜单集合 传递到 admin_role_modify.jsp
        request.setAttribute("role",role);
        request.setAttribute("menu1List",menu1List);
        request.getRequestDispatcher("admin_role_modify.jsp").forward(request,response);
    }
}
④: 在admin_role_modify.jsp⻚面显示菜单原始信息及菜单列表
1.将admin_role_modify.html修改给admin_role_modify.jsp
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.10.3 修改⻆色信息

①:数据库操作实现
RoleDAO中定义数据库操作方法完成以下操作
    /**
     * 根据角色id修改角色名称及角色描述
     * @param role
     * @return
     */
    public int updateRole(Role role){
        int i = 0;
        try {
            String sql = "update tb_roles set role_name = ?, role_desc = ? where role_id = ?";
            Object[] params = {role.getRoleName(),role.getRoleDesc(),role.getRoleId()};
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
2.业务逻辑层实现
RoleService中实现添加⻆色的业务
(在RoleService类中定义了roleDAO成员变量)
    /**
     * 修改⻆色信息
     * @param role
     * @param menuIds
     * @return
     */
    public boolean updateRole(Role role, String[] menuIds){
        // 1.修改⻆色信息
        int i = roleDAO.updateRole(role);
        // 2.删除当前⻆色的原始权限
        int j = roleDAO.deleteRoleAndMenuByRoleId(role.getRoleId());
        // 3.新增选择的所有权限
        for (int i1 = 0; i1 < menuIds.length; i1++) {
            int menuId = Integer.parseInt(menuIds[i1]);
            int m = roleDAO.insertRoleAndMenu(role.getRoleId(), menuId);
        }
        // 对于修改⻆色而言,⻆色是可以没有权限菜单的,因此只要i>0就表示⻆色修改成功
        return i > 0;
    }
3.⻚面提交修改后的⻆色信息执行修改
1. 创建RoleUpdateServlet
2. 在admin_role_modify.jsp⻚面使用 form提交
将修改后的⻆色信息以及选择的菜单信息提交到RoleUpdateServlet
在这里插入图片描述
在这里插入图片描述
3. 在RoleUpdateServlet类中,接收修改后的⻆色信息、选择的菜单ID,然后进行修改
@WebServlet(name = "RoleUpdateServlet", value = "/RoleUpdateServlet")
public class RoleUpdateServlet extends HttpServlet {
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收修改后角色的信息
        request.setCharacterEncoding("utf-8");
        int roleId = Integer.parseInt(request.getParameter("roleId"));
        String roleName = request.getParameter("roleName");
        String roleDesc = request.getParameter("roleDesc");
        Role role = new Role(roleId, roleName, roleDesc);
        // 2.获取传递过来的选择的菜单的ID
        String[] roleIds = request.getParameterValues("roleId");
        // 3.执行修改
        boolean b = roleService.updateRole(role, roleIds);
        String tips = b?"<label style='color:green'>修改角色信息成功!</label>"
                :"<label style='color:red'>修改角色信息失败!</label>";
        request.setAttribute("tips",tips);
        request.getRequestDispatcher("prompt.jsp").forward(request,response);
    }
}

9.11 管理员信息管理—列表

作为系统管理员,可以对后台管理系统中的管理员用户信息进行维护。

①: 管理员列表实现流程分析

②: 管理员列表数据操作实现

tb_managers表中查询出所有的管理员信息

1.创建管理员实体类
在进行管理员登录功能实现的数据库操作中已经完成了 Manager类的创建
2.在ManagerDAO类中实现数据库操作
    /**
     * 查询所有管理员信息
     * @return
     */
    public List<Manager> selectManagers(){
        List<Manager> managerList = null;
        try {
            String sql = "SELECT mgr_id mgrId,login_name loginName,login_pwd loginPwd,mgr_name mgrName,mgr_gender mgrGender,mgr_tel mgrTel,mgr_email mgrEmail,mgr_qq mgrQQ,create_time createTime FROM tb_managers";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            managerList = queryRunner.query(sql, new BeanListHandler<Manager>(Manager.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return managerList;
    }

9.11.3 管理员列表业务逻辑层实现

1. 在ManagerService中添加以下方法
    /**
     * 查询所有管理员信息
     * @return
     */
    public List<Manager> listManagers(){
        List<Manager> managerList = managerDAO.selectManagers();
        return managerList;
    }

9.11.4 管理员列表的功能实现

功能实现:视图层与控制层的实现

1. 创建ManagerListServlet
2. 修改主⻚面【管理员管理】菜单点击之后跳转到ManagerListServlet
在这里插入图片描述
3. 在ManagerListServlet中查询管理员信息列表、⻆色信息列表传递到admin_manager_list.jsp
@WebServlet(name = "ManagerListServlet", value = "/ManagerListServlet")
public class ManagerListServlet extends HttpServlet {
    private ManagerService managerService = new ManagerService();
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询管理员信息列表
        List<Manager> managerList = managerService.listManagers();
        // 2.查询角色信息列表
        List<Role> roleList = roleService.getRoles();
        // 3.将管理员信息列表及角色信息列表传递到admin_manager_list.jsp
        request.setAttribute("managerList",managerList);
        request.setAttribute("roleList",roleList);
        request.getRequestDispatcher("admin_manager_list.jsp").forward(request,response);
    }
}
4. 将admin_manager_list.html⻚面修改为admin_manager_list.jsp
5. 在admin_manager_list.jsp⻚面使用JSTL+EL显示⻆色列表及所有管理员信息列表
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

9.12 管理员信息管理—添加管理员

9.12.1 添加管理员实现流程设计

添加管理员使用了弹窗添加,与添加⻆色不同的是没有发生⻚面跳转。
在这里插入图片描述

9.12.2 添加管理员数据库操作实现ManagerDAO

tb_managers表中添加管理员信息
tb_mgr_role表中添加管理员与⻆色关联关系
    /**
     * 添加管理员信息
     * @param manager
     * @return
     */
    public int insertManager(Manager manager){
        int i = 0;
        try {
            String sql = "INSERT INTO tb_managers(mgr_id,login_name,login_pwd,mgr_name,mgr_gender,mgr_tel,mgr_email,mgr_qq,create_time) VALUES(?,?,?,?,?,?,?,?,?)";
            Object[] params = {manager.getMgrId(),manager.getLoginName(),manager.getLoginPwd(),manager.getMgrName(),manager.getMgrGender(),manager.getMgrTel(),manager.getMgrEmail(),manager.getMgrQQ(),manager.getCreateTime()};
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 保存管理员与角色的关联关系
     * @param mgrId
     * @param roleId
     * @return
     */
    public int insertMgrAndRole(String mgrId,int roleId){
        int i = 0;
        try {
            String sql ="insert into tb_mgr_role(mgr_id,role_id) values(?,?)";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, mgrId, roleId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

9.12.3 添加管理员业务实现ManagerService

    public boolean saveManager(Manager manager, int roleId){
        // 1.对manager对象中的密码进行MD5加密处理(数据库中密码要保存密文)
        String s = MD5Utils.md5Encode(manager.getLoginPwd());
        manager.setLoginPwd(s);
        // 2.保存管理员信息
        int i = managerDAO.insertManager(manager);

        // 3.保存管理员和角色关联关系
        int i1 = managerDAO.insertMgrAndRole(manager.getMgrId(), roleId);
        return i > 0;
    }

9.12.4 功能流程代码实现

1. 当点击【添加管理员】按钮,在弹出的div层中显示管理员⻆色列表
在进入到admin_manager_list.jsp⻚面时,将⻆色列表渲染到隐藏的div中
在这里插入图片描述
2. 创建ManagerAddServlet
3. 在admin_manager_list.jsp⻚面点击弹窗中的【提交】按钮,将输入的管理员信息提交到ManagerAddServlet
在这里插入图片描述
修改表单的输入框的name属性:
  <!--添加管理员-->
  <div id="add_administrator_style" class="add_menber" style="display:none">
    <form action="ManagerAddServlet" method="post" id="form-admin-add">
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>编号:</label>
        <div class="formControls">
          <input type="text" class="input-text" value=""  name="mgrId" datatype="*2-10" nullmsg="编号不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>


      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>登录名:</label>
        <div class="formControls">
          <input type="text" class="input-text" value="" placeholder="" id="login-name" name="loginName" datatype="*2-16" nullmsg="用户名不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>初始密码:</label>
        <div class="formControls">
          <input type="password" placeholder="密码" name="loginPwd" autocomplete="off" value="" class="input-text" datatype="*6-20" nullmsg="密码不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>确认密码:</label>
        <div class="formControls ">
          <input type="password" placeholder="确认新密码" autocomplete="off" class="input-text Validform_error" errormsg="您两次输入的新密码不一致!" datatype="*" nullmsg="请再输入一次新密码!" recheck="loginPwd" id="loginPwd2" name="loginPwd2">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>姓名:</label>
        <div class="formControls">
          <input type="text" class="input-text"  name="mgrName" datatype="*2-10" nullmsg="姓名不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>

      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>性别:</label>
        <div class="formControls  skin-minimal">
          <label><input name="mgrGender" type="radio" class="ace" checked value=""><span class="lbl"></span></label>&nbsp;&nbsp;
          <label><input name="mgrGender" type="radio" class="ace" value=""><span class="lbl"></span></label>
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>手机:</label>
        <div class="formControls ">
          <input type="text" class="input-text" placeholder="" name="mgrTel" datatype="m" nullmsg="手机不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>邮箱:</label>
        <div class="formControls ">
          <input type="text" class="input-text" placeholder="@" name="mgrEmail" datatype="e" nullmsg="请输入邮箱!">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label">角色:</label>
        <div class="formControls "> <span class="select-box" style="width:150px;">
				<select class="select" name="roleId" size="1">
                  <c:forEach items="${roleList}" var="role">
					<option value="${role.roleId}">${role.roleName}</option>
                  </c:forEach>
				</select>
				</span> </div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>QQ:</label>
        <div class="formControls">
          <input type="text" class="input-text" name="mgrQQ" datatype="*6-10" nullmsg="QQ不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>

      <div>
        <input class="btn btn-primary radius" type="submit" id="Add_Administrator" value="&nbsp;&nbsp;提交&nbsp;&nbsp;">
      </div>
    </form>
  </div>
4. 在ManagerAddServlet类中,接收管理员信息并保存,查询管理员列表、⻆色列表返回到admin_manager_list.jsp⻚面
@WebServlet(name = "ManagerAddServlet", value = "/ManagerAddServlet")
public class ManagerAddServlet extends HttpServlet {
    private ManagerService managerService = new ManagerService();
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 接收输入的管理员信息,选择的角色ID
        request.setCharacterEncoding("utf-8");
        String mgrId = request.getParameter("mgrId");
        String loginName = request.getParameter("loginName");
        String loginPwd = request.getParameter("loginPwd");
        String mgrName = request.getParameter("mgrName");
        String mgrGender = request.getParameter("mgrGender");
        String mgrTel = request.getParameter("mgrTel");
        String mgrEmail = request.getParameter("mgrEmail");
        String mgrQQ = request.getParameter("mgrQQ");
        String roleId = request.getParameter("roleId");
        Manager manager = new Manager(mgrId, loginName, loginPwd, mgrName, mgrGender, mgrTel, mgrEmail, mgrQQ, new Date());

        // 2. 调用ManagerService 保存管理员信息
        int id = roleId == null ? 0 : Integer.parseInt(roleId);
        boolean b = managerService.saveManager(manager, id);

        // 3. 返回到列表页面
        String tips = b?"<label style='color:green'>管理员添加成功!</label>"
                :"<label style='color:red'>管理员添加失败!</label>";
        // 当再次回到admin_manager_list.jsp页面时,依然需要管理员列表和角色列表

        List<Manager> managerList = managerService.listManagers();
        List<Role> roleList = roleService.getRoles();

        request.setAttribute("tips",tips);
        request.setAttribute("managerList",managerList);
        request.setAttribute("roleList",roleList);
        request.getRequestDispatcher("admin_manager_list.jsp").forward(request,response);
    }
}
5. 回到admin_manager_list.jsp⻚面之后显示提示信息
在这里插入图片描述

9.13 管理员信息管理—删除管理员

9.13.1 删除管理员的实现流程设
在这里插入图片描述
9.13.2 删除管理员数据库操作实现
  • 从tb_mgr_role表中,根据管理员id删除这个管理员与⻆色关联
  • 从tb_managers表中,根据管理员ID删除管理员信息

ManagerDAO类中定义方法实现这个操作

    /**
     * 根据管理员Id删除管理员与角色的关联关系
     * @param mgrId
     * @return
     */
    public int deleteManagerAndRole(String mgrId){
        int i = 0;
        try {
            String sql = "delete from tb_mgr_role where mgr_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, mgrId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 根据管理员Id删除管理员信息
     * @param mgrId
     * @return
     */
    public int deleteManagerById(String mgrId){
        int i = 0;
        try {
            String sql = "delete from tb_managers where mgr_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, mgrId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
9.13.3 删除管理员业务逻辑实现 ManagerService类:
    /**
     * 删除管理员
     * @param mgrId
     * @return
     */
    public boolean deleteManager(String mgrId){
        // 1.删除管理员与角色的关联关系
        int i = managerDAO.deleteManagerAndRole(mgrId);
        // 2.删除管理员信息
        int j = managerDAO.deleteManagerById(mgrId);
        return j > 0;
    }
9.13.4 删除管理员功能流程实现
1. 创建 ManagerDeleteServlet
2. 在amdin_manager_list.jsp点击删除之后通过ajax请求ManagerDeleteServlet
在这里插入图片描述
在这里插入图片描述
3. 在ManagerDeleteServlet类接收id—执行删除—响应结果
@WebServlet(name = "ManagerDeleteServlet", value = "/ManagerDeleteServlet")
public class ManagerDeleteServlet extends HttpServlet {
    private ManagerService managerService = new ManagerService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收管理员ID
        String mgrId = request.getParameter("mgrId");
        // 2.执行删除
        boolean b = managerService.deleteManager(mgrId);
        // 3. 响应ajax请求(响应Json格式)
        String jsonStr = b?"{\"code\":1000,\"msg\":\"success\"}":"{\"code\":1001,\"msg\":\"fail\"}";
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}

9.14 管理员信息管理—修改管理员

①: 修改管理员实现流程设计

在这里插入图片描述

②:修改管理员数据库操作实现

1.根据管理员ID查询管理员信息
2.根据管理员ID修改管理员信息
    /**
     * 根据管理员id查询管理员信息
     * @param mgrId
     * @return
     */
    public Manager selectManagerById(String mgrId){
        Manager manager = null;
        try {
            String sql = "SELECT mgr_id mgrId,login_name loginName,login_pwd loginPwd,mgr_name mgrName,mgr_gender mgrGender,mgr_tel mgrTel,mgr_email mgrEmail,mgr_qq mgrQQ,create_time createTime FROM tb_managers where mgr_id = ?";
            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            manager = queryRunner.query(sql, new BeanHandler<Manager>(Manager.class), mgrId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return manager;
    }

    /**
     * 根据管理员的Id修改管理员信息
     *
     * @param manager
     * @return
     */
    public int updateManager(Manager manager){
        int i = 0;
        try {
            String sql = "update tb_managers set login_name = ?,login_pwd = ?,mgr_name = ?,mgr_gender = ?,mgr_tel = ?,mgr_email = ?,mgr_qq = ?  where mgr_id = ?";
            Object[] params = {manager.getLoginName(),manager.getLoginPwd(),manager.getMgrName(),manager.getMgrGender(),manager.getMgrTel(),manager.getMgrEmail(),manager.getMgrQQ(),manager.getMgrId()};

            QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

③: 修改管理员业务逻辑实现

ManagerService
    /**
     * 根据管理员Id查询管理员信息
     * @param mgrId
     * @return
     */
    public Manager getManagerById(String mgrId){
        Manager manager = managerDAO.selectManagerById(mgrId);
        return manager;
    }

    /**
     * 修改管理员信息
     * @param manager
     * @param roelId
     * @return
     */
    public boolean updateManager(Manager manager, int roelId){
        // 1. 修改管理员密码(如果没有修改密码,则密码为加密状态;如果修改了密码,则,密码为明文)
        // a.如果在修改页面没有输入密码,则认为不修改密码
        // b.如果在修改页面输入流密码,则表示需要将密码修改到数据库
        if (manager.getLoginPwd() == null || "".equals(manager.getLoginPwd())){
            // 将此管理员的原始密码设置到manager中
            Manager oldManager = managerDAO.selectManagerById(manager.getMgrId());
            manager.setLoginPwd(oldManager.getLoginPwd());
        }else {
            // 如果在修改页面输入了密码,则对新密码进行加密
            String s = MD5Utils.md5Encode(manager.getLoginPwd());
            manager.setLoginPwd(s);
        }
        // 2.执行修改管理员
        int i = managerDAO.updateManager(manager);
        // 3.修改管理员角色
        if (i > 0){
            // a.删除当前管理员的原始角色关系关系 
            int i1 = managerDAO.deleteManagerAndRole(manager.getMgrId());
            // b.添加新的管理员与角色的关联关系
            int i2 = managerDAO.insertMgrAndRole(manager.getMgrId(), roelId);
        }
        return i > 0;
    }

④: 修改管理员功能流程实现

1. 创建当前业务流程实现所需的ManagerQueryServletManagerUpdateServlet
2. 在admin_manager_list.jsp⻚面点击【编辑】按钮,触发JS执行,弹出修改弹窗:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3. 同时发送ajax请求ManagerQueryServlet查询当前管理的原始信息,并显示到修改弹窗中:
在这里插入图片描述
  <!--修改管理员-->
  <div id="update_administrator_style" class="add_menber" style="display:none; padding: 20px 10px" >
    <form action="ManagerAddServlet" method="post" id="form-admin-update">
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>编号:</label>
        <div class="formControls">
        <input type="text" class="input-text mgrId" disabled> 
          <input type="hidden" name="mgrId" class="mgrId">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>登录名:</label>
        <div class="formControls">
          <input type="text" class="input-text" value=""id="loginName"  name="loginName" datatype="*2-16" nullmsg="用户名不能为空">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>初始密码:</label>
        <div class="formControls">
          <input type="password" placeholder="若无需修改,密码置空即可" name="loginPwd"  class="input-text">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>确认密码:</label>
        <div class="formControls ">
          <input type="password" placeholder="确认新密码" autocomplete="off" class="input-text Validform_error" name="loginPwd2">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>姓名:</label>
        <div class="formControls">
          <input type="text" class="input-text"  name="mgrName" id="mgrName">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>性别:</label>
        <div class="formControls  skin-minimal">
          <label><input name="mgrGender"  type="radio" id="radio1" class="ace" value=""><span class="lbl"></span></label>&nbsp;&nbsp;
          <label><input name="mgrGender" type="radio" id="radio2" class="ace" value=""><span class="lbl"></span></label>
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label "><span class="c-red">*</span>手机:</label>
        <div class="formControls ">
          <input type="text" class="input-text" placeholder="" name="mgrTel" id="mgrTel">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>邮箱:</label>
        <div class="formControls ">
          <input type="text" class="input-text" placeholder="@" name="mgrEmail" id="mgrEmail">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div class="form-group">
        <label class="form-label">角色:</label>
        <div class="formControls "> <span class="select-box" style="width:150px;">
				<select class="select" name="roleId" size="1">
                  <c:forEach items="${roleList}" var="role">
                    <option value="${role.roleId}">${role.roleName}</option>
                  </c:forEach>
				</select>
				</span> </div>
      </div>
      <div class="form-group">
        <label class="form-label"><span class="c-red">*</span>QQ:</label>
        <div class="formControls">
          <input type="text" class="input-text" name="mgrQQ" id="mgrQQ">
        </div>
        <div class="col-4"> <span class="Validform_checktip"></span></div>
      </div>
      <div>
        <input class="btn btn-primary radius" type="submit" id="update_Administrator" value="&nbsp;&nbsp;提交&nbsp;&nbsp;">
      </div>
    </form>
  </div>
4. 在ManagerQueryServlet查询管理员的原始信息并响应
@WebServlet(name = "ManagerQueryServlet", value = "/ManagerQueryServlet")
public class ManagerQueryServlet extends HttpServlet {
    private ManagerService managerService = new ManagerService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.获取管理员id
        String managerId = request.getParameter("managerId");
        // 2.根据id获取管理员信息
        Manager manager = managerService.getManagerById(managerId);
        String jsonStr = new Gson().toJson(manager);
        // 3.响应ajax请求
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
5. 当在修改管理员信息的弹窗中,点击【提交】按钮,将修改后的信息提交到ManagerUpdateServlet
在这里插入图片描述
6. 在ManagerUpdateServlet类中接收并修改管理员信息
@WebServlet(name = "ManagerUpdateServlet", value = "/ManagerUpdateServlet")
public class ManagerUpdateServlet extends HttpServlet {
    private ManagerService managerService = new ManagerService();
    private RoleService roleService = new RoleService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 接收修改后的管理员信息,选择的角色ID
        request.setCharacterEncoding("utf-8");
        String mgrId = request.getParameter("mgrId");
        String loginName = request.getParameter("loginName");
        String loginPwd = request.getParameter("loginPwd");
        String mgrName = request.getParameter("mgrName");
        String mgrGender = request.getParameter("mgrGender");
        String mgrTel = request.getParameter("mgrTel");
        String mgrEmail = request.getParameter("mgrEmail");
        String mgrQQ = request.getParameter("mgrQQ");
        String roleId = request.getParameter("roleId");
        Manager manager = new Manager(mgrId, loginName, loginPwd, mgrName, mgrGender, mgrTel, mgrEmail, mgrQQ, new Date());

        System.out.println("manager = " + manager);
        // 2.接收选择的角色ID
        int id = roleId == null ? 0 : Integer.parseInt(roleId);
        // 3.执行修改
        boolean b = managerService.updateManager(manager, id);

        String tips = b?"<label style='color:green'>管理员修改成功!</label>"
                :"<label style='color:red'>管理员修改失败!</label>";
        // 4.再次回到admin_manager_list.jsp页面时,依然需要管理员列表和角色列表
        List<Manager> managerList = managerService.listManagers();
        List<Role> roleList = roleService.getRoles();

        request.setAttribute("tips",tips);
        request.setAttribute("managerList",managerList);
        request.setAttribute("roleList",roleList);
        request.getRequestDispatcher("admin_manager_list.jsp").forward(request,response);
    }

十、分类管理、品牌管理

10.1 分类管理

对用户在用户系统中访问的一级分类信息进行管理

①: 实现流程分析

在这里插入图片描述

②: 数据库操作实现

  • 查询所有的分类信息列表

  • 根据分类ID删除一个分类:思考,如果在分类下存在品牌信息,分类信息不能删除

    • 根据分类ID查询分类下的品牌信息
  • 根据分类ID查询分类信息

  • 根据分类ID修改分类信息

  • 添加分类信息

涉及到的数据表:tb_category

1.创建实体类
/**
 * 分类信息实体类
 */
public class Category {
    private int categoryId;
    private String catetoryName;
    private String catetoryIcon;
    private String catetoryStatus;
    // 构造器  set get
}
/**
 * 品牌信息实体类
 */
public class Brand {
    private int brandId;
    private String brandName;
    private String brandLogo;
    private String brandDesc;
    private Date createTime;
    private int brandStatus;
// 构造器  set get
}
2.数据库操作实现
  • 分类数据操作
public class CategoryDAO {
    private QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

    /**
     * 查询所有的分类信息列表
     * @return
     */
    public List<Category> selectCategories(){
        List<Category> categoryList = null;
        try {
            String sql = "SELECT category_id categoryId,category_name categoryName,category_icon categoryIcon,category_status categoryStatus FROM tb_category";
            categoryList = queryRunner.query(sql, new BeanListHandler<Category>(Category.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return categoryList;
    }

    /**
     * 根据Id删除一个分类
     * @param categoryId
     * @return
     */
    public int deleteCategoryById(int categoryId){
        int i = 0;
        try {
            String sql = "delete from tb_category where category_id = ?";
            i = queryRunner.update(sql, categoryId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 根据分类Id查询分类信息
     * @param categoryId
     * @return
     */
    public Category selectCategoryById(int categoryId){
        Category category = null;
        try {
            String sql = "SELECT category_id categoryId,category_name categoryName,category_icon categoryIcon,category_status categoryStatus FROM tb_category where category_id = ?";
            category = queryRunner.query(sql, new BeanHandler<Category>(Category.class), categoryId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return category;
    }

    /**
     * 根据Id修改分类信息
     * @param category (对于分类的状态,通过启用/停用来实现)
     * @return
     */
    public int updateCategory(Category category){
        int i = 0;
        try {
            String sql = "UPDATE tb_category SET category_name = ?,category_icon = ?, category_status = ? WHERE category_id = ?";
            Object[] params = {category.getCategoryName(),category.getCategoryIcon(), category.getCategoryStatus(),category.getCategoryId()};
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;

    }

    /**
     * 添加分类信息
     * @param category
     * @return
     */
    public int addCategory(Category category){
        int i = 0;
        try {
            String sql = "INSERT INTO tb_category(category_name ,category_icon ,category_status) VALUES(?,?,1)";
            Object[] params = {category.getCategoryName(),category.getCategoryIcon()};
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
}
  • 品牌信息操作
/**
 * 对品牌数据库的操作
 */
public class BrandDAO {
    private QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

    /**
     * 根据分类Id查询品牌列表
     * @param categoryId
     * @return
     */
    public List<Brand> selectBrandByCategoryId(int categoryId){
        List<Brand> brandList = null;
        try {
            String sql = "SELECT b.brand_id brandId,b.brand_name brandName,b.brand_logo brandLogo,b.brand_desc brandDesc,b.create_time createTime,b.brand_status brandStatus FROM tb_category_brand cb INNER JOIN tb_brand b ON cb.fk_brand_id = b.brand_id WHERE cb.fk_category_id = ?";
            brandList = queryRunner.query(sql, new BeanListHandler<Brand>(Brand.class), categoryId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return brandList;
    }
}

③: 业务逻辑代码实现

1. 创建CategoryService类
public class CategoryService {
    private CategoryDAO categoryDAO = new CategoryDAO();
    private BrandDAO brandDAO = new BrandDAO();

    /**
     * 查询分类列表
     * @return
     */
    public List<Category> lsitCatetories(){
        List<Category> categories = categoryDAO.selectCategories();
        return categories;
    }

    /**
     * 删除分类逻辑
     * @param categoryId
     * @return
     */
    public boolean deleteCategory(int categoryId){
        // 当执行一个分类信息删除操作时,需要先检查这个分类中时否存在品牌,如果存在品牌,则不能删除
        // 根据分类ID查询 品牌信息列表,如果列表为空,则执行删除
        List<Brand> brandList = brandDAO.selectBrandByCategoryId(categoryId);
        if (brandList.size() > 0){
            return false;
        }else {
            int i = categoryDAO.deleteCategoryById(categoryId);
            if (i > 0){
                return true;
            }else {
                return false;
            }
        }
    }

    /**
     * 根据Id查询一个分类信息
     * @param categoryId
     * @return
     */
    public Category getCategoryById(int categoryId){
        return categoryDAO.selectCategoryById(categoryId);
    }

    /**
     * 修改类别信息
     * @param category
     * @return
     */
    public boolean updateCategory(Category category){
        int i = categoryDAO.updateCategory(category);
        return i > 0;
    }

    /**
     * 添加类别信息
     * @param category
     * @return
     */
    public boolean saveCategory(Category category){
        int i = categoryDAO.addCategory(category);
        return i > 0;
    }
}
4.修改完成之后跳转到管理员列表⻚面(需要重新查询管理员列表和⻆色列表

④: 分类列表功能实现

1. 创建CategoryListServlet
2. 点击【分类管理】菜单跳转到CategoryListServlet类 (修改数据表)
在这里插入图片描述
3. 在CategoryListServlet类查询分类列表,并传递到category_list.jsp
/**
 * 分类列表
 */
@WebServlet(name = "CategoryListServlet", value = "/CategoryListServlet")
public class CategoryListServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询分类列表
        List<Category> categoryList = categoryService.lsitCatetories();
        // 2.将分类列表传递到 category_list.jsp
        request.setAttribute("categoryList",categoryList);
        request.getRequestDispatcher("category_list.jsp").forward(request,response);
    }
}

4. 将category_list.html文件转换成category_list.jsp文件
5. 在category_list.jsp文件使用JSTL+EL显示分类列表
在这里插入图片描述

⑤: 添加分类功能实现

1. 将category_add.html文件转换成category_add.jsp文件
2. 在category_list.jsp文件⻚面点击【添加分类】按钮跳转到category_add.jsp文件
在这里插入图片描述
3. 创建CategoryAddServlet
4. 在category_add.jsp通过表单提交分类信息到CategoryAddServlet
在这里插入图片描述
5. 在CategoryAddServlet类接收并保存分类信息(注意:图片上传)
  1. CategoryAddServlet类添加@MultipartConfig注解

  2. 在项目中的web目录下创建一个用于存放分类图片的文件夹categoryImages

     在此文件夹下创建一个文件
    
  3. 保存到数据库分类信息中的图片是图片保存之后的访问路径

@WebServlet(name = "CategoryAddServlet", value = "/CategoryAddServlet")
@MultipartConfig
public class CategoryAddServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收分类名称
        request.setCharacterEncoding("utf-8");
        String categoryName = request.getParameter("categoryName");
        // 2.接收分类图片
        Part part = request.getPart("categoryIcon");
        // 保存分类图片信息
        // a.给图片重命名
        String header = part.getHeader("Content-Disposition");
        int index1 = header.lastIndexOf(".");
        int index2 = header.lastIndexOf("\"");
        String ext = header.substring(index1, index2);
        String iconName = UUID.randomUUID().toString().replace("-", "") + ext;
        // b.获取categoryImages目录的路径(部署到服务器之后的路径)
        String dir = getServletContext().getRealPath("/categoryImages");
        // c.存储图片
        part.write(dir + "/" + iconName);
        // 3.将分类信息保存到数据库
        Category category = new Category(0, categoryName, "categoryImages/" + iconName, 1);
        boolean b = categoryService.saveCategory(category);

        // 4.当保存完成之后,跳转到category_list.jsp页面,要显示分类的列表信息
        String tips = b? "<label style='color:green'>添加分类成功!</label>":"<label style='color:red'>添加分类失败!</label>";
        List<Category> categoryList = categoryService.lsitCatetories();

        request.setAttribute("tips",tips);
        request.setAttribute("categoryList",categoryList);
        request.getRequestDispatcher("category_list.jsp").forward(request,response);
    }
}
  1. category_list.jsp显示添加之后的提示信息
category_list.jsp
在这里插入图片描述

⑥: 删除分类功能实现

1. 创建CategoryDeleteServlet
2. 在category_list.jsp中点击【删除】按钮,触发JS操作,发送ajax请求到CategoryDeleteServlet
在这里插入图片描述
在这里插入图片描述
3. 创建响应ajaxvo类:ResultVO
public class ResultVO {
    private int code;
    private String msg;
    // 无参 有参 get set 
}
4. 在CategoryDeleteServlet类接收要删除的分类ID,执行删除并响应ajax请求删除操作结果
@WebServlet(name = "CategoryDeleteServlet", value = "/CategoryDeleteServlet")
public class CategoryDeleteServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 接收ajax请求发送过来的要删除的分类的ID
        int categoryId = Integer.parseInt(request.getParameter("cid"));
        // 2.执行删除(分类下没有品牌信息才会被成功删除)
        boolean b = categoryService.deleteCategory(categoryId);
        // 3. 返回结果(响应ajax请求)
        ResultVO resultVO = b ? new ResultVO(1000,"success") : new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(resultVO);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}

10.1.7 修改分类功能实现

1. 创建CategoryQueryServlet
2. 在category_list.jsp点击【修改】按钮,将要修改的分类的ID传递到CategoryQueryServlet
在这里插入图片描述
3. 在CategoryQueryServlet类中接收分类ID并查询分类信息传递到修改⻚面
@WebServlet(name = "CategoryQueryServlet", value = "/CategoryQueryServlet")
public class CategoryQueryServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收点击【修改】之后传递过来的分类ID
        int categoryId = Integer.parseInt(request.getParameter("cid"));

        // 2.调用CategoryService中的方法,根据id查询分类的信息
        Category category = categoryService.getCategoryById(categoryId);
        // 3.将查询的分类信息传递到修改页面category_modify.jsp,显示出来
        request.setAttribute("category",category);
        request.getRequestDispatcher("category_modify.jsp").forward(request,response);
    }
}
4. 创建category_modify.jsp⻚面,接收并显示分类的原始信息,进行修改之后点击【提 交保存】,将修改后的信息提交到CategoryUpdateServlet
在这里插入图片描述
5. 创建CategoryUpdateServlet类,接收修改后的分类信息,并执行修改
@WebServlet(name = "CategoryUpdateServlet", value = "/CategoryUpdateServlet")
@MultipartConfig
public class CategoryUpdateServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        request.setCharacterEncoding("utf-8");
        // 1.接收修改页面提交的修改后的分类信息
        int categoryId = Integer.parseInt(request.getParameter("categoryId"));
        String categoryName = request.getParameter("categoryName");
        String categoryStatus = request.getParameter("status");
        // 2.分类的图片西悉尼
        String categoryIcon = request.getParameter("oldCategoryIcon");
        // 接收修改后的图片信息
        Part part = request.getPart("categoryIcon");
        if (part.getSize() > 0){
            // 如果part.size的值为0,表示没有提交新的图片,则分类信息依然使用“oldCategoryIcon”
            // 保存新图片
            // a.给图片重新命名
            String header = part.getHeader("content-Disposition");
            int index = header.lastIndexOf(".");
            int index1 = header.lastIndexOf("\"");
            String ext = header.substring(index, index1);
            String iconName = UUID.randomUUID().toString().replace("-", "") + ext;
            // b.获取categoryImages目录的路径(部署到服务器之后的路径)
            String dir = getServletContext().getRealPath("/categoryImages");
            // 存储图片
            part.write(dir + "/" + iconName);
            categoryIcon = "categoryImages/" + iconName;
        }
        // 3.修改到数据库
        Category category = new Category(categoryId, categoryName, categoryIcon, categoryStatus);
        boolean b = categoryService.updateCategory(category);
        // 4.修改成功后回到,跳转到category_list.jsp页面,要显示分类的列表信息
        String tips = b? "<label style='color:green'>修改分类成功!</label>":"<label style='color:red'>修改分类失败!</label>";
        List<Category> categoryList = categoryService.lsitCatetories();
        request.setAttribute("tips",tips);
        request.setAttribute("categoryList",categoryList);
        request.getRequestDispatcher("category_list.jsp").forward(request,response);
    }
}

10.2 品牌管理

①: 品牌列表

1.实现流程设计
在这里插入图片描述
2.数据库操作实现
  • 查询分类列表[已完成]

  • 根据分类ID查询分类下的品牌列表[已完成]

3.业务实现 创建BrandService
public class BrandService {
    private BrandDAO brandDAO = new BrandDAO();

    /**
     * 根据分类Id查询当前分类下的品牌信息
     * @param categoryId
     * @return
     */
    public List<Brand> listBrandByCategoryId(int categoryId){
        List<Brand> brandList = brandDAO.selectBrandByCategoryId(categoryId);
        return brandList;
    }
}
4.功能实现
  1. 创建BrandListServlet

  2. 点击【品牌管理】菜单,跳转到BrandListServlet
    在这里插入图片描述

  3. BrandListServlet类,接收分类ID,查询分类、品牌列表传递到brand_list.jsp

@WebServlet(name = "BrandListServlet", value = "/BrandListServlet")
public class BrandListServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    private BrandService brandService = new BrandService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收分类Id
        String categoryId = request.getParameter("categoryId");
        // 2.查询所有的分类列表
        List<Category> categoryList = categoryService.lsitCatetories();
        // 3.根据分类ID,查询当前分类下的品牌信息,如果categoryId==null,则默认查询分类列表中第一个分类下的品牌
        int cid = categoryId==null? categoryList.get(0).getCategoryId():Integer.parseInt(categoryId);
        List<Brand> brandList = brandService.listBrandByCategoryId(cid);
        // 4. 将分类列表、当前显示的分类Id、分类ID喜爱的品牌列表传递到brand_list.jsp
        request.setAttribute("categoryList",categoryList);
        request.setAttribute("cid",cid);
        request.setAttribute("brandList",brandList);
        request.getRequestDispatcher("brand_list.jsp").forward(request,response);
    }
}
  1. brand_manage.html转换成brand_list.jsp,并在brand_list.jsp通过JSTL+EL显示
brand_list.jsp
在这里插入图片描述
在这里插入图片描述

10.2.2 添加品牌

①:实现流程设计

在这里插入图片描述

②:数据库操作实现
1.添加品牌信息(tb_brand) ,将tb_brand表中create_time列的数据类型由datetime修改为timestamp
保存品牌与分类的关系(tb_category_brand)
BrandDAO中完成以下两个操作
    /**
     * 保存品牌信息
     * @param brand
     * @return
     */
    public int insertBrand(Brand brand){
        int i = 0;
        try {
            String sql = "INSERT INTO tb_brand(brand_name,brand_logo,brand_desc,create_time,brand_status) VALUES(?,?,?,?,?)";
            Object[] parms = {brand.getBrandName(),brand.getBrandLogo(),brand.getBrandDesc(),brand.getCreateTime(),brand.getBrandStatus()};
            BigInteger insert = queryRunner.insert(sql, new ScalarHandler<>(), parms);
            i = insert.intValue();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 保存分类与品牌的关联关系
     * @param cid
     * @param bid
     * @return
     */
    public int insertCategoryAndBrand(int cid,int bid){
        int i = 0;
        try {
            String sql = "INSERT INTO tb_category_brand(fk_category_id,fk_brand_id) VALUES(?,?)";
            i = queryRunner.update(sql, cid, bid);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
③:业务实现
BrandService
    /**
     * 保存品牌信息
     * @param brand
     * @param categoryId
     * @return
     */
    public boolean addBrand(Brand brand,int categoryId){
        // 保存品牌信息,获取生成的品牌ID
        int brandId = brandDAO.insertBrand(brand);
        // 保存品牌与分类之间的关联关系
        int i = brandDAO.insertCategoryAndBrand(categoryId, brandId);
        // 返回执行结果
        return i > 0;
    }
④:显示一级分类功能实现
1. 创建CategoryLoadServlet
2. 在brand_list.jsp点击【添加品牌】按钮,跳转到CategoryLoadServlet
在这里插入图片描述
3. CategoryLoadServlet类查询分类列表,传递到brand_add.jsp
@WebServlet(name = "CategoryLoadServlet", value = "/CategoryLoadServlet")
public class CategoryLoadServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        List<Category> categoryList = categoryService.lsitCatetories();
        request.setAttribute("categoryList",categoryList);
        request.getRequestDispatcher("brand_add.jsp").forward(request,response);
    }
}
4. 将brand_list.html转换成brand_add.jsp
5. 在brand_add.jsp中显示一级分类下拉菜单
在这里插入图片描述
⑤:文件异步上传功能实现

在输入品牌信息的过程中,当选择图片时触发JS通过ajax请求实现文件上传

1. 创建ImageUploadServlet
2. 在brand_add.jsp中为图片上传控件添加监听事件,当选择文件就触发ajax请求,将文 件上传到ImageUploadServlet
在这里插入图片描述
3. ImageUploadServlet类接收并保存图片,将图片的路径返回给ajax
@WebServlet(name = "ImageUploadServlet", value = "/ImageUploadServlet")
@MultipartConfig
public class ImageUploadServlet extends HttpServlet {
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 接收并保存文件
        request.setCharacterEncoding("utf-8");
        Part part = request.getPart("brandLogoImg");
        String header = part.getHeader("Content-Disposition");
        int index1 = header.lastIndexOf(".");
        int index2 = header.lastIndexOf("\"");
        String ext = header.substring(index1, index2);
        String imagName = UUID.randomUUID().toString().replace("-", "") + ext;
        String dir = getServletContext().getRealPath("/upload");
        part.write(dir + "/" + imagName);

        // 返回文件的访问路径
        String path = "upload/" + imagName;
        ResultVO resultVO = new ResultVO(1000, path);
        String jsonStr = new Gson().toJson(resultVO);
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
⑥:保存品牌信息功能实现
1. 创建BrandAddServlet
2. 在brand_add.jsp点击【保存】,通过form表单提交数据到BrandAddServlet
将上传成功的图片路径设置到隐藏输入框中
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3. BrandAddServlet类接收并保存品牌信息,然后查询分类列表、品牌列表和提示信息 一起传递到brand_list.jsp⻚面
@WebServlet(name = "BrandAddServlet", value = "/BrandAddServlet")
public class BrandAddServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收品牌信息
        String brandName = request.getParameter("brandName");
        String brandLogoPath = request.getParameter("brandLogoPath");
        String brandDesc = request.getParameter("brandDesc");
        int brandStatus = Integer.parseInt(request.getParameter("brandStatus"));
        Brand brand = new Brand(0, brandName, brandLogoPath, brandDesc, new Date(), brandStatus);
        // 2.接收选择的分类Id
        int categoryId = Integer.parseInt(request.getParameter("categoryId"));
        // 3.执行保存
        boolean b = brandService.addBrand(brand, categoryId);
        String tips = b?"<label style='color:green'>品牌添加成功!</label>":
                "<label style='color:red'>品牌添加失败!</label>";
        // 4.跳转到brand_list.jsp
        List<Category> categoryList = categoryService.lsitCatetories();
        int cid = categoryList.get(0).getCategoryId();
        List<Brand> brandList = brandService.listBrandByCategoryId(cid);

        request.setAttribute("tips",tips);
        request.setAttribute("categoryList",categoryList);
        request.setAttribute("cid",cid);
        request.setAttribute("brandList",brandList);
        request.getRequestDispatcher("brand_list.jsp").forward(request,response);
    }
}
4. 在brand_list.jsp显示提示信息
在这里插入图片描述

10.2.3 修改品牌

修改品牌过程中不做分类的修改

①:实现流程设计

在这里插入图片描述

②:数据库操作实现
  1. 根据品牌ID查询品牌信息

  2. 根据品牌ID修改品牌信息

3.BrandDAO新增一下两个方法
    /**
     * 根据Id查询品牌信息
     * @param brandId
     * @return
     */
    public Brand selectBrandByBrandId(int brandId){
        Brand brand = null;
        try {
            String sql = "SELECT brand_id brandId,brand_name brandName,brand_logo brandLogo,brand_desc brandDesc,create_time createTime,brand_status brandStatus FROM tb_brand WHERE brand_id = ?";
            brand = queryRunner.query(sql, new BeanHandler<Brand>(Brand.class), brandId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return brand;
    }

    /**
     * 修改品牌信息
     * @param brand
     * @return
     */
    public int updateBrand(Brand brand){
        int i = 0;
        try {
            String sql = "update tb_brand set brand_name=?,brand_logo=?,brand_desc=?,create_time=?,brand_status=? where brand_id = ?";
            Object[] params = {brand.getBrandName(),brand.getBrandLogo(),brand.getBrandDesc(),brand.getCreateTime(),brand.getBrandStatus(),brand.getBrandId()};
            i = queryRunner.update(sql, params);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;

    }
③:业务处理实现
BrandService中新增以下两个方法
    /**
     * 根据品牌Id查询品牌信息
     * @param brandId
     * @return
     */
    public Brand getBrandById(int brandId){
        Brand brand = brandDAO.selectBrandByBrandId(brandId);
        return brand;
    }

    /**
     * 修改品牌信息(此处不允许修改当前品牌的分类)
     * @param brand
     * @return
     */
    public boolean updateBrand(Brand brand){
        int i = brandDAO.updateBrand(brand);
        return i>0;
    }
④:功能流程实现
1. 创建BrandQueryServlet
2. 点击brand_list.jsp⻚面中的【编辑】按钮,跳转到BrandQueryServlet类,并将要修改的品牌ID传递
在这里插入图片描述
3. 在BrandQueryServlet类中接收品牌ID、查询品牌信息并传递到brand_modify.jsp⻚面
@WebServlet(name = "BrandQueryServlet", value = "/BrandQueryServlet")
public class BrandQueryServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收品牌Id
        int brandId = Integer.parseInt(request.getParameter("brandId"));
        // 2.根据Id查询品牌信息(如果支持修改分类的话,也需要查询对应的分类列表)
        Brand brand = brandService.getBrandById(brandId);
        // 3.传递到修改的页面
        request.setAttribute("brand",brand);
        request.getRequestDispatcher("brand_modify.jsp").forward(request,response);

    }
}
4. 创建brand_modify.jsp⻚面(修改⻚面和添加⻚面高度相似),显示品牌的原始信息
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
5. 创建BrandUpdateServlet
6. 在brand_modify.jsp中修改品牌信息并提交到BrandUpdateServlet
在这里插入图片描述
7. 在BrandUpdateServlet类中接收修改后的品牌信息并保存
@WebServlet(name = "BrandUpdateServlet", value = "/BrandUpdateServlet")
public class BrandUpdateServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收品牌信息
        request.setCharacterEncoding("utf-8");
        int brandId = Integer.parseInt(request.getParameter("brandId"));
        String brandName = request.getParameter("brandName");
        String brandLogoPath = request.getParameter("brandLogoPath");
        String brandDesc = request.getParameter("brandDesc");
        int brandStatus = Integer.parseInt(request.getParameter("brandStatus"));
        Brand brand = new Brand(brandId, brandName, brandLogoPath, brandDesc, new Date(), brandStatus);

        // 2.执行修改
        boolean b = brandService.updateBrand(brand);
        String tips = b?"<label style='color:green'>品牌修改加成功!</label>":
                "<label style='color:red'>品牌修改失败!</label>";
        // 4.跳转到brand_list.jsp
        // a.查询分类列表
        List<Category> categoryList = categoryService.lsitCatetories();
        // b.第一个分类ID
        int cid = categoryList.get(0).getCategoryId();
        // c.第一个分类ID下的品牌列表
        List<Brand> brandList = brandService.listBrandByCategoryId(cid);

        request.setAttribute("tips",tips);
        request.setAttribute("categoryList",categoryList);
        request.setAttribute("cid",cid);
        request.setAttribute("brandList",brandList);
        request.getRequestDispatcher("brand_list.jsp").forward(request,response);
    }
}

10.2.4 删除品牌

①:实现流程设计

在这里插入图片描述

②:数据库操作实现
  • 根据品牌ID查询当前品牌下的商品列表
  • 根据品牌ID删除品牌信息
1. 创建商品实体类Goods
public class Goods {
    
    private int goodsId;
    private String goodsName;
    private String goodsImg;
    private int goodsCost;
    private int goodsMinPrice;
    // get set ~
}
2. 创建GoodsDAO类,根据品牌ID查询商品列表
public class GoodsDAO {
    private QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

    /**
     * 根据品牌Id,查询此品牌下的商品信息
     * @param brandId
     * @return
     */
    public List<Goods> selectGoodsByBrandId(int brandId){
        List<Goods> goodsList = null;
        try {
            String sql = "SELECT good_id goodsId,good_name goodsName,good_img goodsImg,good_cost goodsCost,good_min_price goodsMinPrice FROM tb_good g JOIN tb_brand_good bg ON g.good_id = bg.fk_good_id WHERE fk_brand_id = ?";
            goodsList = queryRunner.query(sql, new BeanListHandler<Goods>(Goods.class), brandId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return goodsList;
    }
}
3. BrandDAO : 在BrandDAO中添加删除品牌操作

    /**
     * 删除品牌与分类的关联
     * @param brandId
     * @return
     */
    public int deleteCategoryAndBrand(int brandId){
        int i = 0;
        try {
            String sql = "delete from tb_category_brand where fk_brand_id = ?";
            i = queryRunner.update(sql, brandId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i ;
    }


    /**
     * 根据品牌Id删除品牌信息
     * @param brandId
     * @return
     */
    public int deleteBrand(int brandId){
        int i = 0;
        try {
            String sql = "delete from tb_brand where brand_id = ?";
            i = queryRunner.update(sql, brandId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
③:业务逻辑实现
BrandService中新增删除品牌的方法
    /**
     * 根据品牌ID删除品牌信息,需要保证这个品牌下没有商品信息方可删除
     * @param brandId
     * @return
     */
    public boolean deleteBrandById(int brandId){
        // 1. 根据当前品牌ID查询商品信息
        List<Goods> goodsList = goodsDAO.selectGoodsByBrandId(brandId);
        // 2.如果goodsList为空
        if (goodsList.size() == 0){
            // a.删除品牌和分类的关联关系
            int j = brandDAO.deleteCategoryAndBrand(brandId);
            // b.删除品牌信息
            if (j > 0){
                int i = brandDAO.deleteBrand(brandId);
                return i >0;
            }else {
                return false;
            }
        }else {
            return false;
        }
    }
④:功能流程实现
1. 创建BrandDeleteServlet
2. 在brand_list.jsp中点击【删除】,触发JS操作,并将品牌ID传递到JS方法
在这里插入图片描述
在这里插入图片描述
3. 在BrandDeleteServlet接收品牌ID并执行删除,返回删除结果
@WebServlet(name = "BrandDeleteServlet", value = "/BrandDeleteServlet")
public class BrandDeleteServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.获取brandId执行删除
        int brandId = Integer.parseInt(request.getParameter("brandId"));
        boolean b = brandService.deleteBrandById(brandId);
        // 2.响应ajax请求
        ResultVO resultVO = b? new ResultVO(1000,"success"):new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(resultVO);

        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}

十一、评估类目管理、评估选项管理

11.1 评估类目管理

  • 类目列表(✔)

  • 添加类目(✔)

  • 修改类目(自主)

  • 删除类目(自主)

①: 流程设计

在这里插入图片描述

②: 类目列表功能实现

1.数据库操作实现
1.创建评估类目实体类
/**
 * 评估类目信息实体类
 */
public class BasicInfo {
    private int basicInfoId;
    private String basicInfoName;
    private int basicInfoStatus;
    
}
2. 创建BasicInfoDAO实现数据库操作
3,查询所有类目信息
public class BasicInfoDAO {
    private QueryRunner queryRunner = new QueryRunner(DruidUtils.getDataSource());

    /**
     * 查询所有评估类目的列表
     * @return
     */
    public List<BasicInfo> selectBasicInfos(){
        List<BasicInfo> basicInfoList = null;
        try {
            String sql = "SELECT basic_info_id basicInfoId,basic_info_name basicInfoName,basic_info_status basicInfoStatus FROM tb_basic_info";
            basicInfoList = queryRunner.query(sql, new BeanListHandler<BasicInfo>(BasicInfo.class));
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return basicInfoList;

    }
}
2.业务逻辑实现
1.创建BasicInfoService
public class BasicInfoService {
    private BasicInfoDAO basicInfoDAO = new BasicInfoDAO();

    /**
     * 评估类目列表
     * @return
     */
    public List<BasicInfo> listBasicInfos(){
        return basicInfoDAO.selectBasicInfos();
    }
}
3.功能流程实现
1. 创建BasicInfoListServlet
2. 修改【评估管理-评估类目】的访问连接,跳转到BasicInfoListServlet
在这里插入图片描述
3. 在BasicInfoListServlet类查询类目信息,并传递到basic_info_list.jsp
@WebServlet(name = "BasicInfoListServlet", value = "/BasicInfoListServlet")
public class BasicInfoListServlet extends HttpServlet {
    private BasicInfoService basicInfoService = new BasicInfoService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询所有评估类目列表
        List<BasicInfo> basicInfoList = basicInfoService.listBasicInfos();

        // 2.将类目列表信息传递到basic_info_list.jsp
        request.setAttribute("basicInfoList",basicInfoList);
        request.getRequestDispatcher("basic_info_list.jsp").forward(request,response);
    }
}
4. 将basic_info_list.html文件修改为basic_info_list.jsp文件,并通过JSTL+EL显示类目信息列表
在这里插入图片描述

11.2.2 类目添加功能实现

①:数据库操作实现
BasicInfoDAO中新增添加类目数据库操作
    /**
     * 添加类目信息到数据库
     * @param basicInfo
     * @return
     */
    public int insertBasicInfo(BasicInfo basicInfo) {
        int i = 0;
        try {
            String sql = "insert into tb_basic_info(basic_info_name,basic_info_status) values(?,?)";
            i = queryRunner.update(sql, basicInfo.getBasicInfoName(), basicInfo.getBasicInfoStatus());
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
}
②:业务逻辑实现
BasicInfoService中新增如下业务实现:完成类目保存业务
    /**
     * 保存类目信息
     * @param basicInfo
     * @return
     */
    public boolean saveBasicInfo(BasicInfo basicInfo) {
        int i = basicInfoDAO.insertBasicInfo(basicInfo);
        return i>0;
    }
③:功能流程实现
1. 在basic_info_list.jsp中点击【添加新类目】按钮,在弹窗中输入类目名称,点击【提交】按钮,将表单提交到BasicInfoAddServlet
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
2. 创建BasicInfoAddServlet类,并在此类中接收类目名称,保存类目信息;之后查询类目列表重新跳转到basic_info_list.jsp
@WebServlet(name = "BasicInfoAddServlet", value = "/BasicInfoAddServlet")
public class BasicInfoAddServlet extends HttpServlet {
    private BasicInfoService basicInfoService = new BasicInfoService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.接收类目名称
        request.setCharacterEncoding("utf-8");
        String basicInfoName = request.getParameter("basicInfoName");
        BasicInfo basicInfo = new BasicInfo(0, basicInfoName, 1);

        // 2.保存类目信息
        boolean b = basicInfoService.saveBasicInfo(basicInfo);
        // 3.查询所有评估类目列表、跳转到basic_info_list.jsp
        // a.添加操作的提示信息
        String tips = b?"<label style='color:green>添加评估类目成功!</label>'":
                "<label style='color:red>添加评估类目失败!</label>'";
        request.setAttribute("tips",tips);
        // b.类目列表
        List<BasicInfo> basicInfoList = basicInfoService.listBasicInfos();
        request.setAttribute("basicInfoList",basicInfoList);
        // c.跳转
        request.getRequestDispatcher("basic_info_list.jsp").forward(request,response);
    }
}
3. 在basic_info_list.jsp显示添加操作的提示信息
在这里插入图片描述

11.2 评估选项管理

  • 评估选项列表(根据评估类目显示当前类目下的选项) ✔

  • 添加评估选项 ✔

  • 删除评估选项 (自主完成)

  • 修改评估选项 (自主完成)

11.2.1 评估选项列表功能实现

①:实现流程设计

在这里插入图片描述

②:数据库操作实现

根据类目ID查询评估选项( tb_info_detail )

1.创建评估选项实体类InfoDetail
public class InfoDetail {
    private int infoDetailId;
    private String infoDetailName;
    private String infoDetailDesc;
    // get set 
}
2. 创建InfoDetailDAO类完成数据库操作
/**
 * 关于评估选项的数据库操作
 */
public class InfoDetailDAO {
    private QueryRunner queryRunner = new QueryRunner();

    /**
     * 根据评估类目ID,查询此评估类目下的所有的评估选项
     * @param basicInfoId
     * @return
     */
    public List<InfoDetail> selectInfoDetailsByBasicInfo(int basicInfoId){
        List<InfoDetail> infoDetailList = null;
        try {
            String sql = "SELECT info_detail_id infoDetailId, info_detail_name infoDetailName, info_detail_desc infoDetailDesc FROM tb_info_detail WHERE fk_basic_info_id = ?";
            infoDetailList = queryRunner.query(sql, new BeanListHandler<InfoDetail>(InfoDetail.class), basicInfoId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return infoDetailList;
    }
}
③:业务逻辑实现
创建InfoDetailService
public class InfoDetailService {
    private InfoDetailDAO infoDetailDAO = new InfoDetailDAO();

    /**
     * 根据类目ID查询类目中的选项
     * @param basicInfo
     * @return
     */
    public List<InfoDetail> listInfoDetailByBasicInfo(int basicInfo){
        return infoDetailDAO.selectInfoDetailsByBasicInfo(basicInfo);
    }
}
④:类目和选项列表功能实现
1. basic_info_detail.html文件修改为basic_info_detail.jsp文件
2. 点击【评估选项】菜单,跳转到basic_info_detail.jsp⻚面
在这里插入图片描述
3. 当basic_info_detail.jsp⻚面加载完毕触发JS发送ajax请求 到BasicInfoLoadServlet类,获取评估类目列表信息
basic_info_detail.jsp 文件最后添加一个script标签
在这里插入图片描述
4. 创建BasicInfoLoadServlet类 ,查询评估类目列表,转换成JSON格式,响应ajax请求
(注意:ResultVO新增了data属性)
public class ResultVO {
    private int code;
    private String msg;
    private Object data; // 新增一个data属性,用于响应ajax请求时传递数据
    // 无参 有参 get set

    public ResultVO() {
    }

    public ResultVO(int code, String msg) { //两个参数构造器保留(之前的业务使用了这个构造器)
        this.code = code;
        this.msg = msg;
    }

    public ResultVO(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }
  }
@WebServlet(name = "BasicInfoLoadServlet", value = "/BasicInfoLoadServlet")
public class BasicInfoLoadServlet extends HttpServlet {
    private BasicInfoService basicInfoService = new BasicInfoService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询评估类目信息
        List<BasicInfo> basicInfoList = basicInfoService.listBasicInfos();
        // 2.响应ajax请求,将basicInfoList转换成JSON格式响应给页面的ajax请求
        ResultVO vo = basicInfoList != null ? new ResultVO(1000,"success",basicInfoList):
                new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(vo);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
5. 在basic_info_detail.jsp⻚面的ajax的回调函数中获取类目列表,并显示在⻚面上
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
6. 在basic_info_detail.jsp⻚面的ajax的回调函数中显示完成评估类目信息之后,加载第一个类目下的评估选项: 发送ajax请求到InfoDetailListByBasicServlet
在这里插入图片描述
7. 创建InfoDetailListByBasicServlet类,接收类目ID,根据类目ID查询类目下的选项,以json格式响应ajax请求
@WebServlet(name = "InfoDetailListByBasicServlet", value = "/InfoDetailListByBasicServlet")
public class InfoDetailListByBasicServlet extends HttpServlet {
    private InfoDetailService infoDetailService = new InfoDetailService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收ajax请求传递过来类目ID
        int basicInfoId = Integer.parseInt(request.getParameter("basicInfoId"));
        // 2.根据类目ID查询选项
        List<InfoDetail> infoDetailList = infoDetailService.listInfoDetailByBasicInfo(basicInfoId);
        // 3.响应ajax请求
        ResultVO vo = infoDetailList != null? new ResultVO(1000,"success",infoDetailList):
                                              new ResultVO(1001, "fail");
        String jsonStr = new Gson().toJson(vo);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
8. 在basic_info_detail.jsp⻚面查询评估选项的ajax请求的回调函数中
在这里插入图片描述
在这里插入图片描述
⑤:根据类目联动加载选项功能实现
1. 在JS中显示评估类目时,给评估类目的链接添加点击事件监听
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

11.2.2 添加评估选项功能

①:实现流程设计

在这里插入图片描述

②:在添加⻚面加载评估类目列表
1. 在basic_info_detail.jsp⻚面点击【添加评估选项】跳转到basic_info_detail_add.jsp
在这里插入图片描述
2. 将basic_info_detail_add.html修改为basic_info_detail_add.jsp文件
3. basic_info_detail_add.jsp加载完毕就触发JS发送ajax请求评估类目列表 :BasicInfoLoadServlet并显示
在这里插入图片描述
在这里插入图片描述
③:保存评估选项功能实现
1. 在InfoDetailDAO类中完成添加评估选项的数据库操作实现
    /**
     * 添加评估选项
     * @param infoDetail
     * @param basicInfoId
     * @return
     */
    public int insertInfoDetail(InfoDetail infoDetail,int basicInfoId){
        int i = 0;
        try {
            String sql = "insert into tb_info_detail(info_detail_name, info_detail_desc,fk_basic_info_id) values(?,?,?) ";
            i = queryRunner.update(sql,infoDetail.getInfoDetailName(),infoDetail.getInfoDetailDesc(),basicInfoId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }
2. 在InfoDetailService类中完成保存评估选项的业务实现
    /**
     * 保存评估选项
     * @param infoDetail
     * @param basicInfoId
     * @return
     */
    public boolean saveInfoDetail(InfoDetail infoDetail, int basicInfoId){
        int i = infoDetailDAO.insertInfoDetail(infoDetail, basicInfoId);
        return i >0;
    }
3. 在basic_info_detail_add.jsp中点击提交按钮之后,触发js,使用ajax请求提交评估选项数据到InfoDetailAddServlet
在这里插入图片描述
在这里插入图片描述
4. 创建InfoDetailAddServlet类,接收评估选项信息并保存,然后响应ajax请求
@WebServlet(name = "InfoDetailAddServlet", value = "/InfoDetailAddServlet")
public class InfoDetailAddServlet extends HttpServlet {
    private InfoDetailService infoDetailService = new InfoDetailService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 接收ajax提交过来的评估选项信息
        int basicInfoId = Integer.parseInt(request.getParameter("basicInfoId"));
        String infoDetailName = request.getParameter("infoDetailName");
        String infoDetailDesc = request.getParameter("infoDetailDesc");
        InfoDetail infoDetail = new InfoDetail(0, infoDetailName, infoDetailDesc);
        // 2. 调用InfoDetailService保存评估选项信息
        boolean b = infoDetailService.saveInfoDetail(infoDetail, basicInfoId);
        // 3.响应ajax请求
        ResultVO vo = b?new ResultVO(1000,"success"):new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(vo);
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
5. 在添加评估选项的ajax请求的回调函数中,进行提示:成功:成功提示,并在1s后跳转到列表⻚面 失败:失败提示
在这里插入图片描述

十二、商品管理

12.1 商品列表功能

①: 商品列表显示实现流程设计

在这里插入图片描述

②: 在商品列表⻚面加载一级分类

1. 点击“全部商品”菜单跳转到products_list.jsp⻚面(修改数据库tb_menus表)
在这里插入图片描述
2. 将products_list.html文件修改为products_list.jsp文件
3. 在products_list.jsp⻚面,当文件加载完成之后触发JS发送ajax请求获取一级分类数据
在这里插入图片描述
4. 创建CategoryListForAjaxServlet类,查询一级分类信息,并转换成JSON响应ajax请求
@WebServlet(name = "CategoryListForAjaxServlet", value = "/CategoryListForAjaxServlet")
public class CategoryListForAjaxServlet extends HttpServlet {
    private CategoryService categoryService = new CategoryService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1. 查询一级分类信息
        List<Category> categoryList = categoryService.lsitCatetories();
        // 2.转换成json格式
        ResultVO resultVO = categoryList != null ? new ResultVO(1000,"success",categoryList):
                new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(resultVO);
        // 3.响应ajax请求
        response.setCharacterEncoding("utf-8");
        response.setContentType("application/json;charset=utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
5. 在ajax请求回调函数中显示一级分类下拉菜单
在这里插入图片描述
在这里插入图片描述

③: 商品列表⻚面品牌与分类的联动

1. 在products_list.jsp监听一级分类下来菜单的change事件,一旦一级分类发生变化,通过ajax加载品牌列表: ajax请求BrandListForAjaxServlet
在这里插入图片描述
在这里插入图片描述
2. 创建BrandListForAjaxServlet类,接收分类ID,根据分类ID查询品牌列表,并以json响应ajax请求
@WebServlet(name = "BrandListForAjaxServlet", value = "/BrandListForAjaxServlet")
public class BrandListForAjaxServlet extends HttpServlet {
    private BrandService brandService = new BrandService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收分类Id 根据分类Id查询品牌信息
        int categoryId = Integer.parseInt(request.getParameter("categoryId"));
        List<Brand> brandList = brandService.listBrandByCategoryId(categoryId);
        // 2.转换成json格式
        ResultVO resultVO = brandList != null?new ResultVO(1000,"success",brandList):
                new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(resultVO);
        // 3.响应ajax请求
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}

④: 根据品牌查询并显示商品列表

1. 当点击【查询】按钮,触发JS操作,获取品牌ID,根据品牌ID异步查询并显示商品列表
在这里插入图片描述
在这里插入图片描述
       $(".btn_search").click(function(){
       // 1.获取选择的品牌Id
       var brandId = $("#brandSelect").val();
        console.log(brandId);
       if (brandId == ""){
           layer.msg("请选择品牌!",{
               icon:5,
               time:1000

           })
       }else {
           // 2.发送ajax请求,查询商品信息
           $.post("GoodsListForAjaxServlet",{brandId:brandId},function(res){
               // 3.显示返回的商品信息
               if (res.code == 1000){
                   var goodsArr = res.data;
                   // 显示商品列表之间先清空
                   $("#goodsListTbody").html("");
                   for (let i = 0; i < goodsArr.length; i++) {
                       var goods = goodsArr[i];
                       var trStr = "<tr>"+
                       "<td width='25px'><label><input type='checkbox' class='ace' ><span class='lbl'></span></label></td>"+
                       "<td width='80px'>"+goods.goodsId+"</td>"+
                       "<td width='250px'><u style='cursor:pointer' class='text-primary' οnclick=''>"+goods.goodsName+"</u></td>"+
                       "<td width='100px'><img src='' height='40'/></td>"+
                       "<td width='100px'>¥"+goods.goodsCost+".00</td>"+
                       "<td width='100px'>¥"+goods.goodsMinPrice+".00</td>"+
                       "<td class='td-status'><span class='label label-success radius'>已启用</span></td>"+
                       "<td class='td-manage'>"+
                       "<a  href='javascript:;' title='停用'  class='btn btn-xs btn-success'><i class='icon-ok bigger-120'></i></a>"+
                       "<a title='编辑'  href='javascript:;'  class='btn btn-xs btn-info' ><i class='icon-edit bigger-120'></i></a>"+
                       "<a title='删除' href='javascript:;'  class='btn btn-xs btn-warning' ><i class='icon-trash  bigger-120'></i></a>"+
                       "</td>"+
                   "</tr>";
                       $("#goodsListTbody").append(trStr);
                   }
               }
           },"json");
       }
    });
2. 创建GoodsListForAjaxServlet类,接收品牌ID,根据品牌ID查询商品列表并以json格式响应ajax请求
@WebServlet(name = "GoodsListForAjaxServlet", value = "/GoodsListForAjaxServlet")
public class GoodsListForAjaxServlet extends HttpServlet {
    private GoodsService goodsService = new GoodsService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收品牌ID
        int brandId = Integer.parseInt(request.getParameter("brandId"));
        List<Goods> goodsList = goodsService.listGoodsByBrandId(brandId);

        // 2.转换成json格式
        ResultVO resultVO = goodsList != null?new ResultVO(1000,"success",goodsList):
                new ResultVO(1001,"fail");
        String jsonStr = new Gson().toJson(resultVO);
        // 3.响应json请求
        response.setContentType("application/json;charset=utf-8");
        response.setCharacterEncoding("utf-8");
        PrintWriter out = response.getWriter();
        out.println(jsonStr);
        out.flush();
        out.close();
    }
}
3. 创建GoodsService类,完成根据品牌ID查询商品列表的业务
public class GoodsService {
    private GoodsDAO goodsDAO = new GoodsDAO();

    /**
     * 根据品牌Id查询商品列表
     * @param brandId
     * @return
     */
    public List<Goods> listGoodsByBrandId(int brandId) {
        List<Goods> goodsList = goodsDAO.selectGoodsByBrandId(brandId);
        return goodsList;
    }
}

12.2 添加商品功能

①: 添加商品实现流程设计

在这里插入图片描述

②: 商品添加⻚面的数据加载实现

  • 同步加载商品的类目及选项

  • 异步加载一级分类

  • 根据一级分类联动显示品牌列表

  • 选择图片实现异步上传

| 1. 创建BasicInfoAndDetailListServlet

2. 在products_list.jsp⻚面点击【添加商品】按钮,跳转到创建BasicInfoAndDetailListServlet
在这里插入图片描述
3. 在BasicInfoAndDetailListServlet类中查询评估类目列表、并且根据每一个评估类目ID查询对应的评估选项,然后将包含评估选项的评估类目列表传递到products_add.jsp⻚面
@WebServlet(name = "BasicInfoAndDetailListServlet", value = "/BasicInfoAndDetailListServlet")
public class BasicInfoAndDetailListServlet extends HttpServlet {
    private BasicInfoService basicInfoService = new BasicInfoService();
    private InfoDetailService infoDetailService = new InfoDetailService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.查询所有的评估类目
        List<BasicInfo> basicInfoList = basicInfoService.listBasicInfos();
        // 2.遍历所有类目
        for (int i = 0; i < basicInfoList.size(); i++) {
            BasicInfo basicInfo = basicInfoList.get(i);
            // 根据评估类目的ID查询此评估类目下的选项
            List<InfoDetail> infoDetailList = infoDetailService.listInfoDetailByBasicInfo(basicInfo.getBasicInfoId());
            // 将此评估类目下的选项存储到basicInfo对象中
            basicInfo.setInfoDetailList(infoDetailList);
        }
        // 3.将评估类目集合传递到商品添加页面 products_add.jsp
        request.setAttribute("basicInfoList",basicInfoList);
        request.getRequestDispatcher("products_add.jsp").forward(request,response);
    }
}

4. 为评估类目实体类BasicInfo添加集合属性,存放当前类目下的选项
public class BasicInfo {
    private int basicInfoId;
    private String basicInfoName;
    private int basicInfoStatus;
    // 定义infoDetailList属性,存放当前类目下的选项 提供此属性的get set方法
    private List<InfoDetail> infoDetailList;
    }
5. 将products_add.html文件修改为products_add.jsp文件,在products_add.jsp⻚面通过JSTL+EL显示评估类目及选项
在这里插入图片描述
6. 在products_add.jsp⻚面通过ajax加载一级分类下拉菜单
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
<script type="text/javascript">
	$(function (){
		// 1.加载一级分类
		$.post("CategoryListForAjaxServlet",function (res){
			if (res.code == 1000){
				var categoryArr = res.data;
				for (let i = 0; i < categoryArr.length; i++) {
					var category = categoryArr[i];
					var optionStr = "<option value='"+category.categoryId+"'>"+category.categoryName+"</option>";
					$("#categorySelect").append(optionStr);
				}
			}
		},"json")
	});

	// 监听一级分类下拉菜单change事件
	$("#categorySelect").change(function(){
		var categoryId = $("#categorySelect").val();
		// 当显示一个分类下的品牌列表时,先将品牌下拉菜单清空
		$("#brandSelect").html("<option value=''>请选择商品品牌</option>");
		if (categoryId != ""){
			// 发送ajax请求到BrandListForAjaxServlet,通过分类Id,查询品牌列表
			$.post("BrandListForAjaxServlet",{categoryId:categoryId},function (res){
				// 处理响应的品牌列表
				if (res.code == 1000){
					var brandArr = res.data;
					// 遍历显示品牌下拉菜单
					for (let i = 0; i < brandArr.length; i++) {
						var brand = brandArr[i];
						var  optionstr = "<option value='"+brand.brandId+"'>"+brand.brandName+"</option>";
						$("#brandSelect").append(optionstr);
					}
				}else if (res.code == 1001){
					layer.msg("品牌信息加载失败!");
				}
			},"json");
		}
	});


</script>

③: 商品添加⻚面图片异步上传

在这里插入图片描述在这里插入图片描述

④: 提交商品信息并保存

1. 创建GoodsAddServlet
2. 在products_add.jsp⻚面点击【提交】按钮,将数据以表单的形式同步提交到GoodsAddServlet
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
3. 在GoodsAddServlet类接收数据,,保存商品信息(商品与品牌的关系),保存商品与选项的关联,跳转到products_list.jsp⻚面并提示

①:需要调用 GoodsService 中的 saveGoods(goods,brandId)保存商品信息

②:需要调用 GoodsService 中的 saveGoodsAndInfoDetail(goodsId,infoDetailId,price)保存商品与选项的关联信息

@WebServlet(name = "GoodsAddServlet", value = "/GoodsAddServlet")
public class GoodsAddServlet extends HttpServlet {
    private GoodsService goodsService = new GoodsService();
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        doPost(request, response);
    }

    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        // 1.接收商品信息
        String goodsName = request.getParameter("goodsName");
        String goodsImg = request.getParameter("goodsImgPath");
        int goodsCost = Integer.parseInt(request.getParameter("goodsCost"));
        int goodsMinPrice = Integer.parseInt(request.getParameter("goodsMinPrice"));
        Goods goods = new Goods(0, goodsName, goodsImg, goodsCost, goodsMinPrice);
        // 2.接收品牌ID
        int brandId = Integer.parseInt(request.getParameter("brandId"));
        // 【保存商品信息】
        int goodsId = goodsService.saveGoods(goods, brandId);
        // 3.接收选择的评估选项的ID
        String[] infoDetailIds = request.getParameterValues("infoDetailId");
        // 遍历每一个评估选项,获取价格
        for (int i = 0; i < infoDetailIds.length; i++) {
            int infoDetailId = Integer.parseInt(infoDetailIds[i]);
            int price = Integer.parseInt(request.getParameter("price_" + infoDetailId));
            // 【保存商品与选项的关系】
            boolean b = goodsService.saveGoodsAndInfoDetail(goodsId,infoDetailId,price);
        }
        // 4.跳转到商品列表页面,并传递提示信息
        String tips = goodsId > 0 ?"<label style='color:green'>添加商品成功!</label>":
                "<label style='color:red'>添加商品失败!</label>";
        request.setAttribute("tips",tips);
        request.getRequestDispatcher("products_list.jsp").forward(request,response);
    }
}

4.在GoodsService类中新增以下两个业务实现

    /**
     * 保存商品信息与品牌的关联
     * @param goods
     * @param brandId
     * @return
     */
    public int saveGoods(Goods goods, int brandId) {
        // 保存商品信息
        int goodsId = goodsDAO.insertGoods(goods);
        if (goodsId > 0){
            // 保存商品与品牌的关联关系
            int i = goodsDAO.insertGoodsAndBrand(goodsId,brandId);
            if (i > 0){
                return goodsId;
            }
        }
        return 0;
    }

    /**
     * 保存商品与选项的关联关系
     * @param goodsId
     * @param infoDetailId
     * @param price
     * @return
     */
    public boolean saveGoodsAndInfoDetail(int goodsId, int infoDetailId, int price) {
        int  i = goodsDAO.insertGoodsAndInfoDetail(goodsId,infoDetailId,price);
        return i > 0;
    }
5.在GoodsDAO类中新增以下三个数据库实现
    /**
     * 保存商品信息
     * @param goods
     * @return
     */
    public int insertGoods(Goods goods) {
        int goodsId = 0;
        try {
            String sql = "insert into tb_good(good_name, good_img, good_cost, good_min_price) values (?,?,?,?)";
            BigInteger insert = queryRunner.insert(sql, new ScalarHandler<>(), goods.getGoodsName(), goods.getGoodsImg(), goods.getGoodsCost(), goods.getGoodsMinPrice());
            goodsId = insert.intValue();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return goodsId;
    }

    /**
     * 保存商品与品牌的关联关系
     * @param goodsId
     * @param brandId
     * @return
     */
    public int insertGoodsAndBrand(int goodsId, int brandId) {
        int i = 0;
        try {
            String sql = "insert into tb_brand_good(fk_brand_id, fk_good_id) VALUES (?,?)";
            i = queryRunner.update(sql, brandId, goodsId);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;
    }

    /**
     * 保存商品与选项的关联关系
     * @param goodsId
     * @param infoDetailId
     * @param price
     * @return
     */
    public int insertGoodsAndInfoDetail(int goodsId, int infoDetailId, int price) {
        int i = 0;
        try {
            String sql = "insert into tb_good_detail(fk_good_id, fk_info_detail_id, good_discount) values (?,?,?)";
            i = queryRunner.update(sql, goodsId, infoDetailId, price);
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
        return i;

    }
7. 在products_list.jsp显示添加操作的提示信息
在这里插入图片描述

十三、系统功能实现总结

十四、《卖淘乐》后台管理系统项目部署

基于提供的项目源码、导入到idea并运行起来

14.1 项目资源说明

在这里插入图片描述

14.2 数据库环境部署

  1. 安装MySQL数据库(v8.0.26) 【B站:千锋教育】 数据库帐号和密码 root / @QFedu123

  2. 安装Navicat Premium 12数据库可视化管理工具,并连接到mysql

  3. 通过Navicat工具创建数据库 : db_mtlms

  4. 打开创建的数据库,导入提供的数据库脚本:

  • mysql版本5.x : db_mtl_5.sql

  • mysql版本8.x : db_mtl_8.sql

14.3 将源码导入到Idea

准备工作:

  • 安装JDK

  • 安装IDEA(v2019.2.1) :

    • 链接:https://pan.baidu.com/s/1uM5eL8Y_ZZirLntF4Pwjtg

    • 提取码:076o

  • 安装Tomcat(v8.5+)

    • 链接:https://pan.baidu.com/s/1f7bAnxbMe4buysDsR9lZOg

    • 提取码:0ar5

  1. 将提供的项目源码文件夹mtlms拷⻉到计算机的指定目录(例如:D:\workspace)

在这里插入图片描述

  1. 删除项目源码中的:
    在这里插入图片描述

  2. 打开idea——点击Open——选择D:\workspace\mtlms

  3. 配置web环境(Tomcat)

  • File——Project structure
    在这里插入图片描述

  • 选择Tomcat版本
    在这里插入图片描述

  • 点击Source,将项目的src标记为资源目录,点击OK
    在这里插入图片描述

  1. 将项目中的jar文件添加到依赖库

在这里插入图片描述

14.4 部署并运行项目

  1. 添加服务器配置
    在这里插入图片描述

  2. 导出项目,部署到Tomcat

在这里插入图片描述

  • File——Project Structure
    在这里插入图片描述

  • 指定项目运行时编译文件的存储目录
    在这里插入图片描述

  • 将项目部署到Tomcat

在这里插入图片描述在这里插入图片描述

  • 修改项目源码中数据库的数据源信息
    在这里插入图片描述
  1. 运行Tomcat,进行访问测试
  • 直接运行Tomcat
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

七@归七

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值