JSR303校验

介绍

JSR303 JAVA SE6的一项数据校验规范;

周末时间在编写项目时,需要对起前端传递的数据进行校验,避免后期因为数据异常导致读写出错。我们可以通过在bean数据上增加一层注解的方式,实现对后端传递数据的校验。

上实体类:

com.zpy.entity.PmsBrandEntity,代码如下:

@Data

@TableName("pms_brand")

public class PmsBrandEntity implements Serializable {

private static final long serialVersionUID = 1L;

/**

 * 品牌id

 */

@TableId(type = IdType.AUTO) // 设置id自动增长

@NotBlank(message = "修改状态id字段不能为空")

private Long brandId;

/**

 * 品牌名

 */

@NotNull(message = "品牌名称不能为空")

private String name;

/**

 * 品牌logo地址

 */

@NotNull(message = "logo地址不能为空")

@URL(message = "logo 必须是一个URL地址")

private String logo;

/**

 * 介绍

 */

private String descript;

/**

 * 显示状态[0-不显示;1-显示]

 */

@NotNull(message = "是否显示字段不能为空")

@ListValue(groups = {AddInterface.class},vals = {0,1},message = "{com.zpy.exception.validate_annotation.ListValue.message}")

private Integer showStatus;

/**

 * 检索首字母

 */

@NotNull(message = "该字段必填")

@Pattern(regexp = "^[a-zA-Z]$", message = "首字母必须是大写或者小写字母")

private String firstLetter;

/**

 * 排序

 */

@NotNull(message = "该字段必填")

@Min(value = 0, message = "排序字段必须是一个大于等于0的整数")

private Integer sort;

}

 

实体类上 使用的注解 @Blank @Null @Min @Pattern 注解,会对传递到后端的数据中的不同字段进行校验;如 sort 字段,上面标有注解 @NotNull 和@Min 注解,表示只有当传递进来的bean对象中,sort字段不为Null,并且最小值为0;如果sort字段为null的情况下,则提示信息“该字段必填”,如果sort字段 的值小于0,则提示“排序字段必须是一个大于等于0的整数”;

那么,该怎么去使用这些验证呢?

我在对应的controller方法上增加了注解@validate

如下:

public R save(@Valid @RequestBody PmsBrandEntity pmsBrand )

表示,当我的系统调用save方法,参数中传递pmsBrand 的entity实体参数,按照实体中不同注解的校验规则进行校验。对于数据中出现异常的数据,进行记录;

如果我想获取到哪些字段出现了哪些问题,有什么方法吗?

--- 可以在传参中定义 BindingResult result对象,具体实现方法如下:

public R save(@Valid @RequestBody PmsBrandEntity pmsBrand , BindingResult result)

可以在方法中,将内容打印出来:

 if (result.hasErrors()) { //判断是否有错误

            result.getFieldErrors().forEach(item->{

                String filed = item.getField(); // 获取到出错字段

                String message = item.getDefaultMessage(); // 获取到出错时返回的信息

            });

        }

BindResult 需要import的包: import org.springframework.validation.BindingResult;

 

注意:@NotBlank   @NotEmpty  @NotNull 的区别:

@NotNull 表示当前数据不为null值,但可以为empty,没有Size的约束

@NotEmpty 用在集合类上面 加了@NotEmpty的String类、Collection、Map、数组,是不能为null或者长度为0的(String Collection Map的isEmpty()方法)

@NotBlank只用于String,不能为null且trim()之后size>0;

 

注解中可以配置哪些参数呢?

通用的message: 表示当前字段校验出错的情况下,提示哪些信息;如果这个字段不做任何要求的情况下,那么当前提示信息设置为默认值;可以根据自己的要求进行设置,所有注解中都会有这个字段;

value:表示当前校验字段可以是哪些值;如@Min @Max中存在这个字段;

group:分组,下面会提到;

 

Message可以设置提示信息,我可以将它的信息设置到Properties配置文件中,message中可以直接引用其配置;创建的配置文件名称一定要叫:ValidationMessages.properties

在配置文件中:

com.zpy.exception.validate_annotation.ListValue.message=请填写对应的值

