我有一个用 spring boot 开发的 Rest 服务器,我需要返回一个属性格式错误的错误报告(无效日期,无效整数,无效字符串,对象而不是数组,..)
问题是,如果发送的 json 对象中的参数无效,我们必须返回一个包含 {field, errorMsg} 列表的对象
例子
{
"message": "Invalid request parameters",
"properties_errors": [
{
"property": "mail",
"cause": "Email format invalid"
},
{
"property": "startDate",
"cause": "Date format invalid"
}
]
}
在 Controller 中,我用@Valid @RequestBody MyObj obj 注释了要验证的对象,作为参数给定 之后我找到了两个解决方案:
- 自定义反序列化器
定义自定义反序列化器 (com.fasterxml.jackson.databind.JsonDeserializer),将 json 对象的字符串或对象值转换为所需类型 实体属性的注释,并使用 @JsonDeserialize (using = MyCustomDeserializer.class) 注释这些属性。
这个解决方案的问题是它在第一个错误时失败(只返回一个属性错误)。 Spring 使用 HttpMessageConverter 将 http 请求主体转换为实体对象,我们案例中的 spring 实现是使用 jackson 的 MappingJackson2HttpMessageConverter Objectmapper,它使用 com.fasterxml.jackson.databind.deser.BeanDeserializer,它在第一次反序列化错误时失败并出现 IOException,之后将被 MessageConverter 封装在 HttpMessageNotReadableException 中
这个方法看起来更简洁,但我不知道我们是否可以重新定义 ObjectMapper 或 BeanDeserializer 以失败并生成包含所有有问题的属性的根异常报告
- 实体的 DTO
第二种解决方案是定义要在 Controller (而不是实体)中使用的 DTO 对象,其中所有属性都是 Object 类型,并且在创建这个对象之后(让 spring 和 jackson 创建这个 dto)我们做这些属性的验证(使用特定的 javax.validation.ConstraintValidator 检查类型 Object 的 DTO 属性是否是我们所需类型的 instanceOf)
第二个解决方案给出了期望的最终结果,因为它使用了已经给出了 MethodArgumentNotValidException 的 spring API 验证。但是让具有 Object 类型属性的 DTO 进行验证然后将它们转换为业务层的正确模型是非常丑陋的,它不是通用的,...
是否有更好的解决方案或方法我错过了这样的结果
最佳答案
我没有在您的场景中测试以下内容,但我相信可以使用类似的解决方案。
使用@ControllerAdvice 处理带有@ExceptionHandler(MethodArgumentNotValidException.class) 的异常。获取所有错误结果,然后返回包含验证错误的对象列表。示例如下。
@ControllerAdvice
public class ControllerValidationHandler {
@Autowired
private MessageSource msgSource;
@ExceptionHandler(MethodArgumentNotValidException.class)
@ResponseStatus(HttpStatus.BAD_REQUEST)
@ResponseBody
public ValidationMessages processValidationError(MethodArgumentNotValidException ex) {
BindingResult result = ex.getBindingResult();
List<FieldError> fieldErrors = result.getFieldErrors();
return new ValidationMessages(fieldErrors.stream()
.map(fieldError -> processFieldError(fieldError))
.collect(Collectors.toList()));
}
private ValidationMessage processFieldError(FieldError error) {
ValidationMessage message = null;
if (error != null) {
Locale currentLocale = LocaleContextHolder.getLocale();
String msg;
try {
msg = msgSource.getMessage(error.getDefaultMessage(), null, currentLocale);
} catch (Exception e) {
msg = error.getDefaultMessage();
}
message = new ValidationMessage(error.getField(), msg, MessageType.ERROR);
}
return message;
}
}
关于spring - 如何使用 spring 为 Rest 服务返回带有无效属性列表的错误验证 bean,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/38643894/