作為服務端開發,驗證前端傳入的參數的合法性是一個必不可少的步驟,但是驗證參數是一個基本上是一個體力活,而且備援代碼繁多,也影響代碼的可閱讀性,是以有沒有一個比較優雅的方式來解決這個問題?
這麼簡單的問題當然早就有大神遇到并且解決了,這一篇文章主要講一下解決基于spring-boot的驗證參數的比較好的方法:利用validator-api來進行驗證參數。
在
spring-boot-starter-web
包裡面有 hibernate-validator
包,它提供了一系列驗證各種參數的方法,是以說spring-boot已經幫我們想好要怎麼解決這個問題了。
這篇文章針對spring-boot裡面的spring-mvc介紹三種方式來驗證參數。
(一):這個方法在網上大部分都可以查到,先假設我們的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;
}
利用
validator
提供的一系列注解,比如本例中的
@Range
,就可以表示參數的範圍和出錯時候的提示資訊。還有很多其他注解,這裡就不一一列出
然後我們的Controller層的代碼為
@RequestMapping(value = "/paramErrorTest", method = RequestMethod.GET)
public String paramErrorTest(
@Valid
@ModelAttribute
GradeAndClassroomModel gradeAndClassroomModel,
BindingResult result) {
return classroomService.getTeacherName(gradeAndClassroomModel.getGrade(), gradeAndClassroomModel.getClassroomNumber());
}
其中如果驗證出錯,result對象裡面就會有錯誤資訊,然後可以自己進行處理。
(二): 針對上面的例子,會有人說,就兩個參數,為什麼要作為對象呢?會不會太麻煩?确實,如果隻有少數對象,直接把參數寫到Controller層,然後在Controller層進行驗證就可以了。
@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);
}
如果直接把
validator
提供的注解移除來寫到請求參數上面的話是不是就可以了呢?答案是錯,為什麼這樣不能成功的驗證參數呢?具體原因大家可以參考官方文檔:http://docs.spring.io/spring-framework/docs/current/spring-framework-reference/htmlsingle/#validation-beanvalidation-spring-method
上面的文檔已經說的很清楚了,是以我們需要建立一個Bean
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
然後在類方法上面加上注解
@Validated
@RestController
@RequestMapping("/spring-boot/classroom")
@Validated
public class ClassroomController {
...
}
然後之前沒有生效的注解
@Range
、
@Min
@Max
等
validator
包裡面提供的注解就可以生效了。
(三)估計到了這裡又會有人問,如果
validator
包裡面注解不能滿足我們的需求,我們是否可以自己定義參數驗證的邏輯。答案是肯定的,我們可以利用
@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 {};
}
和
public class Validator implements ConstraintValidator<ParamValidator, Object> {
...
}
組合進行自定義,具體的例子網上其他文章就很多了,這裡就不進行詳細的例子了,但是最終使用的時候就是
@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);
}
另外不要忘記
方法二
裡面裡面提到的
MethodValidationPostProcessor
這個bean,如果沒有初始化這個bean,自定義的驗證方法也不會執行。驗證邏輯會失效。
是不是通過這樣寫注解的方式來驗證進行請求的參數,代碼邏輯更佳清晰和優雅?表達的含義也會更佳清楚?并且沒有了大量重複的類似的驗證代碼。
Ps:這裡的代碼都是基于spring-mvc架構來試驗的,如果有人并沒有使用spring-mvc作為rest架構,而是使用jersey來作為rest架構的話,可能一些細節方面需要調整, 但是這三種方案應該都是可以相容的。
原文位址:https://www.cnblogs.com/mawang/p/6767906.html?utm_source=itdadao&utm_medium=referral