【Java后端】Spring Boot 全局異常處理最佳實踐

Spring Boot 全局異常處理最佳實踐

在日常開發中,異常處理幾乎是繞不過去的一個話題。尤其在 后端 API 項目 中,如果沒有統一的異常處理機制,很容易出現以下問題:

  • Controller 層代碼里充斥著 try-catch,顯得冗余。
  • 前端拿到的錯誤響應格式不一致,增加解析成本。
  • 系統異常與業務異常混雜,難以追蹤和排查。

因此,在 Spring Boot 項目中,我們通常會通過 全局異常處理 來收斂所有錯誤,保證接口返回結構的統一性,并簡化開發。


一、為什么需要全局異常處理?

在沒有全局異常處理之前,開發者常常這樣寫代碼:

@GetMapping("/{id}")
public User getUser(@PathVariable int id) {try {return userService.findById(id);} catch (Exception e) {e.printStackTrace();return null;}
}

問題在于:

  1. try-catch 邏輯冗余,重復代碼太多。
  2. 一旦拋出異常,返回值不明確,前端無法準確感知錯誤信息。

👉 解決方案就是使用 Spring Boot 提供的全局異常處理機制@ControllerAdvice + @ExceptionHandler


二、定義統一返回結果

首先定義一個通用的響應對象 ApiResponse,用于統一接口返回格式:

public class ApiResponse<T> {private int code;private String message;private T data;public ApiResponse(int code, String message, T data) {this.code = code;this.message = message;this.data = data;}public static <T> ApiResponse<T> success(T data) {return new ApiResponse<>(200, "success", data);}public static <T> ApiResponse<T> error(int code, String message) {return new ApiResponse<>(code, message, null);}// getter & setter
}

這樣一來,無論成功還是失敗,都能保證返回結果的結構一致。


三、自定義業務異常

除了系統異常(NullPointerExceptionSQLException 等),我們還需要定義 業務異常,用于明確業務邏輯錯誤:

public class BusinessException extends RuntimeException {private int code;public BusinessException(int code, String message) {super(message);this.code = code;}public int getCode() {return code;}
}

例如:用戶不存在、余額不足、參數非法等,都可以通過 BusinessException 來拋出。


四、編寫全局異常處理器

接下來,通過 @RestControllerAdvice 來統一捕獲異常:

@RestControllerAdvice
public class GlobalExceptionHandler {// 處理業務異常@ExceptionHandler(BusinessException.class)public ApiResponse<?> handleBusinessException(BusinessException ex) {return ApiResponse.error(ex.getCode(), ex.getMessage());}// 處理參數校驗異常@ExceptionHandler(MethodArgumentNotValidException.class)public ApiResponse<?> handleValidException(MethodArgumentNotValidException ex) {String msg = ex.getBindingResult().getFieldError().getDefaultMessage();return ApiResponse.error(400, msg);}// 兜底異常處理@ExceptionHandler(Exception.class)public ApiResponse<?> handleException(Exception ex) {ex.printStackTrace(); // 可接入日志系統return ApiResponse.error(500, "服務器內部錯誤");}
}

這樣,不管是業務異常還是系統異常,都會走到全局處理器,保證返回結果的統一性。


五、使用示例

Controller

@RestController
@RequestMapping("/user")
public class UserController {@GetMapping("/{id}")public ApiResponse<String> getUser(@PathVariable int id) {if (id == 0) {throw new BusinessException(404, "用戶不存在");}return ApiResponse.success("用戶ID: " + id);}
}

請求與響應

  • 正常請求:
{"code": 200,"message": "success","data": "用戶ID: 1"
}
  • 業務異常:
{"code": 404,"message": "用戶不存在","data": null
}
  • 系統異常:
{"code": 500,"message": "服務器內部錯誤","data": null
}

六、總結

通過 全局異常處理,我們實現了以下目標:

  1. 統一返回結構,方便前端解析。
  2. 集中管理異常,減少冗余 try-catch
  3. 區分業務異常與系統異常,提升代碼可維護性。
  4. 可擴展性強,后續可以接入日志系統(如 Logback、ELK)或異常監控平臺(如 Sentry)。

建議在實際項目中,將 全局異常處理 作為基礎框架的一部分,避免每個 Controller 重復造輪子。


七、日志落庫 / ELK 接入最佳實踐

在真實的生產環境中,僅僅返回統一的錯誤信息還不夠。我們還需要對異常進行持久化存儲與分析,以便后續排查問題和改進系統。

常見的做法有兩種:

1. 日志落庫(數據庫存儲)

