最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Spring Boot 中的橫切邏輯統(tǒng)一治理方案

 更新時(shí)間:2026年02月26日 09:55:19   作者:手握風(fēng)云-  
攔截器是Spring框架提供的核心功能之一,核心用于統(tǒng)一攔截用戶的請求,文章主要介紹了Spring框架中的攔截器、統(tǒng)一數(shù)據(jù)返回格式和統(tǒng)一異常處理,本文給大家介紹的非常詳細(xì),感興趣的朋友跟隨小編一起看看吧

一、攔截器

        攔截器是 Spring 框架提供的核心功能之一,核心用于統(tǒng)一攔截用戶的請求,可在目標(biāo)方法執(zhí)行前后執(zhí)行預(yù)先設(shè)定的通用代碼,也能在請求執(zhí)行前阻止其繼續(xù)運(yùn)行,常用來實(shí)現(xiàn)登錄校驗(yàn)、日志記錄等通用操作,是解決接口通用功能處理的高效方式,其入門核心圍繞定義攔截器注冊配置攔截器兩步展開。

1.1. 攔截器入門

1. 攔截器核心定義

        攔截器允許開發(fā)人員在應(yīng)用程序中對請求做通用性處理,在用戶請求響應(yīng)的前后插入自定義邏輯,也可根據(jù)業(yè)務(wù)需求攔截請求(如判斷 Session 中是否有登錄信息,無則攔截請求,有則放行)。就如同學(xué)校的保安,他需要判斷哪些人能進(jìn),哪些人不能進(jìn)。

        攔截器的實(shí)現(xiàn)需要完成自定義攔截器注冊配置攔截器兩個(gè)核心步驟,缺一不可,且需通過指定注解讓 Spring 容器管理相關(guān)類。自定義攔截器相當(dāng)于告知保安的工作,注冊配置攔截器相當(dāng)于將保安放到指定的崗位上。

2. 定義攔截器

package org.springframework.web.servlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.jspecify.annotations.Nullable;
public interface HandlerInterceptor {
    default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        return true;
    }
    default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
    }
    default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
    }
}

        自定義類實(shí)現(xiàn) Spring 提供的 HandlerInterceptor 接口,并重寫里面的方法。preHandle 方法在請求到達(dá)具體的控制器方法之前執(zhí)行,它是攔截器中最先被調(diào)用的方法。該方法返回一個(gè)布爾值,如果返回 true,表示請求繼續(xù)向下傳遞,進(jìn)入后續(xù)的攔截器或控制器;如果返回 false,則表示請求被終止。postHandle 方法在控制器方法執(zhí)行完畢之后,但在視圖渲染之前執(zhí)行。這意味著在這個(gè)階段,開發(fā)者已經(jīng)可以訪問到控制器處理后的 ModelAndView 對象,因此常用于對模型數(shù)據(jù)進(jìn)行統(tǒng)一的修改或補(bǔ)充,或者根據(jù)不同的視圖需求進(jìn)行相應(yīng)的處理。afterCompletion 方法在整個(gè)請求處理完成之后執(zhí)行,即在視圖渲染結(jié)束后進(jìn)行回調(diào)。無論請求是否成功,只要 preHandle 返回了 true,該方法最終都會(huì)被執(zhí)行。

3. 注冊配置攔截器

package com.yang.test2_22_1.config;
import com.yang.test2_22_1.interceptor.LoginInterceptor;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LoginInterceptor()).addPathPatterns("/**");
    }
}

1.2. 攔截器詳解

1. 攔截路徑

        攔截路徑用于指定自定義攔截器對哪些請求生效,在注冊配置攔截器時(shí)通過兩個(gè)核心方法配置:addPathPatterns(),指定需要攔截的請求路徑;excludePathPatterns(),指定需要排除、不進(jìn)行攔截的請求路徑。

        攔截路徑支持通配符匹配,核心規(guī)則如下表,規(guī)則可攔截項(xiàng)目中所有 URL(包括圖片、JS、CSS 等靜態(tài)文件):

攔截路徑含義
/*一級路徑
/**任意級路徑
/api/*/api下的一級路徑
/api/**/api下的任意級路徑
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**") // 攔截所有請求
                .excludePathPatterns("/api/login"); // 排除登錄請求,不攔截
    }
}

