文章目录
一、JSR-303
- 什么是JSR-303?
JSR-303 是 JAVA EE 6 中的一项子规范,叫做 Bean Validation,官方参考实现是Hibernate Validator。
位于javax.validation下的一些类。
- 详细用法
- @Null 验证对象是否为null
- @NotNull 验证对象是否不为null, 无法查检长度为0的字符串
- @NotBlank 检查约束字符串是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.
- @NotEmpty 检查约束元素是否为NULL或者是EMPTY.
- @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: 指定
- @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=)
二、使用
1.简单使用
a) 实体类
//这里只写了几个作为参考
@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地址
*/
@NotBlank
@URL(message = "logo必须是合法的url地址")
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0,message = "排序必须大于0")
private Integer sort;
}
b) R类
public class R extends HashMap<String, Object> {
private static final long serialVersionUID = 1L;
public R() {
put("code", 0);
put("msg", "success");
}
public static R error() {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, "未知异常,请联系管理员");
}
public static R error(String msg) {
return error(HttpStatus.SC_INTERNAL_SERVER_ERROR, msg);
}
public static R error(int code, String msg) {
R r = new R();
r.put("code", code);
r.put("msg", msg);
return r;
}
public static R ok(String msg) {
R r = new R();
r.put("msg", msg);
return r;
}
public static R ok(Map<String, Object> map) {
R r = new R();
r.putAll(map);
return r;
}
public static R ok() {
return new R();
}
public R put(String key, Object value) {
super.put(key, value);
return this;
}
}
c) Controller层
/**
*
* @param brand 实体类
* @param result 校验结果判断
* @return
*/
@RequestMapping("/save")
//@Valid 这个是必须要加的,否则校验不起作用
public R save(@Valid @RequestBody BrandEntity brand, BindingResult result){
Map<String,String> map = new HashMap();
if(result.hasErrors()){
List<FieldError> fieldErrors = result.getFieldErrors();
fieldErrors.forEach(fieldError -> {
String message = fieldError.getDefaultMessage();
String file = fieldError.getField();
map.put(file,message);
});
return R.error(400,"提交的数据不合法").put("data",map);
}
brandService.save(brand);
return R.ok();
}
d) 测试结果
这里不传名字,测试
2.统一异常返回
a) 统一错误枚举类
public enum BizCodeEnum {
VALID_EXCEPTION(10000,"系统未知异常"),
UNKNOWN_EXCEPTION(10001,"参数格式校验失败"),
PASSWORD_ERROR_EXCEPTION(10002,"密码错误");
private int code;
private String msg;
public int getCode() {
return code;
}
public void setCode(int code) {
this.code = code;
}
public String getMsg() {
return msg;
}
public void setMsg(String msg) {
this.msg = msg;
}
BizCodeEnum(int code, String msg) {
this.code = code;
this.msg = msg;
}
}
b) controller层
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Valid @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}
c) 统一异常处理类
@Slf4j
@RestControllerAdvice(basePackages = "com.product.controller")
public class ExceptionAdvice {
// 这里是要捕获的具体异常类型
@ExceptionHandler(value = MethodArgumentNotValidException.class)
public R handleValidException(MethodArgumentNotValidException e) {
log.error("数据校验出现问题{},异常类型为{}", e.getMessage(), e.getClass());
BindingResult bindingResult = e.getBindingResult();
Map<String, String> map = new HashMap();
List<FieldError> fieldErrors = bindingResult.getFieldErrors();
fieldErrors.forEach(fieldError -> {
map.put(fieldError.getField(), fieldError.getDefaultMessage());
});
return R.error(BizCodeEnum.VALID_EXCEPTION.getCode(), BizCodeEnum.VALID_EXCEPTION.getMsg()).put("data", map);
}
// 这里返回一个全局的异常处理
@ExceptionHandler(value = Throwable.class)
public R handleValidException(Throwable t) {
return R.error(BizCodeEnum.UNKNOWN_EXCEPTION.getCode(), BizCodeEnum.UNKNOWN_EXCEPTION.getMsg());
}
}
d) 启动项目测试
3、分组校验
a) 分组标识类
AddGroup
public interface AddGroup {
}
UpdateGroup
public interface UpdateGroup {
}
b) 实体类改造
@Data
@TableName("pms_brand")
public class BrandEntity implements Serializable {
private static final long serialVersionUID = 1L;
/**
* 品牌id
*/
@NotNull(message = "修改必须指定品牌ID",groups = {UpdateGroup.class})
@Null(message = "新增不能指定id",groups = {AddGroup.class})
@TableId
private Long brandId;
/**
* 品牌名
*/
@NotBlank(message = "品牌名必须提交",groups = {AddGroup.class,UpdateGroup.class})
private String name;
/**
* 品牌logo地址,指定校验分组
*/
@NotEmpty(groups = {AddGroup.class})
@URL(message = "logo必须是合法的url地址",groups = {AddGroup.class,UpdateGroup.class})
private String logo;
/**
* 介绍
*/
private String descript;
/**
* 显示状态[0-不显示;1-显示]
*/
private Integer showStatus;
/**
* 检索首字母
*/
@Pattern(regexp = "/^[a-zA-Z]$/",message = "检索首字母必须是字母")
private String firstLetter;
/**
* 排序
*/
@Min(value = 0,message = "排序必须大于0")
private Integer sort;
}
c) 方法改造
/**
* 保存
*/
@RequestMapping("/save")
public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand){
brandService.save(brand);
return R.ok();
}
/**
* 修改
*/
@RequestMapping("/update")
public R update(@Validated({AddGroup.class, UpdateGroup.class})@RequestBody BrandEntity brand){
brandService.updateById(brand);
return R.ok();
}
d) 测试
4、自定义校验
a)引入jar包
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
b) 编写注解
@Documented
@Constraint(validatedBy = {ListValueConstraintValidator.class })
@Target({ METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE })
@Retention(RUNTIME)
public @interface ListValue {
String message() default "必须提交指定的值";
Class<?>[] groups() default { };
Class<? extends Payload>[] payload() default { };
int[] vals() default { };
}
c) 自定义校验器
public class ListValueConstraintValidator implements ConstraintValidator<ListValue,Integer> {
private Set<Integer> set = new HashSet<>();
//初始化方法
@Override
public void initialize(ListValue constraintAnnotation) {
int[] vals = constraintAnnotation.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);
}
}
d) 实体类修改
/**
* 显示状态[0-不显示;1-显示]
*/
@ListValue(vals={0,1},groups = {AddGroup.class,UpdateGroup.class})
private Integer showStatus;