在全局異常處理器中,可以將異常信息寫入數據庫(例如 MySQL、PostgreSQL):

@ExceptionHandler(Exception.class)
public ApiResponse<?> handleException(Exception ex, HttpServletRequest request) {// 記錄日志信息ErrorLog log = new ErrorLog();log.setUri(request.getRequestURI());log.setMethod(request.getMethod());log.setMessage(ex.getMessage());log.setStackTrace(Arrays.toString(ex.getStackTrace()));log.setCreateTime(LocalDateTime.now());errorLogRepository.save(log); // JPA 或 MyBatis 保存return ApiResponse.error(500, "服務器內部錯誤");
}

其中 ErrorLog 可以定義為:

@Entity
public class ErrorLog {@Id@GeneratedValue(strategy = GenerationType.IDENTITY)private Long id;private String uri;private String method;private String message;private String stackTrace;private LocalDateTime createTime;// getter & setter
}

這樣就能將異常詳細信息落到數據庫,方便后續查詢與統計。


2. 接入 ELK(Elasticsearch + Logstash + Kibana)

如果系統日志量較大,推薦接入 ELK,實現實時日志收集與可視化。

(1)配置 Logback 輸出 JSON 日志

logback-spring.xml 中使用 logstash-logback-encoder 輸出 JSON:

<configuration><appender name="LOGSTASH" class="ch.qos.logback.core.rolling.RollingFileAppender"><file>logs/app-log.json</file><encoder class="net.logstash.logback.encoder.LoggingEventEncoder"/></appender><root level="INFO"><appender-ref ref="LOGSTASH"/></root>
</configuration>
(2)通過 Logstash 收集日志

配置 Logstash(logstash.conf):

input {file {path => "/usr/local/app/logs/app-log.json"codec => json}
}output {elasticsearch {hosts => ["http://localhost:9200"]index => "springboot-error-%{+YYYY.MM.dd}"}
}
(3)在 Kibana 可視化

通過 Kibana Dashboard,可以實現:

  • 錯誤趨勢圖
  • 按 API 維度統計異常數量
  • 按時間維度分析錯誤高峰
  • 搜索具體異常堆棧

3. 最佳實踐建議

  • 開發環境:控制臺打印異常即可,方便調試。
  • 測試環境:日志落庫,方便 QA 排查問題。
  • 生產環境:接入 ELK,實時收集和可視化,必要時配合 告警系統(如飛書/釘釘機器人、Prometheus Alertmanager)

八、飛書機器人告警接入

在生產環境中,僅僅記錄日志還不夠。當發生嚴重異常時,我們希望能 實時收到告警通知,避免問題被埋沒。常見的方式就是接入 企業 IM 工具(如飛書、釘釘、企業微信)。

下面以 飛書自定義機器人 為例,展示如何在全局異常處理器中推送告警。


1. 創建飛書自定義機器人

  1. 打開飛書群聊 → 設置 → 群機器人 → 添加機器人 → 選擇 自定義機器人
  2. 復制生成的 Webhook 地址,類似:
https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxx

2. 編寫工具類(推送異常消息)

使用 RestTemplate 發送 POST 請求:

@Component
public class FeishuBotNotifier {private static final String WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/xxxxxx";private final RestTemplate restTemplate = new RestTemplate();public void sendAlert(String title, String content) {Map<String, Object> body = new HashMap<>();body.put("msg_type", "text");Map<String, String> text = new HashMap<>();text.put("text", String.format("【異常告警】\n標題: %s\n詳情: %s", title, content));body.put("content", text);restTemplate.postForEntity(WEBHOOK_URL, body, String.class);}
}

3. 在全局異常處理器中調用

當捕獲到異常時,推送到飛書:

