5

瑞吉外卖实战项目全攻略——第二天

 1 year ago
source link: https://www.cnblogs.com/qiuluoyuweiliang/p/16808425.html
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

瑞吉外卖实战项目全攻略——第二天

该系列将记录一份完整的实战项目的完成过程,该篇属于第二天

案例来自B站黑马程序员Java项目实战《瑞吉外卖》,请结合课程资料阅读以下内容

该篇我们将完成以下内容:

  • 完善登陆系统
  • 员工信息分页查询
  • 启用/禁止员工账号
  • 编辑员工信息

完善登陆系统

我们的功能完善一般分为三步

我们在前面的文章中已经实现了login的系统登录

但是我们页面的访问并没有设置限制,如果我们直接跳过登陆页面直接输入系统内部页面的url同样可以进入

2886527-20221020073545693-311257361.png

所以我们在进入内部页面时需要先进行检测用户是否登录

我们在之前的login功能中如果登陆成功就会给Session加入一个employee的ID值,我们凭借ID来判断是否登录

此外,我们需要在进入页面之前进行判断,那么我们就需要构造一个过滤器或者拦截器,下面我们采用过滤器Filter实现

我们创建一个filter文件夹专门存放filter过滤器

下面我们根据逻辑进行代码实现过程:

package com.qiuluo.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
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;

/**
 * 检查用户是否已经完成登录
 */

// 注意:需要在启动类上添加@ServletComponentScan注解来帮助识别过滤器
// 过滤器需要添加@WebFilter,设置filterName过滤器名,urlPatterns选择过滤路径
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
@Slf4j
// 注意:需要继承Filter过滤器
public class LoginCheckFilter implements Filter{
    
    //路径匹配器,支持通配符(类似于工具类,带有方法)
    public static final AntPathMatcher PATH_MATCHER = new AntPathMatcher();

    // 实现doFilter方法
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        
        // 类型转换,便于使用对应方法
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //1、获取本次请求的URI:/backend/index.html
        String requestURI = request.getRequestURI();

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

        // 中间步骤:定义不需要处理的请求路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };


        //2、判断本次请求是否需要处理
        boolean check = check(urls, requestURI);

        //3、如果不需要处理,则直接放行
        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、如果未登录则返回未登录结果,通过输出流方式向客户端页面响应数据
        //(前端代码需要我们返回一个"NOTLOGIN"来告诉前端没有登录)
        response.getWriter().write(JSON.toJSONString(Result.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;
            }
        }
        return false;
    }
}

我们首先需要采用clean,清除之前存有的数据操作

直接在浏览器输入系统内部网页的登录URL,如果代码正确,我们会闪回到登陆界面进行登录

我们的功能完善一般分为三步

我们在系统内部页面中点击新增员工,会跳转到另一个页面,这属于前端工作

接下来我们在页面中填写信息,前端会将这些信息封装起来,以Employee的形式发送给后端端口

2886527-20221020073601586-2027857295.png

我们打开F12,输入数据点击保存后查看数据的请求方式(点击负载,可以查看到填写信息的Employee内容,这里不再展示):

2886527-20221020073606613-1402368157.png

这个请求方式的路径就是我们需要完善的代码URL的路径

现在我们来到IDEA中进行简单的开发:

package com.qiuluo.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Employee;
import com.qiuluo.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

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

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

    @Autowired
    private EmployeeService employeeService;

    /**
     * 新增员工
     * @param employee
     * @return
     */
    @PostMapping
    public Result<String> save(HttpServletRequest request,@RequestBody Employee employee){
        // 日志输出
        log.info("添加员工");

        // 1.根据数据库的设置,补全相关信息(密码,注册事件,修改时间,注册人ID,修改人ID)
        employee.setPassword(DigestUtils.md5DigestAsHex("123456".getBytes()));

        employee.setCreateTime(LocalDateTime.now());
        employee.setUpdateTime(LocalDateTime.now());

        Long empId = (Long) request.getSession().getAttribute("employee");

        employee.setCreateUser(empId);
        employee.setUpdateUser(empId);

        // 2.调用业务层方法直接新增数据进入数据库中
        employeeService.save(employee);

        // 3.返回Result返回体
        return Result.success("新增员工成功");
    }

}

在主页面输入相关资料后,查看数据库是否发生改变即可(因为主页面的分页操作还未完成,我们无法在前台看到信息)

在介绍下一节之前,我们需要注意:

  • 数据库中的ID设为主键,意味着我们的账号只能设置单独的ID

因此,如果我们连续两次输入ID相同的员工创建,就会报错导致程序出现异常

因此我们需要对异常进行处理,异常处理通常分为两种方法:

  • 在Controller方法中使用try,catch进行异常捕获
  • 使用异常处理器进行全局异常捕获

