spring - 在 Spring 应用程序中处理异常的位置

标签 spring spring-boot exception

我还在学习Spring。我设置了一个应用程序,我正在尝试了解 Spring 中的异常处理。

我正在使用 @ControllerAdvice来处理异常。在我的应用程序中,只有很少的层,例如 Services , Controllers , ModelsRepositories .我应该在哪一层处理我的异常?或者我应该酌情处理每一层的异常?

最佳答案

这是在 Spring 中开始处理异常的好方法:

第 1 步 - 创建一个特定的 DefaultExceptionHandler 类,并使用 对其进行注释。 @ControllerAdvice 注解。在这个处理程序类中,您有不同的方法,可以同时捕获 预期 意外使用 注释的异常@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<Object> handleApplicationSpecificException(ApplicationSpecificExceptionex) {
         final Error error = buildError(ex);
         return handleExceptionInternal(ex, ex.getHttpStatus(), error);
      }

       @ExceptionHandler(Exception.class)
       public ResponseEntity<Object> handleException(Exception ex) {
           final Error error = buildError(ex);
           return handleExceptionInternal(ex, HttpStatus.INTERNAL_SERVER_ERROR, error);
    }
}

第 2 步 - 创建一个用于预期异常的应用程序特定异常(ApplicationSpecificException 类),并在任何级别抛出此异常,它会被 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 类。这允许您在应用程序日志中自动记录异常:
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 步 - 在应用程序的任何地方,您现在都可以抛出异常,这将在应用程序日志中记录异常。由于 Spring @ControllerAdvice 注释,该异常由 DefaultExceptionHandler 抛出并拾取:
throw ExceptionFactory.create(ExceptionType.INTERNAL_SERVER_ERROR);

像这样,您将异常处理过程作为一个横切关注点来处理。不会将内部服务器错误传播给最终用户,并且预期和意外异常都由 DefaultExceptionHandler 处理。异常被分配了一个特定的 HTTP 错误代码和错误信息,这些信息将返回给客户端。

关于spring - 在 Spring 应用程序中处理异常的位置,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/45034371/

相关文章:

java - Spring Boot 应用程序的单元测试

java - 空结果与为可预测但无法预防的故障抛出异常

java - 异常没有被它的 catch block 捕获,然后该方法抛出另一种异常

Spring MVC 3 定时任务在特定时间开始

java - 请推荐将 apache lucene 与 MVC/spring web 应用程序集成的最佳实践

spring-boot - 在 Kotlin 中使用 Jackson2JsonRedisSerializer 的通用 RedisTemplate

c# - 类型加载异常

java - Maven Spring jar 打包

java - Spring Autowiring

java - 如何使用 Spring Security 保护我的 Spring Data Rest 端点?