2. 攔截器執(zhí)行流程

        正常的調(diào)用順序:

        有了攔截器之后的調(diào)用順序:

        攔截器核心作用是在Controller層方法前后插入自定義邏輯,其執(zhí)行流程依賴HandlerInterceptor 接口三個(gè)核心方法,與SpringMVC請求流轉(zhuǎn)緊密相關(guān)。無攔截器時(shí),請求按“用戶請求→Controller→Service→Mapper→數(shù)據(jù)庫”流轉(zhuǎn),處理后原路返回。添加攔截器后,請求先被攔截:到達(dá)Controller前執(zhí)行preHandle(),返回true放行繼續(xù),返回false中斷;若preHandle()返回true,請求正常流轉(zhuǎn),Controller目標(biāo)方法執(zhí)行完、視圖渲染前執(zhí)行postHandle()(后端少用);視圖渲染完畢執(zhí)行afterCompletion()用于收尾。核心方法執(zhí)行順序?yàn)閜reHandle()(Controller前)→目標(biāo)Controller方法→postHandle()(Controller后、視圖渲染前)→afterCompletion()(視圖渲染后),postHandle() 和 afterCompletion() 僅在 preHandle() 返回true時(shí)執(zhí)行。 

1.3. 登錄校驗(yàn)

package com.yang.test2_22_1.controller;
import com.yang.test2_22_1.model.User;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
@RestController
@RequestMapping("/api")
public class LoginController {
    @PostMapping("/login")
    public Map<String, Object> processLogin(@RequestBody User user) {
        Map<String, Object> response = new HashMap<>();
        String validUsername = "admin";
        String validPassword = "password123";
        if (validUsername.equals(user.getUsername()) && validPassword.equals(user.getPassword())) {
            response.put("success", true);
            response.put("message", "登錄成功!歡迎回來," + user.getUsername() + "。");
        } else {
            response.put("success", false);
            response.put("message", "用戶名或密碼錯(cuò)誤,請重試。");
        }
        return response;
    }
    @GetMapping("/secret")
    public String getSecretInfo() {
        return "這是一條機(jī)密信息,只有登錄后的用戶才能看到!";
    }
}
package com.yang.test2_22_1.interceptor;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.jspecify.annotations.Nullable;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
@Slf4j
@Component
public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        Object loginUser = request.getSession().getAttribute("LOGIN_USER");
        if (loginUser == null) {
            response.setStatus(HttpServletResponse.SC_ACCEPTED);
            response.setContentType("application/json;charset=UTF-8");
            response.getWriter().write("{\"error\": \"未登錄,請先登錄系統(tǒng)\"}");
            return false;
        }
        log.info("執(zhí)行 preHandle 方法");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
        log.info("執(zhí)行 postHandle 方法");
    }
}
package com.yang.test2_22_1.config;
import com.yang.test2_22_1.interceptor.LoginInterceptor;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Autowired
    private LoginInterceptor loginInterceptor;
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(loginInterceptor)
                .addPathPatterns("/**")
                .excludePathPatterns("/api/login", "/api/secret");
    }
}

二、統(tǒng)一數(shù)據(jù)返回格式

2.1. 快速入門

        統(tǒng)一的數(shù)據(jù)返回格式通過 @ControllerAdvice + ResponseBodyAdvice 組合實(shí)現(xiàn),核心是對所有接口的返回結(jié)果進(jìn)行統(tǒng)一封裝,簡化前后端交互。

        @ControllerAdvice:控制器通知類,用于全局?jǐn)r截控制器的返回結(jié)果和異常,是實(shí)現(xiàn)統(tǒng)一處理的基礎(chǔ)注解;ResponseBodyAdvice:響應(yīng)體增強(qiáng)接口,提供對返回?cái)?shù)據(jù)的攔截和修改能力,需重寫其核心方法。@RestControllerAdvice 注解是包含了 @ControllerAdvice 和 ResponseBodyAdvice,方法返回值直接寫入 HTTP 響應(yīng)體 (Body),通常轉(zhuǎn)換為 JSON/XML 數(shù)據(jù)。

import com.example.demo.model.Result;
import org.springframework.core.MethodParameter;
import org.springframework.http.MediaType;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;
@ControllerAdvice
public class ResponseAdvice implements ResponseBodyAdvice {
    // 判斷是否執(zhí)行beforeBodyWrite方法(true=執(zhí)行,false=不執(zhí)行)
    @Override
    public boolean supports(MethodParameter returnType, Class converterType) {
        return true; // 對所有接口的返回結(jié)果都進(jìn)行統(tǒng)一封裝
    }
    // 對返回?cái)?shù)據(jù)進(jìn)行具體封裝處理
    @Override
    public Object beforeBodyWrite(Object body, MethodParameter returnType, 
                                  MediaType selectedContentType, Class selectedConverterType, 
                                  ServerHttpRequest request, ServerHttpResponse response) {
        return Result.success(body); // 調(diào)用Result工具類封裝數(shù)據(jù)
    }
}

        supports 方法作用是控制哪些接口的返回結(jié)果需要被統(tǒng)一處理,并且可通過 returnType 獲取當(dāng)前執(zhí)行的類名和方法名,實(shí)現(xiàn)精準(zhǔn)匹配。

