Use hibernate-validator and javax.validation to validate spring-boot's @RequestParam, @Request parameters

 

As a server-side development, verifying the legitimacy of the parameters passed in from the front-end is an essential step, but verifying parameters is basically a manual task, and there are many redundant codes, which also affect the readability of the code, so there are There isn't a more elegant way to solve this problem?

Of course, such a simple problem has long been encountered and solved by the great gods. This article mainly talks about a better way to solve the verification parameters based on spring-boot: using validator-api to verify parameters.

There is a package in spring-boot-starter-webthe hibernate-validatorpackage, which provides a series of methods to verify various parameters, so spring-boot has already helped us figure out how to solve this problem.

This article introduces three ways to verify parameters for spring-mvc in spring-boot.

(一):这个方法在网上大部分都可以查到,先假设我们的restful的接口接受一个GradeAndClassroomModel类型的对象,并且这个类被定义成

@Data
public class GradeAndClassroomModel {  
@Range(min = 1, max = 9, message = "年级只能从1-9")  
private int grade;  
@Range(min = 1, max = 99, message = "班级只能从1-99")  
private int classroomNumber;
}

Using validatora series of annotations provided, such as in this example @Range, you can indicate the range of parameters and prompt information when an error occurs. There are many other annotations, which are not listed here.

Then the code of our Controller layer is

@RequestMapping(value = "/paramErrorTest", method = RequestMethod.GET)
public String paramErrorTest(    
  @Valid    
  @ModelAttribute    
  GradeAndClassroomModel gradeAndClassroomModel, 
  BindingResult result) {  
  return classroomService.getTeacherName(gradeAndClassroomModel.getGrade(), gradeAndClassroomModel.getClassroomNumber());
}

If there is an error in the verification, there will be an error message in the result object, and then you can handle it yourself.

(2): In response to the above example, some people will say, with only two parameters, why should it be used as an object? Will it be too much trouble? Indeed, if there are only a few objects, it is enough to write the parameters directly to the Controller layer and then verify them in the Controller layer.

@RequestMapping(value = "/teacherName", method = RequestMethod.GET)
public String teacherName(
  @Range(min = 1, max = 9, message = "年级只能从1-9")        
  @RequestParam(name = "grade", required = true) 
  int grade,  
  @Min(value = 1, message = "班级最小只能1")    
  @Max(value = 99, message = "班级最大只能99")      
  @RequestParam(name = "classroom", required = true)    
  int classroom) {  
return classroomService.getTeacherName(grade, classroom);
}

Is it okay if the validatorprovided annotations are removed directly and written to the request parameters? The answer is wrong, why can't this successfully validate the parameters? For specific reasons, you can refer to the official documentation: http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/htmlsingle/#validation-beanvalidation-spring-method

The above document has said it very clearly, so we need to create a Bean

@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {  
  return new MethodValidationPostProcessor();
}

Then add an annotation to the class method@Validated

@RestController
@RequestMapping("/spring-boot/classroom")
@Validated
public class ClassroomController {
 ...
}

Then the annotations provided in the package that did not take effect before @Range, , @Min, @Maxetc. validatorcan take effect.

(3) It is estimated that some people will ask if validatorthe annotations in the package cannot meet our needs, whether we can define the logic of parameter verification by ourselves. The answer is yes, we can use

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER, ElementType.FIELD})
@Constraint(validatedBy = {Validator.class})
public @interface ParamValidator {

  String message() default "Parameter error!";

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

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

}

and

public class Validator implements ConstraintValidator<ParamValidator, Object> {
  ...
}

The combination is customized. There are many other articles on the Internet for specific examples. I will not give detailed examples here, but the final use is

  @RequestMapping(value = "/paramValidator", method = RequestMethod.GET)
  public String paramValidator(
      @ParamValidator(isRequired = true, desc = "年级", range = "int:1~9", message = "年级只能从1-9")
      @RequestParam(name = "grade", required = true)
      int grade,
      @ParamValidator(isRequired = true, desc = "班级", range = "int:1~99", message = "班级只能从1-99")
      @RequestParam(name = "classroom", required = true)
      int classroom) {
    return classroomService.getTeacherName(grade, classroom);
  }

In addition, don't forget the bean 方法二mentioned in MethodValidationPostProcessorit. If the bean is not initialized, the custom validation method will not be executed. Validation logic will fail.

Is it better to verify the parameters of the request by writing annotations in this way, the code logic is more clear and elegant? The meaning of the expression will be more clear? And there's no massive duplication of similar verification code.

Ps: The code here is tested based on the spring-mvc framework. If someone does not use spring-mvc as the rest framework, but uses jersey as the rest framework, some details may need to be adjusted, but these three solutions Should be compatible.

Author: LOC_Thomas
Link: http://www.jianshu.com/p/2c2da2adef81
Source: Jianshu
Copyright belongs to the author. For commercial reprints, please contact the author for authorization, and for non-commercial reprints, please indicate the source.

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=326435412&siteId=291194637