validation参数检验 - 注解介绍

Maven 依赖

项目为 springboot 项目,主要依赖有以下三个,其中spring-boot-starter-validation包含了 jakarta.validation-api(包含了 javax.validation)、hibernate-validator

	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-validation</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-web</artifactId>
	</dependency>

	<dependency>
		<groupId>org.projectlombok</groupId>
		<artifactId>lombok</artifactId>
		<optional>true</optional>
	</dependency>

注解介绍

javax.validation 中的注解(22个)

javax.validation 中的注解

注解 验证的数据类型 说明
Null 所有类型 验证元素值必须为 null
NotNull 所有类型 验证元素值必须不为 null
NotBlank CharSequence 验证元素值不能为 null,并且至少包含一个非空白字符。
NotEmpty CharSequence、Collection、Map、Array 验证元素值不能为 null,且不能为空
Size(min = min, max = max) 同 NotEmpty 验证元素的 size 必须在 min 和 max 之间(包含边界),认为 null 是有效的
AssertFalse boolean、Boolean 验证元素值必须为 false,认为 null 是有效的
AssertTrue 同 AssertFalse 验证元素值必须为 true,认为 null 是有效的
DecimalMax(value=, inclusive=) BigDecimal、BigInteger、CharSequence,byte、 short、int、long 及其包装类型,由于舍入错误,不支持double和float 验证元素值必须小于等于指定的 value 值,认为 null 是有效的
DecimalMin 同 DecimalMax 验证元素值必须大于等于指定的 value 值,认为 null 是有效的
Max 同 DecimalMax,不支持CharSequence 验证元素值必须小于等于指定的 value 值,认为 null 是有效的
Min 同 DecimalMax,不支持CharSequence 验证元素值必须大于等于指定的 value 值,认为 null 是有效的
Digits(integer =, fraction =) 同 DecimalMax 验证元素整数位数的上限 integer 与小数位数的上限 fraction,认为 null 是有效的
Positive BigDecimal、BigInteger,byte、short、int、long、float、double 及其包装类型 验证元素必须为正数,认为 null 是有效的
PositiveOrZero 同Positive 验证元素必须为正数或 0,认为 null 是有效的
Negative 同Positive 验证元素必须为负数,认为 null 是有效的
NegativeOrZero 同Positive 验证元素必须为负数或 0,认为 null 是有效的
Future Date、Calendar、Instant、LocalDate、LocalDateTime、LocalTime、MonthDay、OffsetDateTime、OffsetTime、Year、YearMonth、ZonedDateTime、HijrahDate、JapaneseDate、MinguoDate、ThaiBuddhistDate 验证元素值必须是一个将来的时间,认为 null 是有效的
FutureOrPresent 同 Future 验证元素值必须是当前时间或一个将来的时间,认为 null 是有效的
Past 同 Future 验证元素值必须是一个过去的时间,认为 null 是有效的
PastOrPresent 同 Future 验证元素值必须是当前时间或一个过去的时间,认为 null 是有效的
Email(regexp = 正则表达式,flag = 标志的模式) CharSequence 验证注解的元素值是Email,可以通过 regexp 和 flag 指定自定义的 email 格式,认为 null 是有效的
Pattern 同 Email 验证元素值符合正则表达式,认为 null 是有效的

Null、NotNull

验证元素值必须为 null (Null),必须不为 null(NotNull),支持所有类型。

    @GetMapping("null")
    public String isNull(@Null Integer b) {
        return "pass: " + b;
    }

    @GetMapping("notNull")
    public String notNull(@NotNull Integer b) {
        return "pass: " + b;
    }

Null_NotNull

NotBlank

验证元素值不能为null,并且至少包含一个非空白字符。支持的类型:CharSequence

    @GetMapping("notBlank")
    public String notBlank(@NotBlank String b) {
        return "pass: " + b;
    }

notBlank

NotEmpty

