Skip to content

验证模块

最后更新: 12 小时前
实践版本: v2.13.0

简介

continew-starter-validation 是 ContiNew Starter 提供的增强验证模块,在 jakarta.validation-api 标准规范基础上扩展了常用验证场景,简化复杂业务校验逻辑。通过引入自定义注解和 SpEL 表达式校验能力,显著提升开发效率。

xml
<dependency>
    <groupId>top.continew.starter</groupId>
    <artifactId>continew-starter-validation</artifactId>
</dependency>

主要特性

  • 开箱即用: 提供高频验证注解

    • @EnumValue:枚举值校验
    • @Mobile:校验中国大陆手机号码
    • @Phone:校验座机号码、手机号码(中国大陆)、手机号码(中国香港)、手机号码(中国台湾)、手机号码(中国澳门)
    • @JsonString:JSON字符串格式校验
  • 表达式校验: 基于 SpEL Validator 组件实现基于 SpEL 的 Java 参数校验器

  • 无缝集成: 与 Spring Validation 体系深度兼容,分组等场景均正常支持

@EnumValue 注解

介绍

枚举值有效性校验。

java
/**
 * 枚举校验注解
 *
 * <p>
 * {@code @EnumValue(value = XxxEnum.class, message = "参数值无效")} <br />
 * {@code @EnumValue(enumValues = {"F", "M"} ,message = "性别只允许为F或M")}
 * </p>
 *
 * @author Jasmine
 * @author Charles7c
 * @since 2.7.3
 */
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValueValidator.class)
public @interface EnumValue {

    /**
     * 枚举类
     *
     * @return 枚举类
     */
    Class<? extends Enum> value() default Enum.class;

    /**
     * 枚举值
     *
     * @return 枚举值
     */
    String[] enumValues() default {};

    /**
     * 获取枚举值的方法名
     *
     * @return 获取枚举值的方法名
     */
    String method() default "";

    /**
     * 提示消息
     *
     * @return 提示消息
     */
    String message() default "参数值无效";

    /**
     * 分组
     *
     * @return 分组
     */
    Class<?>[] groups() default {};

    /**
     * 负载
     *
     * @return 负载
     */
    Class<? extends Payload>[] payload() default {};
}

示例

java
/**
 * 参数类别枚举
 *
 * @author Charles7c
 * @since 2024/11/14 20:00
 */
public enum OptionCategoryEnum {

    /**
     * 系统配置
     */
    SITE,

    /**
     * 密码配置
     */
    PASSWORD,

    /**
     * 邮箱配置
     */
    MAIL,

    /**
     * 登录配置
     */
    LOGIN,
}
java
@EnumValue(value = OptionCategoryEnum.class, message = "类别无效")
private String category;

@Mobile 注解

介绍

仅支持校验中国大陆手机号码。

java
/**
 * 手机号校验注解
 *
 * <p>
 * 校验中国大陆手机号码
 * {@code @Mobile(message = "手机号格式不正确")} <br />
 * </p>
 *
 * @author Charles7c
 * @since 2.10.0
 */
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MobileValidator.class)
public @interface Mobile {

    /**
     * 提示消息
     *
     * @return 提示消息
     */
    String message() default "手机号格式不正确";

    /**
     * 分组
     *
     * @return 分组
     */
    Class<?>[] groups() default {};

    /**
     * 负载
     *
     * @return 负载
     */
    Class<? extends Payload>[] payload() default {};
}

示例

java
@Mobile(message = "手机号格式不正确")
private String phone;

@Phone 注解

介绍

校验座机号码、手机号码(中国大陆)、手机号码(中国香港)、手机号码(中国台湾)、手机号码(中国澳门)。

java
/**
 * 手机号校验注解
 *
 * <p>
 * 校验座机号码、手机号码(中国大陆)、手机号码(中国香港)、手机号码(中国台湾)、手机号码(中国澳门)
 * {@code @Phone(message = "手机号格式不正确")} <br />
 * </p>
 *
 * @author Charles7c
 * @since 2.13.0
 */
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = PhoneValidator.class)
public @interface Phone {

    /**
     * 提示消息
     *
     * @return 提示消息
     */
    String message() default "手机号格式不正确";

    /**
     * 分组
     *
     * @return 分组
     */
    Class<?>[] groups() default {};

    /**
     * 负载
     *
     * @return 负载
     */
    Class<? extends Payload>[] payload() default {};
}

示例

java
@Phone(message = "手机号格式不正确")
private String phone;

@JsonString 注解

介绍

校验字符串是否为 JSON 格式字符串。

java
/**
 * JSON 格式字符串校验注解
 *
 * <p>
 * 校验字符串是否为 JSON 格式字符串
 * {@code @JsonString(message = "必须为有效的 JSON 格式")} <br />
 * </p>
 *
 * @author Charles7c
 * @since 2.12.0
 */
@Documented
@Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = JsonStringValidator.class)
public @interface JsonString {

    /**
     * 提示消息
     *
     * @return 提示消息
     */
    String message() default "必须为有效的 JSON 格式";

    /**
     * 分组
     *
     * @return 分组
     */
    Class<?>[] groups() default {};

    /**
     * 负载
     *
     * @return 负载
     */
    Class<? extends Payload>[] payload() default {};
}

示例

java
@JsonString(message = "必须为有效的 JSON 格式")
private String metaInfo;

SpEL Validator

SpEL Validator 是基于 Spring Expression Language 的参数校验包,也是 jakarta.validation-api 的扩展增强包,用于简化参数校验,它几乎支持所有场景下的参数校验。

设计的初衷是为了解决一些需要判断另一个字段的值来决定当前字段是否校验的场景。

示例场景: 公告需要定时发送时,对应的发布时间参数不能为空。

没有 SpEL 表达式支持前:

java
// 校验定时发布
if (Boolean.TRUE.equals(req.getIsTiming())) {
    ValidationUtils.throwIf(req.getPublishTime() == null, "定时发布时间不能为空");
    ValidationUtils.throwIf(req.getPublishTime().isBefore(LocalDateTime.now()), "定时发布时间不能早于当前时间");
}

有了 SpEL 表达式的支持: 以往需要单独增加的校验逻辑得以简化,复用性和可读性极佳。

java
@Data
@SpelValid
@Schema(description = "公告创建或修改请求参数")
public class NoticeReq implements Serializable {
    
    // 其他略...
    
    /**
     * 是否定时
     */
    @Schema(description = "是否定时", example = "true")
    @NotNull(message = "是否定时不能为空")
    private Boolean isTiming;

    /**
     * 发布时间
     */
    @Schema(description = "发布时间", example = "2023-08-08 00:00:00", type = "string")
    @SpelNotNull(condition = "#this.isTiming == true", message = "定时发布时间不能为空")
    @Future(message = "定时发布时间不能早于当前时间")
    private LocalDateTime publishTime;
}

核心依赖

依赖描述
top.continew.starter:continew-starter-core核心模块
org.springframework.boot:spring-boot-starter-validationSpring Boot 校验模块(Hibernate Validator)
cn.sticki:spel-validator-jakartaSpEL Validator(基于 SpEL 的 jakarta.validation-api 扩展增强包)

参考资料

  1. SpEL Validator: https://spel-validator.sticki.cn/guide/introduction.html