第一种方法只能作用在当前情况下,但这种情况并不仅仅在当前情况出现,例如我们修改id如果修改为相同id也会报错

第二种方法可以作用在全局状态下,只要遇见这种问题,我们都会进行处理

因此我们采用第二种方法处理:

package com.qiuluo.reggie.common;

import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.*;

import java.sql.SQLIntegrityConstraintViolationException;

/**
 * 全局异常处理
 * @ControllerAdvice 来书写需要修改异常的注解类(该类中包含以下注解)
 * @ResponseBody 因为返回数据为JSON数据,需要进行格式转换
 */
@ControllerAdvice(annotations = {RestController.class, Controller.class})
@ResponseBody
@Slf4j
public class GlobalExceptionHandler {

    /**
     * 处理异常
     * @ExceptionHandler 来书写需要修改的异常
     * SQLIntegrityConstraintViolationException.class是我们错误时系统弹出的,直接复制即可
     * @return
     */
    @ExceptionHandler(SQLIntegrityConstraintViolationException.class)
    public Result<String> exceptionHandler(SQLIntegrityConstraintViolationException ex){

        // 我们可以通过log.error输出错误提醒
        // (我们可以得到以下提示信息:Duplicate entry '123' for key 'employee.idx_username')
        log.error(ex.getMessage());
        // 我们希望将id:123提取出来做一个简单的反馈信息
        if (ex.getMessage().contains("Duplicate entry")){
            String[] split = ex.getMessage().split(" ");
            String msg = split[2] + "已存在";
            return Result.error(msg);
        }
        return Result.error("未知错误");
    }

}

员工信息分页查询

我们的功能完善一般分为三步

我们要将数据库信息通过分页查询的方法查询出来并反馈到页面中

我们打开页面后,直接查找报错的部分,查看其请求信息以及相关URL:

2886527-20221020073617748-1037345948.png

打开负载,查看传递的信息:

2886527-20221020073622597-974814296.png

还需要注意的是,当我们输入查询信息后,我们会多一个参数name,这个参数也需要进行后台操作:

2886527-20221020073628788-594446724.png

我们需要注意的是我们采用的是数据库的分页查询,因此我们需要设置一个分页插件来将数据插入

此外我们的代码书写只需要采用page,pageSize查询数据,将name进行近似匹配并当作查询条件即可

首先我们先来实现分页插件:

package com.qiuluo.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;

/**
 * 配置MP的分页插件
 * 注意:设置为配置类,使Spring可以搜索到
 */
@Configuration
public class MyBatisPlusConfig {

    // 设置为Bean,受管理权限
    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        // 1.创建一个大型Interceptor 
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        // 2.添加PaginationInnerInterceptor进Interceptor里即可
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        // 3.返回Interceptor 
        return mybatisPlusInterceptor;
    }
}

接下来再来实现主页面的代码:

package com.qiuluo.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Employee;
import com.qiuluo.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

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

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

    @Autowired
    private EmployeeService employeeService;

    /**
     * 员工信息分页查询
     */
    @GetMapping("/page")
    public Result<Page> page(int page, int pageSize, String name){

        // 构造分页构造器
        Page pageInfo = new Page(page,pageSize);
        // 构造条件构造器
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
        // 添加排序条件
        queryWrapper.orderByDesc(Employee::getUpdateTime);
        // 执行查询
        employeeService.page(pageInfo,queryWrapper);
        return Result.success(pageInfo);
    }

}

打开主页面,数据出现即为成功

启动/禁用员工账号

我们的功能完善一般分为三步

当点击我们的员工行列后的启动/禁止,数据库的Status进行转换

我们同样点击后打开F12查看请求URL以及参数:

2886527-20221020073640901-641626591.png
2886527-20221020073645279-67209484.png

我们可以看到它将id作为判断员工的标准,将status的值传入便于我们修改

其中前端将修改状态的操作和修改员工信息的操作列为同一个请求,所以我们直接完成修改员工全部信息的操作即可

我们直接书写后端代码:

package com.qiuluo.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Employee;
import com.qiuluo.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

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

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

    @Autowired
    private EmployeeService employeeService;

    /**
     * 根据id修改员工信息
     * @param employee
     * @return
     */
    @PutMapping
    public Result<String> update(HttpServletRequest request,@RequestBody Employee employee){

        // 1.得到当前修改人的id
        long empId = (long)request.getSession().getAttribute("employee");

        // 2.对被修改员工的修改时间和修改人进行修改
        employee.setUpdateTime(LocalDateTime.now());
        employee.setUpdateUser(empId);

        // 3.直接将数据修改即可(被修改的数据已经被封装到了employee中,所以我们直接传递即可)
        employeeService.updateById(employee);

        return Result.success("更新成功");
    }

}

我们点击启动或者禁用,数据库或前端页面的状态码发生变化,即为成功

