导读:本期聚焦于小伙伴创作的《如何用Spring Validation优雅实现抽象请求参数类的校验?》,敬请观看详情,探索知识的价值。以下视频、文章将为您系统阐述其核心内容与价值。如果您觉得《如何用Spring Validation优雅实现抽象请求参数类的校验?》有用,将其分享出去将是对创作者最好的鼓励。

在Spring Boot项目开发中,我们经常会有多个接口使用相似请求参数的情况,比如用户注册和用户更新接口都需要校验用户名、手机号等基础信息,这时候抽象出公共的请求参数父类能有效减少重复代码。但很多开发者会发现,直接在抽象类上添加Spring Validation的校验注解,子类继承后校验往往不会生效,本文就来讲讲如何优雅解决这个问题。

如何用Spring Validation优雅实现抽象请求参数类的校验?

抽象请求参数类的校验痛点

首先我们看一个常见的错误实践,定义一个抽象的公共参数类,然后在子类继承后直接使用,这时候校验注解是不会生效的:

// 抽象公共参数类
public abstract class BaseRequest {
    @NotBlank(message = "用户名不能为空")
    private String username;

    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确")
    private String phone;

    // getter和setter省略
}

// 子类请求参数类
public class RegisterRequest extends BaseRequest {
    @NotBlank(message = "密码不能为空")
    private String password;

    // getter和setter省略
}

出现这个问题的核心原因是Spring Validation默认不会扫描父类上的校验注解,只会处理当前类直接声明的注解,所以抽象类上的校验规则会被忽略。

方案一:使用@Validated触发父类校验

第一种解决方式是结合@Validated注解,在控制器方法的参数上使用@Validated,同时保证参数类型声明为子类,Spring Validation会自动递归校验父类的属性:

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/register")
    public String register(@Validated @RequestBody RegisterRequest request) {
        // 业务逻辑处理
        return "注册成功";
    }
}

这种方式的前提是父类中的属性必须有正确的getter和setter方法,Spring Validation是通过反射获取属性值进行校验的,如果缺少getter方法,即使有注解也不会生效。同时要注意,如果抽象类中的校验注解需要区分场景,比如注册和更新的校验规则不同,这种简单方式就无法满足需求。

方案二:结合校验分组实现场景化校验

当不同接口对抽象参数类的校验规则有差异时,我们可以使用校验分组来区分。首先在抽象类中定义分组接口,然后给注解指定对应的分组:

public abstract class BaseRequest {
    // 定义分组接口
    public interface RegisterGroup {}
    public interface UpdateGroup {}

    @NotBlank(message = "用户名不能为空", groups = {RegisterGroup.class, UpdateGroup.class})
    private String username;

    // 注册时手机号必填,更新时可选
    @Pattern(regexp = "^1[3-9]\\d{9}$", message = "手机号格式不正确", groups = RegisterGroup.class)
    private String phone;

    // getter和setter省略
}

public class RegisterRequest extends BaseRequest {
    @NotBlank(message = "密码不能为空", groups = RegisterGroup.class)
    private String password;

    // getter和setter省略
}

public class UpdateRequest extends BaseRequest {
    @NotNull(message = "用户ID不能为空", groups = UpdateGroup.class)
    private Long userId;

    // getter和setter省略
}

然后在控制器方法中指定要生效的分组:

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/register")
    public String register(@Validated(BaseRequest.RegisterGroup.class) @RequestBody RegisterRequest request) {
        // 注册逻辑
        return "注册成功";
    }

    @PostMapping("/update")
    public String update(@Validated(BaseRequest.UpdateGroup.class) @RequestBody UpdateRequest request) {
        // 更新逻辑
        return "更新成功";
    }
}

这样不同场景下只会触发对应分组的校验规则,抽象类中的校验注解也能正确生效,完美适配不同接口的参数校验需求。

方案三:自定义校验器适配复杂抽象场景

如果遇到抽象类中包含自定义校验逻辑,或者需要校验抽象类的泛型参数等复杂场景,我们可以通过自定义校验器来实现。首先定义自定义校验注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = BaseRequestValidator.class)
public @interface ValidBaseRequest {
    String message() default "参数校验失败";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}

然后实现自定义校验器,在校验器中处理抽象类的校验逻辑:

public class BaseRequestValidator implements ConstraintValidator<ValidBaseRequest, BaseRequest> {
    @Override
    public boolean isValid(BaseRequest request, ConstraintValidatorContext context) {
        // 自定义校验逻辑,比如校验用户名和手机号的匹配关系
        if (request.getUsername() != null && request.getPhone() != null) {
            // 示例:假设用户名包含手机号后四位则校验通过
            String phoneSuffix = request.getPhone().substring(request.getPhone().length() - 4);
            return request.getUsername().contains(phoneSuffix);
        }
        return true;
    }
}

最后在抽象类上添加自定义注解即可:

@ValidBaseRequest
public abstract class BaseRequest {
    // 原有属性和注解省略
}

这种方式可以灵活处理各种复杂的抽象参数校验场景,扩展性更强。

实践注意事项

  • 抽象类的属性必须有公共的getter方法,否则Spring Validation无法获取属性值进行校验。
  • 如果使用了Lombok的@Data注解,要确保生成的getter方法符合预期,避免因为Lombok版本问题导致方法缺失。
  • 校验分组的接口不需要有任何方法,只是作为标识使用,建议定义在对应的抽象类内部,方便管理。
  • 自定义校验器实现时,要注意空值处理,避免空指针异常。

通过以上几种方式,我们可以让Spring Validation完美支持抽象请求参数类的校验,既保留了抽象类的代码复用优势,又能保证参数校验的完整性和灵活性,让项目的参数校验逻辑更清晰、更易维护。

Spring_Validation抽象请求参数类参数校验校验分组自定义校验器修改时间:2026-05-30 23:35:25

免责声明:​ 已尽一切努力确保本网站所含信息的准确性。网站内容多为原创整理与精心编撰,观点力求客观中立。本站旨在免费分享,内容仅供个人学习、研究或参考使用。若引用了第三方作品,版权归原作者所有。如内容涉及您的权益,请联系我们处理。
内容垂直聚焦
专注技术核心技术栏目,确保每篇文章深度聚焦于实用技能。从代码技巧到架构设计,为用户提供无干扰的纯技术知识沉淀,精准满足专业提升需求。
知识结构清晰
覆盖从开发到部署的全链路。AI、前端、编程、数据库、服务器、建站、系统层层递进,构建清晰学习路径,帮助用户系统化掌握开发与运维所需的核心技术。
深度技术解析
拒绝泛泛而谈,深入技术细节与实践难点。无论是数据库优化还是服务器配置,均结合真实场景与代码示例进行剖析,致力于提供可直接应用于工作的解决方案。
专业领域覆盖
精准对应开发生命周期。从前端界面到后端编程,从数据库操作到服务器运维,形成完整闭环,一站式满足全栈工程师和运维人员的技术需求。
即学即用高效
内容强调实操性,步骤清晰、代码完整。用户可根据教程直接复现和应用于自身项目,显著缩短从学习到实践的距离,快速解决开发中的具体问题。
持续更新保障
专注既定技术方向进行长期、稳定的内容输出。确保各栏目技术文章持续更新迭代,紧跟主流技术发展趋势,为用户提供经久不衰的学习价值。