// 獲取當(dāng)前執(zhí)行的控制器類
Class<?> declaringClass = returnType.getMethod().getDeclaringClass();
// 獲取當(dāng)前執(zhí)行的方法
Method method = returnType.getMethod();

        beforeBodyWrite 方法作用是對接口返回的原始數(shù)據(jù)(body)進(jìn)行封裝,返回統(tǒng)一格式的 Result 對象。依賴 Result 工具類:需提前定義 Result 泛型類,包含 status(狀態(tài))、errorMessage(錯(cuò)誤信息)、data(業(yè)務(wù)數(shù)據(jù))三個(gè)核心字段。

三、統(tǒng)一異常處理

        SpringBoot 中統(tǒng)一異常處理核心通過 @ControllerAdvice + @ExceptionHandler 注解組合實(shí)現(xiàn),實(shí)現(xiàn)了項(xiàng)目中異常的統(tǒng)一捕獲、處理和返回格式標(biāo)準(zhǔn)化,避免零散的異常處理邏輯,降低前后端溝通和開發(fā)成本。

3.1. 核心注解

  • @ControllerAdvice:標(biāo)識為控制器通知類,作用于全局,可捕獲所有控制器層拋出的異常;
  • @ExceptionHandler:異常處理器注解,標(biāo)注在方法上,指定該方法處理的異常類型;
  • @ResponseBody:若需要將異常處理結(jié)果以 JSON 等數(shù)據(jù)格式返回給前端,需在類或方法上添加該注解。

3.2. 基礎(chǔ)實(shí)現(xiàn)方式

  • 創(chuàng)建全局異常處理類,添加@ControllerAdvice和@ResponseBody注解;
  • 定義異常處理方法,添加@ExceptionHandler注解,方法參數(shù)為需要處理的異常類型(如Exception),返回項(xiàng)目統(tǒng)一的結(jié)果對象(如Result);
  • 方法名、類名無強(qiáng)制要求,核心是注解的正確使用,方法內(nèi)可通過異常對象獲取信息并封裝統(tǒng)一的失敗返回結(jié)果。

3.3. 異常匹配順序

        當(dāng)存在多個(gè)異常處理方法時(shí),優(yōu)先匹配最具體的異常類型,匹配規(guī)則為:當(dāng)前異常類及其子類向上依次匹配

  • 底層通過ExceptionDepthComparator按異常深度排序,拋出的異常與處理方法聲明的異常類型深度越小,優(yōu)先級越高;
  • 例如:空指針異常(NullPointerException)會(huì)優(yōu)先匹配標(biāo)注@ExceptionHandler(NullPointerException.class)的方法,而非處理通用Exception的方法。
package com.yang.test2_25_1.exception;
import com.yang.test2_25_1.common.ApiResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 處理用戶未找到異常
     */
    @ExceptionHandler(UserNotFoundException.class)
    public ApiResponse<Void> handleUserNotFoundException(UserNotFoundException e) {
        log.warn("參數(shù)異常:{}", e.getMessage());
        return ApiResponse.error(404, e.getMessage());
    }
    /**
     * 處理參數(shù)異常
     */
    @ExceptionHandler(IllegalArgumentException.class)
    public ApiResponse<Void> handleIllegalArgumentException(IllegalArgumentException e) {
        log.warn("參數(shù)異常:{}", e.getMessage());
        return ApiResponse.error(400, e.getMessage());
    }
    /**
     * 處理所有異常
     */
    @ExceptionHandler(Exception.class)
    public ApiResponse<Void> handleException(Exception e) {
        log.error("系統(tǒng)內(nèi)部發(fā)生未知異常", e.getMessage());
        return ApiResponse.error(500, "服務(wù)器內(nèi)部開小差了,請稍后再試");
    }
}

3.4. 核心效果

  • 所有異常統(tǒng)一捕獲,返回格式與項(xiàng)目統(tǒng)一數(shù)據(jù)返回格式保持一致(如Result對象),方便前端統(tǒng)一解析;
  • 避免出現(xiàn)前端接收到雜亂的原生異常信息,減少前后端對接問題;
  • 項(xiàng)目異常處理邏輯集中管理,便于維護(hù)和修改,統(tǒng)一后端技術(shù)規(guī)范。

