@Validated和@Valid的区别?校验级联属性(内部类)
- 2019 年 10 月 3 日
- 笔记
????
NBA???????????????????????
????
???Java??????????Java Bean Validation 2.0?JSR303?JSR349?JSR380?Hibernate-Validation 6.x????
???Spring??Controller????????????????Spring MVC??@Valid???JavaBean?????
???Spring?Spring?????????@Validated + MethodValidationPostProcessor???????????
??
???? ???Spring
?????????????????????????????Spring MVC
?Controller
???????????????????Spring MVC
??????~
?????????????????????Controller
????????????????????????????~??????????????????????????????????
- ???????????????
Spring
???????
?????????Spring MVC
???????@Valid
??????- ????????????
SpringBoot
?????????????????????Spring MVC
??????????????????
- ????????????
- ?????
Spring MVC
?HandlerInterceptor
?AOP
????????????????????@EnableAspectJAutoProxy
?????????~
??????????????????????????????????????????????????????????????????????????~
????
??????????Spring MVC
?????????????????Java???????????????????????????????“??”
???????????????Spring???????????Controller
???@Validated
????JavaBean
???~
???????????????????
@Getter @Setter @ToString public class Person { @NotNull private String name; @NotNull @Positive private Integer age; @Valid // ?InnerChild???????? @NotNull private InnerChild child; @Getter @Setter @ToString public static class InnerChild { @NotNull private String name; @NotNull @Positive private Integer age; } } @RestController @RequestMapping public class HelloController { @PostMapping("/hello") public Object helloPost(@Valid @RequestBody Person person, BindingResult result) { System.out.println(result.getErrorCount()); System.out.println(result.getAllErrors()); return person; } }
??post???/hello
Content-Type=application/json
????json????
{ "name" : "fsx", "age" : "-1", "child" : { "age" : 1 } }
?????????
2 [Field error in object 'person' on field 'child.name': rejected value [null]; codes [NotNull.person.child.name,NotNull.child.name,NotNull.name,NotNull.java.lang.String,NotNull]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.child.name,child.name]; arguments []; default message [child.name]]; default message [???null], Field error in object 'person' on field 'age': rejected value [-1]; codes [Positive.person.age,Positive.age,Positive.java.lang.Integer,Positive]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [person.age,age]; arguments []; default message [age]]; default message [?????]]
????????????????????????????????????????
????????????
@RequestBody
????????????json????????????????????????~- ???????
BindingResult result
?????????????400????????????????????org.springframework.web.bind.MethodArgumentNotValidException
???????????????~
????????????????????????????????90%
???????????????????????????~
????????????????????????@Valid
???????????????????????????????????if else
?????????????????????????case??@Valid?????????????JavaBean
??????????????????????????????????????????????????~
????
Controller
?????@Valid
????JavaBean
?????Spring???????????????????????Spring MVC
????Spring AOP
?????~????????????
?????
??
????????????????????????????????????????????????bug????~
??DataBinder
/WebDataBinder
??Spring
?????????????????????????????????
- ???Spring???Spring?????? — DataBinder????????
- ???Spring???Spring?????? — WebDataBinder?ServletRequestDataBinder?WebBindingInitializer…
DataBinder
???????????org.springframework.validation
??????Spring???????????????????????????????????????Spring
???????????????????????????????????
????DataBinder
????????bind(PropertyValues pvs)
?validate()
???????????/??????????????
public class DataBinder implements PropertyEditorRegistry, TypeConverter { ... @Nullable private AbstractPropertyBindingResult bindingResult; // ???BindingResult @Nullable private MessageCodesResolver messageCodesResolver; private BindingErrorProcessor bindingErrorProcessor = new DefaultBindingErrorProcessor(); // ????????org.springframework.validation.Validator // ??DataBinder ??????????????????Bean?????????????????????????????~~~? private final List<Validator> validators = new ArrayList<>(); public void bind(PropertyValues pvs) { MutablePropertyValues mpvs = (pvs instanceof MutablePropertyValues ? (MutablePropertyValues) pvs : new MutablePropertyValues(pvs)); doBind(mpvs); } ... public void validate() { Object target = getTarget(); Assert.state(target != null, "No target to validate"); BindingResult bindingResult = getBindingResult(); // ???????? ??????target????~~~ // Call each validator with the same binding result for (Validator validator : getValidators()) { validator.validate(target, bindingResult); } } }
DataBinder
?????????????????? + ?????????????????+?????????????~
????????
DataBinder
???????????????????????????????????????????????~
Spring MVC
???????
Spring MVC
??????????????????????Spring MVC
?????????HandlerMethodReturnValueHandler
????
???Spring?Spring MVC???web?????—HandlerAdapter????—??????????????HandlerMethodReturnValueHandler
???????????@RequestBody
???????????~
?????????HandlerMethodArgumentResolver
???@RequestBody
??????????RequestResponseBodyMethodProcessor
?Spring
??????????????????????????????~
RequestResponseBodyMethodProcessor
??????????????????MVC??????????????????@ResponseBody
???????????supportsReturnType()
??~?
???????????????????????????@RequestBody
??~?
????????????HandlerMethodReturnValueHandler
??????????HandlerMethodArgumentResolver
???????Processor
???Resolver/Handler
??????????~
// @since 3.1 public class RequestResponseBodyMethodProcessor extends AbstractMessageConverterMethodProcessor { @Override public boolean supportsParameter(MethodParameter parameter) { return parameter.hasParameterAnnotation(RequestBody.class); } // ??????????@ResponseBody???? @Override public boolean supportsReturnType(MethodParameter returnType) { return (AnnotatedElementUtils.hasAnnotation(returnType.getContainingClass(), ResponseBody.class) || returnType.hasMethodAnnotation(ResponseBody.class)); } // ??????????????????????? @Override public Object resolveArgument(MethodParameter parameter, @Nullable ModelAndViewContainer mavContainer, NativeWebRequest webRequest, @Nullable WebDataBinderFactory binderFactory) throws Exception { // ????`Optional`??? parameter = parameter.nestedIfOptional(); // ???????HttpInputMessage?request?????? // ????????????Person?????????????????Person???????? Object arg = readWithMessageConverters(webRequest, parameter, parameter.getNestedGenericParameterType()); // ???????? // ????????????????????????????????????????personAAA???name????person String name = Conventions.getVariableNameForParameter(parameter); // ????binderFactory?????????????~ // ??web????ServletRequestDataBinderFactory if (binderFactory != null) { WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name); // ??????????????? if (arg != null) { // ????????+????~~~~~????????????????Errors?? // Applicable??? validateIfApplicable(binder, parameter); // ??????hasErrors()?????????????Errors???Spring MVC???????MethodArgumentNotValidException?? // ?????????? if (binder.getBindingResult().hasErrors() && isBindExceptionRequired(binder, parameter)) { throw new MethodArgumentNotValidException(parameter, binder.getBindingResult()); } } // ???????? ??????????~~~ // ???????MODEL_KEY_PREFIX??key?~~~~ if (mavContainer != null) { mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult()); } } return adaptArgumentIfNecessary(arg, parameter); } // ????????????WebDataBinder???????????????~ ??????????? // ???MethodParameter parameter protected void validateIfApplicable(WebDataBinder binder, MethodParameter parameter) { // ?????????????????????@Valid?@RequestBody????? Annotation[] annotations = parameter.getParameterAnnotations(); for (Annotation ann : annotations) { // ??????@Validated Validated validatedAnn = AnnotationUtils.getAnnotation(ann, Validated.class); // ?????????????????@Validated?? ???????Valid??? ????? //???????????@Valid??????????????????Valid????~~~~~ if (validatedAnn != null || ann.annotationType().getSimpleName().startsWith("Valid")) { // ????group????binder?validate()????~~~~ // ???????????????????break?~~~ // ???????????@Validated?@Valid???????~ Object hints = (validatedAnn != null ? validatedAnn.value() : AnnotationUtils.getValue(ann)); Object[] validationHints = (hints instanceof Object[] ? (Object[]) hints : new Object[] {hints}); binder.validate(validationHints); break; } } } ... }
??????????@Valid
?????????????????????????
- ???
@RequestBody
???????name(???)
?????????????????????????????????????????????? @Validated
?@Valid
??????????????????????????"Valid"???????????????
1. ????????Valid
???????value
????????Group
??
2. ????????@Validated
???????@Valid
??????????????????????~- ???
Errors(BindingResult)
???????@Valid
??????Spring MVC
??????????????????????????????????MethodArgumentNotValidException
??~
????@RequestBody
??@Valid
???????????????Spring MVC
???@RequestPart
?????????????????????????????RequestPartMethodArgumentResolver
????????????????Multipart
???????~
==??????????????????????????????????????@RequestBody
????==
?????????????????????????
@PostMapping("/hello") public Object helloPost(@Valid @RequestBody Person personAAA, BindingResult result, @Valid @RequestBody Person personBBB) { ... }
???????
Resolved [org.springframework.http.converter.HttpMessageNotReadableException: I/O error while reading input message; nested exception is java.io.IOException: Stream closed]
?????????????Body??????????????????????
??????????????URL?????????
???????????????????????????????????????~
???????Map?List??????
@RequestBody
??????????????????Map?List????????????????????
???????????????????????????
@InitBinder
???~~~
?????????@Validated
?????????????????????????????????????~
????????
???????Spring
???MethodArgumentNotValidException
???????????????BindingResult
????????????????????????
@RestControllerAdvice public class MethodArgumentNotValidExceptionHandler { @ExceptionHandler(MethodArgumentNotValidException.class) public Result handleMethodArgumentNotValid(MethodArgumentNotValidException ex) { BindingResult bindingResult = ex.getBindingResult(); StringBuilder stringBuilder = new StringBuilder(); for (FieldError error : bindingResult.getFieldErrors()) { String field = error.getField(); Object value = error.getRejectedValue(); String msg = error.getDefaultMessage(); String message = String.format("?????%s?????%s????%s?", field, value, msg); stringBuilder.append(message).append("rn"); } return Result.error(MsgDefinition.ILLEGAL_ARGUMENTS.codeOf(), stringBuilder.toString()); } }
????
????????Spring MVC
???????????????????????????????????????????JavaBean
?????????????Body?????get???????JavaBean????????????
????????????????Controller
???????????
???????????
??????
@PutMapping("/hello/id/{id}/status/{status}") public Object helloGet(@PathVariable Integer id, @PathVariable Integer status) { ... return "hello world"; }
??????get???case?@RequestParam
?????????????????????????????case???????????if else
??????
?????????????????????????????????Spring??Controller????????????????Spring MVC??@Valid???JavaBean?????
==@Validated?@Valid???==
?????????????????????????????????????????????????????
@Valid
???JSR-303?????????????????????????????????@Validated
?Spring
???????JSR-303
?????????????????????????????????????????????- ?
Controller
???????????@Valid?@Validated?????????????????? @Validated
??????????????Spring????????????@Valid
????????????????????@Validated
??????????????@Valid
????????????????
???????
Spring Boot
?Web Starter
?????Bean Validation
???????????????????Spring MVC
????????~
??
?????????????????????????@Validated
??Controller
?????????????????????????????????@Validated?@Valid
??????????????????????????????~
????
???????????
?????-????-????-????-????
==The last????????????????????????????????????????????????~
==
?????????????wx????Java??????3?
?
??????????wx??fsx641385712
???????wx??????????"java??"
??????????