验证元素值不能为null,且不能为空。支持的类型:

  • CharSequence (length of character sequence is evaluated)
  • Collection (collection size is evaluated)
  • Map (map size is evaluated)
  • Array (array length is evaluated)
    @GetMapping("notEmpty")
    public String notEmpty(@NotEmpty @RequestParam(name = "list", required = false) ArrayList<String> list) {
        return "pass: " + list;
    }

notEmpty

Size

验证元素的size必须在 min 和 max 之间(包含边界),认为 null 是有效的。支持的类型:

  • CharSequence (length of character sequence is evaluated)
  • Collection (collection size is evaluated)
  • Map (map size is evaluated)
  • Array (array length is evaluated)

Size
min()
size 的最小值,默认为 0

max()
size 的最大值,默认为 Integer.MAX_VALUE

    @GetMapping("size")
    public String size(@Size(min = 2, max = 3) @RequestParam(name = "list", required = false) ArrayList<String> list ) {
        return "pass: " + list;
    }

size

AssertFalse、AssertTrue

验证元素值必须为false/true,认为 null 是有效的(见测试结果),支持booleanBoolean

    @GetMapping("wrapperAssertFalse")
    public String wrapperAssertFalse(@AssertFalse Boolean b) {
        return "pass: " + b;
    }

    @GetMapping("wrapperAssertTrue")
    public String wrapperAssertTrue(@AssertTrue Boolean b) {
        return "pass: " + b;
    }

    @GetMapping("primitiveAssertFalse")
    public String primitiveAssertFalse(@AssertFalse boolean b) {
        return "pass: " + b;
    }

    @GetMapping("primitiveAssertTrue")
    public String primitiveAssertTrue(@AssertTrue boolean b) {
        return "pass: " + b;
    }

测试结果

primitiveAssertTrue

wrapperAssertTrue

primitiveAssertFalse

wrapperAssertFalse

注解 数据类型 true false null
@AssertTrue 基本类型 × ×
@AssertTrue 包装类型 ×
@AssertFalse 基本类型 ×
@AssertFalse 包装类型 ×

关于 null 的特除处理
  在AssertTrueAssertFalse的 javadoc 中都有一句 null elements are considered valid,意思就是 null 被认为是有效的。那为什么 AssertTrue 对基本类型 boolean 会验证失败呢?我觉得是因为基本类型的默认值导致的,当前端传值为 null 时,Boolean会使用直接使用 null,但是基本类型不能为 null,所以boolean使用的是默认值 false,false != true,所以验证失败。

DecimalMax、DecimalMin、Max、Min

验证元素值必须小于等于 / 大于等于指定的 value 值,认为 null 是有效的。

  • BigDecimal
  • BigInteger
  • CharSequence,Max、Min 不支持
  • byte、short、int、long 及其包装类型
  • 由于舍入错误,不支持double和float

Max

DecimalMax
value() 方法
指定的最大、最小值

inclusive() 方法
验证时是否可以包含边界值(value()方法指定的值),默认为 true
Max、Min 不支持。

    @GetMapping("decimalMinInteger")
    public String decimalMinInteger(@DecimalMin(value = "10") Integer b) {
        return "pass: " + b;
    }

    @GetMapping("decimalMinInt")
    public String decimalMinInt(@DecimalMin(value = "10") int b) {
        return "pass: " + b;
    }
	
    @GetMapping("decimalMinIntegerExclusive")
    public String decimalMinIntegerExclusive(@DecimalMin(value = "10", inclusive = false) Integer b) {
        return "pass: " + b;
    }

decimalMinInteger
上图中使用的是包装类型 Integer, 有两个特殊情况:

  1. 当无法将字符串转换为对应数值类型时,会抛出异常,但此异常并不是验证失败,因为还没有走到验证那一步就报错了
  2. 当值为 null时,通过了验证

decimalMinInt
上图中使用的是基本类型 int,与图 decimalMinInteger 相比, 可以看出与 Integer 的区别,在于对 null 的处理,int 是直接抛出了异常,而 Integer 是通过了验证

