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

SpringBoot項(xiàng)目實(shí)現(xiàn)統(tǒng)一異常處理的最佳方案

 更新時(shí)間:2024年02月05日 09:26:06   作者:程序員偏安  
在前后端分離的項(xiàng)目開(kāi)發(fā)過(guò)程中,我們通常會(huì)對(duì)數(shù)據(jù)返回格式進(jìn)行統(tǒng)一的處理,這樣可以方便前端人員取數(shù)據(jù),后端發(fā)生異常時(shí)同樣會(huì)使用此格式將異常信息返回給前端,本文介紹了如何在SpringBoot項(xiàng)目中實(shí)現(xiàn)統(tǒng)一異常處理,如有錯(cuò)誤,還望批評(píng)指正

前言

近日心血來(lái)潮想做一個(gè)開(kāi)源項(xiàng)目,目標(biāo)是做一款可以適配多端、功能完備的模板工程,包含后臺(tái)管理系統(tǒng)和前臺(tái)系統(tǒng),開(kāi)發(fā)者基于此項(xiàng)目進(jìn)行裁剪和擴(kuò)展來(lái)完成自己的功能開(kāi)發(fā)。本項(xiàng)目為前后端分離開(kāi)發(fā),后端基于Java21SpringBoot3開(kāi)發(fā),后端使用Spring Security、JWT、Spring Data JPA等技術(shù)棧,前端提供了vueangular、react、uniapp、微信小程序等多種腳手架工程。

項(xiàng)目地址:https://gitee.com/breezefaith/fast-alden

在前后端分離的項(xiàng)目開(kāi)發(fā)過(guò)程中,我們通常會(huì)對(duì)數(shù)據(jù)返回格式進(jìn)行統(tǒng)一的處理,這樣可以方便前端人員取數(shù)據(jù),后端發(fā)生異常時(shí)同樣會(huì)使用此格式將異常信息返回給前端。本文將介紹在SpringBoot項(xiàng)目中如何實(shí)現(xiàn)統(tǒng)一異常處理。

實(shí)現(xiàn)步驟

定義統(tǒng)一響應(yīng)對(duì)象類(lèi)

/**
 * 響應(yīng)結(jié)果類(lèi)
 *
 * @param <T> 任意類(lèi)型
 */
@Data
public class ResponseResult<T> {
    /**
     * 響應(yīng)狀態(tài)碼,200是正常,非200表示異常
     */
    private int status;
    /**
     * 異常編號(hào)
     */
    private String errorCode;
    /**
     * 異常信息
     */
    private String message;
    /**
     * 響應(yīng)數(shù)據(jù)
     */
    private T data;
    public static <T> ResponseResult<T> success() {
        return success(HttpServletResponse.SC_OK, null, null);
    }
    public static <T> ResponseResult<T> success(T data) {
        return success(HttpServletResponse.SC_OK, null, data);
    }
    public static <T> ResponseResult<T> fail(String message) {
        return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, null, message, null);
    }
    public static <T> ResponseResult<T> fail(String errorCode, String message) {
        return fail(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, errorCode, message, null);
    }
    public static <T> ResponseResult<T> success(int status, String message, T data) {
        ResponseResult<T> r = new ResponseResult<>();
        r.setStatus(status);
        r.setMessage(message);
        r.setData(data);
        return r;
    }
    public static <T> ResponseResult<T> fail(int status, String errorCode, String message) {
        return fail(status, errorCode, message, null);
    }
    public static <T> ResponseResult<T> fail(int status, String errorCode, String message, T data) {
        ResponseResult<T> r = new ResponseResult<>();
        r.setStatus(status);
        r.setErrorCode(errorCode);
        r.setMessage(message);
        r.setData(data);
        return r;
    }
}

定義業(yè)務(wù)異常枚舉接口和實(shí)現(xiàn)

通常一個(gè)系統(tǒng)中的自定義業(yè)務(wù)異常是可窮舉的,可以考慮通過(guò)定義枚舉的方式來(lái)列舉所有的業(yè)務(wù)異常。

首先我們來(lái)定義一個(gè)異常信息枚舉的基類(lèi)接口。

public interface IBizExceptionEnum {
    String getCode();
    String getMessage();
}

再給出一個(gè)常用的異常信息的枚舉類(lèi),如果有其他業(yè)務(wù)模塊的異常信息,同樣可以通過(guò)實(shí)現(xiàn)IBizExceptionEnum接口來(lái)進(jìn)行定義。

