在Spring应用程序中处理exception的位置

我还在学spring。 我有一个应用程序设置,我正在尝试理解Spring中的exception处理。

我正在使用@ControllerAdvice来处理exception。 在我的应用程序中,有几个层,如ServicesControllersModelsRepositories 。 我应该在哪个层处理exception? 或者我应该在适当的时候处理每一层中的exception?

这是在Spring中启动exception处理的好方法:

步骤1 –创建特定的DefaultExceptionHandler类,并使用@ControllerAdvice批注对其进行批注。 在此处理程序类中,您有不同的方法,捕获预期意外的exception,这些exception使用@ExceptionHandler批注进行批注:

 @ControllerAdvice("com.stackoverflow.example") @SuppressWarnings("WeakerAccess") public class DefaultExceptionHandler extends ResponseEntityExceptionHandler { private final Logger log = LoggerFactory.getLogger("DefaultExceptionHandler"); private final MessageSourceAccessor messageSource; @Autowired public DefaultExceptionHandler(MessageSourceAccessor messageSource) { Assert.notNull(messageSource, "messageSource must not be null"); this.messageSource = messageSource; } @ExceptionHandler(ApplicationSpecificException.class) public ResponseEntity handleApplicationSpecificException(ApplicationSpecificExceptionex) { final Error error = buildError(ex); return handleExceptionInternal(ex, ex.getHttpStatus(), error); } @ExceptionHandler(Exception.class) public ResponseEntity handleException(Exception ex) { final Error error = buildError(ex); return handleExceptionInternal(ex, HttpStatus.INTERNAL_SERVER_ERROR, error); } } 

第2步 –创建一个特定于应用程序的exception(ApplicationSpecificException类),用于预期的exception,并在任何级别抛出此exception,它将被Spring接收:

 public class ApplicationSpecificException extends RuntimeException { private static final long serialVersionUID = 1L; private final ExceptionType exceptionType; public ApplicationSpecificException(ExceptionType exceptionType, Object... messageArguments) { super(MessageFormat.format(exceptionType.getMessage(), messageArguments)); this.exceptionType = exceptionType; } public ApplicationSpecificException(ExceptionType exceptionType, final Throwable cause, Object... messageArguments) { super(MessageFormat.format(exceptionType.getMessage(), messageArguments), cause); this.exceptionType = exceptionType; } public HttpStatus getHttpStatus() { return exceptionType.getStatus(); } public ExceptionType getExceptionType() { return exceptionType; } } 

ExceptionType是一个枚举:

 public enum ExceptionType { HTTP_INTERNAL_SERVER_ERROR(HttpStatus.INTERNAL_SERVER_ERROR, "An internal server error occurred."); //you can specify your own exception types... private HttpStatus status; private String message; ExceptionType(HttpStatus status, String message) { this.status = status; this.message = message; } public HttpStatus getStatus() { return status; } public String getMessage() { return message; } } 

第3步 –最后,创建了一个ExceptionFactory类。 这允许您在应用程序日志中自动记录exception:

 public class ExceptionFactory { private static final Logger LOG = LoggerFactory.getLogger(ExceptionFactory.class); public static ApplicationSpecificException create(final Throwable cause, final ExceptionType exceptionType, final Object... messageArguments) { LOG.error(MessageFormat.format(exceptionType.getMessage(), messageArguments), cause); return new ApplicationSpecificException (exceptionType, cause, messageArguments); } public static ApplicationSpecificException create(final ExceptionType exceptionType, final Object... messageArguments) { LOG.error(MessageFormat.format(exceptionType.getMessage(), messageArguments)); return new TerminologyServerException(exceptionType, messageArguments); } } 

步骤4 –在应用程序的任何位置,您现在可以抛出exception,这将在应用程序日志中记录exception。 由于Spring @ControllerAdvice注释,DefaultExceptionHandler抛出并拾取此exception:

 throw ExceptionFactory.create(ExceptionType.INTERNAL_SERVER_ERROR); 

像这样,您应对exception处理流程作为一个跨领域的问题。 不会将内部服务器错误传播给最终用户,并且DefaultExceptionHandler会处理预期和意外exception。 exception被分配了一个HTTP错误代码和错误消息,它将返回给客户端。

使用@ControllerAdvice注释的专用类可以处理所有意外问题,这是一个很好的做法。 通过这样做,您可以防止将应用程序的内部暴露给客户端。

 @ControllerAdvice public class UncaughtExceptionHandler { private static final Logger log = LoggerFactory.getLogger(UncaughtExceptionHandler.class); @ResponseStatus(HttpStatus.INTERNAL_SERVER_ERROR) @ExceptionHandler(Exception.class) public void handleAll(Exception e) { log.error("Unhandled exception occurred", e); } } 

对于预期的exception (不要与已检查的exception混淆),您可能会在出现问题的地方处理问题。 一些exception可以传播或包装并重新抛出到与@ControllerAdvice一样实现的同一个全局处理程序,以保持整个逻辑专用于单个点中的exception。

您应该尝试@ExceptionHandler注释。

你可以在这里阅读更多相关信息: https : //spring.io/blog/2013/11/01/exception-handling-in-spring-mvc

您可以在Spring应用程序中使用@ControllerAdvice作为全局exception处理程序。 检查这个很好解释教程。 使用@ControllerAdvice可以减少您的业务代码的混乱,然后您可以在一个单独的位置处理所有exception。 @ControllerAdvice使您坚持设计原则分离的关注点 。

使用Spring Framework有三种方法可以处理exception,

  1. @ExceptionHandler – 基于控制器

    这个处理程序是基于控制器的,我们需要有一个用@ExceptionHandler注释的方法,它接受Exception Class [你要处理的任何exception]作为参数,如果在控制器中引发任何这些exception,那么这个处理程序方法将处理。

    如果我们在同一个控制器中有两个处理程序方法,比如说一个Exception处理程序和另一个RuntimeException处理程序,则会触发更接近Exception Class hirarchy的处理程序方法。 在这种情况下,抛出NullpointerException然后触发IOException处理程序方法,该方法最接近Exception类。

  2. @ControllerAdvice – 全局exception处理程序

    这用于Spring应用程序中的全局error handling。 您需要拥有的是使用@ControllerAdvice注释的类。 如果在定义的控制器中引发任何exception[您可以定义此控制器建议应该在哪些包中监听基本包中的exception],那么它将由ControllerAdvice处理。

    您将在ControllerAdvice中拥有多个@ExceptionHandler,如下面的代码段所示。 此类可以是单个位置,您可以在其中处理整个应用程序的exception。

     @ControllerAdvice(basePackages = "{com.exampe.controller}") public class RestApiExceptionHandlerAdvice { /** Handling Business exception */ @ExceptionHandler(value = BadRequestException.class) public ErrorMessage handleBadRequest(BadRequestException exception) { //code... return errMsg; } @ExceptionHandler(value = GatewayTimeoutException.class) public ErrorMessage handleGatewayTimeout(GatewayTimeoutException exception) { //code... return errMsg; } } 
  3. HandlerExceptionResolver

    通过以上两种方法,我们大多数时候都使用静态页面。 在这种情况下,我们可以将不同的视图返回到不同的exception。 我们可以在spring.xml中使用MySimpleMappingExceptionResolver进行配置,您可以指定需要为哪个exception呈现哪个视图。