项目使用SpringBoot进行开发
maven依赖:
org.springframework.boot spring-boot-starter-web
查看依赖可以看到Hibernate validator已被spring boot starter web 集成,所以无需再另外引入依赖即可使用
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。注解如下:
@AssertFalse:被注释的元素必须为false。
@AssertTrue:被注释的元素必须为true。
@DecimalMax:带注释的元素必须是一个数值,其值必须小于或等于指定的最大值。
@DecimalMin:带注释的元素必须是一个数值,其值必须高于或等于指定的最小值。
@Digits:带注释的元素必须是支持的可接受范围内的数字。
@Email:字符串必须是格式正确的电子邮件地址。
@Future:带注释的元素必须是将来的一个瞬间、日期或时间。
@FutureOrPresent:带注释的元素必须是当前或将来的瞬间、日期或时间。
@Max:带注释的元素必须是一个数值,其值必须小于或等于指定的最大值。
@Min:带注释的元素必须是一个数值,其值必须大于或等于指定的最大值。
@Negative:带注释的元素必须是严格的负数(即0被视为无效值)。
@NegativeOrZero:带注释的元素必须是负数或0。
@NotBlank:带注释的元素不能是 null ,并且必须至少包含一个非空白字符。
@NotEmpty:带注释的元素不能是 null ,也不能为空。
@NotNull:带注释的元素不能是 null 。
@Null:带注释的元素必须是 null 。
@Past:带注释的元素必须是过去的一个瞬间、日期或时间。
@PastOrPresent:带注释的元素必须是过去或现在的瞬间、日期或时间。
@Pattern:带注释的字符串必须与指定的正则表达式匹配。
@Positive:带注释元素必须是严格的正数(即0被视为无效值)。
@PositiveOrZero:带注释的元素必须是正数或0。
@Size:带注释的元素大小必须在指定的边界(包括)之间。
……其余注解可去源码中查看
注解具体支持的类型可去源码中查看。
1、JavaBean中添加校验注解
package com.example.demo.dto;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
public class PersonInfoDto {
/**
* 姓名
*/
@NotBlank(message = "姓名不能为空!")
private String name;
/**
* 出生日期
*/
@NotBlank(message = "出生日期不能为空!")
private String birthday;
/**
* 电话
*/
@Pattern(regexp = "\\d{3}-\\d{8}|\\d{4}-\\{7,8}", message = "电话号码格式不正确!")
private String phone;
/**
* 邮箱
*/
@Email(message = "邮箱格式不正确!")
@NotBlank(message = "邮箱不能为空!")
private String email;
//get、set省略...
}
2、在controller中使用参数校验
package com.example.demo.controller;
import com.example.demo.dto.PersonInfoDto;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.validation.Valid;
@RestController
@RequestMapping("/person")
public class PersonInfoController {
private static final Logger logger=LoggerFactory.getLogger(PersonInfoController.class);
@PostMapping("/add")
public void addPersonInfo(@RequestBody @Valid PersonInfoDto dto){
logger.info("{}",dto.toString());
}
}
当访问这个post接口时,如果参数不符合Model中定义的话,程序中就回抛出400异常,并提示错误信息。
1、注解定义
package com.example.demo.constraints;
import javax.validation.Constraint;
import javax.validation.Payload;
import javax.validation.constraints.Pattern;
import java.lang.annotation.Documented;
import java.lang.annotation.Repeatable;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import static java.lang.annotation.ElementType.ANNOTATION_TYPE;
import static java.lang.annotation.ElementType.CONSTRUCTOR;
import static java.lang.annotation.ElementType.FIELD;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.ElementType.PARAMETER;
import static java.lang.annotation.ElementType.TYPE_USE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
@Documented
@Constraint(validatedBy = {PhoneValidatorImpl.class})
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Repeatable(Phone.List.class)
public @interface Phone {
/**
* 必须的属性
* 显示 校验信息
* 利用 {} 获取 属性值,参考了官方的message编写方式
*/
String message() default "必须是真实电话号码!";
/**
* 用于分组
*/
Class>[] groups() default { };
Class extends Payload>[] payload() default { };
/**
* 正则校验规则,非必须
*/
String regexp() default "\\d{3}-\\d{8}|\\d{4}-\\{7,8}";
/**
*与{@link #regexp()}结合使用,以指定正则表达式选项
*/
Pattern.Flag[] flags() default { };
/**
* 定义List,为了让Bean的一个属性上可以添加多套规则
*
* @see Phone
*/
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
public @interface List {
Phone[] value();
}
}
2、注解实现类
package com.example.demo.constraints;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.regex.Pattern;
public class PhoneValidatorImpl implements ConstraintValidator {
private String phoneFormat;
/**
* 获取校验规则
* @param constraintAnnotation
*/
@Override
public void initialize(Phone constraintAnnotation) {
this.phoneFormat=constraintAnnotation.regexp();
}
/**
* 校验逻辑实现
* @param value 需要校验的值
* @param context
* @return
*/
@Override
public boolean isValid(String value, ConstraintValidatorContext context) {
if (value.isEmpty()){
return true;
}
boolean matches = Pattern.matches(this.phoneFormat, value);
return matches;
}
}
3、JavaBean添加注解
package com.example.demo.dto;
import com.example.demo.constraints.Phone;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Pattern;
public class PersonInfoDto {
//其它参数...
/**
* 电话
*/
@Phone
private String phone;
//get、set省略...
}
使用方法同上。
对同一个JavaBean,我们在增加和修改时对参数的校验也是不一样的,这个时候我们就需要定义分组验证
1、定义两个空接口,分别代表增加和修改是的校验规则
package com.example.demo.validated;
public interface AddValidated {
}
package com.example.demo.validated;
public interface UpdateValidated {
}
2、JavaBean上添加注解时指明分组
package com.example.demo.dto;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
/**
* @author: shenzeyu
* @date: 2019.09.23
*/
public class PersonInfoDto {
//其它参数...
/**
* 邮箱
*/
@Email(message = "邮箱格式不正确!",groups = {AddValidated.class})
@NotBlank(message = "邮箱不能为空!",groups = {UpdateValidated.class})
private String email;
//get、set省略...
}
3、接口处启用校验
package com.example.demo.controller;
import com.example.demo.dto.PersonInfoDto;
import com.example.demo.validated.AddValidated;
import com.example.demo.validated.UpdateValidated;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/person")
public class PersonInfoController {
private static final Logger logger=LoggerFactory.getLogger(PersonInfoController.class);
@PostMapping("/add")
public void addPersonInfo(@RequestBody @Validated(value = AddValidated.class) PersonInfoDto dto){
logger.info("{}",dto.toString());
}
@PostMapping("/update")
public void updatePersonInfo(@RequestBody @Validated(value = UpdateValidated.class) PersonInfoDto dto){
logger.info("{}",dto.toString());
}
}
备注:此处@Validated(AddValidated.class) 表示使用AddValidated这套校验规则,若使用@Valid 则表示使用默认校验规则
@Validated与@Valid的区别可参考此篇文章https://blog.csdn.net/qq_27680317/article/details/79970590
JSR和Hibernate validator的校验只能对Object的属性进行校验,不能对单个的参数进行校验,spring 在此基础上进行了扩展,添加了MethodValidationPostProcessor拦截器,可以实现对方法参数的校验
1、实例化MethodValidationPostProcessor
package com.example.demo.config;
import org.springframework.context.annotation.Bean;
public class MethodValidationPostProcessor {
@Bean
public MethodValidationPostProcessor methodValidationPostProcessor() {
return new MethodValidationPostProcessor();
}
}
2、在所要实现方法参数校验的类上面添加@Validated,及在方法上面添加校验规则:
package com.example.demo.controller;
import com.example.demo.dto.PersonInfoDto;
import com.example.demo.validated.AddValidated;
import com.example.demo.validated.UpdateValidated;
import org.hibernate.validator.constraints.Length;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/person")
@Validated
public class PersonInfoController {
private static final Logger logger=LoggerFactory.getLogger(PersonInfoController.class);
//其它接口省略
@GetMapping("/get")
public void getPersonInfo(@Length(max = 3) String name){
logger.info("{}",name);
}
@PostMapping("/add")
public void addPersonInfo(@RequestBody @Validated(value = AddValidated.class) PersonInfoDto dto){
logger.info("{}",dto.toString());
}
}
本文章仅仅只是对JSR303,Hibernate validator做了简单介绍,关于参数检验的方式还有很多,后续可能会继续研究。
文章中如有不正之处,望请斧正