JavaRush /Java Blog /Random-JA /Spring Boot コントローラーでの例外処理
Павел
レベル 11

Spring Boot コントローラーでの例外処理

Random-JA グループに公開済み
この記事の内容 サイクル こんにちは!キーボードのほこりを取り除きましょう。スプリングブート プロジェクトを作成します。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 の記事の次の行で疑問が生じた場合: generated = APPLICATION_JSON_VALUEですが、これは例外処理とは何の関係もなく、デフォルトでこのコントローラーのすべてのメソッドが JSON を返すと書かれていることがわかります。必要に応じて、特定のメソッドで、この値を別のMediaTypeにオーバーライドできます 。上記の記事では、ハンドラーのさまざまなオプションについて説明しています。その中で最も柔軟なもの: @ControllerAdvice - エラーが発生した場合に、標準応答のコードと本文の両方を変更できます。さらに、1 つのメソッドで複数の例外を一度に処理できます。しかし、それだけではありません。さらに読み進めると、改良された@ControllerAdvice を完全に無料で入手できます。いくつかの準備作業を行ってみましょう。応答にカスタム エラー メッセージと標準エラー メッセージの両方を表示したいと考えています。これを行うには、 Responseクラスに変更を加えましょう。フィールドを 1 つ追加します。

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);
    }
}
postman でテストしてみましょう: JSON を http://localhost:8080/testExtendsControllerAdviceに送信します

{
    "message": "message"
}
応答として、ステータス 200 と本文を受け取ります。

{
    "message": "message",
    "debugMessage": null
}
ここで、明らかに間違った JSON を送信します。

{
    11"message": "message"
}
応答として、ステータス 400 (意味を忘れた場合はインターネットで調べてください) と空の応答本文を受け取ります。もちろん、これに満足する人は誰もいません。闘いましょう。以前は@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 (Bad Request) と本文を含む応答を受け取ります。

{
    "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アノテーション ライブラリに含まれており、何ができるかを知るのに非常に役立ちます。ここでは 2 つの記事から選択できます: Jackson の注釈。 著者は翻訳しましたが、翻訳は完了していません。Google Translit は素晴らしい仕事をしています。 検証 このトピックを検証などの概念で補足する必要があります。簡単に言うと、これはオブジェクトが期待どおりのオブジェクトであるかどうかをチェックすることです。たとえば、「電話帳」アプリケーションでデータベース内の電話番号の存在を確認する必要がある場合、データベースにアクセスする前に、ユーザーが数字の代わりに文字を入力したかどうかを確認するのが論理的です。複雑さが増す検証に関する 3 つの記事: Spring での Bean の検証 Spring Framework での DTO 検証の設定 Spring Boot でのデータ検証 今日の理論はこれで終わりです。 トレーニングのために、次のタスクをお勧めします。 NightclubBouncer アプリケーションを実装する必要があります。要件: 1) アプリケーションは入力として JSON を受け入れ、データベースに書き込む必要があります。JSON の例:

{
    "name": "Katy Perry"
    “status”:super star”
}
そして、応答の本文には次の記述が含まれている必要があります: ようこそ +名前! 2) アプリケーションは次のメソッドを実装する必要があります: - IDによってデータベースからクライアント (Postman) にレコードを出力します。- フィールド名によるレコードの削除。3) dtoレイヤーからエンティティへのマッピング、およびその逆のマッピングを実装する必要があります。4)受信 JSON のステータスフィールドがスーパースターに等しくない場合、アプリケーションは KickInTheAssException エラーをスローする必要があります(独自に開発する必要があります) 。 5) KickInTheAssExceptionエラーはControllerAdvice によって処理され、応答本文にはメッセージ:「もうここでは会わせないでください!応答ステータスは 400 である必要があります。 6) 標準エラーEntityNotFoundException 。たとえば、ケイティ ペリーだけがクラブに来て、 id = 1でデータベースに保存され、 「id によるレコードの表示」メソッドを呼び出して、必要な場合に発生します。データベースにないid = 2のレコードを表示します。このエラーは、 ResponseEntityExceptionHandlerクラスのオーバーライドされたメソッドで処理する必要があります。どのメソッドを使用するかは自分で判断してください。応答には適切なステータスが必要です。7) 検証を実行します。簡単なオプションです。JSON フィールドは null であってはなりません。さらに難しいのは、「名前」フィールドはラテン文字の 2 つの単語で構成され、両方とも大文字で始まる必要があります。無効な値は例外をスローし、何らかの方法で処理し、適切なエラー コードとエラー メッセージを出力する必要があります: No validate。そして、これらすべてを Lombok ライブラリを使用せずに実装し、プロジェクトの依存関係として含めないでください 😅
コメント
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION