@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????????wx??`Java??????3?`????????


??

???? ???Spring?????????????????????????????Spring MVC?Controller???????????????????Spring MVC??????~

?????????????????????Controller????????????????????????????~??????????????????????????????????

  1. ???????????????Spring????????????????Spring MVC???????@Valid??????
    1. ????????????SpringBoot?????????????????????Spring MVC??????????????????
  2. ?????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 [?????]]

????????????????????????????????????????

????????????

  1. @RequestBody????????????json????????????????????????~
  2. ???????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?????????????????????????????????

  1. ???Spring???Spring?????? — DataBinder????????
  2. ???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?????????????????????????

  1. ???@RequestBody???????name(???)??????????????????????????????????????????????
  2. @Validated?@Valid??????????????????????????"Valid"???????????????
    1. ????????Valid???????value????????Group??
    2. ????????@Validated???????@Valid??????????????????????~
  3. ???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???==

?????????????????????????????????????????????????????

  1. @Valid???JSR-303?????????????????????????????????
  2. @Validated?Spring???????JSR-303?????????????????????????????????????????????
  3. ?Controller???????????@Valid?@Validated??????????????????
  4. @Validated??????????????Spring????????????@Valid????????????????????
  5. @Validated??????????????@Valid????????????????

???????Spring Boot?Web Starter?????Bean Validation???????????????????Spring MVC????????~

??

?????????????????????????@Validated??Controller?????????????????????????????????@Validated?@Valid??????????????????????????????~

????

????????????????-????-????-????-????

==The last????????????????????????????????????????????????~==

?????????????wx????Java??????3??
??????????wx??fsx641385712???????wx??????????"java??" ??????????