@Getter
public enum BizExceptionEnum implements IBizExceptionEnum {
    ENTITY_IS_NULL("Base_Entity_Exception_0001", "實(shí)體為空"),
    ENTITY_ID_IS_NULL("Base_Entity_Exception_0002", "實(shí)體id字段為空"),
    ENTITY_ID_IS_DUPLCATED("Base_Entity_Exception_0003", "實(shí)體id字段%s重復(fù)");
    private final String code;
    private final String message;
    BizExceptionEnum(String code, String message) {
        this.code = code;
        this.message = message;
    }
}

定義業(yè)務(wù)異?;?lèi)

業(yè)務(wù)異?;?lèi)BizException繼承自RuntimeException,代碼中主動(dòng)拋出的異常建議都包裝為該類(lèi)的實(shí)例。

/**
 * 業(yè)務(wù)異常基類(lèi),支持參數(shù)化的異常信息
 */
@Getter
@Setter
public class BizException extends RuntimeException {
    private String code;
    private Object[] args;
    public BizException() {
        super();
    }
    public BizException(String message) {
        super(message);
    }
    public BizException(Throwable cause) {
        super(cause);
    }
    public BizException(String message, Throwable cause) {
        super(message, cause);
    }
    public BizException(Throwable cause, String code, String message, Object... args) {
        super(message, cause);
        this.code = code;
        this.args = args;
    }
    public BizException(String code, String message, Object... args) {
        super(message);
        this.code = code;
        this.args = args;
    }
    public BizException(IBizExceptionEnum exceptionEnum, Object... args) {
        this(exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
    }
    public BizException(Throwable cause, IBizExceptionEnum exceptionEnum, Object... args) {
        this(cause, exceptionEnum.getCode(), exceptionEnum.getMessage(), args);
    }
    @Override
    public String getMessage() {
        if (code != null) {
            if (args != null && args.length > 0) {
                return String.format(super.getMessage(), args);
            }
        }
        return super.getMessage();
    }
}

定義全局異常處理切面

本步驟需要使用@RestControllerAdvice注解,它是一個(gè)組合注解,由@ControllerAdvice、@ResponseBody組成,而@ControllerAdvice繼承了@Component,因此@RestControllerAdvice本質(zhì)上是個(gè)Component,用于定義@ExceptionHandler@InitBinder@ModelAttribute方法,適用于所有使用@RequestMapping方法。

還要用到@ExceptionHandler注解,可以認(rèn)為它是一個(gè)異常攔截器,它采用“就近原則”,存在多個(gè)滿(mǎn)足條件的異常處理器時(shí)會(huì)選擇最接近的一個(gè)來(lái)使用。它本質(zhì)上就是使用Spring AOP定義的一個(gè)切面,在系統(tǒng)拋出異常后執(zhí)行。

具體實(shí)現(xiàn)代碼如下:

/**
 * 全局異常處理切面
 */
@RestControllerAdvice
public class GlobalExceptionHandlerAdvice {
    private static final Logger log = LoggerFactory.getLogger(GlobalExceptionHandlerAdvice.class);
    @ExceptionHandler({BizException.class})
    public ResponseResult<Object> handleBizException(BizException e, HttpServletRequest request, HttpServletResponse response) {
        log.error(e.getCode() + ": " + e.getMessage(), e);
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        return ResponseResult.fail(e.getCode(), e.getMessage());
    }
    @ExceptionHandler({RuntimeException.class, Exception.class})
    public ResponseResult<Object> handleRuntimeException(Exception e, HttpServletRequest request, HttpServletResponse response) {
        log.error(e.getMessage(), e);
        response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
        return ResponseResult.fail(e.getMessage());
    }
}

上述代碼會(huì)對(duì)系統(tǒng)中拋出的BizException、RuntimeExceptionException對(duì)象進(jìn)行處理,把異常包裝為ResponseResult對(duì)象后將異常編號(hào)和異常信息返回給前端。

測(cè)試和驗(yàn)證

下面我們就可以定義一個(gè)Controller類(lèi)來(lái)進(jìn)行簡(jiǎn)單的測(cè)試。

@RestController
@RequestMapping("/demo")
public class DemoController {
    @GetMapping("/method1")
    public ResponseResult<Integer> method1() {
        throw new BizException(BizExceptionEnum.ENTITY_IS_NULL);
    }
    @GetMapping("/method2")
    public void method2() {
        throw new BizException(BizExceptionEnum.ENTITY_ID_IS_NULL);
    }
    @GetMapping(value = "/method3")
    public String method3() {
        throw new BizException(BizExceptionEnum.ENTITY_ID_IS_DUPLCATED, "1");
    }
    @GetMapping(value = "/method4")
    public String method4() {
        // 拋出ArithmeticException異常
        return String.valueOf(1 / 0);
    }
}

總結(jié)

本文介紹了如何在SpringBoot項(xiàng)目中實(shí)現(xiàn)統(tǒng)一異常處理,如有錯(cuò)誤,還望批評(píng)指正。

在后續(xù)實(shí)踐中我也是及時(shí)更新自己的學(xué)習(xí)心得和經(jīng)驗(yàn)總結(jié),希望與諸位看官一起進(jìn)步。

到此這篇關(guān)于SpringBoot項(xiàng)目實(shí)現(xiàn)統(tǒng)一異常處理的最佳方案的文章就介紹到這了,更多相關(guān)SpringBoot統(tǒng)一異常處理內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Spring Boot 項(xiàng)目搭建教程及注解

