validation参数检验 - 注解介绍

本文深入解析Java中常用的22个javax.validation验证注解及hibernate.validator扩展注解,覆盖从基本类型到复杂对象的全面验证策略,适用于Spring Boot项目。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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
NotBlankCharSequence验证元素值不能为 null,并且至少包含一个非空白字符。
NotEmptyCharSequence、Collection、Map、Array验证元素值不能为 null,且不能为空
Size(min = min, max = max)同 NotEmpty验证元素的 size 必须在 min 和 max 之间(包含边界),认为 null 是有效的
AssertFalseboolean、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 是有效的
PositiveBigDecimal、BigInteger,byte、short、int、long、float、double 及其包装类型验证元素必须为正数,认为 null 是有效的
PositiveOrZero同Positive验证元素必须为正数或 0,认为 null 是有效的
Negative同Positive验证元素必须为负数,认为 null 是有效的
NegativeOrZero同Positive验证元素必须为负数或 0,认为 null 是有效的
FutureDate、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

注解数据类型truefalsenull
@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。
Currencyjavax.money.MonetaryAmount 子类型检查注解的货币单位 javax.money.MonetaryAmount 是否为指定货币单位的一部分
DurationMaxDuration注解的 Duration 必须小于等于 DurationMax 指定的值,默认包含边界
DurationMinDuration注解的 Duration 必须大于等于 DurationMax 指定的值,默认包含边界
EANCharSequence是否是有效的国际商品编号,null 是有效的
ISBNCharSequence是否是有效的国际标准书号,null 是有效的
LengthCharSequence长度必须在 min 和 max之间,包含边界
RangeBigDecimal、BigInteger、CharSequence,byte、 short、int、long 及其包装类型数字大小必须在 min 和 max 之间,包含边界
UniqueElementsCollection检测集合中的值都是唯一的(集合不能包含相同的元素,null 是有效的)
URLCharSequence根据RFC2396检查字符序列是否为有效URL
LuhnCheckCharSequence检查字符序列中的数字是否通过Luhn校验和算法
Mod10CheckCharSequence检查字符序列中的数字是否通过通用mod 10校验和算法。
Mod11CheckCharSequence检查字符序列中的数字是否通过通用mod 11校验和算法。
CodePointLengthCharSequence验证字符序列的 code point 长度是否介于 min 和 max 之间。code point 是字符的编码,比如 😂 code point 为 \uD83D\uDE02,code point length 为 1,但 length 却为 2
CNPJCharSequence验证巴西公司纳税人注册编号
CPFCharSequence验证巴西个人纳税人注册号
TituloEleitoralCharSequence验证巴西选民身份证号
NIPCharSequence验证波兰增值税标识号
PESELCharSequence验证波兰的国家标识号
REGONCharSequence验证波兰纳税人识别码
ScriptAssert用于类级别类级约束,用于根据带注释的元素计算脚本表达式。此约束可用于实现验证例程,这些例程依赖于被注解元素的多个属性。 JSR 223
ParameterScriptAssert用于方法级别方法级约束,用于根据带注解的方法或构造函数计算脚本表达式。此约束可用于实现验证例程,这些例程依赖于被注解方法的多个参数。 JSR 223

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;
	}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值