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

@ControllerAdvice之全局異常處理過程

 更新時(shí)間:2025年11月05日 09:37:46   作者:Tech_Jia_Hui  
文章介紹了在Java中處理異常的兩種方式:就地解決和向上拋出,并重點(diǎn)介紹了Spring框架中的@ControllerAdvice注解,用于實(shí)現(xiàn)全局異常處理,從而避免了在每個(gè)Controller類中重復(fù)編寫try-catch代碼塊,這種方法不僅提高了代碼的可維護(hù)性,還使得異常處理邏輯的修改更加方便

背景

在業(yè)務(wù)邏輯中存在大量重復(fù)的 try-catch 代碼塊(且沒有全局異常處理機(jī)制)會(huì)帶來以下顯著問題:

  • 每個(gè)方法都需要手動(dòng)編寫 try-catch,導(dǎo)致大量重復(fù)代碼,違反 DRY(Don’t Repeat Yourself)原則。
  • 如果異常處理邏輯需要調(diào)整(例如日志格式、錯(cuò)誤碼規(guī)范),必須逐個(gè)修改所有 try-catch 塊,容易遺漏或出錯(cuò)。
public void processOrder() {
    try {
        // 業(yè)務(wù)邏輯
    } catch (OrderException e) {
        log.error("訂單處理失敗: {}", e.getMessage());
    }
}

public void refundOrder() {
    try {
        // 業(yè)務(wù)邏輯
    } catch (RefundException e) {
        log.error("退款失敗: {}", e.getMessage());
    }
}

java中的異常處理方式

1、就地解決

即用try-catch塊包裹住容易發(fā)生異常的代碼片段,這樣當(dāng)該代碼片段真正發(fā)生異常后,就會(huì)立即被catch塊捕捉并在catch塊中處理,從而使代碼繼續(xù)往下執(zhí)行,不影響其他代碼的執(zhí)行。

2、向上拋出

如果不想立馬就地處理,可以選擇將該異常向上拋出,讓方法的調(diào)用者處理。若方法的調(diào)用者也不行處理,同樣可以繼續(xù)向上拋出該異常,以此類推,直到將該異常拋給JVM處理??墒荍VM懶啊,一看你們?cè)撎幚淼亩疾惶幚硎前?,好,我也不處理,我還要把你們方法的調(diào)用過程給曬出來,結(jié)果就可以在控制臺(tái)看到方法調(diào)用的堆棧信息了。

為什么要使用全局異常處理

總是用try-catch塊包裹代碼塊也不好,影響性能不說代碼看著不是很美觀,所以我們選擇用第二種——向上拋出的方式。向上拋出沒問題,但總要有一個(gè)地方處理該異常,在web系統(tǒng)當(dāng)中還應(yīng)該將該異常以一個(gè)用戶可以接受的方式返回給前端,不但在接口對(duì)接的時(shí)候讓前端小姐姐知道是我們后臺(tái)接口出現(xiàn)了問題,不至于摸不著頭腦;而且我們后端開發(fā)人員也能根據(jù)接口返回的結(jié)果快速的知道到底是哪里出現(xiàn)了問題,才能快速解決問題。

全局異常處理

Spring在3.2版本增加了一個(gè)注解@ControllerAdvice,可以與@ExceptionHandler、@InitBinder、@ModelAttribute 等注解注解配套使用。

不過跟異常處理相關(guān)的只有注解@ExceptionHandler(該注解是springmvc中的一個(gè)注解)

該注解的作用:它通常用在控制器(Controller)類的方法上,以指定該方法用于處理特定類型的異常。當(dāng)控制器中的其他方法拋出該異常時(shí),Spring 會(huì)自動(dòng)調(diào)用帶有 @ExceptionHandler 注解的方法來處理該異常。

import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;

// 這是一個(gè)簡(jiǎn)單的控制器類
@RestController
public class MyController {

    // 一個(gè)可能會(huì)拋出異常的方法
    public String doSomething() {
        // 假設(shè)這里有一些邏輯,可能會(huì)拋出 IllegalArgumentException
        if (true) { // 這里只是為了演示,實(shí)際上應(yīng)該有具體的邏輯判斷
            throw new IllegalArgumentException("Invalid argument provided");
        }
        return "Success";
    }

    // 使用 @ExceptionHandler 來處理 IllegalArgumentException
    @ExceptionHandler(IllegalArgumentException.class)
    @ResponseBody
    public ResponseEntity<String> handleIllegalArgumentException(IllegalArgumentException ex) {
        // 創(chuàng)建一個(gè)包含錯(cuò)誤信息的響應(yīng)實(shí)體
        return new ResponseEntity<>("Invalid argument: " + ex.getMessage(), HttpStatus.BAD_REQUEST);
    }
}
在上面的例子中,doSomething 方法可能會(huì)拋出一個(gè) IllegalArgumentException。當(dāng)這個(gè)異常被拋出時(shí),Spring 會(huì)自動(dòng)調(diào)用 handleIllegalArgumentException 方法來處理它,并返回一個(gè)包含錯(cuò)誤信息的 ResponseEntity 對(duì)象,其 HTTP 狀態(tài)碼為 400 Bad Request。

但是,這樣一來,就必須在每一個(gè)Controller類都定義一套這樣的異常處理方法,因?yàn)楫惓?梢允歉鞣N各樣。這樣一來,就會(huì)造成大量的冗余代碼,而且若需要新增一種異常的處理邏輯,就必須修改所有Controller類了,很不優(yōu)雅。

當(dāng)然你可能會(huì)說,那就定義個(gè)類似BaseController的基類,這樣總行了吧。

這種做法雖然沒錯(cuò),但仍不盡善盡美,因?yàn)檫@樣的代碼有一定的侵入性和耦合性。簡(jiǎn)簡(jiǎn)單單的Controller,我為啥非得繼承這樣一個(gè)類呢,萬一已經(jīng)繼承其他基類了呢。大家都知道Java只能繼承一個(gè)類。

那有沒有一種方案,既不需要跟Controller耦合,也可以將定義的 異常處理器 應(yīng)用到所有控制器呢?所以注解@ControllerAdvice出現(xiàn)了,簡(jiǎn)單的說,該注解可以把異常處理器應(yīng)用到所有控制器,而不是單個(gè)控制器。借助該注解,我們可以實(shí)現(xiàn):在獨(dú)立的某個(gè)地方,比如單獨(dú)一個(gè)類,定義一套對(duì)各種異常的處理機(jī)制,然后在類的簽名加上注解@ControllerAdvice,統(tǒng)一對(duì) 不同階段的、不同異常 進(jìn)行處理。這就是統(tǒng)一異常處理的原理。

@ControllerAdvice使用

1、創(chuàng)建 MyControllerAdvice.java

如下:

package com.sam.demo.controller;

import org.springframework.ui.Model;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.*;

import java.util.HashMap;
import java.util.Map;

/**
 * controller 增強(qiáng)器
 *
 * @author sam
 * @since 2017/7/17
 */
@ControllerAdvice
public class MyControllerAdvice {

    /**
     * 全局異常捕捉處理
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = Exception.class)
    public Map errorHandler(Exception ex) {
        Map map = new HashMap();
        map.put("code", 100);
        map.put("msg", ex.getMessage());
        return map;
    }
    
    /**
     * 攔截捕捉自定義異常 MyException.class
     * @param ex
     * @return
     */
    @ResponseBody
    @ExceptionHandler(value = MyException.class)
    public Map myErrorHandler(MyException ex) {
        Map map = new HashMap();
        map.put("code", ex.getCode());
        map.put("msg", ex.getMsg());
        return map;
    }

}

2、controller中拋出異常進(jìn)行測(cè)試

@RequestMapping("/home")
public String home() throws Exception {

//        throw new Exception("Sam 錯(cuò)誤");
    throw new MyException("101", "Sam 錯(cuò)誤");

}

啟動(dòng)應(yīng)用,訪問:http://localhost:8080/home ,正常顯示以下json內(nèi)容,證明自定義異常已經(jīng)成功被攔截。

{"msg":"Sam 錯(cuò)誤","code":"101"}

@ControllerAdvice的原理

1、組件掃描與注冊(cè)

  • 注解標(biāo)記:當(dāng)類被 @ControllerAdvice 標(biāo)注時(shí),Spring 會(huì)在啟動(dòng)時(shí)通過組件掃描(Component Scan)發(fā)現(xiàn)該類。
  • Bean 注冊(cè):將該類注冊(cè)為特殊的全局組件,其優(yōu)先級(jí)高于普通 Controller,但低于具體的 Controller 方法。

2、異常處理流程

當(dāng) Controller 方法拋出異常時(shí),Spring MVC 的處理流程如下:

  • 異常拋出:Controller 方法執(zhí)行中拋出異常(如 throw new ServiceException())。
  • 異常傳播:異常被 Spring 的 DispatcherServlet 捕獲。
  • 查找處理器:Spring 遍歷所有 @ControllerAdvice 類中的 @ExceptionHandler 方法,尋找與異常類型匹配的方法。
    執(zhí)行處理:調(diào)用匹配的 @ExceptionHandler 方法生成響應(yīng)(如返回 JSON 錯(cuò)誤信息)。
  • 返回響應(yīng):將處理結(jié)果返回客戶端,中斷原始請(qǐng)求流程。
@ControllerAdvice
public class GlobalExceptionHandler {

    // 處理特定異常
    @ExceptionHandler(ServiceException.class)
    @ResponseBody
    public ResponseResult<Void> handleServiceException(ServiceException e) {
        return ResponseResult.fail(e.getCode(), e.getMessage());
    }

    // 處理所有未捕獲的異常
    @ExceptionHandler(Exception.class)
    @ResponseBody
    public ResponseResult<Void> handleException(Exception e) {
        return ResponseResult.fail(500, "系統(tǒng)繁忙");
    }
}

