一,JSR303
JSR303是Java为Bean数据合法性校验提供给的标准框架,已经包含在 JavaEE6.0中,JSR303通过在Bean 属性中标注类似 @NotNull @Max 等标准的注解指定校验规则,并通过标准的验证接口对 Bean进行验证。
二,JSR303常用注解
注解 | 作用 |
---|---|
@Null | 被注解的元素必须为null |
@NotNull | 被注解的元素必须不为null |
@NotBlank | 用于String类型参数校验,检查字符串不能为null且trim()之后的size>0。 |
@NotEmpty | 被注解的字符串的值必须非空 |
@AssortTrue | 被注解的元素必须为true |
@AssortFalse | 被注解的元素必须为false |
@Min(value) | 被注解的元素必须是一个数字,其值必须小于等于指定的最小值 |
@Max(value) | 被注解的元素必须是一个数字,其值必须大于等于指定的最大值 |
@Size(max,min) | 被注解的元素的大小必须在指定的范围内 |
@Digits(integer,fraction) | 被注解的元素必须是一个数字,其值必须在可接受范围内 |
@Past | 被注解元素必须是一个过去的日期 |
@Future | 被注解元素必须是一个将来的日期 |
@Pattern(value) | 被注解的元素必须符合指定的正则表达式 |
被注解的元素必须是电子邮箱地址 | |
@Length | 被注解的字符串的大小必须在指定的范围内 |
@Range | 被注解的元素必须在合适的范围内 |
三,如何使用这些注解进行校验
1.引入
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-validation -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
<version>2.7.16</version>
</dependency>
2.在实体类的成员属性上标注上注解
package com.wufeng.gulimall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须提交")
private String name;
/**
* 品牌logo地址
*/
@URL(message = "logo必须是一个url格式的地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@NotNull
@Pattern(regexp = "^[A-Za-z]$", message = "检索首字母必须为字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0, message = "排序必须大于等于0")
private Integer sort;
}
3.Controller中的方法上添加注解@Valid注解
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand/*, BindingResult result*/){
// //数据校验不通过
// if (result.hasErrors()) {
// HashMap<String, String> map = new HashMap<>();
// //1.获取校验的错误结果
// result.getFieldErrors().forEach((item)->{
//
// //2.获取错误的属性名字
// String field = item.getField();
// String message = item.getDefaultMessage();
// map.put(field,message);
//
// });
// return R.error(400,"提交的数据不合法").put("data",map);
// }
brandService.save(brand);
return R.ok();
}
四,分组校验
1.编写分组标识接口
public interface AddGroup {
}
public interface UpdateGroup{
}
2.实体类中的注解添加分组属性
package com.wufeng.gulimall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.wufeng.common.valid.AddGroup;
import com.wufeng.common.valid.UpdateGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@Null(message = "新增不能指定品牌id",groups = {UpdateGroup.class})
@NotNull(message = "修改必须指定品牌id",groups = {AddGroup.class})
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
private String name;
/**
* 品牌logo地址
*/
@URL(message = "logo必须是一个url格式的地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@NotNull
@Pattern(regexp = "^[A-Za-z]$", message = "检索首字母必须为字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0, message = "排序必须大于等于0")
private Integer sort;
}
3.在Controller的方法中标注@Validated注解并添加使用的分组
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand/*, BindingResult result*/){
// //数据校验不通过
// if (result.hasErrors()) {
// HashMap<String, String> map = new HashMap<>();
// //1.获取校验的错误结果
// result.getFieldErrors().forEach((item)->{
//
// //2.获取错误的属性名字
// String field = item.getField();
// String message = item.getDefaultMessage();
// map.put(field,message);
//
// });
// return R.error(400,"提交的数据不合法").put("data",map);
// }
brandService.save(brand);
return R.ok();
}
这时,如果调用的是save这个方法,会校验BrandEntity实体中标注了该AddGroup.class组的注解的成员属性,没有AddGroup.class这个属性的校验注解不生效。
五,自定义校验注解
1.编写一个自定义校验注解
@Constraint(
validatedBy = {}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ListValue {
//校验出错后,message去ValidationMessages.properties文件里取com.wufeng.common.valid.ListValue.message这个值
String message() default "{com.wufeng.common.valid.ListValue.message}";
//支持分组校验
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
//自己定义的属性
int[] vals() default {};
}
2.编写一个自定义校验器
//必须实现ConstraintValidator接口,第一个泛型是你的校验注解,第二个泛型需要校验的属性的类型
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
//初始化方法,写你自己的逻辑
@Override
public void initialize(ListValue constraintAnnotation) {
//获取注解中定义的vals的值,添加到set中
int[] vals = constraintAnnotation.vals();
for (int val : vals) {
set.add(val);
}
}
//校验方法,false校验信息有误,写你自己的逻辑
@Override
public boolean isValid(Integer value, ConstraintValidatorContext constraintValidatorContext) {
//校验的值是否是set中的值,是-true,否-false
return set.contains(value);
}
}
3.关联自定义校验器和自定义校验注解,在自定义注解中关联自定义校验器(可以有多个)
@Constraint(
//关联校验器,校验器是ListValueConstraintValidator.class这个类,可以写多个校验类
validatedBy = {ListValueConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR, ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface ListValue {
//校验出错后,message去ValidationMessages.properties文件里取com.wufeng.common.valid.ListValue.message这个值
String message() default "{com.wufeng.common.valid.ListValue.message}";
//支持分组校验
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
//自己定义的属性
int[] vals() default {};
}
4.ValidationMessages.properties中配置message信息
也可以不配置该文件,但是需要在使用注解时带上message属性
com.wufeng.common.valid.ListValue.message=Must be a value within the specified range
5.在实体类中使用自定义注解(在实体类中的需要校验的属性上使用该注解)
@ListValue(vals = {0,1},groups = {AddGroup.class})
private Integer showStatus;
6.测试方法
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}