欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Spring Boot全局異常處理保姆級教程從入門到實(shí)戰(zhàn)(看完秒懂)

 更新時(shí)間:2025年06月26日 11:34:02   作者:碼不停蹄的玄黓  
本文講解SpringBoot全局異常處理,通過@RestControllerAdvice集中處理異常,統(tǒng)一響應(yīng)格式,提升代碼簡潔性與安全性,涵蓋業(yè)務(wù)異常、參數(shù)校驗(yàn)及系統(tǒng)異常處理,避免敏感信息泄露,并提供日志記錄與狀態(tài)碼自定義等進(jìn)階技巧,感興趣的朋友跟隨小編一起看看吧

在Spring Boot開發(fā)中,你是否遇到過這樣的困擾?
每個(gè)Controller方法都要寫一堆try-catch塊,代碼冗余到懷疑人生;前端抱怨接口返回格式不統(tǒng)一,有的返回JSON,有的返回HTML;系統(tǒng)報(bào)錯(cuò)時(shí)直接把數(shù)據(jù)庫異常堆棧暴露給用戶,安全隱患拉滿……

別慌!今天這篇文章帶你徹底搞定全局異常處理,用一行代碼替代所有重復(fù)的try-catch,讓異常處理變得優(yōu)雅又高效!

一、為什么要學(xué)全局異常處理?看完你就懂了!

1.1 痛點(diǎn)驅(qū)動(dòng)

想象一下:你有10個(gè)Controller,每個(gè)都要處理NullPointerExceptionIllegalArgumentException,甚至還要處理業(yè)務(wù)自定義的“用戶不存在”異常……代碼重復(fù)率高達(dá)80%,改個(gè)返回格式就得改10個(gè)地方,這不是在寫代碼,是在“復(fù)制粘貼”!

1.2 核心價(jià)值

  • 代碼簡潔:只需一個(gè)類集中處理所有異常,告別重復(fù)try-catch。
  • 響應(yīng)統(tǒng)一:前端收到的永遠(yuǎn)是{code: 200, msg: "成功", data: ...}格式,解析無壓力。
  • 安全可控:系統(tǒng)異常(如數(shù)據(jù)庫崩潰)不暴露堆棧,業(yè)務(wù)異常(如“余額不足”)明確提示用戶。
  • 日志友好:異常信息集中記錄,排查問題不用翻遍各個(gè)Controller。

二、Spring Boot全局異常處理的核心實(shí)現(xiàn)

Spring Boot提供了超好用的@RestControllerAdvice注解(@ControllerAdvice+@ResponseBody的組合),專門用于前后端分離場景的全局異常處理。咱們直接上干貨!

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

前端需要“標(biāo)準(zhǔn)化”的錯(cuò)誤提示,所以先定義一個(gè)通用的Result類,所有接口返回值都用它包裝。

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Result<T> {
    private Integer code;  // 狀態(tài)碼(200=成功,400=參數(shù)錯(cuò)誤,500=系統(tǒng)錯(cuò)誤)
    private String msg;    // 提示信息
    private T data;        // 業(yè)務(wù)數(shù)據(jù)(可選)
    // 快速構(gòu)建成功響應(yīng)(帶數(shù)據(jù))
    public static <T> Result<T> success(T data) {
        return new Result<>(200, "操作成功", data);
    }
    // 快速構(gòu)建失敗響應(yīng)(自定義code和msg)
    public static <T> Result<T> error(Integer code, String msg) {
        return new Result<>(code, msg, null);
    }
}

2.2 第二步:編寫全局異常處理器

@RestControllerAdvice標(biāo)記一個(gè)類,Spring Boot會(huì)自動(dòng)掃描并攔截所有Controller的異常。重點(diǎn)是用@ExceptionHandler指定要處理的異常類型。

場景1:處理業(yè)務(wù)自定義異常(比如“用戶不存在”)

