瑞吉外賣實戰項目全攻略——第二天

瑞吉外賣實戰項目全攻略——第二天

該系列將記錄一份完整的實戰項目的完成過程,該篇屬於第二天

案例來自B站黑馬程序員Java項目實戰《瑞吉外賣》,請結合課程資料閱讀以下內容

該篇我們將完成以下內容:

  • 完善登陸系統
  • 新增員工
  • 員工信息分頁查詢
  • 啟用/禁止員工賬號
  • 編輯員工信息

完善登陸系統

我們的功能完善一般分為三步

需求分析

我們在前面的文章中已經實現了login的系統登錄

但是我們頁面的訪問並沒有設置限制,如果我們直接跳過登陸頁面直接輸入系統內部頁面的url同樣可以進入

所以我們在進入內部頁面時需要先進行檢測用戶是否登錄

我們在之前的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的形式發送給後端端口

我們打開F12,輸入數據點擊保存後查看數據的請求方式(點擊負載,可以查看到填寫信息的Employee內容,這裡不再展示):

這個請求方式的路徑就是我們需要完善的代碼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:

打開負載,查看傳遞的信息:

還需要注意的是,當我們輸入查詢信息後,我們會多一個參數name,這個參數也需要進行後台操作:

我們需要注意的是我們採用的是數據庫的分頁查詢,因此我們需要設置一個分頁插件來將數據插入

此外我們的代碼書寫只需要採用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以及參數:

我們可以看到它將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);
    }
}

編輯員工信息

我們的功能完善一般分為三步

需求分析

當我們點擊頁面員工的編輯後,跳轉頁面:

這裡我們需要注意,我們的數據會直接出現在頁面中,這說明我們在點擊編輯時,後台會將我們的數據傳遞給前端,前端才能將數據展現出來

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

我們會發現,它調用了GET類型的請求,並將我們的id傳入,這說明我們需要創建一個路徑來根據id獲得數據

然後我們點擊編輯里的保存,查看F12:

我們會發現,這個路徑和我們上一步實現的啟動禁用賬號的路徑相同,所以當我們點擊修改後自動調用根據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