瑞吉外卖项目学习笔记(二)后台系统的员工管理业务开发

一、完善登录功能

1.1 问题分析

1.2 代码实现

package com.itheima.reggie.filter;

//这是一个过滤器类
//登录检查过滤器

import com.alibaba.fastjson.JSON;
import com.itheima.reggie.common.R;
import lombok.extern.slf4j.Slf4j;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.AntPathMatcher;

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

/**
 * 检查用户是否已经完成登录
 */
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
public class LoginCheckFilter implements Filter {

    //路径匹配器,支持通配符写法(专门用来路径比较的)
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    /**
     * 过滤的方法
     * @param servletRequest
     * @param servletResponse
     * @param filterChain
     * @throws IOException
     * @throws ServletException
     */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;
        /**
         * 1、获取本次请求的URI
         * 2、判断本次请求是否需要处理(是否需要检查用户已经登录了)【检查登录状态】
         * 3、如果不需要处理,则直接放行
         * 4、判断登录状态,如果已登录,则直接放行
         * 5、如果未登录则返回未登录结果
         */
        //1、获取本次请求的URI
        String requestURI = request.getRequestURI();

        //日志:拦截到的请求
        log.info("拦截到的请求:{}", requestURI);

        //2、判断本次请求是否需要处理(是否需要检查用户已经登录了)【检查登录状态】
        //定义一些不需要处理的请求路径(直接放行),只拦截针对Controller的请求
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };
        //判断是否需要处理
        boolean check = check(urls, requestURI);

        //3、如果不需要处理,则直接放行
        //check = true时不需要处理
        if (check) {
            log.info("本次请求{}不需要处理", requestURI);
            //放行
            filterChain.doFilter(request, response);
            return;
        }

        //4、判断登录状态,如果已登录,则直接放行


        if (request.getSession().getAttribute("employee") != null) {
            log.info("用户已登录,用户id为{}", request.getSession().getAttribute("employee"));
            //放行
            filterChain.doFilter(request, response);
            return;
        }

        log.info("用户未登录");
        //5、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
        response.getWriter().write(JSON.toJSONString(R.error("NOTLOGIN")));
        return;


    }

    /**
     * 路径匹配,检查本次请求是否需要放行
     * @param urls
     * @param requestURI
     * @return
     */
    //封装方法
    public boolean check(String[] urls,String requestURI) {
        for (String url : urls) {
            boolean match = PATH_MATCHER.match(url, requestURI);
            if (match) {
                return true;
            }
        }
        //整个for循环都遍历完了都没有匹配上,就返回false
        return false;
    }
}

1.3 功能测试

二、新增员工

2.1 需求分析

2.2 数据模型

2.3 代码开发

package com.itheima.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.itheima.reggie.common.R;
import com.itheima.reggie.entity.Employee;
import com.itheima.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import java.time.LocalDateTime;

@Slf4j
@RestController
@RequestMapping("/employee")
public class EmployeeController {

    //自动装配
    @Autowired
    private EmployeeService employeeService;


