spring validation的使用与自定义校验注解
前言
前端录入数据,在后台进行校验工作是必不可少的。例如:为空校验,邮箱格式校验,手机号校验等。
后端校验的目的是避免用户绕过浏览器,使用http工具直接向后端请求一些违法数据,服务端的数据校验也是必要的,可以防止脏数据落到数据库中,如果数据库中出现一个非法的邮箱格式,也会让运维人员头疼不已。
下面介绍spring 框架中的自动校验机制。
框架提供的校验注解
注解 | 说明 |
@NotNull | 值不能为空 |
@Null | 值必须为空 |
@Pattern(regexp=) | 字符串必须匹配正则表达式 |
@Size(min=,max=) | 集合的元素数量必须在min和max之间 |
@CreditCardNumber(ignoreNonDigitCharacters) | 字符串必须是信用卡号(按美国标准校验) |
字符串必须是Email邮箱 | |
@Length(min=,max=) | 检查字符串的长度 |
@NotBlank | 字符串必须有字符 |
@NotEmpty | 字符串不为null,集合有元素 |
@Range(min=,max=) | 数字必须大于等于min,小于等于max |
@SafeHtml | 字符串是安全的html |
@URL | 字符串是合法的URL |
@AssertFalse | 值必须是false |
@AssertTrue | 值必须是true |
@DecimalMax(value=,inclusive=) | 值必须小于等于(inclusive=true)/小于(inclusive=false) value属性指定的值,可以注解在字符串类型的属性上 |
@DecimalMin(value=,inclusive=) | 值必须大于等于(inclusive=true)/大于(inclusive=false) value属性指定的值,可以注解在字符串类型的属性上 |
@Digits(integer=,fraction=) | 数字格式检查,integer指定整数部分的最大长度,fraction指定小数部分的最大长度 |
@Future | 值必须是未来的日期 |
@Past | 值必须是过去的日期 |
@Max(value=) | 值必须小于等于value指定的值,不能注解在字符串类型的属性上 |
@Min(value=) | 值必须大于等于value指定的值,不能注解在字符串类型的属性上 |
引入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.1.6.RELEASE</version>
</dependency>
<!--用lombok ,让代码更简洁-->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
</dependency>
实体类
public class User implements Serializable {
private static final long serialVersionUID = -8441401775719174836L;
private Integer id;
private String userName;
"密码不能为空") (message =
private String password;
"生日必须是过去的时间") (message =
private Date birthDay;
}
控制层
import javax.validation.Valid;
import org.springframework.validation.BindingResult;
/**
* 说明:
* 添加 BindingResult参数后,就算验证不通过,也能继续执行方法体
* BindingResult的参数的作用:
* 方便记录日志(如果不想继续向下执行,可以直接再抛异常)
* @param user
* @param errors
* @return
*/
public Object create( User user, BindingResult result){
// 判断BindingResult是否保存错误的验证信息,如果有,则直接return
if (errors.hasErrors()) {
Map<String, String> errors = Maps.newHashMap();
result.getFieldErrors().stream().forEach(f -> errors.put(f.getField(), f.getDefaultMessage()));
return errors;
}
//对 user的处理,然后返回
return user;
}
自定义校验注解
自定义注解用途:校验字段的在数据库里的唯一性等
定义注解类
**
* 自定义校验注解
* 类似与
*
* 指明这是一个校验的注解
* validatedBy = MyConstraintValidator.class 指定由MyConstraintValidator类去校验
*
* 必须定义三个成员 message,groups,payload
*
*/
public MyConstraint {
String message() default "{javax.validation.constraints.NotEmpty.message}";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
}
定义校验类
/**
* 不用添加 @Component注解
* spring会扫描实现了ConstraintValidator 接口的类后,然后自动管理
*
* ConstraintValidator<MyConstraint, String>:
* 泛型参数说明:
* 第一个参数 指定校验MyConstraint注解的字段
* 第二参数 注解修改字段的类型
* @author chennan
* @date 2019.7.22 22:19
*/
public class MyConstraintValidator implements ConstraintValidator<MyConstraint, String> {
/**
* 可以注入任何spring管理的服务
*/
private HelloService helloService;
public boolean isValid(String value, ConstraintValidatorContext context) {
System.out.println("------------MyConstraintValidator---------");
System.out.println(value);
System.out.println(helloService.greeting("tom"));
System.out.println("------------MyConstraintValidator---------");
//true-校验通过 false-校验不通过
return false;
}
public void initialize(MyConstraint constraintAnnotation) {
System.out.println("my validator init");
}
}
使用自定义校验注解
public class User implements Serializable{
private static final long serialVersionUID = -8441401775719174836L;
"测试自定义注解") (message =
private String userName;
}