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

SpringBoot使用@ControllerAdvice進行統(tǒng)一處理異常詳解

 更新時間:2026年01月07日 08:38:46   作者:程序員大華  
在實際開發(fā)中,程序運行時難免會遇到各種意外,如果不做統(tǒng)一處理,用戶可能會看到一堆錯誤信息,下面我們就來看看SpringBoot如何使用@ControllerAdvice進行統(tǒng)一處理異常吧

一、什么是全局異常處理?

在實際開發(fā)中,程序運行時難免會遇到各種意外。這些意外在 Java 中就表現(xiàn)為異常(Exception)。如果不做統(tǒng)一處理,用戶可能會看到一堆錯誤信息。

常見場景

  • NullPointerException(空指針異常):前端傳了一個用戶 ID,但后端沒做判空,直接調(diào)用 user.getName(),結(jié)果 user 是 null 導(dǎo)致程序崩潰!
  • SQLException(數(shù)據(jù)庫連接失?。簲?shù)據(jù)庫宕機或網(wǎng)絡(luò)中斷,導(dǎo)致查詢失敗,直接拋出 SQL 異常。
  • NumberFormatException(參數(shù)格式錯誤):前端傳了個字符串 "abc",后端試圖用 Integer.parseInt() 轉(zhuǎn)成數(shù)字失??!

如果不做處理,會發(fā)生什么

SpringBoot 默認(rèn)會把異常的完整堆棧信息原樣返回給前端,比如:

{
  "timestamp": "2025-11-26T12:00:00",
  "status": 500,
  "error": "Internal Server Error",
  "message": "/ by zero",
  "path": "/api/calculate"
}

甚至在開發(fā)環(huán)境下,還可能返回幾十行 Java 堆棧,這些會導(dǎo)致以下以下問題:

  • 用戶看不懂,
  • 前端無法統(tǒng)一處理,
  • 更嚴(yán)重的是:可能泄露類名、方法名、服務(wù)器路徑等敏感信息!

有了全局異常處理,就能

  • 攔截所有異常,統(tǒng)一返回結(jié)構(gòu)化錯誤信息
  • 區(qū)分不同異常類型,返回不同的狀態(tài)碼和提示語
  • 自動記錄日志,方便排查問題
  • 避免敏感信息外泄,提升系統(tǒng)安全性

最終返回給前端的,可能是這樣一段干凈、友好的 JSON:

{
  "code": 400,
  "message": "用戶ID不能為空",
  "data": null
}

或者:

{
  "code": 200,
  "message": "訂單創(chuàng)建成功",
  "data": true
}

是不是清爽又專業(yè)多了

二、如何做異常處理

傳統(tǒng)做法(不推薦)

每個 Controller 方法里都寫 try-catch

@GetMapping("/user/{id}")
public ResponseEntity getUser(@PathVariable Long id) {
    try {
        User user = userService.findById(id);
        return ResponseEntity.ok(user);
    } catch (UserNotFoundException e) {
        return ResponseEntity.status(404).body("用戶不存在");
    } catch (Exception e) {
        return ResponseEntity.status(500).body("系統(tǒng)錯誤");
    }
}

問題很明顯:

  • 代碼重復(fù)
  • 難維護
  • 容易漏掉

全局異常處理(推薦)

只寫一次,全局生效!

下面主要寫 SpringBoot 的處理。

三、SpringBoot 中如何實現(xiàn)全局異常處理?

核心就靠一個注解:@ControllerAdvice

第一步:定義統(tǒng)一的錯誤響應(yīng)格式

// 統(tǒng)一返回結(jié)構(gòu),前端好解析
public class ErrorResponse {
    private int code;
    private String message;
    private Object data; // 一般為 null,但保留擴展性

    public ErrorResponse(int code, String message) {
        this.code = code;
        this.message = message;
    }

    // getter / setter 省略(實際項目中建議用 Lombok)
}

第二步:創(chuàng)建全局異常處理器類

// 1. 創(chuàng)建一個類,加上 @ControllerAdvice 注解
@ControllerAdvice
public class GlobalExceptionHandler {

    // 2. 用 @ExceptionHandler 捕獲特定異常
    @ExceptionHandler(UserNotFoundException.class)
    public ResponseEntity handleUserNotFound(UserNotFoundException e) {
        ErrorResponse error = new ErrorResponse(404, e.getMessage());
        return ResponseEntity.status(404).body(error);
    }

    // 3. 捕獲所有其他異常(兜底)
    @ExceptionHandler(Exception.class)
    public ResponseEntity handleGenericException(Exception e) {
        ErrorResponse error = new ErrorResponse(500, "服務(wù)器內(nèi)部錯誤,請聯(lián)系管理員");
        return ResponseEntity.status(500).body(error);
    }
}

第三步:自定義業(yè)務(wù)異常(可選但推薦)