    /**
     * 员工登录
     * @param request
     * @param employee
     * @return
     */
    //前端发送的请求是 post 请求
    @PostMapping("/login")
    //接收json数据
    //requset对象可以get
    public R<Employee> login(HttpServletRequest request, @RequestBody Employee employee){
        /**
         * 1、将页面提交的密码password进行md5的加密处理
         * 2、根据页面提交的用户名username查询数据库
         * 3、如果没有查询到则返回登录失败的结果
         * 4、密码比对,如果不一致则返回登录失败结果
         * 5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
         * 6、登录成功,将员工id存入Session并返回登录成功结果
         */


        // 1、将页面提交的密码password进行md5的加密处理
        //从employee中把password拿到
        String password = employee.getPassword();
        //调用工具类中的md5加密的方法
        password = DigestUtils.md5DigestAsHex(password.getBytes());

        //2、根据页面提交的用户名username查询数据库
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        //添加查询条件
        queryWrapper.eq(Employee::getUsername, employee.getUsername());
        //数据库已经对user_name做了唯一约束
        Employee emp = employeeService.getOne(queryWrapper);

        //3、如果没有查询到则返回登录失败的结果
        if(emp == null){
            return R.error("登录失败");
        }

        //4、密码比对,如果不一致则返回登录失败结果
        if(!password.equals(emp.getPassword())){
            //密码匹配不成功
            return R.error("登录失败");
        }

        //登录成功
        //5、查看员工状态,如果为已禁用状态,则返回员工已禁用结果
        if (emp.getStatus() == 0){
            return R.error("账号已经被禁用");
        }

        //6、登录成功,将员工id存入Session并返回登录成功结果
        request.getSession().setAttribute("employee", emp.getId());

        //这是我们从数据库中查出来的对象
        return R.success(emp);
    }

    /**
     * 退出方法
     */
    /**
     * 员工退出
     * @param request
     * @return
     */
    @PostMapping("/logout")
    public R<String> logout(HttpServletRequest request){
        //清理Session中保存的当前登录员工的id
        request.getSession().removeAttribute("employee");
        return R.success("退出成功");
    }

    /**
     * 新增员工
     * @param employee
     * @return
     */
    @PostMapping
    public R<String> save(HttpServletRequest request,@RequestBody Employee employee){
        log.info("新增员工,员工信息:{}",employee.toString());

        //设置初始密码:123456,需要进行md5加密处理。getBytes():设置成getBytes()数组
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));

        //登录时间和更新时间
        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());

        //获得当前登录用户的id
        Long empId = (Long) request.getSession().getAttribute("employee");

        employee.setCreateUser(empId);
        employee.setUpdateUser(empId);
        //保存对象
        employeeService.save(employee);

        //新增员工成功
        return R.success("新增员工成功");

    }
}

package com.itheima.reggie.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常捕获处理
 * RestController.class, Controller.class:只有有这两个注解的类都会被我们这个类来处理
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class}) //通知
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 异常处理方法
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public R<String> exceptionHandler(SQLIntegrityConstraintViolationException ex) {
        log.error(ex.getMessage());

        //判断异常获取信息中是否有:Duplicate entry(重复条目)
        if(ex.getMessage().contains("Duplicate entry")){
            //根据空格进行分割,把异常信息存储到 split数组中
            String[] split = ex.getMessage().split(" ");
            //获取数组中已经用户名信息(唯一约束)
            String msg = split[2] + "已存在";
            //输出错误信息(账户已存在的信息)
            //return 把错误信息输出到页面上
            return R.error(msg);
        }


        //显示到页面的信息
        return R.error("未知错误");
    }
}


 

2.4 功能测试

2.5 总结

1、根据产品原型明确业务需求

2、重点分析数据的流转过程和数据格式

3、通过debug断点调试跟踪程序执行过程

三、员工信息分页查询

3.1 需求分析

在后台显示界面,一页显示出所有员工信息不利于查看。

解决方法:将员工信息进行分页展示

  • 输入框:可以添加过滤条件,在添加过滤条件的同时进行分页处理
  • 页码展示、可以跳转到相应的页码、也可直接点击相应的页码

3.2 代码开发

3.2.1 梳理程序执行流程

  1. 页面发送 ajax 请求,将分页查询参数(page、pageSize、name)提交到服务器
  2. 服务端 Controller 接收页面提交的数据并调用 Service 查询数据
  3. Service 调用 Mapper 操作数据库,查询分页数据
  4. Controller 将查询到的分页数据转成 JSON 响应给页面
  5. 页面接收到分页数据并通过 ElementUI 的 Table 组件展示到页面上

分页插件的使用:

MyBatisPlus 给我们提供了一个分页插件。

package com.itheima.reggie.config;

import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * 配置MybatisPlus 的分页插件,配置类要加 @Configuration 注解
 */
