4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Phone AppliAdvent Calendar 2021

Day 5

独自 例外ハンドリング (基本)

Last updated at Posted at 2021-12-06

PHONEAPPLIアドベントカレンダー1回目です。(早速、投稿が遅れました。すみません・・・・)
今回は、例外処理の基本的な部分を投稿したいと思います。

きっかけ

  • 独自例外処理の知識を整理をしたかったから
  • 基本的な部分の理解が出来ていない気がするから

前提

  • Spring Boot + kotlin で行う
  • タスク作成 ツールの開発を想定します。

扱う例外

  • HTTP method が違う
  • アノテーションによる例外
    • Null + 空文字

これらを、HTTPステータスと例外をレスポンスとして出力できるようにする。

やり方の種類

  • ResponseEntityExceptionHandler を継承している場合は、override fun handleHttpRequestMethodNotSupported を使う(今回のHTTP methodが異なる場合に使用)
  • ResponseEntityExceptionHandler を継承しない場合は、以下を使いたい関数の上におく
    • @ExceptionHandler(HttpRequestMethodNotSupportedException::class)(今回のアノテーションエラーで使用)

共通レスポンス

レスポンスとしての例外フォーマットは、独自フォーマット にします。

{
   "message": "Request method 'POST' not supported",
   "status": 405
}

実装

HTTP method が違う 場合

ResponseEntityExceptionHandler を継承しているパターンで行う

  1. ControllerAdvice クラスを作成
  2. ControllerAdvice クラスに @RestControllerAdvice をつける(必須
  3. ResponseEntityExceptionHandler を継承
  4. handleHttpRequestMethodNotSupported をオーバーライドする

ResponseEntityExceptionHandler は、例外時の基本的な処理が記載されている。エラーパターンも網羅されているため、エラーメッセージを表示したい時にデフォルトが表示したくない場合に使えると思う。

TaskControllerAdvice.kt

TaskControllerAdvice.kt
@RestControllerAdvice
class TaskControllerAdvice(): ResponseEntityExceptionHandler() {
    
    override fun handleHttpRequestMethodNotSupported(
        ex: HttpRequestMethodNotSupportedException,
        headers: HttpHeaders,
        status: HttpStatus,
        request: WebRequest
    ): ResponseEntity<Any> {
        return super.handleExceptionInternal(
            ex,
            createErrorResponse(ex, status), //-> ここで、JSONで返す値を加える
            httpheaderJson,
            status,
            request
        )
    }

    private fun createErrorResponse(
        ex: Exception,
        status: HttpStatus
    ): ErrorResponse {
        return ErrorResponse(
            message = ex.message,
            status = status.value()
        )
    }
}

class ErrorResponse(
    val message: String?,
    val status: Int
)

レスポンス

{
    "message": "Request method 'POST' not supported",
    "status": 405
}

アノテーションエラーの場合

ResponseEntityExceptionHandler を継承していないパターンで行う

  1. TaskController.kt : エラーチェックをしたいクラスに @Valid をつける
  2. TaskRequest.kt: 実際に、@NotBlank などのアノテーションをつける
  3. TaskControllerAdvice.kt: クラス・ファイルを作成後、実際の例外処理を記載する(アノテーションでのエラーは、MethodArgumentNotValidException がキャッチしてくれると思う)

TaskController.kt

TaskController.kt
@PostMapping
    fun create(
        @RequestBody @Valid taskRequest: TaskRequest
    ) {
        // 省略
    }

TaskRequest.kt

TaskRequest.kt
data class TaskRequest (
    val id: Int,

    @field: NotBlank
    val content: String,
)

TaskControllerAdvice.kt

@ExceptionHandler(MethodArgumentNotValidException::class)
fun handleMethodNotValidException(
   ex: MethodArgumentNotValidException
): ErrorResponse{
   return (
     ErrorResponse(
       message = ex.bindingResult.fieldError?.defaultMessage,
       status = HttpStatus.BAD_REQUEST.value()
     )
  )
}

class ErrorResponse(
    val message: String?,
    val status: Int
)

レスポンス

{
    "message": "空白は許可されていません",
    "status": 400
}

まとめ

  • 今回は、HTTPメソッドが違う場合、アノテーションエラーに引っかかった場合での例外処理を書いてみました。
  • ResponseEntityExceptionHandler を継承すれば、引数にも多くの情報が入っているので例外として出力したいことを表示したい時に、使えるかなと思いました。
4
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?