3、優(yōu)先級(jí)規(guī)則

  • 精確匹配優(yōu)先:@ExceptionHandler 方法定義的異常類型越具體,優(yōu)先級(jí)越高。
  • Controller 內(nèi)優(yōu)先:若 Controller 內(nèi)部定義了 @ExceptionHandler,則優(yōu)先于全局 @ControllerAdvice。
  • 多個(gè) @ControllerAdvice 類:通過 @Order 注解指定優(yōu)先級(jí),數(shù)值越小優(yōu)先級(jí)越高。

總結(jié)

以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 詳解Spring AOP 攔截器的基本實(shí)現(xiàn)

    詳解Spring AOP 攔截器的基本實(shí)現(xiàn)

    本篇文章主要介紹了詳解Spring AOP 攔截器的基本實(shí)現(xiàn),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-03-03
  • Java 中的CharArrayReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    Java 中的CharArrayReader 介紹_動(dòng)力節(jié)點(diǎn)Java學(xué)院整理

    CharArrayReader 是字符數(shù)組輸入流。它和ByteArrayInputStream類似,只不過ByteArrayInputStream是字節(jié)數(shù)組輸入流,而CharArray是字符數(shù)組輸入流。CharArrayReader 是用于讀取字符數(shù)組,它繼承于Reader
    2017-05-05
  • 解決spring-boot-maven-plugin報(bào)紅的問題

    解決spring-boot-maven-plugin報(bào)紅的問題

    這篇文章主要給大家介紹一下如何解決spring-boot-maven-plugin報(bào)紅的問題,文中通過圖文講解的非常詳細(xì),具有一定的參考價(jià)值,需要的朋友可以參考下
    2023-08-08
  • 詳解Java中運(yùn)算符及用法

    詳解Java中運(yùn)算符及用法

    這篇文章主要介紹了詳解Java中運(yùn)算符以及相關(guān)的用法講解,一起跟著小編學(xué)習(xí)下吧。
    2017-12-12
  • Java 深入探討設(shè)計(jì)模式之原型模式篇

    Java 深入探討設(shè)計(jì)模式之原型模式篇

    設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用、多數(shù)人知曉的、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)。使用設(shè)計(jì)模式是為了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性
    2021-10-10
  • Java使用OpenOffice將office文件轉(zhuǎn)換為PDF的示例方法

    Java使用OpenOffice將office文件轉(zhuǎn)換為PDF的示例方法

    OpenOffice是一個(gè)開源的辦公套件,它包含了文檔處理、電子表格、演示文稿以及繪圖等多種功能,類似于Microsoft Office,本文將給大家介紹Java使用OpenOffice將office文件轉(zhuǎn)換為PDF的示例方法,需要的朋友可以參考下
    2024-09-09
  • springboot訪問不存在的URL時(shí)的處理方法

    springboot訪問不存在的URL時(shí)的處理方法

    在前后端分離的模式下,當(dāng)Spring Boot應(yīng)用接收到一個(gè)不存在的URL請(qǐng)求時(shí),通常希望返回一個(gè)固定的JSON字符串作為響應(yīng),以便前端能夠據(jù)此進(jìn)行相應(yīng)的處理,本文給大家介紹了springboot訪問不存在的URL時(shí)的處理方法,需要的朋友可以參考下
    2024-12-12
  • Java CountDownLatch應(yīng)用場(chǎng)景代碼實(shí)例

    Java CountDownLatch應(yīng)用場(chǎng)景代碼實(shí)例

    這篇文章主要介紹了Java CountDownLatch應(yīng)用場(chǎng)景代碼實(shí)例,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-09-09
  • Springboot如何連接遠(yuǎn)程服務(wù)器上的數(shù)據(jù)庫實(shí)踐

    Springboot如何連接遠(yuǎn)程服務(wù)器上的數(shù)據(jù)庫實(shí)踐

    本文主要介紹了Springboot如何連接遠(yuǎn)程服務(wù)器上的數(shù)據(jù)庫實(shí)踐,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2022-04-04
  • JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    JDK1.6“新“特性Instrumentation之JavaAgent(推薦)

    這篇文章主要介紹了JDK1.6“新“特性Instrumentation之JavaAgent,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2020-08-08

最新評(píng)論

板桥市| 南安市| 瑞安市| 佛学| 通辽市| 武义县| 东宁县| 陈巴尔虎旗| 无极县| 甘泉县| 武定县| 花垣县| 金山区| 宁城县| 洛南县| 枝江市| 双峰县| 福建省| 西城区| 贡嘎县| 金寨县| 巩留县| 洪雅县| 三明市| 巴青县| 五河县| 盐津县| 上蔡县| 安庆市| 富平县| 错那县| 阿拉善右旗| 汝城县| 开鲁县| 丹阳市| 固原市| 龙山县| 龙里县| 台中市| 汶上县| 军事|