JavaRush /Java Blog /Random-TW /Spring Boot 控制器中的異常處理
Павел
等級 11

Spring Boot 控制器中的異常處理

在 Random-TW 群組發布
文章內容 再次您好!是時候撣去鍵盤上的灰塵了。建立一個 spring-boot 專案。從 Maven 依賴項我們需要:
<properties>
    <maven.compiler.source>1.8</maven.compiler.source>
    <maven.compiler.target>1.8</maven.compiler.target>
    <java.version>1.8</java.version>
</properties>

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>2.2.0.RELEASE</version>
    <relativePath/><!-- lookup parent from repository -->
</parent>
<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
</dependencies>
在進一步閱讀之前,先建立一個專案結構: Spring Boot 控制器中的異常處理 - 1 BusinessException 和 CustomException:
public class BusinessException extends Exception{
    public BusinessException(String message) {
        super(message);
    }
}

public class CustomException extends Exception{
    public CustomException(String message) {
        super(message);
    }
}
響應類
public class Response {

    private String message;

    public Response() {
    }

    public Response(String message) {
        this.message = message;
    }

    public String getMessage() {
        return message;
    }

    public void setMessage(String message) {
        this.message = message;
    }
}
現在,我將用我的耳朵來表演一下,並請 Alexey Kutepov 發言,在他的文章《Spring 控制器中的異常處理》中, 他將告訴我們如何用正確的內容填充這些文件。慢慢閱讀,小心地將所有範例複製到您的專案中,在 Postman 中執行和測試。如果在 Alexey 的文章中,以下行對您提出了問題: Produces = APPLICATION_JSON_VALUE,那麼知道它與異常處理無關,它表示預設情況下該控制器的所有方法都會傳回 JSON。如果有必要,在特定的方法中,可以將這個值重寫為另一個MediaType。 如果您已經閱讀過,請繼續。上面的文章討論了處理程序的不同選項。其中最靈活的是: @ControllerAdvice - 它允許您在發生錯誤時更改標準回應的程式碼和正文。此外,它還允許您在一種方法中同時處理多個異常。但這還不是全部,如果您進一步閱讀,您將完全免費獲得改進的@ControllerAdvice 。讓我們做一些準備工作:我希望回應顯示自訂和標準錯誤訊息。為此,我們對Response類別進行更改:再添加一個字段
private String debugMessage;
讓我們建立一個額外的建構函數:
public Response(String message, String debugMessage) {
    this.message = message;
    this.debugMessage = debugMessage;
}
並且不要忘記為新字段創建 Getter 和 Setter。現在進入正題。讓我們來寫另一個控制器:
@RestController
public class Example7Controller {
    @GetMapping(value = "/testExtendsControllerAdvice")
    public ResponseEntity<?> testExtendsControllerAdvice(@RequestBody Response response) {
        return  ResponseEntity.ok(response);
    }
}
讓我們在郵差中測試:將 JSON 發送 到http://localhost:8080/testExtendsControllerAdvice
{
    "message": "message"
}
作為回應,我們將收到狀態 200 和正文
{
    "message": "message",
    "debugMessage": null
}
現在我們將發送明顯不正確的 JSON
{
    11"message": "message"
}
作為回應,我們將收到狀態 400(如果您忘記了它的含義,請在 Internet 上查找)和空響應正文。當然,沒有人對此感到滿意,我們還是鬥爭吧。之前,我們從頭開始建立了@ControllerAdvice,但在 Spring Boot 中有一個範本 - ResponseEntityExceptionHandler。它已經處理了許多異常,例如:NoHandlerFoundExceptionHttpMessageNotReadableExceptionMethodArgumentNotValidException等。這個類別處理錯誤。它有很多方法,其名稱基於句柄+異常名稱的原則。如果我們想處理一些基本的異常,那麼我們繼承這個類別並重寫所需的方法。讓我們最終確定預設的諮詢類
@ControllerAdvice
public class DefaultAdvice extends ResponseEntityExceptionHandler {//унаследовались от обработчика-заготовки

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        Response response = new Response(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }
//Небольшое отступление: В обработчике выше, обратите внимание на HttpStatus.OK,
//он может быть и HttpStatus.BAD_REQUEST or другим, тут ограничений нет,
//попробуйте поменять статусы и потестить этот обработчик