如果按照上述操作进行,是无法成功修改状态的,但是程序也不会发生报错

这是因为我们的数据库ID中设置长度为19位,但是我们的JS处理器的Long类型只能精确到前16位

这就会导致我们的ID数据的最后三位在传递时变化为000,导致前端传递ID与数据库实际ID无法匹配,无法成功修改

我们采用的处理方法是将服务端传递的JSON数据进行处理,我们希望将Long类型的数据全部转变为String类型,这样就不会省略为0

具体步骤如下:

  1. 提供对象转换器JacksonObjectMapper,基于Jackson进行Java对象到json数据的转换(资料提供)
package com.qiuluo.reggie.common;

import com.fasterxml.jackson.databind.DeserializationFeature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.module.SimpleModule;
import com.fasterxml.jackson.databind.ser.std.ToStringSerializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;

import java.math.BigInteger;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;

import static com.fasterxml.jackson.databind.DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES;

/**
 * 对象映射器:基于jackson将Java对象转为json,或者将json转为Java对象
 * 将JSON解析为Java对象的过程称为 [从JSON反序列化Java对象]
 * 从Java对象生成JSON的过程称为 [序列化Java对象到JSON]
 */
public class JacksonObjectMapper extends ObjectMapper {

    public static final String DEFAULT_DATE_FORMAT = "yyyy-MM-dd";
    public static final String DEFAULT_DATE_TIME_FORMAT = "yyyy-MM-dd HH:mm:ss";
    public static final String DEFAULT_TIME_FORMAT = "HH:mm:ss";

    public JacksonObjectMapper() {
        super();
        //收到未知属性时不报异常
        this.configure(FAIL_ON_UNKNOWN_PROPERTIES, false);

        //反序列化时,属性不存在的兼容处理
        this.getDeserializationConfig().withoutFeatures(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);


        SimpleModule simpleModule = new SimpleModule()
                .addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)))

                .addSerializer(BigInteger.class, ToStringSerializer.instance)
                .addSerializer(Long.class, ToStringSerializer.instance)
                .addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_TIME_FORMAT)))
                .addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ofPattern(DEFAULT_DATE_FORMAT)))
                .addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern(DEFAULT_TIME_FORMAT)));

        //注册功能模块 例如,可以添加自定义序列化器和反序列化器
        this.registerModule(simpleModule);
    }
}
  1. 在WebMvcConfig配置类中扩展springMvc的消息转换器,在此消息转换器中使用提供的对象转换器进行Java到Json数据的转换
package com.qiuluo.reggie.config;

import com.qiuluo.reggie.common.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.List;

@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        log.info("开始静态映射");

        registry.addResourceHandler("/backend/**").addResourceLocations("classpath:/backend/");
        registry.addResourceHandler("/front/**").addResourceLocations("classpath:/front/");

    }

    /**
     * 扩展mvc框架的消息转换器
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        log.info("扩展消息转换器...");
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }
}

编辑员工信息

我们的功能完善一般分为三步

当我们点击页面员工的编辑后,跳转页面:

2886527-20221020073658321-935789123.png

这里我们需要注意,我们的数据会直接出现在页面中,这说明我们在点击编辑时,后台会将我们的数据传递给前端,前端才能将数据展现出来

所以我们回到上一步,F12查看操作:

2886527-20221020073703599-776889525.png

我们会发现,它调用了GET类型的请求,并将我们的id传入,这说明我们需要创建一个路径来根据id获得数据

然后我们点击编辑里的保存,查看F12:

2886527-20221020073709304-1117731134.png

我们会发现,这个路径和我们上一步实现的启动禁用账号的路径相同,所以当我们点击修改后自动调用根据id修改参数的方法

我们只需要实现第一个方法根据ID获得数据即可:

package com.qiuluo.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Employee;
import com.qiuluo.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

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

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

    @Autowired
    private EmployeeService employeeService;

    /**
     * 根据id查询员工
     * @param id
     * @return
     */
    @GetMapping("/{id}")
    public Result<Employee> getById(@PathVariable Long id){

        // 根据路径获得id,直接调用业务层方法获得employee
        Employee emp = employeeService.getById(id);
        if (emp != null){
            return Result.success(emp);
        }else {
            return Result.error("未查询成功");
        }
    }
}

返回主页面,点击员工后面的编辑后,跳转页面时带有数据即可

在这里我们会点出该项目目前容易出错的位置

过滤器的使用

Filter也称之为过滤器,它是Servlet技术中的技术,Web开发人员通过Filter技术,对web服务器管理的所有web资源

实现步骤主要分为两步:

  1. 创建Java类,添加注解,继承Filter
package com.qiuluo.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
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注解配置相关信息
@WebFilter(filterName = "loginCheckFilter",urlPatterns = "/*")
public class LoginCheckFilter implements Filter{

}
  1. 继承并书写doFilter方法
package com.qiuluo.reggie.filter;

import com.alibaba.fastjson.JSON;
import com.qiuluo.reggie.common.Result;
import lombok.extern.slf4j.Slf4j;
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();

    
    /*
    doFilter用来实现过滤功能
    在最开始我们设置了需要过滤的路径
    doFilter里在来设置在该路径下哪些路径可以直接跳过
    doFilter里也可以设置需要经过哪些判断或哪些处理才能经过
    filterChain携带req和resp来表示通过过滤器    
    */
    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        //1、获取本次请求的URI
        String requestURI = request.getRequestURI();// /backend/index.html

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

        //定义不需要处理的请求路径
        String[] urls = new String[]{
                "/employee/login",
                "/employee/logout",
                "/backend/**",
                "/front/**"
        };


        //2、判断本次请求是否需要处理
        boolean check = check(urls, requestURI);

        //3、如果不需要处理,则直接放行
        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(Result.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;
            }
        }
        return false;
    }
}

数据库的分页操作

数据库的分页操作需要在数据库内部的特定位置(limit)处修改值

所以需要设置一个MyBatisPlus拦截器来完成操作,MyBatisPlus已经为我们简化了步骤,我们只需要将相对应的拦截器添加即可:

package com.qiuluo.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;

/**
 * 配置MP的分页插件
 */
@Configuration
public class MyBatisPlusConfig {

    @Bean
    public MybatisPlusInterceptor mybatisPlusInterceptor(){
        MybatisPlusInterceptor mybatisPlusInterceptor = new MybatisPlusInterceptor();
        mybatisPlusInterceptor.addInnerInterceptor(new PaginationInnerInterceptor());
        return mybatisPlusInterceptor;
    }
}

然后我们就需要注意业务层继承的实现类中所给的方法的参数即可:

package com.qiuluo.reggie.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.qiuluo.reggie.common.Result;
import com.qiuluo.reggie.domain.Employee;
import com.qiuluo.reggie.service.EmployeeService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.DigestUtils;
import org.springframework.web.bind.annotation.*;

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

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

    @Autowired
    private EmployeeService employeeService;

    /**
     * 员工信息分页查询
     */
    @GetMapping("/page")
    public Result<Page> page(int page, int pageSize, String name){

        // 构造分页构造器
        Page pageInfo = new Page(page,pageSize);
        // 构造条件构造器
        LambdaQueryWrapper<Employee> queryWrapper = new LambdaQueryWrapper<>();
        // 这里是一个like自带的判断,如果StringUtils.isNotEmpty(name)为true,才会执行该操作,否则无效
        queryWrapper.like(StringUtils.isNotEmpty(name),Employee::getName,name);
        // 添加排序条件
        queryWrapper.orderByDesc(Employee::getUpdateTime);
        // 执行查询(参数为Page和qw类型,所以我们前面创建相应类型填充数据)
        employeeService.page(pageInfo,queryWrapper);
        return Result.success(pageInfo);
    }

}

消息转换器

首先我们来简单解释一下消息转换器是什么:

  • 消息转换器用于将请求/响应体内部的数据提取出来
  • 例如在请求体中是URL的一部分,但是我们的后台代码中却是参数
  • 消息转换器就是用于这一部分参数的转换,系统中配置了许多默认的消息转换器

但默认的消息转换器有时不能满足我们的需求,例如上述异常处理中,我们希望直接将JSON数据转化为String类型的数据

这时我们就需要手动设置消息转换器:

package com.qiuluo.reggie.config;

import com.qiuluo.reggie.common.JacksonObjectMapper;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;

import java.util.List;

@Slf4j
@Configuration
public class WebMvcConfig extends WebMvcConfigurationSupport {

    /**
     * 扩展mvc框架的消息转换器
     * 其中JacksonObjectMapper是我们自己创建的/下载的消息转换器,里面设置了我们所需要的转换方式
     * 下述操作只是将该转换器添加到系统的转换器队列中,以便于能够执行该转换器的操作
     * @param converters
     */
    @Override
    protected void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        //创建消息转换器对象
        MappingJackson2HttpMessageConverter messageConverter = new MappingJackson2HttpMessageConverter();
        //设置对象转换器,底层使用Jackson将Java对象转为json
        messageConverter.setObjectMapper(new JacksonObjectMapper());
        //将上面的消息转换器对象追加到mvc框架的转换器集合中
        converters.add(0,messageConverter);
    }
}

该篇内容到这里就结束了,希望能为你带来帮助~

该文章属于学习内容,具体参考B站黑马程序员的Java项目实战《瑞吉外卖》

这里附上视频链接:业务开发Day2-01-本章内容介绍_哔哩哔哩_bilibili


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK