JSR303数据校验
例如:JSR303数据校验功能学习文章目录
一、JSR303数据校验是什么?
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。
此实现与 Hibernate ORM 没有任何关系。 JSR 303 用于对 Java Bean 中的字段的值进行验证。
Spring MVC 3.x 之中也大力支持 JSR-303,可以在控制器中对表单提交的数据方便地验证。
注:可以使用注解的方式进行验证
二、JSR303数据校验使用步骤
1.引入库
代码如下(示例):
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
2.实体类上加校验注解
代码如下(示例):
@NotBlank
@NotEmpty
@NotNull
@Pattern
@Url
package com.travel.mall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
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.Min;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
/**
* 品牌
*
* @author liyong
* @email liyong@gmail.com
* @date 2021-05-27 11:03:30
* JSR303数据校验功能,entity属性上加注解@NotBlank(message = "品牌名不能为空"),controller方法加@Valid注解@Valid @RequestBody BrandEntity brand
* 分组校验:groups,@Validated
*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
private Long id;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空")
private String name;
/**
* 品牌logo地址
*/
@NotBlank(message = "品牌logo不能为空")
@URL(message = "品牌logo必须是一个合法的URL地址")
private String logo;
/**
* 显示状态[0-不显示;1-显示]
*/
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
/**
* 排序
*/
@NotNull(message = "排序字段不能为空")
@Min(value = 0,message = "排序字段必须大于0")
private Integer sort;
}
## 3.在controller方法中加上@Valid注解
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
接口返回结果
```javascript
{
"msg": "系统未知错误",
"code": 400,
"data": {
"name": "品牌名不能为空",
"logo": "品牌logo不能为空",
}
}
3.JSR分组校验功能:
1.应用场景:
实际开发中我们存在这样一个场景:新增和修改是对参数的校验是不同的,例如主键id在新增时必须为空,在修改时不能为空,如果直接在id属性上添加@NotNull注解,则在提交表单时不论时添加还是修改都是校验,不符合业务要求,此时就需要使用JSR的分组校验功能。
2.分组校验使用步骤
在@NotNull注解中有个groups属性,里面存放一个接口数组,例如:
@NotNull(message = “修改时品牌id不能为空”,groups = {UpdateGroup.class,AddGroup.class})
package com.travel.mall.product.entity;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableLogic;
import com.baomidou.mybatisplus.annotation.TableName;
import java.io.Serializable;
import java.util.Date;
import com.travel.common.vaild.AddGroup;
import com.travel.common.vaild.UpdateGroup;
import lombok.Data;
import org.hibernate.validator.constraints.URL;
import javax.validation.constraints.*;
/**
* 品牌
*
* @author liyong
* @email liyong@gmail.com
* @date 2021-05-27 11:03:30
* JSR303数据校验功能,entity属性上加注解@NotBlank(message = "品牌名不能为空"),controller方法加@Valid注解@Valid @RequestBody BrandEntity brand
* 分组校验:groups,@Validated
*/
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@TableId
@NotNull(message = "修改时品牌id不能为空",groups = {UpdateGroup.class})
@Null(message = "新增时品牌id必须为空",groups = {AddGroup.class})
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名不能为空",groups = {AddGroup.class,UpdateGroup.class})
private String name;
/**
* 品牌logo地址
*/
@NotBlank(message = "品牌logo不能为空",groups = {AddGroup.class,UpdateGroup.class})
@URL(message = "品牌logo必须是一个合法的URL地址",groups = {AddGroup.class,UpdateGroup.class})
private String logo;
/**
* 显示状态[0-不显示;1-显示]
*/
@TableLogic(value = "1",delval = "0")
private Integer showStatus;
}
UpdateGroup和AddGroup接口需要自定义,里面无需实现任何内容。
例如:
在接口入口方法上加上@Validated(AddGroup.class)注解,用来执行进行哪个组的校验。
注:因为用了@Validated,故在实体类加上了校验注解后必须指定分组否则无法进行校验。
/**
* 保存
*/
@RequestMapping("/save")
//@RequiresPermissions("product:brand:save")
public R save(@Validated(AddGroup.class) @RequestBody BrandEntity brand) {
brandService.save(brand);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
//@RequiresPermissions("product:brand:update")
public R update(@Validated(UpdateGroup.class) @RequestBody BrandEntity brand) {
brandService.updateById(brand);
return R.ok();
}
3.自定义参数校验注解
1.使用方法:
新建一个注解类:
package com.travel.common.vaild;
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;
@Documented
@Constraint(
validatedBy = {StatusValidConstraintValidator.class}
)
@Target({ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR,
ElementType.PARAMETER, ElementType.TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
public @interface StatusValid {
String message() default "{com.travel.mall.valid.StatusValid.message}";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
int[] vals() default {};
}
自定义注解校验类:
package com.travel.common.vaild;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.util.HashSet;
import java.util.Set;
/**
* @Author LiYong
* @Date 2021/5/31 15:05
**/
public class StatusValidConstraintValidator implements ConstraintValidator<StatusValid, Integer> {
Set<Integer> set = new HashSet<>();
/**
* 初始化
*
* @param constraintAnnotation
*/
@Override
public void initialize(StatusValid constraintAnnotation) {
int[] vals = constraintAnnotation.vals();
for (int i = 0; i < vals.length; i++) {
set.add(vals[i]);
}
}
/**
* 判断校验是否通过
*
* @param constraintValidatorContext
* @return
*/
@Override
public boolean isValid(Integer integer, ConstraintValidatorContext constraintValidatorContext) {
return set.contains(integer);
}
}
在实体类中使用自定义校验注解
/**
* 显示状态[0-不显示;1-显示]
*/
@TableLogic(value = "1",delval = "0")
@StatusValid(message = "数值不在范围内",vals = {0,1},groups = {AddGroup.class})
private Integer showStatus;