Spring Boot 使用 spring-boot-starter-validation 实现优雅的参数校验,一文讲透!

💡 前言

在开发 RESTful 接口时,接口参数校验是保障系统健壮性和安全性的重要一环 。Spring Boot 提供了对 Bean Validation 的开箱即用支持 ------ 通过 spring-boot-starter-validation 模块,我们可以非常方便地使用 JSR-380 标准定义的注解(如 @NotNull@NotBlank@Email 等)进行参数校验。

本文将带你从零开始掌握如何在 Spring Boot 中使用 spring-boot-starter-validation,并通过多个实际案例演示其强大功能,包括:

  • 单个参数校验
  • 对象嵌套校验
  • 自定义校验规则
  • 全局异常统一处理
  • 多语言错误信息支持

无论你是初学者,还是有一定经验的开发者,这篇文章都能让你写出更规范、更健壮的接口!


📦 一、什么是 spring-boot-starter-validation

✅ 定义:

spring-boot-starter-validation 是 Spring Boot 提供的一个 starter 模块,它默认集成了 Hibernate Validator,实现了 Java 的 Bean Validation 规范(JSR-380),可以用于对 Java Bean 的字段进行自动校验。

✅ 特性:

特性 描述
零配置 默认集成 Hibernate Validator
注解驱动 支持 @NotNull, @Size, @Email 等丰富注解
分组校验 可以根据业务场景分组验证
异常统一处理 结合 @ControllerAdvice 统一处理校验失败
多语言支持 支持国际化错误提示

🔧 二、快速入门:引入与使用

Step 1:添加依赖

如果你创建的是一个标准的 Spring Boot Web 项目,spring-boot-starter-web 已经默认包含了 spring-boot-starter-validation,无需额外添加。

xml 复制代码
<!-- 如果你想显式添加 -->
<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

Step 2:定义请求对象并添加校验注解

java 复制代码
import javax.validation.constraints.*;

public class UserRequest {

    @NotBlank(message = "用户名不能为空")
    private String username;

    @Email(message = "邮箱格式不正确")
    private String email;

    @Min(value = 18, message = "年龄不能小于18岁")
    @Max(value = 120, message = "年龄不能大于120岁")
    private int age;

    // getters and setters...
}

Step 3:在 Controller 中启用校验

在 Controller 方法中,使用 @Valid 注解开启校验逻辑,并结合 @RequestBody 使用。

java 复制代码
@RestController
@RequestMapping("/users")
public class UserController {

    @PostMapping
    public String createUser(@Valid @RequestBody UserRequest request) {
        return "用户提交成功:" + request.toString();
    }
}

📌 注意:

  • @Valid 必须写在方法参数上;
  • 如果校验失败,会抛出 MethodArgumentNotValidException 异常;

🎯 三、实战:全局异常统一处理

为了统一返回错误信息,我们可以使用 @ControllerAdvice 来捕获所有校验异常。

示例代码:

java 复制代码
@ControllerAdvice
public class GlobalValidationHandler {

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, String> handleValidationExceptions(MethodArgumentNotValidException ex) {
        Map<String, String> errors = new HashMap<>();
        ex.getBindingResult().getAllErrors().forEach((error) -> {
            String fieldName = ((org.springframework.validation.FieldError) error).getField();
            String errorMessage = error.getDefaultMessage();
            errors.put(fieldName, errorMessage);
        });
        return errors;
    }
}

返回示例:

json 复制代码
{
  "username": "用户名不能为空",
  "email": "邮箱格式不正确"
}

🧪 四、高级用法详解

✅ 1. 嵌套对象校验

你可以对嵌套的对象也进行校验:

java 复制代码
public class AddressRequest {
    @NotBlank(message = "地址不能为空")
    private String detail;
    // getter/setter
}

public class UserRequest {
    @NotBlank(message = "用户名不能为空")
    private String username;

    @NotNull(message = "地址信息不能为空")
    private AddressRequest address;
    // getter/setter
}

只要加上 @Valid 注解,Spring 会自动递归校验嵌套对象。


✅ 2. 分组校验(Group Validation)

有时候你希望同一个对象在不同接口中使用不同的校验规则?这时就可以使用分组校验。

第一步:定义分组接口

java 复制代码
public interface OnCreate {}
public interface OnUpdate {}