decimalMinIntegerExclusive
上图中 inclusive = false,与图 decimalMinInteger 的第二个小图相比,图 decimalMinIntegerExclusive 没有通过验证。

Digits

验证元素整数位数的上限 integer 小数位数的上限 fraction,认为 null 是有效的。支持 BigDecimal、BigInteger、CharSequence,byte、 short、int、long 及其包装类型,由于舍入错误,不支持double和float

enter description here
integer()
整数位数的最大值

fraction()
小数位数的最大值

    @GetMapping("digits")
    public String digits(@Digits(integer = 2, fraction = 1) BigDecimal b) {
        return "pass: " + b;
    }

digits

Positive、PositiveOrZero、Negative、NegativeOrZero

验证元素必须为正数(Positive)、正数或 0 (PositiveOrZero)、负数(Negative)、负数或 0 (NegativeOrZero),认为 null 是有效的 ,支持的类型:

  • BigDecimal
  • BigInteger
  • byte、short、int、long、float、double 及其包装类型
    @GetMapping("positive")
    public String positive(@Positive Integer t) {
        return "pass: " + t;
    }

    @GetMapping("positiveOrZero")
    public String positiveOrZero(@PositiveOrZero Integer t) {
        return "pass: " + t;
    }

positive

positiveOrZero

Future、FutureOrPresent、Past、PastOrPresent

验证元素值必须是一个将来的时间(Future)、将来的时间或当前时间(FutureOrPresent)、过去的时间(Past)、过去的时间或当前时间(PastOrPresent),认为 null 是有效的 。此处 present 的概念是相对于使用约束的类型定义的。例如,如果约束条件是一年,那么当前时间就意味着整个当年。支持的类型:

  • java.util.Date
  • java.util.Calendar
  • java.time.Instant
  • java.time.LocalDate
  • java.time.LocalDateTime
  • java.time.LocalTime
  • java.time.MonthDay
  • java.time.OffsetDateTime
  • java.time.OffsetTime
  • java.time.Year
  • java.time.YearMonth
  • java.time.ZonedDateTime
  • java.time.chrono.HijrahDate
  • java.time.chrono.JapaneseDate
  • java.time.chrono.MinguoDate
  • java.time.chrono.ThaiBuddhistDate
    @GetMapping("future")
   public String future(@Future LocalDate t) {
       return "pass: " + t;
   }

   @GetMapping("futureOrPresent")
   public String futureOrPresent(@FutureOrPresent LocalDate t) {
       return "pass: " + t;
   }

测试时间为 2020-04-30

future

futureOrPresent
测试时间为 2020-04-30,可以看到图 future、图 futureOrPresent 的第二张小图,一个验证失败,一个验证通过。

Email、Pattern

验证注解的元素值是Email(Email)、符合正则表达式(Pattern),可以通过 regexp 和 flag 指定自定义的 email、正则格式,认为 null 是有效的 ,支持的类型:CharSequence。

Email
regexp()
正则表达式,Email 默认为 .* 任意字符,Pattern无默认值。
flags()
指定正则的匹配模式,不会用(手动狗头)。

    @GetMapping("email")
    public String email(@Email(regexp = ".+@.+") String email) {
        return "pass: " + email;
    }

email

hibernate.validator 中的注解

hibernate.validator

