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

画像



実際には、多くの場合、コントローラー内またはアプリケーション全体でさえも例外を一元的に処理する必要があります。この記事では、Spring Frameworkがこの問題を解決するために提供する主な機能を分析し、簡単な例を使用して、すべてがどのように機能するかを見てみましょう。このトピックに興味のある人-カットの下で歓迎します!



元々、Spring 3.2より前は、アプリケーションで例外を処理する主な方法は、HandlerExceptionResolver@ExceptionHandlerアノテーションでした。以下で詳細に分析しますが、いくつかの欠点があります。バージョン3.2以降、@ ControllerAdviceアノテーションが表示され、以前のソリューションから制限が削除されましたまた、Spring 5ではRESTAPIの基本的なエラーを処理するのに非常に便利な新しいResponseStatusExceptionクラスが追加されまし



そして今、まず最初に、行きましょう!



コントローラの例外処理-@ ExceptionHandler



@ExceptionHandler . , , .



:



@RestController
public class Example1Controller {

    @GetMapping(value = "/testExceptionHandler", produces = APPLICATION_JSON_VALUE)
    public Response testExceptionHandler(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testExceptionHandler");
        }
        return new Response("OK");
    }

    @ExceptionHandler(BusinessException.class)
    public Response handleException(BusinessException e) {
        return new Response(e.getMessage());
    }

}


testExceptionHandler, BusinessException, — . , , .



handleException . @ExceptionHandler(BusinessException.class), BusinessException. @ExceptionHandler , : @ExceptionHandler({BusinessException.class, ServiceException.class}).



— 200 JSON . , @ResponseStatus, @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR).



:





:





@ExceptionHandler , . @ExceptionHandler , , , .



HandlerExceptionResolver



HandlerExceptionResolver Spring. HandlerExceptionResolver. , , Spring . :



ExceptionHandlerExceptionResolver @ExceptionHandler, .



DefaultHandlerExceptionResolver — Spring , :



Exception HTTP Status Code
BindException 400 (Bad Request)
ConversionNotSupportedException 500 (Internal Server Error)
HttpMediaTypeNotAcceptableException 406 (Not Acceptable)
HttpMediaTypeNotSupportedException 415 (Unsupported Media Type)
HttpMessageNotReadableException 400 (Bad Request)
HttpMessageNotWritableException 500 (Internal Server Error)
HttpRequestMethodNotSupportedException 405 (Method Not Allowed)
MethodArgumentNotValidException 400 (Bad Request)
MissingServletRequestParameterException 400 (Bad Request)
MissingServletRequestPartException 400 (Bad Request)
NoSuchRequestHandlingMethodException 404 (Not Found)
TypeMismatchException 400 (Bad Request)


, REST API . . ModelAndView, , .



ResponseStatusExceptionResolver @ResponseStatus.



ServiceException:



@ResponseStatus(value = HttpStatus.INTERNAL_SERVER_ERROR)
public class ServiceException extends Exception {

    public ServiceException(String message) {
        super(message);
    }

}


ServiceException @ResponseStatus value INTERNAL_SERVER_ERROR, - 500.



:



@RestController
public class Example2Controller {

    @GetMapping(value = "/testResponseStatusExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws ServiceException {
        if (exception) {
            throw new ServiceException("ServiceException in testResponseStatusExceptionResolver");
        }
        return new Response("OK");
    }

}


GET- exception=true, 500- :





— . , @ResponseStatus .



HandlerExceptionResolver , - JSON XML . , .



:



@Component
public class CustomExceptionResolver extends AbstractHandlerExceptionResolver {

    @Override
    protected ModelAndView doResolveException(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) {
        ModelAndView modelAndView = new ModelAndView(new MappingJackson2JsonView());
        if (ex instanceof CustomException) {
            modelAndView.setStatus(HttpStatus.BAD_REQUEST);
            modelAndView.addObject("message", "CustomException was handled");
            return modelAndView;

        }
        modelAndView.setStatus(HttpStatus.INTERNAL_SERVER_ERROR);
        modelAndView.addObject("message", "Another exception was handled");
        return modelAndView;
    }

}


, . , : , ModelAndView. JSON, .



-, . . , . , — :



@RestController
public class Example3Controller {

    @GetMapping(value = "/testCustomExceptionResolver", produces = APPLICATION_JSON_VALUE)
    public Response testCustomExceptionResolver(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws CustomException {
        if (exception) {
            throw new CustomException("CustomException in testCustomExceptionResolver");
        }
        return new Response("OK");
    }

}


:





200 JSON .



@ControllerAdvice



— . Spring 3.2 @ControllerAdvice.



:



@ControllerAdvice
public class DefaultAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        Response response = new Response(e.getMessage());
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}


, @ControllerAdvice , .

DefaultAdvice handleException. handleException @ExceptionHandler, , , . BusinessException.



: @ExceptionHandler({BusinessException.class, ServiceException.class}). @ExceptionHandler .

, handleException ResponseEntity Response:



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;
    }

}


, JSON . message HttpStatus.OK, 200.



:



@RestController
public class Example4Controller {

    @GetMapping(value = "/testDefaultControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testDefaultControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testDefaultControllerAdvice");
        }
        return new Response("OK");
    }

}


, , JSON 200:





?

! :



@ControllerAdvice(annotations = CustomExceptionHandler.class)
public class CustomAdvice {

    @ExceptionHandler(BusinessException.class)
    public ResponseEntity<Response> handleException(BusinessException e) {
        String message = String.format("%s %s", LocalDateTime.now(), e.getMessage());
        Response response = new Response(message);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

}


@ControllerAdvice(annotations = CustomExceptionHandler.class). CustomAdvice , @CustomExceptionHandler.



@CustomExceptionHandler :



@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomExceptionHandler {
}


:



@RestController
@CustomExceptionHandler
public class Example5Controller {

    @GetMapping(value = "/testCustomControllerAdvice", produces = APPLICATION_JSON_VALUE)
    public Response testCustomControllerAdvice(@RequestParam(required = false, defaultValue = "false") boolean exception)
            throws BusinessException {
        if (exception) {
            throw new BusinessException("BusinessException in testCustomControllerAdvice");
        }
        return new Response("OK");
    }

}


Example5Controller @CustomExceptionHandler, Example4Controller . BusinessException CustomAdvice, DefaultAdvice, .



CustomAdvice — :





. @ControllerAdvice, . .



ResponseStatusException.



ResponseStatusException:



@RestController
public class Example6Controller {

    @GetMapping(value = "/testResponseStatusException", produces = APPLICATION_JSON_VALUE)
    public Response testResponseStatusException(@RequestParam(required = false, defaultValue = "false") boolean exception) {
        if (exception) {
            throw new ResponseStatusException(HttpStatus.INTERNAL_SERVER_ERROR, "ResponseStatusException in testResponseStatusException");
        }
        return new Response("OK");
    }

}


ResponseStatusException , , . @ResponseStatus — -. , .



:





要約:例外を処理するさまざまな方法を見てきましたが、それぞれに独自の特性があります。大規模なアプリケーション内では、一度に複数のアプローチを見つけることができますが、非常に注意して、エラー処理ロジックを過度に複雑にしないようにする必要があります。そうしないと、一部の例外が間違ったハンドラーで処理され、応答が予期されたものと異なることが判明します。たとえば、アプリケーションに複数のアドバイザがある場合、新しいアドバイザを作成するときは、古いコントローラからの例外を処理する既存の順序を壊さないようにする必要があります。

だから注意してください、そしてすべてがうまくいくでしょう!



記事からのソースへのリンク




All Articles