第二步:在实体类中指定分组

java 复制代码
public class UserRequest {

    @NotBlank(groups = OnCreate.class, message = "创建时用户名不能为空")
    @NotBlank(groups = OnUpdate.class, message = "更新时用户名不能为空")
    private String username;

    @NotBlank(groups = OnCreate.class, message = "邮箱不能为空")
    private String email;
}

第三步:在 Controller 中指定分组

java 复制代码
@PostMapping("/create")
public String createUser(@Validated(OnCreate.class) @RequestBody UserRequest request) {
    return "创建用户";
}

@PostMapping("/update")
public String updateUser(@Validated(OnUpdate.class) @RequestBody UserRequest request) {
    return "更新用户";
}

📌 注意:此时必须使用 @Validated 注解(来自 org.springframework.validation.annotation.Validated),而非 @Valid


✅ 3. 自定义校验规则

当内置注解不能满足需求时,可以自定义校验器。

步骤如下:

Step 1:创建注解
java 复制代码
@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = MobileValidator.class)
public @interface Mobile {
    String message() default "手机号格式不正确";
    Class<?>[] groups() default {};
    Class<? extends Payload>[] payload() default {};
}
Step 2:实现校验器
java 复制代码
public class MobileValidator implements ConstraintValidator<Mobile, String> {

    private static final String MOBILE_REGEX = "^1[3-9]\\d{9}$";

    @Override
    public boolean isValid(String value, ConstraintValidatorContext context) {
        return value != null && value.matches(MOBILE_REGEX);
    }
}
Step 3:使用注解
java 复制代码
@Mobile(message = "手机号格式错误")
private String mobile;

📘 五、国际化支持(i18n)

你可以为不同语言提供不同的错误提示信息:

messages.properties 文件中定义:

properties 复制代码
NotBlank.userRequest.username=用户名不能为空
Mobile.userRequest.mobile=手机号格式错误

再配合 Spring 的 MessageSourceLocaleResolver,即可实现多语言错误提示。


🧩 六、常见问题与解决方案

问题 解决方案
校验不生效 确保使用 @Valid@Validated
嵌套对象未校验 确保子对象字段也加了注解
分组无效 确保使用 @Validated 并指定分组
错误信息乱码 设置响应编码或使用 JSON 序列化
无法获取字段名 使用 FieldError 获取具体字段

📊 七、总结对比表

功能 描述
校验方式 注解驱动,声明式校验
异常处理 @ControllerAdvice 统一处理
嵌套对象 支持递归校验
分组校验 支持按业务场景定制
自定义规则 支持自定义注解和校验器
国际化 支持多语言提示

🎁 八、结语

Spring Boot 提供的 spring-boot-starter-validation 模块极大简化了接口参数校验的开发流程,使得我们能够以最小的成本写出安全、规范、可维护性强的接口代码。

无论是构建企业级后台系统,还是搭建高并发 API 平台,都应该合理使用参数校验来提升系统的稳定性与用户体验。


🎯 点赞、收藏、转发本文,让更多开发者受益!

相关推荐
java干货15 分钟前
深度解析:Spring Boot 配置加载顺序、优先级与 bootstrap 上下文
前端·spring boot·bootstrap
程序员JerrySUN36 分钟前
[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制
java·linux·架构
2302_8097983239 分钟前
【JavaWeb】Docker项目部署
java·运维·后端·青少年编程·docker·容器
网安INF1 小时前
CVE-2020-17519源码分析与漏洞复现(Flink 任意文件读取)
java·web安全·网络安全·flink·漏洞
一叶知秋哈1 小时前
Java应用Flink CDC监听MySQL数据变动内容输出到控制台
java·mysql·flink
jackson凌1 小时前
【Java学习笔记】SringBuffer类(重点)
java·笔记·学习
sclibingqing1 小时前
SpringBoot项目接口集中测试方法及实现
java·spring boot·后端
程序员JerrySUN1 小时前
全面理解 Linux 内核性能问题:分类、实战与调优策略
java·linux·运维·服务器·单片机
糯米导航1 小时前
Java毕业设计:办公自动化系统的设计与实现
java·开发语言·课程设计
糯米导航1 小时前
Java毕业设计:WML信息查询与后端信息发布系统开发
java·开发语言·课程设计