到此這篇關(guān)于Spring Boot 中的橫切邏輯統(tǒng)一治理方案的文章就介紹到這了,更多相關(guān)Spring Boot 橫切邏輯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 詳解如何將JAR包發(fā)布到Maven中央倉庫

    詳解如何將JAR包發(fā)布到Maven中央倉庫

    這篇文章主要介紹了詳解如何將JAR包發(fā)布到Maven中央倉庫,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-01-01
  • 過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    過濾器 和 攔截器的 6個(gè)區(qū)別(別再傻傻分不清了)

    這篇文章主要介紹了過濾器 和 攔截器的 6個(gè)區(qū)別,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-06-06
  • idea的spring boot項(xiàng)目實(shí)現(xiàn)更改端口號操作

    idea的spring boot項(xiàng)目實(shí)現(xiàn)更改端口號操作

    這篇文章主要介紹了idea的spring boot項(xiàng)目實(shí)現(xiàn)更改端口號操作,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2020-09-09
  • Spring Boot 自定義 Shiro 過濾器無法使用 @Autowired問題及解決方法

    Spring Boot 自定義 Shiro 過濾器無法使用 @Autowired問題及解決方法

    這篇文章主要介紹了Spring Boot 自定義 Shiro 過濾器無法使用 @Autowired問題及解決方法 ,本文給大家介紹的非常詳細(xì),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2019-06-06
  • Java向上轉(zhuǎn)型與向下轉(zhuǎn)型超詳細(xì)圖解

    Java向上轉(zhuǎn)型與向下轉(zhuǎn)型超詳細(xì)圖解

    我們在Java編程中經(jīng)常碰到類型轉(zhuǎn)換,對象類型轉(zhuǎn)換主要包括向上轉(zhuǎn)型和向下轉(zhuǎn)型,這篇文章主要介紹了Java向上轉(zhuǎn)型與向下轉(zhuǎn)型的相關(guān)資料,文中通過代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2025-04-04
  • Springboot?上傳文件或頭像(MultipartFile、transferTo)

    Springboot?上傳文件或頭像(MultipartFile、transferTo)

    本文主要介紹了Springboot?上傳文件或頭像(MultipartFile、transferTo),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2023-04-04
  • idea自帶database連接mysql失敗問題的解決辦法

    idea自帶database連接mysql失敗問題的解決辦法

    在IDEA?帶的數(shù)據(jù)庫連接?具中,可以連接MySQL數(shù)據(jù)庫,但是有的時(shí)候連接出現(xiàn)錯(cuò)誤,連接不上數(shù)據(jù)庫,下面這篇文章主要給大家介紹了關(guān)于idea自帶database連接mysql失敗問題的解決辦法,需要的朋友可以參考下
    2023-06-06
  • Java中this和super關(guān)鍵字的使用詳解

    Java中this和super關(guān)鍵字的使用詳解

    super?代表父類的存儲(chǔ)空間標(biāo)識(可以理解為父親的引用)。?this代表當(dāng)前對象的引用(誰調(diào)用就代表誰)。本文將通過簡單的示例介紹二者的使用與區(qū)別,需要的可以了解一下
    2022-10-10
  • SpringBoot2整合Redis實(shí)現(xiàn)讀寫操作

    SpringBoot2整合Redis實(shí)現(xiàn)讀寫操作

    Redis,對于大家來說應(yīng)該不陌生,是經(jīng)常使用的開發(fā)技術(shù)之一。本文將結(jié)合實(shí)例代碼,介紹SpringBoot2整合Redis實(shí)現(xiàn)讀寫操作,感興趣的小伙伴們可以參考一下
    2021-07-07
  • Java實(shí)現(xiàn)批量向mysql寫入數(shù)據(jù)的方法

    Java實(shí)現(xiàn)批量向mysql寫入數(shù)據(jù)的方法

    這篇文章主要介紹了Java實(shí)現(xiàn)批量向mysql寫入數(shù)據(jù)的方法,涉及java基于JDBC連接mysql數(shù)據(jù)庫及寫入數(shù)據(jù)的相關(guān)操作技巧,非常簡單實(shí)用,需要的朋友可以參考下
    2017-12-12

最新評論

淮阳县| 突泉县| 正蓝旗| 图木舒克市| 五峰| 巍山| 浮山县| 康乐县| 科技| 依安县| 天门市| 松阳县| 承德县| 米易县| 庐江县| 平和县| 三江| 湖北省| 津南区| 五华县| 宜州市| 奉节县| 新竹县| 孝感市| 阿拉尔市| 兰溪市| 甘洛县| 巴马| 太仓市| 泸溪县| 丘北县| 麻城市| 仁寿县| 横山县| 开鲁县| 蚌埠市| 龙岩市| 临泉县| 安阳县| 荣成市| 察哈|