原代碼:
package com.weiyu.exception;import com.weiyu.pojo.Result;
import com.weiyu.utils.ErrorFileResponseUtils;
import jakarta.servlet.http.HttpServletRequest;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;/*** 全局異常處理器*/
@RestControllerAdvice
@SuppressWarnings("unused") // 使用這個注解來抑制警告 或 使用 @Component
@Slf4j
public class GlobalExceptionHandler {/*** 處理防抖異常(同時支持普通請求和文件下載請求)*/@ExceptionHandler(DebounceException.class)public Object handleDebounceException(DebounceException e, HttpServletRequest request) {// 文件下載請求返回錯誤文件if (ErrorFileResponseUtils.isFileDownloadRequest(request)) {return ErrorFileResponseUtils.createErrorFileResponse(e);}// 2. 普通請求返回 json 錯誤return Result.error(e.getMessage(), e.getCode());}/*** 處理其他所有異常*/@ExceptionHandler(Exception.class)public Object handleException(Exception e, HttpServletRequest request) {// ? 禁止使用 printStackTrace 在控制臺輸出異常的詳細堆棧跟蹤信息// e.printStackTrace();// ? 規范做法:使用日志框架記錄異常(參數 e 包含異常的詳細堆棧跟蹤信息)log.error("異常錯誤 {}", e.getMessage(), e);// 文件下載請求返回錯誤文件if (ErrorFileResponseUtils.isFileDownloadRequest(request)) {String message = StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "下載文件失敗";return ErrorFileResponseUtils.createErrorFileResponse(message, HttpStatus.INTERNAL_SERVER_ERROR);}// 普通請求返回 json 錯誤return Result.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失敗", 500);}
}
以下是對提供的Spring Boot全局異常處理代碼的詳細注釋和作用說明:
package com.weiyu.exception;import com.weiyu.pojo.Result; // 自定義的統一響應對象
import com.weiyu.utils.ErrorFileResponseUtils; // 處理錯誤文件響應的工具類
import jakarta.servlet.http.HttpServletRequest; // 獲取HTTP請求信息
import lombok.extern.slf4j.Slf4j; // Lombok日志注解
import org.springframework.http.HttpStatus; // HTTP狀態碼枚舉
import org.springframework.util.StringUtils; // Spring字符串工具類
import org.springframework.web.bind.annotation.ExceptionHandler; // 異常處理器注解
import org.springframework.web.bind.annotation.RestControllerAdvice; // 控制器增強注解/*** 全局異常處理器* 作用:集中處理整個應用程序中控制器層拋出的異常*/
@RestControllerAdvice // 組合注解:包含 @ControllerAdvice + @ResponseBody,使返回值自動轉為JSON
@SuppressWarnings("unused") // 使用這個注解來抑制警告 或 使用 @Component
@Slf4j // 自動生成日志對象
public class GlobalExceptionHandler {/*** 處理防抖異常(DebounceException),同時支持普通請求和文件下載請求* 適用場景:當檢測到重復/頻繁請求時拋出的自定義異常** @param e 捕獲的防抖異常對象* @param request HTTP請求對象* @return 根據請求類型返回不同響應:文件下載請求返回錯誤文件,普通請求返回JSON錯誤信息*/@ExceptionHandler(DebounceException.class) // 指定處理的異常類型public Object handleDebounceException(DebounceException e, HttpServletRequest request) {// 1. 檢查是否為文件下載請求if (ErrorFileResponseUtils.isFileDownloadRequest(request)) {// 生成包含錯誤信息的文件響應(如txt)return ErrorFileResponseUtils.createErrorFileResponse(e);}// 2. 普通請求返回統一JSON錯誤格式return Result.error(e.getMessage(), e.getCode());}/*** 處理所有其他未明確指定的異常(頂級異常處理器)* 作用:作為異常處理的兜底方案,確保所有異常都被處理*/@ExceptionHandler(Exception.class) // 捕獲所有未被處理的異常public Object handleException(Exception e, HttpServletRequest request) {// ? 禁止使用 printStackTrace 在控制臺輸出異常的詳細堆棧跟蹤信息// e.printStackTrace();// ? 規范日志記錄:使用日志框架記錄完整異常堆棧(參數 e 包含異常的詳細堆棧跟蹤信息)log.error("異常錯誤 {}", e.getMessage(), e); // 記錄錯誤消息和詳細堆棧跟蹤信息// 1. 處理文件下載請求的異常if (ErrorFileResponseUtils.isFileDownloadRequest(request)) {// 確保錯誤消息不為空,使用默認消息兜底String message = StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "下載文件失敗";// 生成包含錯誤信息的文件響應,使用500狀態碼return ErrorFileResponseUtils.createErrorFileResponse(message, HttpStatus.INTERNAL_SERVER_ERROR);}// 2. 普通請求的異常處理return Result.error(StringUtils.hasLength(e.getMessage()) ? e.getMessage() : "操作失敗", // 消息處理500 // 統一返回500服務器錯誤狀態碼);}
}
核心作用解析:
統一異常處理
通過
@RestControllerAdvice
注解實現全局攔截控制器層拋出的異常避免在每個Controller中重復編寫異常處理代碼
差異化響應處理
自定義異常處理(DebounceException)
專門處理防抖邏輯相關的異常
使用異常自帶的錯誤碼和消息(
e.getCode()
和e.getMessage()
)示例場景:限制用戶頻繁提交表單/重復請求
全局兜底處理(Exception.class)
捕獲所有未被特殊處理的異常
關鍵安全實踐:禁止使用
printStackTrace()
(會暴露敏感信息)正確做法:通過日志框架記錄完整堆棧(
log.error("msg", e)
)
空消息安全處理
使用
StringUtils.hasLength()
檢查消息有效性提供默認友好提示("操作失敗"/"下載文件失敗")
避免返回空錯誤信息導致客戶端解析失敗
HTTP狀態碼管理
普通請求:返回500錯誤碼(通過Result對象封裝)
文件請求:設置HTTP狀態為500(
HttpStatus.INTERNAL_SERVER_ERROR
)
最佳實踐亮點:
日志規范
java
// 錯誤做法(禁止): 暴露堆棧到控制臺 // e.printStackTrace(); // 正確做法(采用): 日志系統記錄完整錯誤 log.error("異常詳細信息: {}", e.getMessage(), e);
擴展性設計
通過
ErrorFileResponseUtils
工具類分離文件處理邏輯便于后續擴展其他文件類型處理
防御式編程
對
e.getMessage()
進行空值檢測使用工具類方法判斷請求類型(
isFileDownloadRequest
)
響應標準化
統一使用
Result
對象返回JSON格式錯誤
json
// 響應示例 {"code": 500,"msg": "操作失敗","data": null }
該實現有效解決了Spring Boot應用中的三個核心異常處理問題:
① 異常類型差異化處理 ② 響應形式自適配(JSON/文件) ③ 生產環境安全的錯誤日志記錄