@Configuration
public class MyBatisPlusConfig {
    
    //拦截器
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor() {
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

服务端 Controller 接收页面提交的数据并调用 Service 查询数据

//返回泛型Page,这个是MyBatisPlus 封装的类
    //方法中的形参指的是:前端页面传递给我们的值
    /**
     * 员工信息的分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){

        log.info("page = {},pageSize = {},name = {}",page,pageSize,name);

        return null;
    }

分页查询设置

//返回泛型Page,这个是MyBatisPlus 封装的类
    //方法中的形参指的是:前端页面传递给我们的值
    /**
     * 员工信息的分页查询
     * @param page
     * @param pageSize
     * @param name
     * @return
     */
    @GetMapping("/page")
    public R<Page> page(int page, int pageSize, String name){

        log.info("page = {},pageSize = {},name = {}",page,pageSize,name);

        //底层是基于MyBatisPlus提供的分页插件进行分页
        //1、构建分页构造器(分页条件:告诉MyBatisPlus我要查第几页,第几条)
        Page pageInfo = new Page(page, pageSize);

        //2、构造条件构造器(封装过滤分页条件)
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper();
        //添加过滤条件,like查询
        //判断name是否为null,然后再来添加条件
        queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
        //添加排序条件(就是相当于在SQL语句中加一个OrderBy)
        queryWrapper.orderByDesc(Employee::getUpdateTime);

        //3、执行查询
        employeeService.page(pageInfo,queryWrapper);

        return R.success(pageInfo);
    }

3.3 功能测试

四、启动 / 禁用员工账号

4.1 需求分析

  1. 只有管理员(admin 用户)可以对其他普通用户进行启用、禁用操作
  2. 普通用户登录系统后启用、禁用按钮不显示
  3. 账户禁用的员工不能登录系统
  4. 账户启用的员工可以正常登录
  5. 如果某个员工账户状态为正常,则按钮显示为 “禁用”
  6. 如果员工账户状态为已禁用,则按钮显示为 “启用”

4.2 代码开发

在开发代码之前,需要梳理一下整个程序的执行流程:

  1. 页面发送 ajax 请求,将参数(id、status)提交到服务端
  2. 服务端 Controller 接收页面提交的数据并调用 Service 更新数据
  3. Service 调用 Mapper 操作数据库

本质:是一个更新操作(Update),修改状态码

启用、禁用(或者是编辑)员工账号,本质上就是一个更新操作,也就是对 status 状态字段进行操作。

在 Controller 中创建 update 方法,此方法是一个通用的修改员工信息的方法。

4.3 功能测试

4.4 代码修复

五、编辑员工信息

5.1 需求分析

在员工管理列表页面点击编辑按钮,跳转到编辑页面,在编辑页面回显员工信息并进行修改,最后点击保存按钮完成编辑操作。

5.2 代码开发

在开发代码之前需要梳理一下操作过程喝对应的程序的执行流程:

  1. 点击编辑按钮时,页面跳转到 add.html ,并在 url 中携带参数【员工 id】
  2. 在 add.html 页面获取 url 中的参数【员工 id】
  3. 发送 ajax 请求,请求服务端,同时提交员工 id 参数
  4. 服务端接收请求,根据员工 id 查询员工信息,将员工信息以 json 形式响应给页面
  5. 页面接收服务端响应的 json 数据,通过 VUE 的数据绑定进行员工信息回显
  6. 点击保存按钮,发送 ajax 请求,将页面中的员工信息以 json 方式提交给服务端
  7. 服务端接收员工信息,并进行处理,完成后给页面响应
  8. 页面接收到服务端响应信息后进行相应处理

5.3 功能测试

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/666008.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

探索k8s集群的存储卷 emptyDir hostPath nfs

目录 一 含义 查看支持的存储卷类型 emptyDir存储卷 1.1 特点 1.2 用途 1.3部署 二、hostPath存储卷 一 含义 容器磁盘上的文件的生命周期是短暂的&#xff0c;这就使得在容器中运行重要应用时会出现一些问题。首先&#xff0c;当容器崩溃时&#xff0c;kubelet 会重…

磁盘配额的具体操作

磁盘配额&#xff1a; linux的磁盘空间有两个方面&#xff1a;第一个是物理空间&#xff0c;也就是磁盘的容量 第二个inode号耗尽&#xff0c;也无法写入 linux根分区&#xff1a;根分区的空间完全耗尽&#xff0c;服务程序崩溃&#xff0c;系统也无法启动了。 为了防止有人…

师彼长技以助己(2)产品思维

师彼长技以助己&#xff08;2&#xff09;产品思维 前言 我把产品思维称之为&#xff1a;人生底层的能力以及蹉跎别人还蹉跎自己的能力&#xff0c;前者说明你应该具备良好产品思维原因&#xff0c;后者是你没有好的产品思维去做产品带来的灾难。 人欲即天理 请大家谈谈看到这…

错误 0x80070570:文件或目录损坏且无法读取/无法访问[拒绝访问]-解决方法

1.起因&#xff1a;在挪动&#xff35;盘文件时&#xff0c;出现无法移动的报错提示&#xff1a; and无法访问[拒绝访问]: 2.原因&#xff3b;大多是胡乱拔出&#xff35;盘&#xff3d; &#xff3b;来自0x80070570 文件或目录损坏且无法读取 CHKDSK 修复方法-CSDN博客&#…

【介绍下SCSS的基本使用】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

【AI应用开发框架】应用phidata快速构建你的智能体(如个人知识库、自动选股等)

1.phidata是什么&#xff1f; AI APP开发框架&#xff0c;基于此框架可快速搭建智能体或智能助手以实现记忆、知识库及工具使用等功能。 2.框架是怎样的&#xff1f; 3.为什么选择phidata&#xff1f; 问题&#xff1a;LLMs 的上下文有限&#xff0c;无法执行具体动作 解决…

[数据集][目标检测]猫狗检测数据集VOC+YOLO格式8291张2类别

数据集格式&#xff1a;Pascal VOC格式YOLO格式(不包含分割路径的txt文件&#xff0c;仅仅包含jpg图片以及对应的VOC格式xml文件和yolo格式txt文件) 图片数量(jpg文件个数)&#xff1a;8291 标注数量(xml文件个数)&#xff1a;8291 标注数量(txt文件个数)&#xff1a;8291 标注…

LeetCode-131 分割回文串

LeetCode-131 分割回文串 题目描述解题思路C 代码 题目描述 给你一个字符串 s&#xff0c;请你将 s 分割成一些子串&#xff0c;使每个子串都是 回文串。返回 s 所有可能的分割方案。 示例 1&#xff1a; 输入&#xff1a;s “aab” 输出&#xff1a;[[“a”,“a”,“b”],…

1.8k Star!RAGApp:在任何企业中使用 Agentic RAG 的最简单方法!

原文链接&#xff1a;&#xff08;更好排版、视频播放、社群交流、最新AI开源项目、AI工具分享都在这个公众号&#xff01;&#xff09; 1.8k Star&#xff01;RAGApp&#xff1a;在任何企业中使用 Agentic RAG 的最简单方法&#xff01; &#x1f31f;在任何企业中使用 Agent…

大数据信用报告分析和评估有什么意义

大数据信用这个词在现在已经是很常见的了&#xff0c;只要是申贷的朋友对它就不陌生&#xff0c;在明面上的信用资质刚刚满足审核要求&#xff0c;但又要把控风险的时候&#xff0c;这个时候大数据信用就会作为风控机构交叉核查的重要依据。那你知道大数据信用报告分析和评估有…

二、线性回归模型

目录 一、线性回归 1.模型示例 2.代码实验&#xff08;C1_W1_Lab03_Model_Representation&#xff09; (1).工具使用 (2).问题描述-房价预测 (3).输入数据 (4).绘制数据集坐标点 (5).建模构造函数 二、代价函数&#xff08;Cost function&#xff09; 1.解释一下概念…

上架 Google Play 的那些辛酸泪

一、注册 Google 账号 首先你要有个账号&#xff0c;地址如下&#xff1a; accounts.google.com/signup/v2/w… 按照 Google 爸爸要求&#xff0c;该填写的都填了&#xff0c;随后点击下一步。 验证手机号&#xff1a; 输入验证码验证当前手机号&#xff1a; 其他信息填写&a…

废品回收小程序怎么做?有哪些核心功能?

废品回收行业正逐步走向高质量发展的道路。在国家政策的推动下&#xff0c;再生资源市场需求旺盛&#xff0c;行业内部竞争格局逐渐明朗。 随着互联网技术的发展&#xff0c;"互联网回收"成为废品回收行业的一个新趋势。通过微信小程序这种线上平台&#xff0c;用户…

Linux--EXT2文件系统

参考资料&#xff1a; linux之EXT2文件系统--理解block/block group/索引结点inode/索引位图_一个块组中索引节点表和数据块区最多占用字节-CSDN博客 linux环境&#xff1a; Linux version 5.15.146.1-microsoft-standard-WSL2 (root65c757a075e2) (gcc (GCC) 11.2.0, GNU ld…

Wpf 使用 Prism 实战开发Day30

登录界面设计 一.准备登录界面图片素材&#xff08;透明背景图片&#xff09; 1.把准备好的图片放在Images 文件夹下面&#xff0c;格式分别是.png和.ico 2.选中 login.png图片鼠标右键&#xff0c;选择属性。生成的操作选择>资源 3.MyTodo 应用程序右键&#xff0c;属性&a…

音量的对数表示与浮点数表示

音量用浮点数&#xff08;float&#xff09;和对数&#xff08;logarithmic scale&#xff09;表示各有特点和应用场景 浮点数&#xff1a;直接使用线性刻度表示音量&#xff0c;例如在0.0&#xff08;最小音量&#xff09;到1.0&#xff08;最大音量&#xff09;的范围内。对…

YZW900规格书

title: “深圳市沃进科技有限公司” 深圳市沃进科技有限公司 TOP视图 特性 异地组网&#xff0c;远程访问有线/无线备份单模双卡备份5G转有线&#xff0c;5G转WIFI2.4G5.8G双频WIFI三网口&#xff0c;WAN/LAN可切换软硬件看门狗智能防掉线云平台、客户端远程管理安装支架安装铝…

MyBatis延迟加载缓存分页逆向工程

文章目录 延迟加载概述步骤 缓存一级缓存介绍原理 二级缓存介绍 设置缓存对象策略原理开启步骤属性解释是否使用一级缓存 分页插件使用步骤 逆向工程介绍搭建使用增删修改查 延迟加载 概述 延迟加载本身是依赖于多表查询的 延迟加载中返回值要选择resultMap返回的结果一定是D…

【QEMU 中文文档】0. Hello QEMU!

最近&#xff0c;我开始研究QEMU这个超强的虚拟化和仿真工具。不得不说&#xff0c;读英文文档真是让我头大 &#x1f974;。于是我灵机一动&#xff0c;为什么不做个QEMU的中文文档呢&#xff1f;毕竟&#xff0c;现在有了ChatGPT的强大翻译能力&#xff0c;我决定尝试一下&am…

分形之科赫雪花

前言 分形是一种具有自相似性的几何图形或数学对象。它的特点是无论在任何放大或缩小的尺度下,都能够看到与整体相似的图形。分形的形状可以非常复杂,常常具有分支、重复的图案,以及细节层次丰富的结构。 分形在自然界中广泛存在,如云朵、树枝、山脉、海岸线等,它们都展…