Tag:spring validation GET
Article From:https://www.cnblogs.com/daoqidelv/p/9061862.html

This article briefly introduces how to introduce validation, and how to reduce the amount of code and improve productivity through custom validation. Special mention: valid of non basic type attributes, handling of GET methods, and unification of validation error information. ReSolve.

The actual implementation of validation is entrusted to Hibernate validation processing in this article.

Basic configuration

pomIntroducing Maven dependency

<!-- validation begin -->
<!-- validation end -->

Add validation configuration

Add the following configuration in spring-mvc-servlet.xml:

<mvc:annotation-driven validator="validator">

<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator" />
    <property name="validationMessageSource" ref="messageSource"/>
//messageSource For I18N resource management bean, see applicationContext.xml configuration

Custom exceptionHandler

Personalization handles validation error messages and returns to callers with more friendly information.Add the following configuration in applicationContext.xml:

<!--  Load the I18N message resource file -->< bean id= "messageSource" class= "org.springframework.context.support.Resourc"EBundleMessageSource ">< property name= "basenames" >< list>< value> errormsg< /value>< value> validation_error< /value>< /list>< /property>< /bean>< bean id= "validationExceptionResolver" CLass= "com.*.exception.ValidationExceptionResovler" />

Add on the project class path: validation_error_zh_CN.properties resource file:

#the error msg for input validation
#common field.can.not.be.null={field}Can't be emptyField.can.not.be.empty={field} cannot be empty or empty string.Field.must.be.greater.than.min={field} should not be less than {value}FIeld.must.be.letter.than.max={field} can not exceed {value}

 1 @Slf4j
 2 public class ValidationExceptionResovler extends AbstractHandlerExceptionResolver {
 3     public ValidationExceptionResovler() {
 4         // Set order to execute before DefaultHandlerExceptionResolver.
 5         this.setOrder(0);
 6     }
 8     /**
 9      * Handle the case where an argument annotated with {@code @Valid} such as
10      * an {@link } or {@link } argument fails validation.
11      * <p>
12      * Custom ValidationException exception handler13      * Gets the specific validation error information, assembles CommonResponse, and returns it to the caller.14      *
15      * @param request  current HTTP request
16      * @param response current HTTP response
17      * @param handler  the executed handler
18      * @return an empty ModelAndView indicating the exception was handled
19      * @throws IOException potentially thrown from response.sendError()
20      */
21     @ResponseBody
22     protected ModelAndView handleMethodArgumentNotValidException(BindingResult bindingResult,
23                                                                  HttpServletRequest request,
24                                                                  HttpServletResponse response,
25                                                                  Object handler)
26             throws IOException {
28         List<ObjectError> errors = bindingResult.getAllErrors();
29         StringBuffer errmsgBF = new StringBuffer();
30         for (ObjectError error : errors) {
31             String massage = error.getDefaultMessage();
32             errmsgBF.append(massage);
33             errmsgBF.append("||");
34         }
35         String errmsgString = errmsgBF.toString();
36         errmsgString = errmsgString.length() > 2 ? errmsgString.substring(0, errmsgString.length() - 2) : errmsgString;
37         log.error("Validation failed! {} ", errmsgString);
39         Map<String, Object> map = new TreeMap<String, Object>();
40         map.put("success", false);
41         map.put("errorCode", "9999");
42         map.put("errorMsg", errmsgString);
44         ModelAndView mav = new ModelAndView();
45         MappingJackson2JsonView view = new MappingJackson2JsonView();
46         view.setAttributesMap(map);
47         mav.setView(view);
49         return mav;
50     }
52     @Override
53     protected ModelAndView doResolveException(HttpServletRequest request,
54                                               HttpServletResponse response, Object handler,
55                                               Exception ex) {
56         BindingResult bindingResult = null;
57         if (ex instanceof MethodArgumentNotValidException) {
58             bindingResult = ((MethodArgumentNotValidException) ex).getBindingResult();
59         } else if(ex instanceof BindException) {
60             bindingResult = ((BindException) ex).getBindingResult();
61         } else {
62             //other exception , ignore
63         }
65         if(bindingResult != null) {
66             try {
67                 return handleMethodArgumentNotValidException(bindingResult, request, response, handler);
68             } catch (IOException e) {
69                 log.error("doResolveException: ", e);
70             }
71         }
73         return null;
74     }
75 }


Adding @Valid to controller