注解 数据类型 说明
CreditCardNumber(ignoreNonDigitCharacters=) CharSequence 检查字符序列是否通过Luhn校验和测试。请注意,此验证旨在检查用户错误,而不是信用卡有效性!ignoreNonDigitCharacters允许忽略非数字字符,默认值为false。
Currency javax.money.MonetaryAmount 子类型 检查注解的货币单位 javax.money.MonetaryAmount 是否为指定货币单位的一部分
DurationMax Duration 注解的 Duration 必须小于等于 DurationMax 指定的值,默认包含边界
DurationMin Duration 注解的 Duration 必须大于等于 DurationMax 指定的值,默认包含边界
EAN CharSequence 是否是有效的国际商品编号,null 是有效的
ISBN CharSequence 是否是有效的国际标准书号,null 是有效的
Length CharSequence 长度必须在 min 和 max之间,包含边界
Range BigDecimal、BigInteger、CharSequence,byte、 short、int、long 及其包装类型 数字大小必须在 min 和 max 之间,包含边界
UniqueElements Collection 检测集合中的值都是唯一的(集合不能包含相同的元素,null 是有效的)
Url CharSequence 根据RFC2396检查字符序列是否为有效URL
LuhnCheck CharSequence 检查字符序列中的数字是否通过Luhn校验和算法
Mod10Check CharSequence 检查字符序列中的数字是否通过通用mod 10校验和算法。
Mod11Check CharSequence 检查字符序列中的数字是否通过通用mod 11校验和算法。
ScriptAssert 任意类型
CodePointLength CharSequence
CNPJ CharSequence 验证巴西公司纳税人注册编号
CPF CharSequence 验证巴西个人纳税人注册号
TituloEleitoral CharSequence 验证巴西选民身份证号
NIP CharSequence 验证波兰增值税标识号
PESEL CharSequence 验证波兰的国家标识号
REGON CharSequence 验证波兰纳税人识别码

DurationMax、DurationMax

注解的 Duration 必须小于等于(DurationMax)、大于等于(DurationMin) 指定的值,默认包含边界。支持的类型 java.time.Duration

DurationMax

@RestController
public class HibernateController {

    private final HibernateService hibernateService;

    public HibernateController(HibernateService hibernateService) {
        this.hibernateService = hibernateService;
    }

    @GetMapping("durationMax")
    public String durationMax(long minutes) {
        Duration duration = Duration.ofMinutes(minutes);
        return "pass: " + hibernateService.durationMax(duration);
    }
}

@Validated
@Service
public class HibernateService {

    public long durationMax(@DurationMax(minutes = 2) Duration d) {
        return d.toMinutes();
    }
}

durationMax

Length

字符长度必须在 min 和 max之间,包含边界。支持的类型:CharSequence

Length

    @GetMapping("length")
    public String length(@Length(min = 2, max = 3) StringBuilder s) {
        return "pass: " + s.toString();
    }

length

Range

数字大小必须在 min 和 max 之间,包含边界。支持的类型:

  • BigDecimal
  • BigInteger
  • CharSequence
  • byte、 short、int、long 及其包装类型

Range

    @GetMapping("range")
    public String range(@Range(min = 3, max = 10) Integer s) {
        return "pass: " + s.toString();
    }

range

UniqueElements

检测集合中的值都是唯一的(集合不能包含相同的元素),null 是有效的。支持的类型:Collection

    @GetMapping("uniqueElements")
    public String uniqueElements(@UniqueElements @RequestParam("list") List<String> list) {
        return "pass: " + list;
    }

uniqueElements

使用技巧

自定义 message、读取配置文件

问题

为什么同是基本类型,boolean、int 对 null 的处理不同?

如下代码可以看出,在值为 null 时,spring 对 Boolean 进行的特殊处理,直接返回了 false,而对其他基本类型抛出了异常。

	// org.springframework.web.method.annotation.AbstractNamedValueMethodArgumentResolver
	
	@Nullable
	private Object handleNullValue(String name, @Nullable Object value, Class<?> paramType) {
		if (value == null) {
			if (Boolean.TYPE.equals(paramType)) {
				return Boolean.FALSE;
			}
			else if (paramType.isPrimitive()) {
				throw new IllegalStateException("Optional " + paramType.getSimpleName() + " parameter '" + name +
						"' is present but cannot be translated into a null value due to being declared as a " +
						"primitive type. Consider declaring it as object wrapper for the corresponding primitive type.");
			}
		}
		return value;
	}
展开阅读全文
©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客
应支付0元
点击重新获取
扫码支付

支付成功即可阅读