瑞吉外賣實戰專案全攻略——第二天

2022-10-20 09:00:22

瑞吉外賣實戰專案全攻略——第二天

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

案例來自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