業(yè)務(wù)中經(jīng)常需要拋“用戶不存在”、“訂單已支付”這類異常,咱們可以自定義異常類,然后在全局處理器里捕獲。

步驟1:定義業(yè)務(wù)異常類

// 自定義業(yè)務(wù)異常(繼承RuntimeException,方便在Service層拋出)
public class BusinessException extends RuntimeException {
    private Integer code;  // 業(yè)務(wù)錯(cuò)誤碼(如4001=用戶不存在)
    public BusinessException(Integer code, String msg) {
        super(msg);
        this.code = code;
    }
    public Integer getCode() {
        return code;
    }
}

步驟2:全局捕獲業(yè)務(wù)異常

@RestControllerAdvice
public class GlobalExceptionHandler {
    // 處理業(yè)務(wù)異常(比如用戶不存在)
    @ExceptionHandler(BusinessException.class)
    public Result<?> handleBusinessException(BusinessException e) {
        return Result.error(e.getCode(), e.getMessage());
    }
}
場景2:處理參數(shù)校驗(yàn)異常(@Valid校驗(yàn)失?。?/h5>

@Valid校驗(yàn)請求參數(shù)時(shí),參數(shù)不合法會(huì)拋MethodArgumentNotValidException,咱們可以提取錯(cuò)誤信息,友好提示用戶。

// 全局處理參數(shù)校驗(yàn)異常(@RequestBody參數(shù)校驗(yàn)失?。?
@ExceptionHandler(MethodArgumentNotValidException.class)
public Result<?> handleValidationException(MethodArgumentNotValidException e) {
    // 提取所有校驗(yàn)失敗的字段信息(比如"用戶名不能為空")
    String errorMsg = e.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(";"));
    return Result.error(400, "參數(shù)校驗(yàn)失?。? + errorMsg);
}
場景3:處理系統(tǒng)未知異常(兜底方案)

數(shù)據(jù)庫崩潰、空指針等系統(tǒng)級異常,必須捕獲并返回通用提示,同時(shí)記錄完整日志(避免暴露敏感信息)。

// 全局處理其他未捕獲的異常(系統(tǒng)級錯(cuò)誤)
@ExceptionHandler(Exception.class)
public Result<?> handleSystemException(Exception e) {
    // 記錄完整異常堆棧(生產(chǎn)環(huán)境必加?。?
    log.error("系統(tǒng)發(fā)生未知異常,請求路徑:{}", getRequestPath(), e);
    // 返回友好提示(前端看到的是"服務(wù)器繁忙,請稍后再試")
    return Result.error(500, "服務(wù)器繁忙,請稍后再試");
}
// 輔助方法:獲取當(dāng)前請求路徑(需要spring-web依賴)
private String getRequestPath() {
    ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
    return attributes == null ? "" : attributes.getRequest().getRequestURI();
}

2.3 第三步:在業(yè)務(wù)中拋異常,測試效果!

現(xiàn)在,在Service層拋出自定義異常,看看是否被全局處理器捕獲。

@Service
public class UserService {
    public User getUserById(Long id) {
        // 模擬數(shù)據(jù)庫查詢(假設(shè)id=100的用戶不存在)
        User user = null; 
        if (user == null) {
            throw new BusinessException(4001, "用戶ID=" + id + "不存在"); // 拋業(yè)務(wù)異常
        }
        return user;
    }
}
@RestController
@RequestMapping("/users")
public class UserController {
    @Autowired
    private UserService userService;
    @GetMapping("/{id}")
    public Result<User> getUser(@PathVariable Long id) {
        User user = userService.getUserById(id);
        return Result.success(user); // 正常返回
    }
}

測試結(jié)果:

  • 當(dāng)id=100時(shí),返回{"code":4001,"msg":"用戶ID=100不存在","data":null}(業(yè)務(wù)異常被捕獲)。
  • 當(dāng)id=1(存在用戶)時(shí),返回{"code":200,"msg":"操作成功","data":{...}}(正常響應(yīng))。

三、進(jìn)階玩法:這些場景也能輕松搞定!

3.1 自定義HTTP狀態(tài)碼(比如404)

如果想讓某些異常返回特定的HTTP狀態(tài)碼(如“資源不存在”返回404),可以用@ResponseStatus注解。

// 自定義異常(標(biāo)記為404狀態(tài)碼)
@ResponseStatus(HttpStatus.NOT_FOUND) 
public class ResourceNotFoundException extends RuntimeException {
    public ResourceNotFoundException(String msg) {
        super(msg);
    }
}
// 全局處理(可選,也可以直接用@ResponseStatus)
@ExceptionHandler(ResourceNotFoundException.class)
public Result<?> handleResourceNotFound(ResourceNotFoundException e) {
    return Result.error(404, e.getMessage());
}

3.2 處理表單參數(shù)校驗(yàn)異常(@ModelAttribute)

如果是表單提交(非@RequestBody),參數(shù)校驗(yàn)失敗會(huì)拋BindException,處理方式和MethodArgumentNotValidException類似:

@ExceptionHandler(BindException.class)
public Result<?> handleBindException(BindException e) {
    String errorMsg = e.getBindingResult().getFieldErrors().stream()
            .map(FieldError::getDefaultMessage)
            .collect(Collectors.joining(";"));
    return Result.error(400, "參數(shù)校驗(yàn)失?。? + errorMsg);
}

3.3 記錄異常日志的細(xì)節(jié)

全局處理中記錄日志時(shí),建議帶上請求路徑、用戶ID(如果有登錄)等信息,方便排查問題:

@ExceptionHandler(Exception.class)
public Result<?> handleSystemException(Exception e) {
    // 獲取請求路徑
    String path = getRequestPath();
    // 獲取用戶ID(假設(shè)從Token中解析)
    String userId = SecurityUtils.getCurrentUserId(); 
    // 記錄日志(包含關(guān)鍵上下文信息)
    log.error("系統(tǒng)異常 | 用戶ID={} | 路徑={} | 異常信息={}", 
              userId, path, e.getMessage(), e); 
    return Result.error(500, "服務(wù)器繁忙,請稍后再試");
}

四、避坑指南:這些坑別踩!

4.1 全局異常不生效?

  • 檢查是否添加了@RestControllerAdvice注解(別漏了@ResponseBody)。
  • 檢查異常類的包路徑是否被Spring掃描到(確保全局處理器和業(yè)務(wù)類在同一個(gè)或子包下)。
  • 檢查是否有局部try-catch覆蓋了全局處理(比如Controller里自己catch了異常,沒拋出去)。

4.2 生產(chǎn)環(huán)境暴露敏感信息?

  • 系統(tǒng)異常(如SQLException)的msg不要直接返回給前端,用“服務(wù)器繁忙”代替。
  • 日志中可以記錄完整堆棧,但響應(yīng)體里只保留友好提示。

4.3 自定義異常沒被捕獲?

  • 確保自定義異常是RuntimeException的子類(Spring默認(rèn)只捕獲RuntimeExceptionError)。
  • 如果是檢查型異常(如IOException),需要在方法上聲明throws,或手動(dòng)拋RuntimeException包裝。

五、總結(jié):全局異常處理的學(xué)習(xí)路線

  1. 基礎(chǔ)用法:用@RestControllerAdvice+@ExceptionHandler捕獲所有異常,返回統(tǒng)一Result。
  2. 業(yè)務(wù)異常:自定義BusinessException,在Service層拋出,全局處理返回業(yè)務(wù)碼。
  3. 參數(shù)校驗(yàn):用@Valid+MethodArgumentNotValidException,提取校驗(yàn)錯(cuò)誤信息。
  4. 系統(tǒng)異常:兜底處理Exception,記錄日志并返回友好提示。
  5. 進(jìn)階優(yōu)化:自定義狀態(tài)碼、記錄請求上下文、處理表單參數(shù)異常。

掌握這些,你的Spring Boot項(xiàng)目異常處理將告別“屎山代碼”,變得簡潔、優(yōu)雅、易維護(hù)!趕緊動(dòng)手試試吧~ 有其他問題歡迎在評論區(qū)留言,我會(huì)一一解答! ??

到此這篇關(guān)于Spring Boot全局異常處理保姆級教程從入門到實(shí)戰(zhàn)(看完秒懂)的文章就介紹到這了,更多相關(guān)Spring Boot全局異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • SpringBoot是如何使用SQL數(shù)據(jù)庫的?

    SpringBoot是如何使用SQL數(shù)據(jù)庫的?

    今天給大家?guī)淼氖顷P(guān)于Springboot的相關(guān)知識,文章圍繞著SpringBoot是如何使用SQL數(shù)據(jù)庫的展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下
    2021-06-06
  • Springboot+Netty+Websocket實(shí)現(xiàn)消息推送實(shí)例

    Springboot+Netty+Websocket實(shí)現(xiàn)消息推送實(shí)例

    這篇文章主要介紹了Springboot+Netty+Websocket實(shí)現(xiàn)消息推送實(shí)例,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-02-02
  • java代碼實(shí)現(xiàn)C盤文件統(tǒng)計(jì)工具

    java代碼實(shí)現(xiàn)C盤文件統(tǒng)計(jì)工具

    今天周末,給大家分享基于java代碼實(shí)現(xiàn)C盤文件統(tǒng)計(jì)工具,在這小編使用的版本是Maven-3.9.9,jdk1.8,代碼簡單易懂,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友參考下吧
    2021-07-07
  • IDEA中 Getter、Setter 注解不起作用的問題如何解決

    IDEA中 Getter、Setter 注解不起作用的問題如何解決

    這篇文章主要介紹了IDEA中 Getter、Setter 注解不起作用的問題如何解決,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08
  • Spring中的Sentinel熔斷降級詳解

    Spring中的Sentinel熔斷降級詳解

    這篇文章主要介紹了Spring中的Sentinel熔斷降級詳解,熔斷降級是一種保護(hù)系統(tǒng)穩(wěn)定性和可用性的機(jī)制,旨在防止故障的擴(kuò)散和蔓延,提高用戶體驗(yàn)和信任度,需要的朋友可以參考下
    2023-09-09
  • Java8如何從一個(gè)list中獲取某一元素集合

    Java8如何從一個(gè)list中獲取某一元素集合

    這篇文章主要介紹了Java8如何從一個(gè)list中獲取某一元素集合,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-07-07
  • SpringBoot2.X Devtools熱部署實(shí)現(xiàn)解析

    SpringBoot2.X Devtools熱部署實(shí)現(xiàn)解析

    這篇文章主要介紹了SpringBoot2.X Devtools熱部署實(shí)現(xiàn)解析,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-08-08
  • springboot中@RequestMapping的用法

    springboot中@RequestMapping的用法

    這篇文章主要介紹了springboot中@RequestMapping的用法,具有很好的參考價(jià)值,希望對大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2022-02-02
  • vue+springboot上傳文件、圖片、視頻及回顯到前端詳解

    vue+springboot上傳文件、圖片、視頻及回顯到前端詳解

    一般來說vue可以使用axios或者fetch等ajax庫發(fā)送文件請求,而springboot則可以使用Spring MVC的方式來處理上傳文件請求,下面這篇文章主要給大家介紹了關(guān)于vue+springboot上傳文件、圖片、視頻及回顯到前端的相關(guān)資料,需要的朋友可以參考下
    2023-04-04
  • Java swing實(shí)現(xiàn)酒店管理系統(tǒng)

    Java swing實(shí)現(xiàn)酒店管理系統(tǒng)

    這篇文章主要為大家詳細(xì)介紹了Java swing實(shí)現(xiàn)酒店管理系統(tǒng),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-02-02

最新評論