在 Spring Data REST 中处理 DataIntegrityViolationExceptions

Pat*_*čin 5 spring-data-rest spring-boot

假设我有带属性的 Airport 实体:

@Column(nullable = false, unique = true)
private final String code;
Run Code Online (Sandbox Code Playgroud)

显然,当我使用之前使用的代码持久化实体时,它会抛出 DataIntegrityViolationException

我有启用了 Spring Data REST 的 Spring Boot 应用程序。

对于这种情况,RepositoryRestExceptionHandler需要处理DataIntegrityViolationExceptions 并将它们映射到409状态代码:

@ExceptionHandler({ OptimisticLockingFailureException.class, DataIntegrityViolationException.class })
ResponseEntity<ExceptionMessage> handleConflict(Exception o_O) {
    return errorResponse(HttpStatus.CONFLICT, new HttpHeaders(), o_O);
}
Run Code Online (Sandbox Code Playgroud)

典型的响应如下所示:

HTTP/1.1 409
X-Application-Context: application
Content-Type: application/hal+json;charset=UTF-8
Transfer-Encoding: chunked
Date: Fri, 28 Apr 2017 10:21:31 GMT

{
  "cause" : {
    "cause" : {
      "cause" : null,
      "message" : "Unique index or primary key violation: \"UK_X9RMMVEVTW274QQXGT73OQ74_INDEX_C ON PUBLIC.AIRPORT(CODE) VALUES ('null', 54)\"; SQL statement:\ninsert into AIRPORT (id, rec_version, code, description) values (null, ?, ?, ?) [23505-194]"
    },
    "message" : "could not execute statement"
  },
  "message" : "could not execute statement; SQL [n/a]; constraint [\"UK_X9RMMVEVTW274QQXGT73OQ74_INDEX_C ON PUBLIC.AIRPORT(CODE) VALUES ('null', 54)\"; SQL statement:\ninsert into AIRPORT (id, rec_version, code, description) values (null, ?, ?, ?) [23505-194]]; nested exception is org.hibernate.exception.ConstraintViolationException: could not execute statement"
}
Run Code Online (Sandbox Code Playgroud)

问题是用 SQL 异常散布响应是否是一种好方法。在我看来不是。

如果没有,要遵循哪些良好实践以及如何在引导和数据 REST 中实施它们?

Afr*_*idi 4

在响应中添加 SQL 异常是否是一个好方法?

在大多数情况下,最好在将此类异常发送到客户端应用程序之前将其转换为自定义错误消息/错误代码。

需要遵循哪些良好实践以及如何在引导和数据 REST 中实现它们?

在 spring-boot 和 REST 中,您可以实现自己的 ExceptionController/ExceptionHandler 来处理此类类型的异常。在这里您可以捕获任何类型的异常,并可以将其转换为任何形式的自定义对象。

例如:

@ControllerAdvice
@RestController
public class ExceptionController {

@ExceptionHandler(value = Exception.class)
public ResponseEntity<?> handleException(Exception e) {
    UserResponse response = null;

    if(e instanceof DataIntegrityViolationException){
        DataIntegrityViolationException ex = (DataIntegrityViolationException) e;
        response = new UserResponse(ErrorCodes.DuplicateMobNo, "This mobile no is already Registered!");
        return new ResponseEntity<UserResponse>(response, HttpStatus.CONFLICT);
    }
}
Run Code Online (Sandbox Code Playgroud)

其中 UserResponse 可以是这样的:

public class UserResponse extends GenericResponse{

    private Long customErrorCode;
    private String errorMsg;

public UserResponse() {

}

    public UserResponse(Long code, String msg) {
        this.customErrorCode = code;
        this.errorMsg = msg;
    }

    public String getCustomErrorCode () {
        return customErrorCode ;
    }

    public void setCustomErrorCode (Long customErrorCode ) {
        this.customErrorCode = customErrorCode ;
    }

    public String getErrorMsg  () {
        return errorMsg ;
    }

    public void setErrorMsg  (String errorMsg ) {
        this.errorMsg = errorMsg ;
    }
}
Run Code Online (Sandbox Code Playgroud)

您可以创建自己的自定义错误代码,例如 DuplicateMobileNo 等

  • 如何确定错误与哪个字段相关? (13认同)