则在配置文件中,可以设置为:

@NotNull(message = "{com.zpy.exception.validate_annotation.ListValue.message}")

private Integer sort

 

 

分组校验

entity中,有些字段(如id)在新增的时候不需要做任何校验,但是在修改的时候,我需要对它进行非空验证;这个情况下需要如何处理呢?

我们可以进行验证的分组设置,以:

public R save(@Valid @RequestBody PmsBrandEntity pmsBrand )

为例,这里我们定义两个接口:

public interface AddInterface {

}

public interface Updateinterface {

}

这两个接口不需要做任何实现,什么作用呢?在下面的分组操作,仅仅起到一个标志位的作用;

 

我们将controller中的注解@Valid 切换成@Validated,并设置分组内容:

@Validated({AddInterface.class})

再执行save方法的时候,标记为AddInterface.class的字段才会进行验证;

Entity中的配置:

@Data

@TableName("pms_brand")

public class PmsBrandEntity implements Serializable {

private static final long serialVersionUID = 1L;

/**

 * 品牌id

 */

@TableId(type = IdType.AUTO) // 设置id自动增长

@NotBlank(message = "修改状态id字段不能为空", groups = {Updateinterface.class})

private Long brandId;

/**

 * 品牌名

 */

@NotNull(message = "品牌名称不能为空", groups = {Updateinterface.class, AddInterface.class})

private String name;

/**

 * 品牌logo地址

 */

@NotNull(message = "logo地址不能为空",groups = {Updateinterface.class, AddInterface.class})

@URL(message = "logo 必须是一个URL地址",groups = {Updateinterface.class, AddInterface.class})

private String logo;

/**

 * 介绍

 */

private String descript;

/**

 * 显示状态[0-不显示;1-显示]

 */

@NotNull(message = "是否显示字段不能为空",groups = {Updateinterface.class, AddInterface.class})

@ListValue(groups = {AddInterface.class},vals = {0,1},message = "{com.zpy.exception.validate_annotation.ListValue.message}")

private Integer showStatus;

/**

 * 检索首字母

 */

@NotNull(message = "该字段必填",groups = {Updateinterface.class, AddInterface.class})

@Pattern(regexp = "^[a-zA-Z]$", message = "首字母必须是大写或者小写字母",groups = {Updateinterface.class, AddInterface.class})

@NotEmpty

private String firstLetter;

/**

 * 排序

 */

@NotNull(message = "该字段必填",groups = {Updateinterface.class, AddInterface.class})

@Min(value = 0, message = "排序字段必须是一个大于等于0的整数",groups = {Updateinterface.class, AddInterface.class})

private Integer sort;

}

注意一点,如果我们在程序中开启了分组校验,那么我们需要注意的是,entity中每个字段的每一种校验方式都需要增加group分组属性,如果存在校验方式注解中未标注group,那么在任何时候,都不会触发当前字段的校验;

 

对于id字段,我们可以可以设置注解 @NotBlank(message = "修改状态id字段不能为空", groups = {Updateinterface.class}),然后在controller中

public R update(@Validated({Updateinterface.class}) @RequestBody PmsBrandEntity pmsBrand )

增加分组信息,这样,当我们调用update方法对数据进行修改时,则会触发对id的校验;

 

自定义校验注解

如果给定的校验注解,无法满足日常需求,我们可以自定义校验注解,比如我想对showStatus字段增加校验,只允许它的值是0 或 1;

存在如下步骤:

  1. 创建自定义注解@ListValue,并为它增加对应的属性;

import com.zpy.exception.validate_constraint.ListValueConstraint;

 

import javax.validation.Constraint;

import javax.validation.Payload;

import java.lang.annotation.Documented;

import java.lang.annotation.Retention;

import java.lang.annotation.Target;

import static java.lang.annotation.ElementType.*;

import static java.lang.annotation.ElementType.TYPE_USE;

import static java.lang.annotation.RetentionPolicy.RUNTIME;

@Documented

@Constraint(validatedBy = {})// 表示可以使用哪个类作为校验方式

@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE }) // 标志注解可以在哪里使用

@Retention(RUNTIME)// 什么时候执行

