表单校验是我们在提交表单时不可缺少的一个环节,普通的校验方法是针对每个参数进行单独的判断,但是这样不仅麻烦,并且如果参数很多的情况下我们写过多的if会使得代码非常臃肿,并且可读性较差,以登录为例,假设我我们需要mobile
和 password
两个参数,那么就需要进行如下的校验:
if(StringUtils.isEmpty(mobile)){
return false;
}
if(!Validator.isMobile(mobile)){
return false;
}
if(StringUtils.isEmpty(password)){
return false;
}
这个时候,我们的jsr303就闪亮登场了
同样使用登录为例,我们先定义一个UserVO用来接收前端穿过来的参数:
public class UserVo {
private String mobile;
private String password;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
然后我们定义我们的控制器UserController:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@PostMapping("login")
public String login(UserVo userVo){
return "";
}
}
接下来在pom.xml中添加jsr303的依赖:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
这样在Controller传递参数的时候我们使用@Valid 来告诉系统这个参数我们需要进行校验
@Valid UserVo userVo
接下来我们只需要到Vo里边,在需要校验的变量上边使用注解即可,例如我们需要密码不为空,则可以使用@NotNull
,如果还需要限制密码长度最小不得小于8位,可以使用@Length(min = 8)
,此外系统还为我们提供了许多注解:
@NotNull 注解元素必须是非空
@Null 注解元素必须是空
@Digits 验证数字构成是否合法
@Future 验证是否在当前系统时间之后
@Past 验证是否在当前系统时间之前
@Max 验证值是否小于等于最大指定整数值
@Min 验证值是否大于等于最小指定整数值
@Pattern 验证字符串是否匹配指定的正则表达式
@Size 验证元素大小是否在指定范围内
@DecimalMax 验证值是否小于等于最大指定小数值
@DecimalMin 验证值是否大于等于最小指定小数值
@AssertTrue 被注释的元素必须为true
@AssertFalse 被注释的元素必须为false
如果我们需要的校验方式系统中没有,我们也可以自己实现一个,例如我们需要校验mobile是否为一个正确的手机号码,则可以自己定义一个@IsMobile :
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Constraint(
validatedBy = {IsMobileValidator.class} // 此处是对参数进行校验的具体实现
)
public @interface IsMobile {
boolean required() default true; //自己定义 是否表示属性是否必须填写
String message() default "手机号码格式错误"; //校验失败之后的提示
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}
此时注解有了之后,我们需要来实现一个方法来校验手机号码,也就是上方注解 validatedBy = {IsMobileValidator.class}
中的 IsMobileValidator
这个类,这个类需要实现 ConstraintValidator<注解,参数类型> 这个接口:
public class IsMobileValidator implements ConstraintValidator<IsMobile, String> {
private boolean required = false;
@Override
public void initialize(IsMobile constraintAnnotation) {
required = constraintAnnotation.required();
}
@Override
public boolean isValid(String s, ConstraintValidatorContext constraintValidatorContext) {
//如果参数是必须填写的,那么进行校验
if(required){
return ValidatorUtil.isMobile(s);
}
//如果参数不是必须填写的,那么如果是空的也算符合要求了
if(StringUtils.isEmpty(s)){
return true;
}
return ValidatorUtil.isMobile(s);
}
}
其中判断字符串是否为一个手机号的类的具体实现ValidatorUtil:
/**
* 参数校验工具
* author:shine
*/
public class ValidatorUtil {
/**
* 校验手机号
* @param mobile
* @return
*/
public static boolean isMobile(String mobile){
Pattern mobilePattern = Pattern.compile("^((13[0-9])|(14[5,7,9])|(15[^4])|(18[0-9])|(17[0,1,3,5,6,7,8]))\\d{8}$");
Matcher m = mobilePattern.matcher(mobile);
return m.matches();
}
}
好了,这样@IsMobile这个注解就实现了,我们在moble参数上写上这个注解:
public class UserVo {
@IsMobile
private String mobile;
@NotNull
@Length(min = 8)
private String password;
public String getMobile() {
return mobile;
}
public void setMobile(String mobile) {
this.mobile = mobile;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
接下来我们测试一下,由于我们还没有写页面,这里我们就用postman来模拟请求一下:
当我们手机号和密码都是正确的情况下,可以看到什么错误也没有报,说明我们的请求参数是通过校验了的,接下来我们试一下如果使用长度小于8的密码:
可以看到请求出来的是一个错误信息,接下来我们在使用一个不合法的手机号来测试一下:
可以看到我们自定义的校验也是可以的