JSR303校验
JSR303校验
添加依赖
<!-- 字段校验一般用在实体类上 --> <!-- https://mvnrepository.com/artifact/org.hibernate.validator/hibernate-validator --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>6.1.5.Final</version> </dependency>
JSR
提供的校验注解:
@Null 被的注解元素必须为 null @NotNull 被注解的元素必须不为 null @AssertTrue 被注解的元素必须为 true @AssertFalse 被注解的元素必须为 false @Min(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 @Max(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 @DecimalMin(value) 被注解的元素必须是一个数字,其值必须大于等于指定的最小值 @DecimalMax(value) 被注解的元素必须是一个数字,其值必须小于等于指定的最大值 @Size(max=, min=) 被注解的元素的大小必须在指定的范围内 集合或数组 集合或数组的大小是否在指定范围内 @Digits (integer, fraction) 被注解的元素必须是一个数字,验证是否是符合指定格式的数字,interger指定整数精度,fraction指定小数精度。 @Past 被注解的元素必须是一个过去的日期 @Future 被注解的元素必须是一个将来的日期 @Pattern(regex=,flag=) 被注解的元素必须符合指定的正则表达式
Hibernate Validator
提供的校验注解:
@Email 被注释的元素必须是电子邮箱地址 @Length(min=,max=) 被注解的值大小必须在指定的范围内 @NotEmpty 被注解的字符串的必须非空 @Range(min=,max=,message=) 验证该值必须在合适的范围内
第一步: 给Bean添加校验注解:javax.validation.constraints,并定义自己的message提示
@Data @EqualsAndHashCode(callSuper = false) @Accessors(chain = true) @TableName("pms_brand") @ApiModel(value = "Brand对象}", description = "品牌") 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; * 介绍 */ private String descript; /**
* 显示状态[0-不显示;1-显示]
*/ @NotNull(groups = {AddGroup.class, UpdateGroup.class}) @ListValue(value = {1, 0}, groups = {AddGroup.class, UpdateGroup.class}) //这里用了自定义校验功能,配合全文看 private Integer showStatus; /**
* 检索首字母
*/ @NotEmpty(groups = {AddGroup.class}) @Pattern(regexp = "^[a-zA-Z]$", message = "检索首字母必须是一个字母", groups = {AddGroup.class, UpdateGroup.class}) private String firstLetter; /**
* 排序
*/ @NotNull(groups = {AddGroup.class}) @Min(value = 0, message = "排序必须大于等于0", groups = {AddGroup.class, UpdateGroup.class}) private Integer sort; }
第二步:开启校验功能
首先了解下:
关于@Valid和@Validated的区别联系
首先了解下:
关于@Valid和@Validated的区别联系
-
@Valid
:javax.validation
, 是javax,也是就是jsr303中定义的规范注解 -
@Validated
:org.springframework.validation.annotation
, 是spring自己封装的注解。参数校验失败抛出org.springframework.validation.BindException
异常。
@Validated` 是 `@Valid` 的一个变种,扩展了 `@Valid` 的功能,支持 `group分组校验` 的写法,所以为了校验统一,尽量使用 `@Validated
/**
* 保存
* 如果不需要分组校验 就开启校验功能`@Valid` 如果bean添加了分组就不校验
* @Validated({AddGroup.class})如果我们添加了分组校验 那么就要带上分组的class
* @Validated 对没添加分组的生效
*/ @RequestMapping("/save") public R save(@Validated({AddGroup.class}) @RequestBody BrandEntity brand) { brandService.save(brand); return R.ok(); }
分组校验(多场景的复杂校验)
- @NotBlank(message = “品牌名必须提交”,groups = {AddGroup.class,UpdateGroup.class})给校验注解标注什么情况需要进行校验
- @Validated({AddGroup.class})
- 默认没有指定分组的校验注解@NotBlank,在分组校验情况@Validated({AddGroup.class})下不生效,只会在@Validated生效;
**创建分组接口
**
package com.initialize.common.valid; public interface AddGroup { }
自定义校验
编写一个自定义的校验注解
import com.initialize.common.valid.validator.ListValueConstraintValidator; 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 = {ListValueConstraintValidator.class})//绑定自定义的校验器 @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})//注解可以加在什么地方 @Retention(RUNTIME)//表示运行时一直保留 public @interface ListValue { String message() default "{com.initialize.common.valid.annotation.ListValue.message}"; Class<?>[] groups() default {};//分组 Class<? extends Payload>[] payload() default {}; int[] value() default {};//可以输入int类型的数组值 }
创建ValidationMessages.properties 配置文件
设置默认提示信息,这个文件名不是随便起的,是和自带的配置文件名一样,可全局搜索 ValidationMessages.properties可以发现有一个自带的额消息提示配置文件
com.initialize.common.valid.annotation.ListValue.message=必须提交指定的值
自定义校验器
import com.initialize.common.valid.annotation.ListValue; import javax.validation.ConstraintValidator; import javax.validation.ConstraintValidatorContext; import java.util.HashSet; import java.util.Set; /**
* @program: gulimall
* @description: 自定义校验器
* @author: Mr.Lu
* @create: 2020-08-04 23:13
**/ /**
* 在自定义注解中 @Constraint(validatedBy = {}) 里面的ConstraintValidator其实是个接口 所以我们要实现这个接口
* 接口的两个范型 第一个 指定注解 第二个 校验什么类型
*/ public class ListValueConstraintValidator implements ConstraintValidator<ListValue, Integer> { //将值设置进去方便下面的拍断校验方法 private Set<Integer> set = new HashSet<>(); /**
* 初始化方法 会将ListValue标注的详细信息返回给我们
*
* @param constraintAnnotation 通过它拿值
*/ @Override public void initialize(ListValue constraintAnnotation) { int[] value = constraintAnnotation.value();//通过ListValue拿到value值 for (int val : value) { set.add(val); } } /**
* 判断是否校验成功
*
* @param value 需要校验的值 就是给这个属性复的值
* @param context 整个校验的上下文信息
* @return
*/ @Override public boolean isValid(Integer value, ConstraintValidatorContext context) { //判读值是否在集合中 不包含返回false return set.contains(value); } }
当我们校验失败的时候 我们统一交给全局异常处理器处理
import com.initialize.common.response.R; import com.initialize.common.response.ResultCode; import lombok.extern.slf4j.Slf4j; import org.springframework.validation.BindException; import org.springframework.validation.BindingResult; import org.springframework.web.bind.MethodArgumentNotValidException; import org.springframework.web.bind.annotation.ExceptionHandler; import org.springframework.web.bind.annotation.RestControllerAdvice; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; /**
* @program: gulimall
* @description: 全局异常处理
* @author: Mr.Lu
* @create: 2020-08-04 20:31
**/ @Slf4j @RestControllerAdvice(basePackages = "com.initialize.gulimall.product.controller") public class ExceptionControllerAdvice { /**
* 参数错误异常
*/ @ExceptionHandler({MethodArgumentNotValidException.class, BindException.class}) public R handleVaildException(HttpServletRequest request, Exception e) { //判断异常是否是MethodArgumentNotValidException if (e instanceof MethodArgumentNotValidException) { //将异常转为MethodArgumentNotValidException MethodArgumentNotValidException validException = (MethodArgumentNotValidException) e; //通过异常获取所有返回验证失败的结果 BindingResult bindingResult = validException.getBindingResult(); HashMap<String, String> errorMap = new HashMap<>(); //判断是否有错 if (bindingResult.hasErrors()) { log.info("### 请求参数错误: \t|对象名| \t\t\t|字段| \t\t\t|错误消息|"); //去除所以字段错误并且遍历处理 bindingResult.getFieldErrors().forEach((fieldError) -> { errorMap.put(fieldError.getField(), fieldError.getDefaultMessage()); log.error("### 请求参数错误: \t{} \t\t{} \t\t{}", fieldError.getObjectName(), fieldError.getField(), fieldError.getDefaultMessage()); }); log.error("### 请求路径RequestURL:{} ###", request.getRequestURL()); return R.error(10001, "参数无效").put("data", errorMap); } } else if (e instanceof BindException) { BindException bindException = (BindException) e; if (bindException.hasErrors()) { log.error("### 请求参数错误: {}", bindException.getAllErrors()); log.error("### 请求路径RequestURL:{} ###", request.getRequestURL()); } } return R.error(10001, "参数无效"); } /**
* 处理所有不可知的异常
*/ @ExceptionHandler(Exception.class) public R handleOtherException(HttpServletRequest request, Exception e) { //打印异常堆栈信息 e.printStackTrace(); // 打印异常信息 log.error("### 不可知的异常:{} ###", e.getMessage()); log.error("### 请求路径RequestURL:{} ###", request.getRequestURL()); return R.error(4444, "系统繁忙,请稍后重试"); } }
本文地址:https://blog.csdn.net/qq_46126559/article/details/107888606
您可能感兴趣的文章:
如您对本文有疑问或者有任何想说的,请 点击进行留言回复,万千网友为您解惑!
网友评论