SpringBoot 實(shí)戰(zhàn) (十四) | 統(tǒng)一處理異常

微信公眾號(hào):一個(gè)優(yōu)秀的廢人
如有問(wèn)題或建議,請(qǐng)后臺(tái)留言,我會(huì)盡力解決你的問(wèn)題。

前言

如題,今天介紹 SpringBoot 是如何統(tǒng)一處理全局異常的。SpringBoot 中的全局異常處理主要起作用的兩個(gè)注解是 @ControllerAdvice@ExceptionHandler ,其中 @ControllerAdvice 是組件注解,添加了這個(gè)注解的類(lèi)能夠攔截 Controller 的請(qǐng)求,而 ExceptionHandler 注解可以設(shè)置全局處理控制里的異常類(lèi)型來(lái)攔截要處理的異常。 比如:@ExceptionHandler(value = NullPointException.class) 。

準(zhǔn)備工作

  • SpringBoot 2.1.3
  • IDEA
  • JDK 8

依賴(lài)配置

<dependencies>
        <!-- JPA 依賴(lài) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-jpa</artifactId>
        </dependency>
        <!-- web 依賴(lài) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

        <!-- mysql 連接類(lèi) -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <scope>runtime</scope>
        </dependency>
        <!-- lombok 依賴(lài) -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <!-- 單元測(cè)試依賴(lài) -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

配置文件

spring:
  # 數(shù)據(jù)庫(kù)相關(guān)
  datasource:
    driver-class-name: com.mysql.jdbc.Driver
    url: jdbc:mysql://127.0.0.1:3306/test?useUnicode=true&characterEncoding=utf8&serverTimezone=UTC&useSSL=true
    username: root
    password: 123456

  jpa:
    hibernate:
      ddl-auto: update   #ddl-auto:設(shè)為 create 表示每次都重新建表
    show-sql: true

返回的消息類(lèi)

public class Message<T> implements Serializable {

    /**
     * 狀態(tài)碼
     */
    private Integer code;

    /**
     * 返回信息
     */
    private String message;

    /**
     * 返回的數(shù)據(jù)類(lèi)
     */
    private T data;

    /**
     * 時(shí)間
     */
    private Long time;

    // getter、setter 以及 構(gòu)造方法略。。。
}

工具類(lèi)

用于處理返回的數(shù)據(jù)以及信息類(lèi),代碼注釋很詳細(xì)不說(shuō)了。

public class MessageUtil {

    /**
     * 成功并返回?cái)?shù)據(jù)實(shí)體類(lèi)
     * @param o
     * @param <E>
     * @return
     */
    public static <E>Message<E> ok(E o){
        return new Message<>(200, "success", o, new Date().getTime());
    }

    /**
     * 成功,但無(wú)數(shù)據(jù)實(shí)體類(lèi)返回
     * @return
     */
    public static <E>Message<E> ok(){
        return new Message<>(200, "success", null, new Date().getTime());
    }

    /**
     * 失敗,有自定義異常返回
     * @param code
     * @param msg
     * @return
     */
    public static <E>Message<E> error(Integer code,String msg){
        return new Message<>(code, msg, null, new Date().getTime());
    }
}

自定義異常

通過(guò)繼承 RuntimeException ,聲明 code 用于定義不同類(lèi)型的自定義異常。主要是用于異常攔截出獲取 code 并將 code 設(shè)置到消息類(lèi)中返回。

public class CustomException extends RuntimeException{

    /**
     * 狀態(tài)碼
     */
    private Integer code;

    public Integer getCode() {
        return code;
    }

    public void setCode(Integer code) {
        this.code = code;
    }

    public CustomException(Integer code, String message){

        super(message);
        this.code = code;

    }
}

異常攔截類(lèi)

通過(guò)加入 @RestControllerAdvice 來(lái)聲明該類(lèi)可攔截 Controller 請(qǐng)求,同時(shí)在 handle方法加入 @ExceptionHandler 并在該注解中指定要攔截的異常類(lèi)。

@RestControllerAdvice // 控制器增強(qiáng)處理(返回 JSON 格式數(shù)據(jù)),添加了這個(gè)注解的類(lèi)能被 classpath 掃描自動(dòng)發(fā)現(xiàn)
public class ExceptionHandle {

    @ExceptionHandler(value = Exception.class) // 捕獲 Controller 中拋出的指定類(lèi)型的異常,也可以指定其他異常
    public <E>Message<E> handler(Exception exception){

        if (exception instanceof CustomException){
            CustomException customException = (CustomException) exception;
            return MessageUtil.error(customException.getCode(), customException.getMessage());
        } else {
            return MessageUtil.error(120, "異常信息:" + exception.getMessage());
        }
    }
}

這里只對(duì)自定義異常以及未知異常進(jìn)行處理,如果你在某方法中明確知道可能會(huì)拋出某個(gè)異常,可以加多一個(gè)特定的處理。比如說(shuō)你明確知道該方法可能拋出 NullPointException 可以追加 NullPointException 的處理:

if (exception instanceof CustomException){
     CustomException customException = (CustomException) exception;
     return MessageUtil.error(customException.getCode(), customException.getMessage());
} else if (exception instanceof NullPointException ){
     return MessageUtil.error(500, "空指針異常信!");
} else {
     return MessageUtil.error(120, "異常信息:" + exception.getMessage());
}

controller 層

@RestController
@RequestMapping("/student")
public class StudentController {

    @Autowired
    private StudentService studentService;

    @GetMapping("/{id}")
    public Message<Student> findStudentById(@PathVariable("id") Integer id){

        if (id < 0){
            //測(cè)試自定義錯(cuò)誤
            throw new CustomException(110, "參數(shù)不能是負(fù)數(shù)!");

        } else if (id == 0){
            //硬編碼,為了測(cè)試
            Integer i = 1/id;
            return null;
        } else {
            Student student = studentService.findStudentById(id);
            return MessageUtil.ok(student);
        }
    }
}

完整代碼

https://github.com/turoDog/Demo/tree/master/springboot_exception_demo

如果覺(jué)得對(duì)你有幫助,請(qǐng)給個(gè) Star 再走唄,非常感謝。

Postman 測(cè)試

訪問(wèn) http://localhost:8080/student/5 測(cè)試正常返回?cái)?shù)據(jù)結(jié)果。

返回正常結(jié)果

訪問(wèn) http://localhost:8080/student/0 測(cè)試未知異常的結(jié)果。

測(cè)試未知異常的情況

訪問(wèn) http://localhost:8080/student/-11 測(cè)試自定義異常的結(jié)果。

測(cè)試自定義異常情況

后語(yǔ)

如果本文對(duì)你哪怕有一丁點(diǎn)幫助,請(qǐng)幫忙點(diǎn)好看。你的好看是我堅(jiān)持寫(xiě)作的動(dòng)力。

另外,關(guān)注之后在發(fā)送 1024 可領(lǐng)取免費(fèi)學(xué)習(xí)資料。資料內(nèi)容詳情請(qǐng)看這篇舊文:Python、C++、Java、Linux、Go、前端、算法資料分享

一個(gè)優(yōu)秀的廢人
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容