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

Java后端Spring?Boot全局異常處理最佳實踐記錄

 更新時間:2025年08月22日 10:10:58   作者:柯南二號  
Spring Boot通過和提供強大的異常處理機制,支持統(tǒng)一REST和頁面錯誤響應(yīng),這篇文章主要介紹了Java后端Spring?Boot全局異常處理的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下

前言

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

  • Controller 層代碼里充斥著 try-catch,顯得冗余。
  • 前端拿到的錯誤響應(yīng)格式不一致,增加解析成本。
  • 系統(tǒng)異常與業(yè)務(wù)異?;祀s,難以追蹤和排查。

因此,在 Spring Boot 項目中,我們通常會通過 全局異常處理 來收斂所有錯誤,保證接口返回結(jié)構(gòu)的統(tǒng)一性,并簡化開發(fā)。

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

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

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

問題在于:

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

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

二、定義統(tǒng)一返回結(jié)果

首先定義一個通用的響應(yīng)對象 ApiResponse,用于統(tǒng)一接口返回格式:

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
}

這樣一來,無論成功還是失敗,都能保證返回結(jié)果的結(jié)構(gòu)一致。

三、自定義業(yè)務(wù)異常

除了系統(tǒng)異常(NullPointerException、SQLException 等),我們還需要定義 業(yè)務(wù)異常,用于明確業(yè)務(wù)邏輯錯誤:

public class BusinessException extends RuntimeException {
    private int code;

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

    public int getCode() {
        return code;
    }
}

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

四、編寫全局異常處理器

接下來,通過 @RestControllerAdvice 來統(tǒng)一捕獲異常:

@RestControllerAdvice
public class GlobalExceptionHandler {

    // 處理業(yè)務(wù)異常
    @ExceptionHandler(BusinessException.class)
    public ApiResponse<?> handleBusinessException(BusinessException ex) {
        return ApiResponse.error(ex.getCode(), ex.getMessage());
    }

    // 處理參數(shù)校驗異常
    @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(); // 可接入日志系統(tǒng)
        return ApiResponse.error(500, "服務(wù)器內(nèi)部錯誤");
    }
}

這樣,不管是業(yè)務(wù)異常還是系統(tǒng)異常,都會走到全局處理器,保證返回結(jié)果的統(tǒng)一性。

五、使用示例

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);
    }
}

請求與響應(yīng)

  • 正常請求:
{
  "code": 200,
  "message": "success",
  "data": "用戶ID: 1"
}
  • 業(yè)務(wù)異常:
{
  "code": 404,
  "message": "用戶不存在",
  "data": null
}
  • 系統(tǒng)異常:
{
  "code": 500,
  "message": "服務(wù)器內(nèi)部錯誤",
  "data": null
}

六、總結(jié)

通過 全局異常處理,我們實現(xiàn)了以下目標(biāo):

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

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

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

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

常見的做法有兩種:

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

在全局異常處理器中,可以將異常信息寫入數(shù)據(jù)庫(例如 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, "服務(wù)器內(nèi)部錯誤");
}

其中 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
}

這樣就能將異常詳細信息落到數(shù)據(jù)庫,方便后續(xù)查詢與統(tǒng)計。

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

如果系統(tǒng)日志量較大,推薦接入 ELK,實現(xiàn)實時日志收集與可視化。

(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,可以實現(xiàn):

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

3. 最佳實踐建議

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

八、飛書機器人告警接入

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

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

1. 創(chuàng)建飛書自定義機器人

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

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

使用 RestTemplate 發(fā)送 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標(biāo)題: %s\n詳情: %s", title, content));
        body.put("content", text);

        restTemplate.postForEntity(WEBHOOK_URL, body, String.class);
    }
}

3. 在全局異常處理器中調(diào)用

當(dāng)捕獲到異常時,推送到飛書:

@RestControllerAdvice
@RequiredArgsConstructor
public class GlobalExceptionHandler {

    private final FeishuBotNotifier feishuBotNotifier;

    @ExceptionHandler(Exception.class)
    public ApiResponse<?> handleException(Exception ex, HttpServletRequest request) {
        // 構(gòu)造告警信息
        String title = "SpringBoot 服務(wù)異常";
        String content = String.format("URI: %s\nMethod: %s\n錯誤: %s",
                request.getRequestURI(), request.getMethod(), ex.getMessage());

        // 發(fā)送飛書告警
        feishuBotNotifier.sendAlert(title, content);

        ex.printStackTrace();
        return ApiResponse.error(500, "服務(wù)器內(nèi)部錯誤");
    }
}

4. 飛書群內(nèi)效果

觸發(fā)異常后,群內(nèi)會收到類似消息:

【異常告警】
標(biāo)題: SpringBoot 服務(wù)異常
詳情: 
URI: /user/0
Method: GET
錯誤: 用戶不存在

九、總結(jié)(終極版 ??)

到這里,我們的 全局異常管理方案 已經(jīng)形成了一整套閉環(huán):

  1. 全局異常處理:統(tǒng)一返回格式,簡化開發(fā)。
  2. 業(yè)務(wù)異常區(qū)分:明確業(yè)務(wù)錯誤與系統(tǒng)錯誤。
  3. 日志落庫:異??沙志没匪?。
  4. ELK 接入:日志可視化分析,支持查詢與報表。
  5. 飛書機器人告警:重大異常實時通知,提高運維響應(yīng)速度。

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

到此這篇關(guān)于Java后端Spring Boot全局異常處理最佳實踐的文章就介紹到這了,更多相關(guān)SpringBoot全局異常處理內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • java內(nèi)部類的最詳細詳解

    java內(nèi)部類的最詳細詳解

    內(nèi)部類是指在一個外部類的內(nèi)部再定義一個類,下面這篇文章主要給大家介紹了關(guān)于java內(nèi)部類的最詳細詳解,文中通過圖文介紹的非常詳細,需要的朋友可以參考下
    2022-06-06
  • 使用mtrace追蹤JVM堆外內(nèi)存泄露的方法

    使用mtrace追蹤JVM堆外內(nèi)存泄露的方法

    這篇文章主要給大家介紹了如何使用mtrace追蹤JVM堆外內(nèi)存泄露,文章通過代碼示例介紹的非常詳細,對大家的學(xué)習(xí)或工作有一定的幫助,需要的朋友可以參考下
    2023-09-09
  • Java實現(xiàn)拓?fù)渑判虻氖纠a

    Java實現(xiàn)拓?fù)渑判虻氖纠a

    這篇文章我們要講的是拓?fù)渑判?,這是一個針對有向無環(huán)圖的算法,主要是為了解決前驅(qū)后繼的關(guān)系,感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2022-05-05
  • SpringBoot Redis配置Fastjson進行序列化和反序列化實現(xiàn)

    SpringBoot Redis配置Fastjson進行序列化和反序列化實現(xiàn)

    這篇文章主要介紹了SpringBoot Redis配置Fastjson進行序列化和反序列化實現(xiàn),文中通過示例代碼介紹的非常詳細,對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-10-10
  • SpringBoot利用redis集成消息隊列的方法

    SpringBoot利用redis集成消息隊列的方法

    這篇文章主要介紹了SpringBoot利用redis集成消息隊列的方法,需要的朋友可以參考下
    2017-08-08
  • Java?中的靜態(tài)字段和靜態(tài)方法?

    Java?中的靜態(tài)字段和靜態(tài)方法?

    這篇文章主要介紹了Java中的靜態(tài)字段和靜態(tài)方法,文章圍繞Java?靜態(tài)方法展開詳細內(nèi)容,具有一定的參考價值,需要的小伙伴可以參考一下
    2022-03-03
  • 最新評論