    Spring Boot 項(xiàng)目搭建教程及注解

    下面小編就為大家?guī)?lái)一篇Spring Boot 項(xiàng)目搭建教程及注解。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-09-09
  • jstack+jdb命令查看線程及死鎖堆棧信息的實(shí)例

    jstack+jdb命令查看線程及死鎖堆棧信息的實(shí)例

    這篇文章主要介紹了jstack+jdb命令查看線程及死鎖堆棧信息的實(shí)例,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2021-02-02
  • java中instanceof與Class的等價(jià)性代碼示例

    java中instanceof與Class的等價(jià)性代碼示例

    這篇文章主要介紹了java中instanceof與Class的等價(jià)性代碼示例,小編覺(jué)得還是挺不錯(cuò)的,具有一定借鑒價(jià)值,需要的朋友可以參考下
    2018-01-01
  • Java SpringBoot自動(dòng)裝配原理詳解

    Java SpringBoot自動(dòng)裝配原理詳解

    這篇文章主要介紹了詳解Spring Boot自動(dòng)裝配的原理,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2021-09-09
  • Javaweb 500 服務(wù)器內(nèi)部錯(cuò)誤的解決

    Javaweb 500 服務(wù)器內(nèi)部錯(cuò)誤的解決

    這篇文章主要介紹了Javaweb 500 服務(wù)器內(nèi)部錯(cuò)誤的解決方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2020-09-09
  • Java接口和抽象類(lèi)用法實(shí)例總結(jié)

    Java接口和抽象類(lèi)用法實(shí)例總結(jié)

    這篇文章主要介紹了Java接口和抽象類(lèi)用法,結(jié)合實(shí)例形式總結(jié)分析了Java接口與抽象類(lèi)的具體定義、使用技巧與相關(guān)注意事項(xiàng),需要的朋友可以參考下
    2015-12-12
  • 實(shí)例講解String Date Calendar之間的轉(zhuǎn)換

    實(shí)例講解String Date Calendar之間的轉(zhuǎn)換

    下面小編就為大家?guī)?lái)一篇實(shí)例講解String Date Calendar之間的轉(zhuǎn)換。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2017-07-07
  • Java中String類(lèi)的常見(jiàn)方法超詳細(xì)講解

    Java中String類(lèi)的常見(jiàn)方法超詳細(xì)講解

    這篇文章主要介紹了Java中String類(lèi)常見(jiàn)方法的相關(guān)資料,String類(lèi)是不可變的,字符串常量池用于存儲(chǔ)字符串字面量,常用方法包括字符串查找、轉(zhuǎn)換、比較、替換、拆分和截取,需要的朋友可以參考下
    2025-04-04
  • JAVA中的deflate壓縮實(shí)現(xiàn)方法

    JAVA中的deflate壓縮實(shí)現(xiàn)方法

    下面小編就為大家?guī)?lái)一篇JAVA中的deflate壓縮實(shí)現(xiàn)方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-09-09
  • SpringBoot實(shí)現(xiàn)excel文件生成和下載

    SpringBoot實(shí)現(xiàn)excel文件生成和下載

    這篇文章主要為大家詳細(xì)介紹了SpringBoot實(shí)現(xiàn)excel文件生成和下載,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-02-02

最新評(píng)論