spring-data-rest - Spring Data Rest:预期 4xx 时出现 500 错误
问题描述
鉴于以下实体,当我“发布”一个“TrainerProfile”的新实体并错过“Location”中的一些@NotNull 参数时,我得到一个 500 以及打包到 JSON 中的堆栈跟踪而不是 400 和有用的信息关于出了什么问题。
@Entity
public class TrainerProfile {
...
@NotNull
@OneToOne(cascade = CascadeType.ALL)
private Location location;
}
@Entity
public class Location {
@Id @GeneratedValue
private Long id;
@NotNull
private String zipcode;
@NotNull
private String city;
@NotNull
private String country;
}
当我将此数据发布到 API 时
{
...
"location": {
"zipcode": "10000"
}
}
我看到以下日志:
javax.validation.ConstraintViolationException: Validation failed for classes [training.edit.provider.model.Location] during persist time for groups [javax.validation.groups.Default, ]
List of constraint violations:[
ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=city, rootBeanClass=class training.edit.provider.model.Location, messageTemplate='{javax.validation.constraints.NotNull.message}'}
ConstraintViolationImpl{interpolatedMessage='must not be null', propertyPath=country, rootBeanClass=class training.edit.provider.model.Location, messageTemplate='{javax.validation.constraints.NotNull.message}'}
]
但是 REST 客户端看到了这一点:
< HTTP/1.1 500
< Vary: Origin
< Vary: Access-Control-Request-Method
< Vary: Access-Control-Request-Headers
< Access-Control-Allow-Origin: http://localhost:4200
< Access-Control-Allow-Credentials: true
< X-Content-Type-Options: nosniff
< X-XSS-Protection: 1; mode=block
< Cache-Control: no-cache, no-store, max-age=0, must-revalidate
< Pragma: no-cache
< Expires: 0
< X-Frame-Options: DENY
< Content-Type: application/json
< Transfer-Encoding: chunked
< Date: Tue, 16 Jun 2020 09:33:16 GMT
< Connection: close
<
{"timestamp":"2020-06-16T09:33:16.605+0000","status":500,"error":"Internal Server Error","message":"Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction","trace":"org.springframework.transaction.TransactionSystemException: Could not commit JPA transaction; nested exception is javax.persistence.RollbackException: Error while committing the transaction\n\tat org.springframework.orm.jpa.JpaTransactionManager.doCommit(JpaTransactionManager.java:543)\n...
文本更长,但我不让你休息。
我这样配置验证:
@Configuration
@RequiredArgsConstructor(onConstructor = @__(@Autowired))
public class RestConfiguration implements RepositoryRestConfigurer {
private final @NonNull Validator validator;
private final @NonNull UriToIdConverter converter;
@Override
public void configureConversionService(ConfigurableConversionService conversionService) {
RepositoryRestConfigurer.super.configureConversionService(conversionService);
conversionService.addConverter(converter);
}
@Override
public void configureValidatingRepositoryEventListener(ValidatingRepositoryEventListener validatingListener) {
validatingListener.addValidator("afterCreate", validator);
validatingListener.addValidator("beforeCreate", validator);
validatingListener.addValidator("afterSave", validator);
validatingListener.addValidator("beforeSave", validator);
}
}
在这种情况下,如何获得正确的错误消息?当我发布不适用于“TrainerProfile”的内容时,我会收到正确的消息和错误代码,但不适用于嵌套对象。
解决方案
中间解决方案
每个 Spring Data REST 请求都会发出一个事务。外部异常RollbackException
会给你一个500
响应,即使这个异常实际上来自嵌套验证失败ConstraintViolationException
。一个可行但不是很好的解决方案应该是ResponseEntityExceptionHandler
提取嵌套异常,如auth0 示例。代码在这里。
建议
只是不要在不符合您要求的地方使用 Spring Data REST。
正如 Spring Data REST 领导者 Oliver Drotbohm 在这个答案中所说。
RESTful API 应该适用于聚合。聚合是一个 DDD 概念。聚合不适用于关系数据库。尝试 No-SQL 数据库,例如 Mongo DB。学习 DDD 的起点是Oliver 的演讲。
推荐阅读
- reactjs - 反应功能组件表单组件onSubmit处理程序不工作
- r - 尝试将 tidymodels 用于 catboost 模型:接收与标签相关的错误
- python - 如何将多边形分成大小大致相等的 n 部分?
- ipaf - 文件作为 ALM 的证据
- python - 在 Python 单元测试中模拟 pymysql.connect 调用
- r - 如何为 R 包创建具有动态输入的函数?
- java - Java Rest api - 限制用户的并发请求
- html - SAPUI5 响应式表多选集选定记录
- reactjs - Laravel 和 React 身份验证设置
- xcode - IOS 15 标头元素中的 SwiftUI 变得拉伸