Gobble up pudding

プログラミングの記事がメインのブログです。

MENU

Spring Boot 例外処理/エラーハンドリングメモ

スポンサードリンク

f:id:fa11enprince:20190306032659j:plain

Spring Bootでは例外処理はthrowしてしまえばわりとよしなにやってくれるが… それでも考えるべきことはある。 場合によっては例外処理をあまり使わず、オブジェクトの戻り値による処理をすることもある。 と、去年の1月からSpring Bootを使い始めてSpringの良さがわかり、Springの深いところに潜り始めた。 気になったところをメモします。 気が向いたら更新しようかと思います。

全てここを参考にさせていただいています。 いろいろ学びが多く、とても良い資料です。 speakerdeck.com

例外処理のパターン@Controller編

基本的には

  1. @Controllerに個別で@ExceptionHandler
  2. @ControllerAdvice@ExceptionHandler
  3. Spring BootのError Controller

3番目は知らなかった 1番目と2番目はよく使うと思う

@Slf4j
@ControllerAdvice("com.example.controllers.foo")
public class GlobalControllerAdvice {
    @ExceptionHandler(Exception.class)
    public String handleException(Exception e, HttpServletResponse response, Model model) {
        response.setStatus(HttpStatus.INTERNAL_SERVER_ERROR.value());
        log.error("Error occurred.", e);
        model.addAttribute("errorMessage", e.getMessage());
        
        return "foo/error";
    }
}

プレゼンテーション層、404エラーなど全ての例外を補足できない&status codeがセットされないという問題がある

ErrorControllerを使う

Spring MVCでは次の順に呼ばれるとのこと

  1. ExceptionHandlerExceptionResolver(@ExceptionHandler)
  2. ResponseStatusExceptionResolver(@ResponseStatus)
  3. DefaultHandlerExceptionResolver(Spring MVCで起きた例外を処理)

ErrorControllerはこれらが適用された後に呼ばれる

例外処理のパターン@RestController編

  1. @RestControllerに個別で@ExceptionHandler
  2. @RestControllerAdvice@ExceptionHandler
  3. @ResponseStatusを付与した例外をThrow

qiita.com

ExceptionHandlerを使う場合

@Data
public class ErrorResponse {
    private String KeyName;
    private String KeyValue;
    private String Message;

    public ErrorResponse(String keyName,String keyValue,String message){
        this.KeyName = keyName;
        this.KeyValue = keyValue;
        this.Message = message;
    }
    public ResponseEntity<ErrorResponse> createResponse(HttpStatus status){
        return new ResponseEntity<ErrorResponse>(this, status);
    }
    public static ResponseEntity<ErrorResponse> createResponse(BadRequestException e){
        return new ResponseEntity<ErrorResponse>(
                new ErrorResponse(e.getKeyName(),e.getKeyValue(),e.getMessage())
                    ,HttpStatus.BAD_REQUEST);
    }
}

自前例外

@Data
public class BadRequestException extends Exception {

    private String keyName;
    private String keyValue;
    private String error;

    public BadRequestException(String error, String keyName, String keyValue){
        this.keyName = keyName;
        this.keyValue = keyValue;
        this.error = error;
    }

}

例外ハンドラ

@RestControllerAdvice
public class BadRequestExceptionHandler {

    @ExceptionHandler(BadRequestException.class)
    public ResponseEntity<ErrorResponse> getException(HttpServletRequest req, BadRequestException e){
        return ErrorResponse.createResponse(e);
    }
    
}

その他リンク

https://www.baeldung.com/exception-handling-for-rest-with-spring https://www.slideshare.net/shintanimoto/spring-boot10 https://docs.spring.io/spring-boot/docs/current/reference/html/common-application-properties.html