JSR 是 Java Specification Requests 的缩写,即 Java 规范提案。
存在各种各样的 JSR,简单的理解为 JSR 是一种 Java 标准。
JSR 303 就是数据检验的一个标准(Bean Validation (JSR 303))。
配置
pom
<!-- 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.3.2.RELEASE</version>
</dependency>
使用
基本
- 在实体类标上对应注解
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotEmpty
private String name;
/**
* 品牌logo地址
*/
@URL
private String logo;
/**
* 介绍
*/
@NotEmpty
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull
private Integer showStatus;
/**
* 检索首字母
*/
@NotEmpty
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须为英文字母")
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0,message = "必须大于0")
private Integer sort;
}
注意:
@NotNull
可以标在任意数据字段上,不能为null,但可为empty,也就是必须有这个参数
@NotEmpty
只能标在如下属性字段上:字符串、集合、Map、数组,校验长度是否大于0
@NotBlank
:只能作用在String上,不能为null,而且调用trim()后,长度必须大于0@Pattern()
自定义正则验证,但不能用于验证Integer等数字类型
- controller层标上
@Valid
注解,并可通过BindingResult
参数获得验证失败的详细信息
@RequestMapping("/save")
//@RequiresPermissions("gulimallproduct:brand:save")
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
if (result.hasErrors()){
Map<String,String> map = new HashMap<>();
result.getFieldErrors().forEach((fieldError -> {
map.put(fieldError.getField(),fieldError.getDefaultMessage());
}));
return R.error(400,"表单信息不合法!").put("data",map);
}
brandService.save(brand);
return R.ok();
}
- 异常也可以不处理(注释上面异常处理的逻辑),使用异常处理类来处理
@RestControllerAdvice
public class GulimallExceptionControllerAdvice{
//方法参数不适配异常
@ExceptionHandler(MethodArgumentNotValidException.class)
public R methodArgumentNotValidException(MethodArgumentNotValidException e){
Map<String, String> map = new HashMap<>();
e.getBindingResult().getFieldErrors().forEach(error->{
map.put(error.getField(),error.getDefaultMessage());
});
return R.error(10001, "参数校验失败")
.put("data",map);
}
//所有异常
@ExceptionHandler(Throwable.class)
public R exception(Throwable e){
return R.error(400, "未知异常")
.put("data",e.getMessage());
}
}
分组group
分组的依据是类:
- 自定义接口,例如:
SaveInterface
public interface SaveInterface {
}
- 在验证注解里加上
groups
属性,并绑定类,例如:
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@Null(groups = {SaveInterface.class},message = "保存信息,主键必须为null")//保存,主键为null
@NotNull(groups = {UpdateInterface.class},message = "修改信息,主键不能为null")//更新,主键不为null
private Long brandId;
/**
* 品牌名
*/
@NotBlank(groups = {SaveInterface.class,UpdateInterface.class})
private String name;
/**
* 品牌logo地址
*/
@NotBlank(groups = {SaveInterface.class})//必须传,且去掉首尾空格后长度大于0
@URL(groups = {SaveInterface.class,UpdateInterface.class})//要么不传,要么传一个url
private String logo;
/**
* 介绍
*/
@NotBlank(groups = {SaveInterface.class})
@NotNull(groups = {SaveInterface.class,UpdateInterface.class})
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
@NotNull
private Integer showStatus;
/**
* 检索首字母
*/
@NotBlank(groups = {SaveInterface.class})
@Pattern(regexp = "^[a-zA-Z]$",message = "检索首字母必须为英文字母",groups = {SaveInterface.class,UpdateInterface.class})
private String firstLetter;
/**
* 排序
*/
@NotNull
@Min(value = 0,message = "必须大于0",groups = {SaveInterface.class,UpdateInterface.class})
private Integer sort;
}
- controller层添加
@Validated
注解,并指定类
public class BrandController {
public R save(@Validated({SaveInterface.class}) @RequestBody BrandEntity brand){
...
}
}
自定义验证
- 想要指定展示状态只能是0或者1:(
@ListAnnotation
在后面创建,而且该注解有vals属性,message
指定和ValidationMessages.properties
配置文件哪个属性绑定)
@ListAnnotation(vals={1,0},groups = {SaveInterface.class,UpdateInterface.class})
private Integer showStatus;
- 自定义
@ListAnnotation
注解,@Constraint(validatedBy = { })
指定用哪个类校验(ListValid
类在后面创建)
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
@Documented
@Constraint(validatedBy = {ListValid.class })//指定校验类
public @interface ListAnnotation {
String message() default "{com.ljy.common.valid.customize.ListAnnotation.message}";//对应配置文件的哪个属性值
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals();//自定义属性
}
- 新建
ValidationMessages.properties
配置文件,内容:(如果乱码,后面有解决方法)
com.ljy.common.valid.customize.ListAnnotation.message = 所传属性不在指定范围内
- 自定义
ListValid
类,需要实现ConstraintValidator
,有两个泛型,第一个泛型是用于和哪个校验注解绑定,第二个是用于检验什么类型数据
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
/**
* @program: gulimall
* @description: 状态校验类
* @author: liangjiayy
* @create: 2022-03-31 16:57
**/
public class ListValid implements ConstraintValidator<ListAnnotation,Integer> {
Set<Integer> set = new HashSet<>();
@Override
//constraintAnnotation可以获取属性内容
public void initialize(ListAnnotation constraintAnnotation) {
//获取vals属性值,并存到set集合
for (int val : constraintAnnotation.vals()) {
set.add(val);
}
}
@Override
//value:提交的值,context:上下文环境
public boolean isValid(Integer value, ConstraintValidatorContext context) {
//检查set集合中是否有指定value
return set.contains(value);
}
}
乱码解决
- 如果读取
ValidationMessages.properties
文件后,返回给浏览器的内容乱码,请设置: - 设置后请重新创建
ValidationMessages.properties
文件,一定要重新创建!!!