// 自定義業(yè)務(wù)異常
public class BusinessException extends RuntimeException {
    private Integer code;
    
    public BusinessException(Integer code, String message) {
        super(message);
        this.code = code;
    }
    
    // getter省略
}

然后在 Service 層這樣用:

public User findById(Long id) {
    if (id == null || id <= 0) {
        throw new BusinessException(&#34;用戶ID無效&#34;);
    }
    // 查詢數(shù)據(jù)庫...
}

可以說配置全局異常是比較簡單的,可能因為簡單,或者是項目里本來就配置的有,所以很多朋友直接忽略掉了這些問題。

四、更智能的異常處理

1. 區(qū)分 Controller 和 REST 接口

如果你既有頁面(返回 HTML),又有 API(返回 JSON),可以用:

@ControllerAdvice(annotations = RestController.class)
public class RestGlobalExceptionHandler {
    // 只處理 @RestController 的異常
}

或者指定包路徑:

@ControllerAdvice(basePackages = &#34;com.example.api&#34;)
public class ApiExceptionHandler { ... }

2. 處理參數(shù)校驗異常(如 @Valid)

SpringBoot 自帶校驗框架,校驗失敗會拋 MethodArgumentNotValidException

@ExceptionHandler(MethodArgumentNotValidException.class)
public ResponseEntity handleValidation(MethodArgumentNotValidException e) {
    String msg = e.getBindingResult().getFieldError().getDefaultMessage();
    return ResponseEntity.badRequest().body(new ErrorResponse(400, msg));
}

3. 記錄日志(非常重要!)

handleGenericException 中加入日志:

private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(Exception.class)
public ResponseEntity handleGenericException(Exception e) {
    log.error(&#34;系統(tǒng)發(fā)生未預(yù)期異常&#34;, e); // 記錄完整堆棧
    return ResponseEntity.status(500).body(new ErrorResponse(500, &#34;服務(wù)器開小差啦~&#34;));
}

五、深入理解@ControllerAdvice

很多同學(xué)可能會好奇:為什么加了@ControllerAdvice后,異常就能被自動捕獲呢?

其實原理很簡單:

  • Spring MVC 在處理請求時,如果 Controller 方法拋出異常
  • Spring 會查找有沒有對應(yīng)的異常處理器(@ExceptionHandler
  • 查找順序是:先找當(dāng)前 Controller 中的 @ExceptionHandler 方法
  • 如果當(dāng)前 Controller 沒有,就找 @ControllerAdvice 標(biāo)注的類中的 @ExceptionHandler 方法
  • 找到匹配的異常處理器后,調(diào)用對應(yīng)的方法處理異常

最佳實踐建議

1. 定義清晰的異常體系

// 基礎(chǔ)異常類
public class BaseException extends RuntimeException {
    private Integer code;
    
    public BaseException(Integer code, String message) {
        super(message);
        this.code = code;
    }
}

// 各種具體異常
public class BusinessException extends BaseException {
    public BusinessException(Integer code, String message) {
        super(code, message);
    }
}

public class SystemException extends BaseException {
    public SystemException(Integer code, String message) {
        super(code, message);
    }
}

2. 使用枚舉管理錯誤碼

public enum ErrorCode {
    SUCCESS(200, &#34;成功&#34;),
    PARAM_ERROR(400, &#34;參數(shù)錯誤&#34;),
    UNAUTHORIZED(401, &#34;未授權(quán)&#34;),
    FORBIDDEN(403, &#34;禁止訪問&#34;),
    NOT_FOUND(404, &#34;資源不存在&#34;),
    SYSTEM_ERROR(500, &#34;系統(tǒng)錯誤&#34;);
    
    private final Integer code;
    private final String message;
    
    ErrorCode(Integer code, String message) {
        this.code = code;
        this.message = message;
    }
    
    // getter方法
}

3. 日志記錄要恰當(dāng)

  • 業(yè)務(wù)異常:一般用warn級別,不需要記錄堆棧
  • 系統(tǒng)異常:用error級別,需要記錄堆棧信息

完整示例代碼

// 統(tǒng)一返回結(jié)果
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result {
    private Integer code;
    private String message;
    private T data;
    
    public static  Result success(T data) {
        return new Result<>(200, &#34;成功&#34;, data);
    }
    
    public static  Result error(Integer code, String message) {
        return new Result<>(code, message, null);
    }
}

// 全局異常處理器
@RestControllerAdvice
public class GlobalExceptionHandler {
    
    private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);
    
    // 處理業(yè)務(wù)異常
    @ExceptionHandler(BusinessException.class)
    public Result handleBusinessException(BusinessException e) {
        logger.warn(&#34;業(yè)務(wù)異常:code={}, message={}&#34;, e.getCode(), e.getMessage());
        return Result.error(e.getCode(), e.getMessage());
    }
    
    // 處理參數(shù)校驗異常
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result handleMethodArgumentNotValidException(MethodArgumentNotValidException e) {
        String message = e.getBindingResult().getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.joining(&#34;, &#34;));
        return Result.error(400, message);
    }
    
    // 處理所有其他異常
    @ExceptionHandler(Exception.class)
    public Result handleException(Exception e) {
        logger.error(&#34;系統(tǒng)異常:&#34;, e);
        return Result.error(500, &#34;系統(tǒng)繁忙,請稍后重試&#34;);
    }
}

總結(jié)

統(tǒng)一格式:前后端約定好錯誤結(jié)構(gòu),溝通更順暢

減少重復(fù)代碼:不用每個方法寫 try-catch

提升健壯性:兜底處理防止系統(tǒng)崩潰,還能記錄日志

到此這篇關(guān)于SpringBoot使用@ControllerAdvice進行統(tǒng)一處理異常詳解的文章就介紹到這了,更多相關(guān)SpringBoot異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java使用ZipInputStream實現(xiàn)讀取和寫入zip文件

    java使用ZipInputStream實現(xiàn)讀取和寫入zip文件

    zip文檔可以以壓縮格式存儲一個或多個文件,本文主要為大家詳細(xì)介紹了java如何使用ZipInputStream讀取Zip文檔與寫入,需要的小伙伴可以參考下
    2023-11-11
  • java獲取系統(tǒng)路徑字體、得到某個目錄下的所有文件名、獲取當(dāng)前路徑

    java獲取系統(tǒng)路徑字體、得到某個目錄下的所有文件名、獲取當(dāng)前路徑

    這篇文章主要介紹了java獲取系統(tǒng)路徑字體、得到某個目錄下的所有文件名、獲取當(dāng)前路徑,需要的朋友可以參考下
    2014-04-04
  • JavaEE中關(guān)于ServletConfig的小結(jié)

    JavaEE中關(guān)于ServletConfig的小結(jié)

    ServletConfig是針對特定的Servlet的參數(shù)或?qū)傩?。ServletConfig是表示單獨的Servlet的配置和參數(shù),只是適用于特定的Servlet。從一個servlet被實例化后,對任何客戶端在任何時候訪問有效,但僅對本servlet有效,一個servlet的ServletConfig對象不能被另一個servlet訪問
    2014-10-10
  • springboot如何根據(jù)配置屏蔽接口返回字段

    springboot如何根據(jù)配置屏蔽接口返回字段

    這篇文章主要介紹了springboot如何根據(jù)配置屏蔽接口返回字段問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 淺談cookie 和session 的區(qū)別

    淺談cookie 和session 的區(qū)別

    下面小編就為大家?guī)硪黄獪\談cookie 和session 的區(qū)別。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2016-06-06
  • Java實現(xiàn)多個文檔合并輸出到一個文檔

    Java實現(xiàn)多個文檔合并輸出到一個文檔

    這篇文章主要為大家詳細(xì)介紹了Java實現(xiàn)多個文檔合并輸出到一個文檔的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-10-10
  • Java可重入鎖ReentrantLock詳解

    Java可重入鎖ReentrantLock詳解

    這篇文章主要介紹了Java可重入鎖ReentrantLock詳解,ReentrantLock是一個可重入且獨占式的鎖,是一種遞歸無阻塞的同步機制,它支持重復(fù)進入鎖,即該鎖能夠支持一個線程對資源的重復(fù)加鎖,除此之外,該鎖的還支持獲取鎖時的公平和非公平性選擇,需要的朋友可以參考下
    2023-09-09
  • JAVA三種異常處理機制的具體使用

    JAVA三種異常處理機制的具體使用

    異常是程序在編譯或執(zhí)行的過程中可能出現(xiàn)的問題,本文主要介紹了JAVA三種異常處理機制的具體使用,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2024-06-06
  • 詳解Java的Enum的使用與分析

    詳解Java的Enum的使用與分析

    這篇文章主要介紹了詳解Java的Enum的使用與分析的相關(guān)資料,需要的朋友可以參考下
    2017-02-02
  • Java+OpenCV實現(xiàn)圖片中的人臉識別

    Java+OpenCV實現(xiàn)圖片中的人臉識別

    這篇文章主要介紹了如何利用java?opencv實現(xiàn)人臉識別功能,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2022-03-03

最新評論

遵义市| 茂名市| 洪洞县| 牟定县| 清原| 广南县| 安顺市| 桐庐县| 民丰县| 伊春市| 石首市| 长顺县| 方山县| 孟州市| 柳江县| 聂拉木县| 乃东县| 威远县| 黄平县| 得荣县| 潼关县| 海晏县| 桃园县| 谢通门县| 札达县| 宕昌县| 阳山县| 河间市| 石阡县| 三门县| 滦平县| 永川市| 上虞市| 南江县| 介休市| 曲阜市| 崇义县| 庆城县| 肇源县| 贺州市| 精河县|