spring - 在REST控制器中,Spring Boot绑定和验证错误处理

当我有以下JSR-303 (验证框架)annotation的模型时:


public enum Gender {


 MALE, FEMALE


}



public class Profile {


 private Gender gender;



 @NotNull


 private String name;



 ...


}



以及以下JSON数据:


{"gender":"INVALID_INPUT" }



在REST控制器中,我想处理绑定错误(gender属性的枚举值无效)和验证错误(name属性不能为空)。

以下控制器方法不起作用:


@RequestMapping(method = RequestMethod.POST)


public Profile insert(@Validated @RequestBody Profile profile, BindingResult result) {


 ...


}



它给出com.fasterxml.jackson.databind.exc.InvalidFormatException 在绑定或验证发生之前发生序列化错误。

经过一些摆弄,我想出了这个自定义代码,它可以满足我的需求:


@RequestMapping(method = RequestMethod.POST)


public Profile insert(@RequestBody Map values) throws BindException {



 Profile profile = new Profile();



 DataBinder binder = new DataBinder(profile);


 binder.bind(new MutablePropertyValues(values));



 // validator is instance of LocalValidatorFactoryBean class


 binder.setValidator(validator);


 binder.validate();



 // throws BindException if there are binding/validation


 // errors, exception is handled using @ControllerAdvice.


 binder.close(); 



 // No binding/validation errors, profile is populated 


 // with request values.



 ...


}



基本上这个代码的作用是序列化为通用映射而不是模型,然后使用自定义代码绑定到模型,并且检查错误。

我有以下问题:

  • 是自定义代码的方式去实现,或者在Spring Boot中有更标准的方法吗?
  • @Validated注释的工作原理? 如何创建自己的自定义注释,使之像@Validated一样封装自定义绑定代码?
时间:

这是我在我的一个项目中使用的代码,用于在spring boot中验证REST api,这与你要求的不一样,但是结果相同。检查是否有帮助


@RequestMapping(value ="/person/{id}",method = RequestMethod.PUT)


@ResponseBody


public Object updatePerson(@PathVariable Long id,@Valid Person p,BindingResult bindingResult){


 if (bindingResult.hasErrors()) {


 List<FieldError> errors = bindingResult.getFieldErrors();


 List<String> message = new ArrayList<>();


 error.setCode(-2);


 for (FieldError e : errors){


 message.add("@" + e.getField().toUpperCase() +":" + e.getDefaultMessage());


 }


 error.setMessage("Update Failed");


 error.setCause(message.toString());


 return error;


 }


 else


 {


 Person person = personRepository.findOne(id);


 person = p;


 personRepository.save(person);


 success.setMessage("Updated Successfully");


 success.setCode(2);


 return success;


 }



Success.java


public class Success {


int code;


String message;



public int getCode() {


 return code;


}



public void setCode(int code) {


 this.code = code;


}



public String getMessage() {


 return message;


}



public void setMessage(String message) {


 this.message = message;


}


}



Error.java


public class Error {


int code;


String message;


String cause;



public int getCode() {


 return code;


}



public void setCode(int code) {


 this.code = code;


}



public String getMessage() {


 return message;


}



public void setMessage(String message) {


 this.message = message;


}



public String getCause() {


 return cause;


}



public void setCause(String cause) {


 this.cause = cause;


}



}



你还可以在这里查看: spring REST Validation

通常,Spring MVC无法读取http消息(例如,请求正文,它将抛出HttpMessageNotReadableException异常的一个实例,因此,如果spring不能绑定到你的模型,它应该抛出异常,另外,如果在方法参数中的每个to-be-validated模型之后,没有定义BindingResult,在验证错误发生时,spring将抛出一个MethodArgumentNotValidException异常,使用这些,可以创建捕获这两个异常,并且以你希望的方式处理它们的ControllerAdvice


@ControllerAdvice(annotations = {RestController.class})


public class UncaughtExceptionsControllerAdvice {


 @ExceptionHandler({MethodArgumentNotValidException.class, HttpMessageNotReadableException.class})


 public ResponseEntity handleBindingErrors(Exception ex) {


 // do whatever you want with the exceptions


 }


}



我已经放弃了 如果没有大量定制代码,就不能使用@RequestBody来获得绑定错误,这与控制器绑定到普通的JavaBeans参数不同,因为@RequestBody使用Jackson来绑定,而不是使用。

请参见https://jira.spring.io/browse/SPR-6740?jql=text%20~%20%22RequestBody%20binding%22

https://blog.codecentric.de/en/2017/11/dynamic-validation-spring-boot-validation/ -你可以在控制器方法中添加额外的参数"错误"


@RequestMapping(method = RequestMethod.POST)


public Profile insert(@Validated @RequestBody Profile profile, Errors errors) {


 ...


}



然后得到验证错误,如果有的话。

...