跳到主要内容
极客日志极客日志面向AI+效率的开发者社区
首页博客GitHub 精选镜像AI 生图工具UI配色美学隐私政策关于联系
搜索内容 / 工具 / 仓库 / 镜像...⌘K搜索
注册
博客列表
Javajava

Spring Boot 数据校验 Validation 实战

Spring Boot 数据校验基于 JSR 303/380 规范,通过注解方式替代 Controller 中冗余的 if-else 手动校验。核心步骤包括引入 spring-boot-starter-validation 依赖、在 DTO 类添加 @NotNull/@NotBlank 等注解、在 Controller 方法参数前使用 @Valid 触发校验。配合全局异常处理器 @RestControllerAdvice 捕获 MethodArgumentNotValidException 实现统一友好的错误返回。支持分组校验处理不同场景规则差异,显著提升代码可维护性与开发效率。

黑客帝国发布于 2025/11/30更新于 2026/7/2737 浏览
Spring Boot 数据校验 Validation 实战

Spring Boot 数据校验 Validation 实战

1. 前言

在日常开发中,后端经常需要对请求参数进行校验。比如注册用户时,用户名不能为空、密码长度要在 6~16 之间、邮箱必须符合格式等。如果不做校验,脏数据可能进入数据库造成业务问题;如果校验方式不合理,代码又会变得臃肿。

相信很多小伙伴还在 Controller 代码中写大量重复的 if-else 判断,既冗余又难维护。下面介绍 Spring Boot 提供的 Validation(基于 JSR 303/380 规范),让我们能通过注解的方式优雅地完成参数校验,极大地提升了开发效率和代码可读性。

2. 没有使用 Validation 的传统写法

当不使用数据校验框架时,我们通常会在 Controller 中手动校验参数,代码会像这样:

场景:创建用户接口

定义接受参数对象 UserDto

// UserDTO 实体类
class UserDto {
    private String name;
    private Integer age;
    private String email;
    // getter 和 setter 省略
}

要求:用户名不能为空,长度 5-10;邮箱格式必须正确;年龄在 18-60 之间。

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/add")
    public String addUser(UserDto user) {
        // 手动校验参数
        if (user.getName() == null || user.getName().trim().isEmpty()) {
            return "用户名不能为空";
        }
        if (user.getName().length() < 5 || user.getName().length() > 10) {
            return "用户名长度必须在 5-10 之间";
        }
        if (user.getAge() == null) {
            return "年龄不能为空";
        }
        if (user.getAge() < 18 || user.getAge() > 60) {
            return "年龄必须在 18-60 之间";
        }
        if (user.getEmail() == null || user.getEmail().trim().isEmpty()) {
            return "邮箱不能为空";
        }
        if (!user.getEmail().matches("^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+$")) {
            return "邮箱格式不正确";
        }
        // 业务逻辑处理
        return "用户添加成功";
    }
}

可以看出上述写法的缺点:代码冗长,不利于维护;每个接口都要写重复的校验逻辑;校验逻辑和业务逻辑耦合,不够优雅。

3. 使用 Validation 的优雅写法

我们可以在实体类上加注解,把校验规则声明在模型上,让 Spring 自动完成校验。

Maven 依赖:

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

UserDto 对象加上注解

import javax.validation.constraints.*;

public class UserDto {
    @NotBlank(message = "用户名不能为空")
    @Size(min = 2, max = 10, message = "用户名长度必须在{min}-{max}之间")
    private String username;

    @NotBlank(message = "邮箱不能为空")
    @Email(message = "邮箱格式不正确")
    // 自带邮箱格式校验,无需自己写正则!
    private String email;

    @NotNull(message = "年龄不能为空")
    @Min(value = 0, message = "年龄最小为{value}")
    @Max(value = 150, message = "年龄最大为{value}")
    private Integer age;

    // 省略 Getter 和 Setter...
}

在 Controller 参数前加@Valid 或@Validated 注解

import javax.validation.Valid;

@RestController
@RequestMapping("/user")
public class UserController {
    @PostMapping("/add")
    // 关键一步:在 @RequestBody 前加上 @Valid 注解
    public String addUser(@Valid @RequestBody UserDto user) {
        // 只需关注核心业务
        System.out.println("用户创建成功:" + user);
        return "success";
    }
}

通过上述使用 validation 改造,Spring 会自动对 UserDto 的字段进行校验,当请求参数不满足规则时,Spring Boot 会自动抛出 MethodArgumentNotValidException 异常,不会进入这个方法体。但我们不能直接给用户返回异常栈,需要统一处理。

4. 全局异常处理(友好返回错误信息)

刚才我们已经说过了参数校验不满足规则,系统会抛出 MethodArgumentNotValidException,那么我们就可以通过 @RestControllerAdvice 捕获 MethodArgumentNotValidException,来实现统一返回错误信息。

import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