@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {private final FeishuBotNotifier feishuBotNotifier;@ExceptionHandler(Exception.class)public ApiResponse<?> handleException(Exception ex, HttpServletRequest request) {// 構造告警信息String title = "SpringBoot 服務異常";String content = String.format("URI: %s\nMethod: %s\n錯誤: %s",request.getRequestURI(), request.getMethod(), ex.getMessage());// 發送飛書告警feishuBotNotifier.sendAlert(title, content);ex.printStackTrace();return ApiResponse.error(500, "服務器內部錯誤");}
}

4. 飛書群內效果

觸發異常后,群內會收到類似消息:

【異常告警】
標題: SpringBoot 服務異常
詳情: 
URI: /user/0
Method: GET
錯誤: 用戶不存在

九、總結(終極版 🚀)

到這里,我們的 全局異常管理方案 已經形成了一整套閉環:

  1. 全局異常處理:統一返回格式,簡化開發。
  2. 業務異常區分:明確業務錯誤與系統錯誤。
  3. 日志落庫:異常可持久化追溯。
  4. ELK 接入:日志可視化分析,支持查詢與報表。
  5. 飛書機器人告警:重大異常實時通知,提高運維響應速度。

👉 這樣一套機制,基本涵蓋了 從接口開發 → 異常收斂 → 日志分析 → 實時告警 的完整鏈路,既保證了系統的可維護性,也提升了線上運維的響應效率。


本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/pingmian/93702.shtml
繁體地址,請注明出處:http://hk.pswp.cn/pingmian/93702.shtml
英文地址,請注明出處:http://en.pswp.cn/pingmian/93702.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

K8S-Configmap資源

目錄 一、核心概念? ?定義? ?核心價值? ?與Secret的區別? ?二、核心特性? ?數據存儲? ?生命周期? ?作用域? 什么是 Configmap&#xff1f; Configmap 能解決哪些問題&#xff1f; ConfigMap 的主要作用 三、命令行直接創建 四、通過文件創建&#xf…

MySQL InnoDB事務acid特性的原理和隔離級別的實現原理

InnoDB存儲引擎 InnoDB存儲結構表空間 則每張表都會有一個表空間&#xff08;xxx.ibd&#xff09;&#xff0c;一個mysql實例可以對應多個表空間 系統表空間 存儲數據字典&#xff08;表結構定義、索引信息等&#xff09;、Change Buffer、Doublewrite Bufferundo log&#xff…

Linux系統之部署nullboard任務管理工具

Linux系統之部署nullboard任務管理工具一、nullboard介紹1.1 nullboard簡介1.2 任務看板工具介紹1.3 nullboard使用場景二、本次實踐介紹2.1 本地環境規劃2.2 本次實踐介紹三、安裝httpd軟件3.1 檢查yum倉庫3.2 安裝httpd軟件3.3 啟動httpd服務3.4 查看httpd服務狀態3.5 防火墻…

Qt設置軟件使用期限【新版防修改系統時間】

在工業軟件或其他領域中&#xff0c;經常會對軟件進行授權&#xff0c;軟件需要付費進行有期限的使用。以下是我用Qt設計的設置軟件使用期限的兩種方案。 主體思想&#xff1a; 1.軟件需要綁定機器&#xff0c;讓用戶無法通過復制在另一臺機器上運行。 2.由廠家提供激活碼供用戶…

【JavaEE】多線程(線程安全問題)

有些代碼在單個線程環境下執行正確&#xff0c;如果同樣的代碼在多個線程下同時執行可能就會出現問題&#xff0c;這個就是線程安全問題&#xff08;或者稱線程不安全問題&#xff09;&#xff0c;簡而言之就是&#xff1a;線程安全問題是由于多線程出現的問題&#xff0c;原因…

NodeJs 桌面開發學習 electron.js (一)

今天開始學習NodeJs 關于 桌面應用的內容&#xff0c;長期目標是 React electron 實現一個桌面應用。今天先實現一個簡單的目標&#xff0c;搭建一個Electron ts 項目架構&#xff0c;并實現主業務線程 和前端渲染線程的交互一、代碼結構和配置例子項目結構大致如下&#xff…

diffusion model(1.4) 相關論文閱讀清單

以下是閱讀清單&#xff1a; 《Deep Unsupervised Learning using Nonequilibrium Thermodynamics》擴散模型&#xff0c;arxiv鏈接《Denoising Diffusion Probabilistic Models》DDPM論文 arxiv鏈接

ESP32-C3_SMARTCAR

前言: 前面用stm32f103c8t6 rt-thread 寫了個智能小車程序 這章用esp32-c3 重新來遍 1&#xff1a;環境 vscodeidf5.4 esp32-3c 找到一塊MIN的底板 湊合用&#xff08;138 cm左右&#xff09; 一個L298N 一個船型開關&#xff0c; 一個665mm 2腳按鈕 鋰電池 186502 及電池盒&a…

消費者API

目錄獨立消費者案例&#xff08;訂閱主題&#xff09;獨立消費者案例&#xff08;訂閱分區&#xff09;消費者組案例獨立消費者案例&#xff08;訂閱主題&#xff09; package com.tsg.kafka.consumer;import org.apache.kafka.clients.consumer.ConsumerConfig; import org.ap…

C# NX二次開發:操作按鈕控件Button和標簽控件Label詳解

大家好&#xff0c;今天介紹ug二次開發過程中的一個叫操作按鈕的控件&#xff0c;這個控件在塊UI編輯器中可以使用。 ? Button這個控件的屬性和方法如下所示&#xff1a; namespace NXOpen.BlockStyler { public class Label : UIBlock { protected intern…

Vue.prototype 的作用

在 Vue.js 中&#xff0c;Vue.prototype 是用來向所有 Vue 實例添加屬性或方法的機制。通過它添加的屬性或方法可以在所有 Vue 組件實例中通過 this 訪問。主要作用添加全局方法或屬性&#xff1a;可以在所有組件中使用的工具方法或常量擴展 Vue 功能&#xff1a;添加 Vue 本身…

Javaee 多線程 --進程和線程之間的區別和聯系

文章目錄進程和線程進程線程進程和線程的區別創建線程的五種寫法繼承Thread,重寫run實現Runnable(接口)&#xff0c;重寫run繼承Thread,重寫run,但是使用匿名內部類實現Runnable(接口)&#xff0c;重寫run&#xff0c;但是使用匿名內部類使用lambda表達式請說明Thread類中run和…

企業如何讓內部視頻僅限指定域名播放,確保視頻不被泄露?

在數字化辦公時代&#xff0c;企業內部的培訓視頻、產品演示或機密會議錄像等敏感內容&#xff0c;一旦被非法傳播或泄露&#xff0c;可能帶來嚴重的商業風險。如何確保這些視頻只能在公司官網或指定域名播放&#xff0c;防止被惡意下載、盜鏈或二次傳播&#xff1f;今天介紹一…

端口映射原理操作詳解教程:實現外網訪問內網服務,本地路由器端口映射公網ip和軟件端口映射域名2種方法

端口映射作為一種不同網絡間通信的關鍵網絡技術&#xff0c;在遠程訪問和內外網連接服務需求日益增長的如今&#xff0c;理解端口映射的原理和設置方法是確保網絡服務可用性的必要技能。本文將深入探討端口映射的基本概念、路由器端口映射設置步驟以及無公網IP用端口映射軟件映…

【PyTorch】多對象分割項目

對象分割任務的目標是找到圖像中目標對象的邊界。實際應用例如自動駕駛汽車和醫學成像分析。這里將使用PyTorch開發一個深度學習模型來完成多對象分割任務。多對象分割的主要目標是自動勾勒出圖像中多個目標對象的邊界。 對象的邊界通常由與圖像大小相同的分割掩碼定義&#xf…

SSH 使用密鑰登錄服務器

用這種方法遠程登陸服務器的時候無需手動輸入密碼 具體步驟 客戶端通過 ssh-keygen 生成公鑰和私鑰 ssh-keygen -t rsa 生成的時候會有一系列問題&#xff0c;根據自己的需要選擇就行。生成的結果為兩個文件&#xff1a; 上傳公鑰至服務器&#xff0c;上述兩個文件一般在客戶…

MySQL 8.4 企業版啟用TDE功能和表加密

一、系統環境操作系統&#xff1a;Ubuntu 24.04 數據庫:8.4.4-commercial for Linux on x86_64 (MySQL Enterprise Server - Commercial)二、安裝TDE組件前提&#xff1a;檢查組件文件是否存在ls /usr/lib/mysql/plugin/component_keyring_encrypted_file.so1.配置全局清單文件…

【Altium designer】導出的原理圖PDF亂碼異常的解決方法

一、有些電源名字無法顯示或器件丟失 解決辦法 (1)首先AD18以及以上的新版本AD不存在該問題。 (2)其次AD17以及更舊版本的AD很可能遇到該問題,參考如下博客筆記進行操作即可: 大致的操作如下:DXP → Preferences → Schematic → Options里面“Render Text with GDI+”…

4.Ansible自動化之-部署文件到主機

4 - 部署文件到受管主機 實驗環境 先通過以下命令搭建基礎環境&#xff08;創建工作目錄、配置 Ansible 環境和主機清單&#xff09;&#xff1a; # 在控制節點&#xff08;controller&#xff09;上創建web目錄并進入&#xff0c;作為工作目錄 [bqcontroller ~]$ mkdir web &a…

Vuex的使用

Vuex 超詳細使用教程&#xff08;從入門到精通&#xff09;一、Vuex 是什么&#xff1f;Vuex 是專門為 Vue.js 設計的狀態管理庫&#xff0c;它采用集中式存儲管理應用的所有組件的狀態。簡單來說&#xff0c;Vuex 就是一個"全局變量倉庫"&#xff0c;所有組件都可以…