public @interface ListValue {

 

    String message() default "{com.zpy.exception.validate_annotation.ListValue.message}";

 

    Class<?>[] groups() default { };

 

    Class<? extends Payload>[] payload() default { };

 

    int[] vals() default {};

}

 

注意:message  groups Payload 三个字段,为必要属性,必须增加;

vals属性为新增属性,我们在这里指定需要校验的字段可以是哪些值;

  1. 自定义校验类,需要实现Constraintvalidator 接口;

import com.zpy.exception.validate_annotation.ListValue;

 

import javax.validation.ConstraintValidator;

import javax.validation.ConstraintValidatorContext;

import java.util.HashSet;

import java.util.Set;

// 第一个泛型表示当前注解,第二泛型表示传入值的类型

public class ListValueConstraint implements ConstraintValidator<ListValue,Integer> {

    private Set<Integer> set = new HashSet<>();

    @Override

    public void initialize(ListValue constraintVals) {// 初始化方法

       int[] vals = constraintVals.vals();

        for (int val:

             vals) {

         set.add(val);

        }

    }

 

    /**

     * @param value 用户需要校验的值

     * @param context

     * @return

     */

    @Override

    public boolean isValid(Integer value, ConstraintValidatorContext context) {// 对用户传入 的值进行校验;

        return set.contains(value);

    }

}

  1. 将自定义校验注解和校验类关联起来;

在自定义注解中@Constraint(validatedBy = {}) 增加validator 类

@Constraint(validatedBy = {ListValueConstraint.class})

附: 校验注解

摘自知乎: JSR303校验 - 知乎 (zhihu.com) ,作者:知者天天学习

空检查 
@Null 验证对象是否为null 
@NotNull 验证对象是否不为null, 无法查检长度为0的字符串 
@NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格. 
@NotEmpty 检查约束元素是否为NULL或者是EMPTY.

Booelan检查 
@AssertTrue 验证 Boolean 对象是否为 true 
@AssertFalse 验证 Boolean 对象是否为 false

长度检查 
@Size(min=, max=) 验证对象(Array,Collection,Map,String)长度是否在给定的范围之内 
@Length(min=, max=) Validates that the annotated string is between min and max included.

日期检查 
@Past 验证 Date 和 Calendar 对象是否在当前时间之前,验证成立的话被注释的元素一定是一个过去的日期 
@Future 验证 Date 和 Calendar 对象是否在当前时间之后 ,验证成立的话被注释的元素一定是一个将来的日期 
@Pattern 验证 String 对象是否符合正则表达式的规则,被注释的元素符合制定的正则表达式,regexp:正则表达式 flags: 指定 Pattern.Flag 的数组,表示正则表达式的相关选项。

数值检查 
建议使用在Stirng,Integer类型,不建议使用在int类型上,因为表单值为“”时无法转换为int,但可以转换为Stirng为”“,Integer为null 
@Min 验证 Number 和 String 对象是否大等于指定的值 
@Max 验证 Number 和 String 对象是否小等于指定的值 
@DecimalMax 被标注的值必须不大于约束中指定的最大值. 这个约束的参数是一个通过BigDecimal定义的最大值的字符串表示.小数存在精度 
@DecimalMin 被标注的值必须不小于约束中指定的最小值. 这个约束的参数是一个通过BigDecimal定义的最小值的字符串表示.小数存在精度 
@Digits 验证 Number 和 String 的构成是否合法 
@Digits(integer=,fraction=) 验证字符串是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。 
@Range(min=, max=) 被指定的元素必须在合适的范围内 
@Range(min=10000,max=50000,message=”range.bean.wage”) 
@Valid 递归的对关联对象进行校验, 如果关联对象是个集合或者数组,那么对其中的元素进行递归校验,如果是一个map,则对其中的值部分进行校验.(是否进行递归验证) 
@CreditCardNumber信用卡验证 
@Email 验证是否是邮件地址,如果为null,不进行验证,算通过验证。 
@ScriptAssert(lang= ,script=, alias=) 
@URL(protocol=,host=, port=,regexp=, flags=)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

VogtZhao

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值