首页 > 解决方案 > 使用 Spring Data Rest 引发自定义异常

问题描述

我正在使用 Spring Boot 和 Spring Data Rest 开发后端。我需要抛出一个自定义异常,而不是具有不同结构的 Spring Data Rest 异常。

这是我编写的代码,但它不会抛出我的异常,而是一个通用的 RuntimeException

import org.springframework.dao.DataIntegrityViolationException;
import org.springframework.data.rest.webmvc.RepositoryRestController;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;

import java.util.Locale;

@ControllerAdvice(annotations = RepositoryRestController.class)
public class RestRepositoryExceptionHandler {

    @ExceptionHandler({DataIntegrityViolationException.class})
    public RuntimeException handle(Exception e, Locale locale) {
        throw new RuntimeException("REST_REPOSITORY_EXCEPTION", e);
//        throw new RuntimeException("DATA_ALREADY_EXISTS");
    }

}

这是一个存储库

import it.edistribuzione.smartgrid.model.User;
import lombok.NonNull;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.rest.core.annotation.RepositoryRestResource;

import java.util.Optional;

@RepositoryRestResource(path = "users")
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByUsername(String username);

    Boolean existsByUsername(String username);

    boolean existsById(@NonNull Long id);
}

标签: javaspringspring-bootspring-data-jpa

解决方案


通常,您的异常处理程序是您作为开发人员编写的最后一层异常处理。您通常不会重新抛出异常,因为那样它将被交给托管您的应用程序的服务器的默认异常处理机制。

您通常会返回包含您希望用户看到的错误的响应。

几乎所有我知道为 500 错误的服务器都会在异常处理机制中匹配抛出 RunntimeException。因此,用户会看到一个 500 错误,这似乎是您的后端失败并且出现了问题。

如果您可以预测会出现什么问题,那么不要让用户看到 500 错误代码,而是告诉他什么是坏的。在那种情况下,当您收到DataIntegrityViolationException它时,这意味着用户提供的输入以一种或另一种方式是错误的。所以它不可能是失败的后端(500错误),而是用户做了一个错误的请求(400错误)。

当客户端可以使后端失败并从默认处理机制中检索堆栈跟踪并了解有关如何构建数据库的信息时,这也可能是一个安全问题。

这是您可以在应用程序中使用的自定义异常

public class ApplicationException extends RuntimeException  {

    private CustomError customError;

    public ApplicationException(CustomError customError){
        super();
        this.customError = customError;
    }
}

这是一个错误模型类

@Getter
@Setter
@NoArgsConstructor
public class CustomError {

    private int code;
    private String message;
    private String cause;

    public CustomError(int code, String message, String cause) {
        this.code = code;
        this.message = message;
        this.cause = cause;
    }
 }

这就是您的错误处理方法如何用于返回用户理解的响应。

@ControllerAdvice
public class RestRepositoryExceptionHandler {
    
    @ExceptionHandler(ApplicationException.class)
    public ResponseEntity handleApplicationException(ApplicationException e) {
        return ResponseEntity.status(e.getCustomError().getCode()).body(e.getCustomError());
    }


   @ExceptionHandler({DataIntegrityViolationException.class})
    public ResponseEntity handle(Exception e, Locale locale) {
        return ResponseEntity.status(400).body(new CustomError(400, e.getMessage(), "this is the cause that the user will see"));
  }
}

以下行可以在您的应用程序中的任何地方重用,例如(Controllers、Services、Daos...)

throw new ApplicationException( new CustomError(400, "This is the error message that the user will see", "this is the cause that the user will see"));

你当然可以修改错误代码而不是只抛出400,还可以在抛出ApplicationException之前修改CustomError中的errorMessageanderrorCause


推荐阅读