SpringBoot利用validation实现数据校验完整指南

 更新时间:2025年09月03日 08:48:20   作者:Micro麦可乐  
Spring Boot 提供的 Validation(基于 JSR 303/380 规范)让我们能通过注解的方式优雅地完成参数校验,极大地提升了开发效率和代码可读性,下面我们就来看看具体实现吧

1. 前言

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

相信很多小伙伴还在 Controller 代码中写大量重复的 if-else 判断,既冗余又难维护!(如果你也是这样操作,那一定要看完本篇文章)

下面博主介绍一下Spring Boot 提供的 Validation(基于 JSR 303/380 规范)让我们能通过注解的方式优雅地完成参数校验,极大地提升了开发效率和代码可读性

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

下面我们先看看没用 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,我们可以告别繁琐的手动参数校验,让代码更加简洁、优雅、易维护。希望本文能帮助你在项目中更好地应用数据校验机制,提升开发效率和代码质量,是开发中必不可少的利器!

到此这篇关于SpringBoot利用validation实现数据校验完整指南的文章就介绍到这了,更多相关SpringBoot validation校验内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • java手动实现常见数据结构的示例代码

    java手动实现常见数据结构的示例代码

    本文介绍了Java中常用数据结构的特点和Java实现,包括数组、动态数组、链表、栈、队列、哈希表、树、堆、图、集合、双向队列以及自定义链表,帮助开发者选择合适的数据结构以提升代码效率,感兴趣的朋友一起看看吧
    2025-02-02
  • java -jar启动服务并输出日志常用命令小结

    java -jar启动服务并输出日志常用命令小结

    这篇文章主要介绍了在Linux环境下运行JAR包的几种方法,包括在命令结尾添加&使其在后台运行,使用nohup使程序不挂断运行,以及将日志输出到指定文件或丢弃,文中通过代码介绍的非常详细,需要的朋友可以参考下
    2025-03-03
  • SpringBoot URL带有特殊字符([]/{}等),报400错误的解决

    SpringBoot URL带有特殊字符([]/{}等),报400错误的解决

    这篇文章主要介绍了SpringBoot URL带有特殊字符([]/{}等),报400错误的解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-02-02
  • java中应用Stack进行算术运算的操作

    java中应用Stack进行算术运算的操作

    这篇文章主要介绍了java中应用Stack进行算术运算的操作,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
    2021-03-03
  • Mybatis中Collection集合标签的使用详解

    Mybatis中Collection集合标签的使用详解

    这篇文章主要介绍了Mybatis中Collection集合标签的使用详解,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-06-06
  • SpringBoot3整合WebSocket详细指南

    SpringBoot3整合WebSocket详细指南

    SpringBoot 3 整合 WebSocket 提供了一种高效的实时通信解决方案,通过本文的配置和示例,可以快速实现,感兴趣的哦朋友跟随小编一起看看吧
    2024-12-12
  • MyBatis-Plus ORM数据库和实体类映射方式

    MyBatis-Plus ORM数据库和实体类映射方式

    本文详细介绍了MyBatis-Plus(MP)在数据库和Java对象映射方面的功能,包括基本映射、主键生成策略、复杂映射(如嵌套对象和集合类型)以及自定义SQL的使用,MP通过丰富的注解和XML配置,简化了数据库操作,提高了开发效率
    2025-01-01
  • Java中的接口以及常见的Cloneable接口用法

    Java中的接口以及常见的Cloneable接口用法

    这篇文章主要介绍了Java中的接口以及常见的Cloneable接口用法,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教
    2024-02-02
  • springboot整合Nginx实现负载均衡反向代理的方法详解

    springboot整合Nginx实现负载均衡反向代理的方法详解

    这篇文章主要给大家介绍了关于springboot整合Nginx实现负载均衡反向代理的相关资料,文中通过图文以及实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2022-01-01
  • Java中基于推、拉模式的sentinel规则持久化详解

    Java中基于推、拉模式的sentinel规则持久化详解

    这篇文章主要介绍了Java中基于推、拉模式的sentinel规则持久化详解,推模式是sentinelDashboard 把规则推给Nacos,Nacos监听规则的变化推给微服务,拉模式是sentinelDashboard 把规则直接给微服务, Nacos定时的同步微服务端的规则,需要的朋友可以参考下
    2023-09-09

最新评论