public BaseResponse buy(@RequestBody @Valid BuyFlowerRequest request) throws Exception {

Add validation annotations for attributes that require validation on request bean

public class BuyFlowerRequest {

    @NotEmpty(message = "{name.can.not.be.null}") 
private String name;

The validation of the two level object

The above method can only be checked on the basic type properties of BuyFlowerRequest, but there is no way to validation the property of the object property. If you need to validation the attribute of the two level object, it needs to be in the two level object and two level.@Valid and specific validation annotations are added to the object property.

The following is written as follows:

public class BuyFlowerRequest {

    @NotEmpty(field = ""Flower name")
    private String name;

    @Min(field = "Price, value = 1)
    private int price;

    private List<PayType> payTypeList;


public class PayType {

    @Min(value = 1)
    private int payType;

    @Min(value = 1)
    private int payAmount;


View Code 

Further reducing the amount of coding

In order to reduce the coding workload, try to pass the validation filed name to the resource file of the wrong information by custom Validation annotations, thus avoiding writing different message templates for each domain.

The following is an example of @NotNull rewritten as an example.

1、Define Validation annotation, note that field () is added to the original annotation to transfer the filed name by validated.

@Target( { ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER })
@Constraint(validatedBy = { NotNullValidator.class })
public @interface NotNull {

    String field() default "";

    String message() default "{field.can.not.be.null}";

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};


2、Define Validator, all Validator achieve ConstraintValidator interface:

 1 public class NotNullValidator implements ConstraintValidator<NotNull, Object> {
 3     @Override
 4     public void initialize(NotNull annotation) {
 6     }
 8     @Override
 9     public boolean isValid(Object str, ConstraintValidatorContext constraintValidatorContext) {
10         return str != null;
11     }
13 }



3、Add the Validation annotation on the filed and note that the filed value is specified. If message does not have a personalized requirement, you can not specify that the validation component will fill the default message itself.

public class BuyFlowerRequest {

    @NotEmpty(field = ""Flower name")
    private String name;

    @Min(field = "Price, value = 1)
    private int price;




Note: the @NotNull annotation has supported a special check for list. For List type nodes, if list==null = = = 0 will return to false, validation fails. It is now in accordance with this thoughtThe road custom has implemented @NotNull, @NotEmpty, @Min and @Max annotations, and can be found in goods project.

Support GET requests

The above examples are all POST requests, @RequestBody can resolve POST requests, but do not support GET requests, read the spring documents and source code, and find that @ModelAttribute can request resol for GETVe is Bean and supports Validation. Specifically, you can browse the spring source code: ModelAttributeMethodProcessor.resolveArgument () method.

Use examples:

@RequestMapping(value = "/buy", method = RequestMethod.GET)
public BaseResponse detail(@Valid @ModelAttribute DetailFlowerRequest request) throws Exception {

    DetailFlowerResponse response = new DetailFlowerResponse();

    return ResultFactory.success(response, BaseResponse.class);

View Code


1、Extend validation based on business scenario, such as date format, amount, etc.

2、Validation supporting multiple field relational validation

 Appendix: Spring validation implementation key code


Implementation class: RequestResponseBodyMethodProcessor.java

public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
Object arg = this.readWithMessageConverters(webRequest, parameter, parameter.getGenericParameterType());
String name = Conventions.getVariableNameForParameter(parameter);
WebDataBinder binder = binderFactory.createBinder(webRequest, arg, name);
if (arg != null) {
this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new MethodArgumentNotValidException(parameter, binder.getBindingResult());

mavContainer.addAttribute(BindingResult.MODEL_KEY_PREFIX + name, binder.getBindingResult());
return arg;


Implementation class: ModelAttributeMethodProcessor.java

public final Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
String name = ModelFactory.getNameForParameter(parameter);
Object attribute = mavContainer.containsAttribute(name) ? mavContainer.getModel().get(name) : this.createAttribute(name, parameter, binderFactory, webRequest);
if (!mavContainer.isBindingDisabled(name)) {
ModelAttribute ann = (ModelAttribute)parameter.getParameterAnnotation(ModelAttribute.class);
if (ann != null && !ann.binding()) {

WebDataBinder binder = binderFactory.createBinder(webRequest, attribute, name);
if (binder.getTarget() != null) {
if (!mavContainer.isBindingDisabled(name)) {
this.bindRequestParameters(binder, webRequest);

this.validateIfApplicable(binder, parameter);
if (binder.getBindingResult().hasErrors() && this.isBindExceptionRequired(binder, parameter)) {
throw new BindException(binder.getBindingResult());

Map<String, Object> bindingResultModel = binder.getBindingResult().getModel();
return binder.convertIfNecessary(binder.getTarget(), parameter.getParameterType(), parameter);


Leave a Reply

Your email address will not be published. Required fields are marked *