JSR303 数据检验

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

分组的依据是类:
在这里插入图片描述

  1. 自定义接口,例如:SaveInterface
public interface SaveInterface {
}
  1. 在验证注解里加上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;

}
  1. 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文件,一定要重新创建!!!
    在这里插入图片描述
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值