@RestControllerAdvice
public class GlobalExceptionHandler {
    /**
     * 处理实体校验异常
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Map<String, Object> handleValidException(MethodArgumentNotValidException e) {
        Map<String, Object> errorResult = new HashMap<>();
        errorResult.put("code", 400);
        errorResult.put("message", "参数校验失败");
        // 从异常对象中拿到具体的错误信息
        // 这里只取第一个错误信息,也可以全部返回
        String defaultMessage = Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage();
        errorResult.put("data", defaultMessage);
        return errorResult;
    }
}

最后我们可以使用 Postman 或 curl 测试,观察接口返回的 JSON 异常数据。

5. 常用校验注解

注解功能说明
@NotNull值不能为 null
@NotBlank字符串不能为空(trim 后长度>0)
@NotEmpty集合、数组、Map、String 不能为空
@Size(min=, max=)检查字符串、集合、数组大小
@Min(value)数字最小值
@Max(value)数字最大值
@Email校验邮箱格式
@Pattern(regexp=)正则表达式匹配
@Positive正数
@Future日期必须在未来
@Past日期必须在过去

6. 分组校验

当同一个实体类在不同场景下有不同的校验规则时,比如新增时 ID 应为空,而更新时 ID 不能为空,这时就需要分组校验。

定义分组接口(标记接口)

public interface CreateGroup {}
// 创建分组
public interface UpdateGroup {}
// 更新分组

在实体上指定分组

继续改造一下我们的 UserDto,这时候需要增加 id 字段。

public class UserDto {
    @Null(groups = CreateGroup.class, message = "创建时 ID 必须为空")
    @NotNull(groups = UpdateGroup.class, message = "更新时 ID 不能为空")
    private Long id;

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

    // ... 其他字段
}

在 Controller 中使用@Validated 指定分组

@PostMapping("/create")
public String create(@Validated(CreateGroup.class) @RequestBody UserDto user) {
    // ... 创建逻辑
}

@PostMapping("/update")
public String update(@Validated(UpdateGroup.class) @RequestBody UserDto user) {
    // ... 更新逻辑
}

7. 结语

通过使用 Spring Boot Validation,我们可以告别繁琐的手动参数校验,让代码更加简洁、优雅、易维护。希望本文能帮助你在项目中更好地应用数据校验机制,提升开发效率和代码质量,是开发中必不可少的利器!

目录

  1. Spring Boot 数据校验 Validation 实战
  2. 1. 前言
  3. 2. 没有使用 Validation 的传统写法
  4. 3. 使用 Validation 的优雅写法
  5. 4. 全局异常处理(友好返回错误信息)
  6. 5. 常用校验注解
  7. 6. 分组校验
  8. 7. 结语
  • 免费图片AI生成工具免费生成了解详情
  • Magick API 一键接入全球大模型注册送1000万token查看
  • 免费图片视频在线生成30秒,将你的创意变成现实开始设计
  • X/Twitter免费视频下载器免登陆无限额度免费视频解析下载了解详情
  • 100+免费在线小游戏爽一把
极客日志微信公众号二维码

微信扫一扫,关注极客日志

微信公众号「极客日志V2」,在微信中扫描左侧二维码关注。展示文案:极客日志V2 zeeklog

更多推荐文章

查看全部
  • OpenClaw 开源个人 AI 智能助理完整部署教程
  • FPGA 实现任意角度图像旋转原理与代码设计
  • 开源大模型 Image-to-Video 本地化部署教程
  • C++ 核心过渡:从 C 到 C++ 的入门指南(上)
  • Redis Hash 详解:C++ 实战与高性能对象存储策略
  • AR 演讲提词器开发实战:基于 Rokid CXR-M SDK
  • 从后端到前端:AI Agent 跨语言全栈项目实战记录(Java + Python + Vue3)
  • Zotero 8.0.1 英文文献批量下载与自动化脚本实战
  • 基于 Rokid 眼镜的 AI 天气应用、GPS 定位与旅游规划实现
  • LLaMA 衍生模型详解:官方演进与社区微调
  • Dify 基于知识库搭建智能客服问答应用详解
  • 大模型突破对话边界:天工 3.0 与 SkyMusic 评测
  • VSCode AI Copilot 自定义指令配置实战指南
  • 基于 Java SSM 的网上挂号系统设计与实现
  • C++ 继承入门 (下):友元、静态成员与菱形继承的底层逻辑
  • 华为光猫 HN8145X6N R023 版本 Shell 补全及公版切换方法
  • 安卓手机本地部署 OpenClaw 与 Llama 大模型教程 (Termux+Ubuntu)
  • OpenClaw 30+ 真实使用案例开源,参考 AI 助理落地方案
  • AI 问答知识库本地化部署指南:基于 FastGPT
  • 基于 LangChain 从零搭建 AI Agent 实战指南

相关免费在线工具

  • Keycode 信息

    查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online

  • Escape 与 Native 编解码

    JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online

  • JavaScript / HTML 格式化

    使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online

  • JavaScript 压缩与混淆

    Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online

  • Base64 字符串编码/解码

    将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online

  • Base64 文件转换器

    将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online