【问题标题】:Spring Data Rest with validation带有验证的 Spring Data Rest
【发布时间】:2020-05-13 16:02:44
【问题描述】:

我正在使用@RepositoryRestResource 来创建我的REST API,这避免了像@RestController 中那样手动编写代码,并且给了我一个很好的HATEOAS 响应。但是现在我添加到我的实体的验证不起作用,或者我得到的是 500 响应代码而不是 400。

我尝试使用@ControllerAdvice + @ExceptionHandler 来捕获ConstraintViolationException,但它似乎之前被捕获并且抛出的是TransactionSystemException。

验证数据是非常基本的事情,但由于某种原因,经过多次谷歌搜索后,我还没有找到解决方案。

编辑:显示代码:

@ControllerAdvice
public class ConstraintViolationExceptionHandler extends  ResponseEntityExceptionHandler {

    @ExceptionHandler({ ConstraintViolationException.class })
    public ResponseEntity<Object> handleConstraintViolationException(
      Exception ex, WebRequest request) {

          return new ResponseEntity<Object>("test 123", HttpStatus.BAD_REQUEST);
    }
}

我仍然得到:

Servlet.service() 用于 servlet [dispatcherServlet] 在上下文中的路径 [] 抛出异常 [请求处理失败;嵌套异常是 org.springframework.transaction.TransactionSystemException:不能 提交 JPA 事务;嵌套异常是 javax.persistence.RollbackException:提交时出错 交易]有根本原因 javax.validation.ConstraintViolationException

因此,Spring Data REST 似乎更早地捕获了 ConstraintViolationException,并引发了 TransactionSystemException。如果我更改代码以捕获此异常,例如:

@ControllerAdvice
public class ConstraintViolationExceptionHandler extends  ResponseEntityExceptionHandler {

    @ExceptionHandler({ TransactionSystemException .class })
    public ResponseEntity<Object> handleConstraintViolationException(
      Exception ex, WebRequest request) {

          return new ResponseEntity<Object>("test 123", HttpStatus.BAD_REQUEST);
    }
}

然后它可以工作,但这不是我应该捕获的例外。

【问题讨论】:

  • 嗨 Kaladin,需要查看您的代码,据我了解,您使用 excpetion 处理程序做得很好......我能想到的唯一场景......您必须在某处处理 ConstraintViolationException 或其父级你的代码
  • 嗨 Swarit Agarwal,我更新了问题。 Spring Data REST 似乎正在捕获和转换异常。

标签: spring spring-boot validation


【解决方案1】:

您可以通过ControllerAdvice处理ConstraintViolationException,我试过了,效果很好,请参考下面的代码sn-ps。

用户.java

@Entity
@Getter
@Setter

public class User {

@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;

@NotNull
private String name;

@NotNull
private String surname;
}

UserRepository.java

@RepositoryRestResource
public interface UserRepository extends JpaRepository<User, Long> {
}

GlobalExceptionHandler.java

@ControllerAdvice
public class GlobalExceptionHandler {
    @ExceptionHandler(ConstraintViolationException.class)
    public ResponseEntity<?> handlerException(ConstraintViolationException e) {
        final List<Object> errors = new ArrayList<>();
        e.getConstraintViolations().stream().forEach(fieldError -> {
            Map<String, Object> error = new HashMap<>();
            error.put("path", String.valueOf(fieldError.getPropertyPath()));
            error.put("messgae", fieldError.getMessage());
            errors.add(error);
        });
        HttpStatus httpStatus = HttpStatus.BAD_REQUEST;
        Map<String, Object> body = new HashMap<>();
        body.put("error", errors);
        return new ResponseEntity<>(body, httpStatus);
    }
}

我已将地图用于响应正文,您可以根据需要使用自定义对象。

然后试试下面的 CURL 来测试 API。

curl --location --request POST 'http://localhost:8080/users' \
--header 'Content-Type: application/json' \
--data-raw '{}'

响应将如下所示。

Status: 400 BAD REQUEST
{"error":[{"path":"surname","messgae":"must not be null"},{"path":"name","messgae":"must not be null"}]}

【讨论】:

  • 是的,使用您的示例有效,因此我查看了我的代码。使用 GenerationType.AUTO 时,未执行 ExceptionHandler(使用 postgres)。将其更改为 GenerationType.IDENTITY 修复了它。
【解决方案2】:

Spring Data REST 提供了一个 RepositoryRestExceptionHandler,其中包含一个 ResponseEntity&lt;RepositoryConstraintViolationExceptionMessage&gt; handleRepositoryConstraintViolationException(RepositoryConstraintViolationException o_O) 方法。

RepositoryRestMvcConfiguration class provides a bean 用于此类异常处理程序。如果您想修改它,请尝试提供您自己的 bean 并将其注册到配置中。例如,您可以通过实现 RepositoryRestConfigurer 来做到这一点,因为您应该熟悉其他 Spring 项目(Spring Security,...)。

【讨论】:

    猜你喜欢
    • 2016-03-02
    • 2014-08-10
    • 2016-05-21
    • 2018-08-22
    • 1970-01-01
    • 2017-03-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多