    @Override//переопределor метод родительского класса
    protected ResponseEntity<Object> handleHttpMessageNotReadable
            (HttpMessageNotReadableException ex, HttpHeaders headers, HttpStatus status, WebRequest request) {
        Response response = new Response("Не правильный JSON",ex.getMessage());
        return new ResponseEntity<>(response, status);
    }
}
正如您所注意到的,負責HttpMessageNotReadableException 的處理程序已被重寫。當傳入控制器方法的請求正文不可讀時(例如,不正確的 JSON),會發生此異常。此異常是由handleHttpMessageNotReadable ()方法造成的。讓我們使用不正確的 JSON 再次發出請求:到http://localhost:8080/testExtendsControllerAdvice
{
    11"message": "message"
}
我們收到帶有代碼 400(錯誤請求)和正文的回應:
{
    "message": "Не правильный JSON",
    "debugMessage": "JSON parse error: Unexpected character ('1' (code 49)): was expecting double-quote to start field name; nested exception is com.fasterxml.jackson.core.JsonParseException: Unexpected character ('1' (code 49)): was expecting double-quote to start field name\n at [Source: (PushbackInputStream); line: 2, column: 6]"
}
現在,回應不僅包含正確的程式碼,還包含包含資訊性訊息的正文。讓我們檢查一下它如何處理正確的 JSON 請求:
{
    "message": "message"
}
我們收到了答案:
{
    "message": "message",
    "debugMessage": null
}
老實說,我不喜歡回應包含值為null 的字段,我們現在將快速修復該問題。前往Response類別並在必填欄位上新增註釋
@JsonInclude(JsonInclude.Include.NON_NULL)
private String debugMessage;
我們重新啟動項目,再次發出先前的請求,並在回應中得到:
{
    "message": "message"
}
感謝@JsonInclude(JsonInclude.Include.NON_NULL) 註解,只有當我們指定該欄位時,該欄位才會包含在回應中。@JsonInclude包含在Jackson註釋庫中,了解它的功能非常有用。這裡有兩篇文章可供選擇: 傑克森註釋。 作者翻譯了,但沒有完成翻譯;Google翻譯做得很好。 驗證 有必要用驗證這樣的概念來補充這個主題。簡單來說,這是檢查該物件是否是我們期望的物件。例如:如果在「電話目錄」應用程式中我們需要檢查資料庫中是否存在電話號碼,那麼在進入資料庫之前,檢查使用者是否輸入了字母而不是數字是合乎邏輯的。三篇關於驗證的文章,其複雜性不斷增加: Spring 中的 Bean 驗證 在 Spring 框架中設定 DTO 驗證 Spring Boot 中的資料驗證 我們已經完成了今天的理論。 對於培訓,我建議執行以下任務: 您需要實作 NightclubBouncer 應用程式。要求: 1) 應用程式必須接受 JSON 作為輸入並寫入資料庫。JSON 範例:
{
    "name": "Katy Perry"
    “status”:super star”
}
回應正文應包含以下內容:歡迎 +姓名!2)應用程式必須實作以下方法: - 根據id從資料庫輸出一筆記錄到客戶端(Postman)。- 按欄位刪除記錄:name。3)必須實現從dto層到實體的映射以及返回。4) 如果傳入的 JSON 中的status字段不等於:super star,應用程式必須拋出KickInTheAssException錯誤(需要自己開發) 5) KickInTheAssException錯誤必須由 ControllerAdvice處理,並且響應正文必須包含訊息:「別讓我再包含訊息:「別讓我再包含訊息在這裡見到你!回應狀態應為 400。6) 標準錯誤EntityNotFoundException,例如,如果只有 Katy Perry 來到俱樂部並使用id = 1儲存到資料庫,並且您呼叫了「按 id 顯示記錄」方法並想要顯示id = 2的記錄,該記錄不在資料庫中。此錯誤必須由ResponseEntityExceptionHandler類別的重寫方法來處理,具體是哪個方法由您自己決定。響應必須具有適當的狀態。7) 進行驗證:一個簡單的選項 - JSON 欄位不能為空,或者更困難的是,「名稱」欄位必須由拉丁字母的兩個單字組成,而且它們都必須以大寫字母開頭。無效值應該拋出異常,以任何方式處理它,列印適當的錯誤代碼和錯誤訊息:No validate。並在不使用 Lombok 庫的情況下實現這一切,不要將其包含為專案依賴項 😅
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION