Skip to content

SpringMVC教程 - 17 数据校验

在Web应用中,数据校验是非常重要的一环。在用户提交表单或发送请求时,我们需要确保输入的数据符合我们的要求,比如不能为空、长度不能超过限制、格式必须正确等。

在Web应用中,数据校验通常分为两种:

  1. 客户端校验:在浏览器端使用JavaScript进行校验,主要目的是提高用户体验,减少不必要的服务器请求
  2. 服务器端校验:在服务器端对数据进行校验,这是必不可少的,因为客户端校验可以被绕过,例如直接请求服务器接口。

SpringMVC主要关注的是服务器端校验。


在 Java EE 规范中,JSR-303(Bean Validation 1.0)和 JSR-349(Bean Validation 1.1)定义了一套用于 Java Bean 验证的标准 API。Hibernate Validator 是该 Bean Validation 规范的一个实现,可以方便地集成到 SpringMVC 框架中,用于对 Java Bean 进行验证。其主要使用方式是在 Java Bean 的属性或方法上添加校验注解,通过注解来声明属性的校验规则。

首先来看一下常用的校验注解,我们会将这些注解添加到 Java Bean 的属性上,并设置校验规则。

Bean Validation规范提供了一系列常用的校验注解,下面是一些最常用的:

注解作用示例
@NotNull不能为 null@NotNull(message = "年龄不能为空")
@NotEmpty不能为 null,且长度 > 0(字符串、集合、数组)@NotEmpty(message = "标签列表不能为空")
@NotBlank不能为 null,且去空格后长度 > 0(字符串)@NotBlank(message = "用户名不能为空")
@Null必须为 null@Null(message = "此字段必须为空")
@Size(min, max)字符串、集合、数组的长度必须在指定范围@Size(min=6, max=20, message="密码长度必须6-20位")
@Min(value)数值必须 ≥ 最小值@Min(18, message="年龄不能小于18岁")
@Max(value)数值必须 ≤ 最大值@Max(120, message="年龄不能大于120岁")
@DecimalMin(value)小数值必须 ≥ 最小值@DecimalMin("0.01", message="金额不能为0")
@DecimalMax(value)小数值必须 ≤ 最大值@DecimalMax("999.99", message="金额太大")
@Digits(integer, fraction)限制小数的整数位与小数位数@Digits(integer=3, fraction=2, message="格式不正确,如123.45")
@Pattern(regexp)必须匹配正则表达式@Pattern(regexp="^[a-zA-Z0-9_]{3,20}$", message="用户名格式非法")
@Email必须是合法邮箱格式@Email(message="邮箱格式不正确")
@Past必须是过去的日期@Past(message="生日必须是过去的日期")
@PastOrPresent必须是过去或现在的日期@PastOrPresent(message="创建日期不能是未来")
@Future必须是将来的日期@Future(message="预约时间必须是未来日期")
@FutureOrPresent必须是未来或现在@FutureOrPresent(message="开始时间不能是过去")
@Positive必须为正数@Positive(message="数量必须大于0")
@PositiveOrZero必须为正数或 0@PositiveOrZero(message="库存不能是负数")
@Negative必须为负数@Negative(message="值必须为负数")
@NegativeOrZero必须为负数或 0@NegativeOrZero(message="温度不能高于0")
@AssertTrue必须为 true@AssertTrue(message="必须同意协议")
@AssertFalse必须为 false@AssertFalse(message="标志位必须为false")
@Valid对嵌套对象执行级联校验@Valid private Address address;

下面就来演示一下。

17.1 数据校验的使用

1 引入依赖

SpringMVC的数据校验需要引入以下依赖:

xml
<!-- 让 Jackson 支持 Java 8 日期时间类型(LocalDate、LocalDateTime 等) -->
<dependency>
    <groupId>com.fasterxml.jackson.datatype</groupId>
    <artifactId>jackson-datatype-jsr310</artifactId>
    <version>2.20.1</version>
</dependency>

<!-- JSR-380 核心依赖,提供 Bean Validation 的标准接口和注解 -->
<dependency>
    <groupId>jakarta.validation</groupId>
    <artifactId>jakarta.validation-api</artifactId>
    <version>4.0.0-M1</version>
</dependency>

<!-- Hibernate Validator 实现(推荐) -->
<dependency>
    <groupId>org.hibernate.validator</groupId>
    <artifactId>hibernate-validator</artifactId>
    <version>9.1.0.Final</version>
</dependency>

<!-- 提供表达式语言支持,用于错误消息插值 -->
<dependency>
    <groupId>org.glassfish</groupId>
    <artifactId>jakarta.el</artifactId>
    <version>5.0.0-M1</version>
</dependency>
  • Hibernate Validator是Bean Validation规范的一个优秀实现,提供了丰富的校验注解和扩展功能。
  • 添加完依赖,pom.xml 右键 —> Maven Reload —> Project

2 配置校验器

在SpringMVC的配置文件中,我们需要配置校验器:

xml
<!-- 配置校验器 -->
<bean id="validator" class="org.springframework.validation.beanvalidation.LocalValidatorFactoryBean">
    <!-- 指定验证器,使用Hibernate Validator -->
    <property name="providerClass" value="org.hibernate.validator.HibernateValidator"/>
</bean>

<!-- 在处理器适配器中添加校验器 -->
<mvc:annotation-driven validator="validator"/>
  • 如果配置文件中已经有<mvc:annotation-driven> 标签了,在现有的标签上添加 validator="validator" 属性。

3 在实体类中使用校验注解

下面我们创建一个用户注册的实体类,并使用校验注解,后面会根据注解指定的内容进行校验:

java
package com.foooor.hellospringmvc.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import jakarta.validation.constraints.*;
import lombok.Data;
import java.time.LocalDate;

@Data
public class UserDto {

    private Long id;

    @NotBlank(message = "用户名不能为空")
    @Size(min = 6, max = 20, message = "用户名长度必须在6-20位之间")
    private String username;

    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[0-9]{11}$", message = "手机号必须是11位数字")
    private String phoneNumber;

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

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
    private String password;

    @NotNull(message = "生日不能为空")
    @Past(message = "生日必须是过去的日期")
    @JsonFormat(pattern = "yyyy-MM-dd")  // 告诉Jackson序列化时使用的日期格式
    private LocalDate birthday;
}
  • @Data 是Lombok提供的注解,自动生成getter、setter等方法;
  • 每个属性都添加了校验的注解,并设置了自定义的错误提示信息;

4 RESTful API校验

对于RESTful API,我们可以使用@Validated注解配合@RequestBody来触发数据校验:

java
package com.foooor.hellospringmvc.controller;

import com.foooor.hellospringmvc.common.ErrorCode;
import com.foooor.hellospringmvc.common.Result;
import com.foooor.hellospringmvc.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@Slf4j
@RestController
@RequestMapping("/user")
public class UserController {

    @PostMapping("/register")
    public Result register(@Validated @RequestBody UserDto user, BindingResult bindingResult) {
        // 检查是否有校验错误
        if (bindingResult.hasErrors()) {
            // 获取第一个错误信息
            String errorMsg = bindingResult.getFieldError().getDefaultMessage();
            return Result.error(ErrorCode.PARAM_ERROR.code, errorMsg);
        }

        // 打印注册信息
        log.info("注册 user: {}", user);

        // 校验通过,进行注册逻辑
        return Result.success();
    }
}
  • @Validated 注解用于触发数据校验,@RequestBody 将请求体转换为Java对象,BindingResult 参数用于接收校验结果,必须紧跟在被校验的参数后面。
  • bindingResult.hasErrors() 检查是否有校验错误;bindingResult.getFieldError().getDefaultMessage() 获取第一个错误信息。

5 测试

此时请求接口,例如通过 Apifox 请求,如果少传递了参数,就会返回错误信息:

17.2 传统项目校验

上面是 Restful API 项目,在传统项目中,需要在 Controller 中校验,在页面上显示错误信息。

1 Controller中校验

在 Controller 也是使用 @Validated 注解和 BindingResult

java
package com.foooor.hellospringmvc.controller;

import com.foooor.hellospringmvc.dto.UserDto;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ModelAttribute;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;

@Slf4j
@Controller
@RequestMapping("/user-form")
public class UserFormController {

    /**
     * 进入注册页面
     */
    @GetMapping("/to-register")
    public String toRegister(Model model) {
        // 提供一个空的User对象给表单
        model.addAttribute("user", new UserDto());
        return "user/register";
    }

    /**
     * 处理注册提交
     */
    @PostMapping("/register")
    public String register(@Validated @ModelAttribute("user") UserDto user, BindingResult bindingResult, Model model) {
        // 检查是否有校验错误
        if (bindingResult.hasErrors()) {
            // 如果有错误,返回注册表单页面,并显示错误信息
            return "user/register";
        }

        // TODO 校验通过,进行注册逻辑

        // 注册成功,重定向到首页
        model.addAttribute("message", "注册成功");

        return "user/registerSuccess";  // 注册成功页面
    }

}
  • 在校验失败时,SpringMVC 会往 Model 中放两个重要对象:表单绑定后的 user 对象和 user 的所有校验错误,在页面上就可以获取到校验错误信息。
  • @ModelAttribute("user") 用来声明这个参数是一个“表单模型对象”,Spring 需要把它放进 Model,并为它配套创建 BindingResult.user

2 在页面显示错误信息

首先创建一个注册模板页面 user/register.html,然后在Thymeleaf模板中,使用 th:errors 标签来显示错误信息。

html
<!DOCTYPE html>
<html xmlns:th="http://www.thymeleaf.org" xmlns:form="http://www.w3.org/1999/xhtml">
<head>
    <meta charset="UTF-8">
    <title>用户注册</title>
    <style>
        .error {
            color: red;
            font-size: 0.8em;
        }
    </style>
</head>
<body>
<div style="width: 400px; margin: 100px auto;">
    <h1>用户注册</h1>

    <!-- Spring表单 -->
    <form th:object="${user}" action="/user-form/register" method="post">
        <!-- 用户名 -->
        <div style="margin-bottom: 10px;">
            <label for="username">用户名:</label>
            <input type="text" id="username" th:field="*{username}" style="width: 200px;">
            <span class="error" th:errors="*{username}"></span>
        </div>

        <!-- 手机号 -->
        <div style="margin-bottom: 10px;">
            <label for="phoneNumber">手机号:</label>
            <input type="text" id="phoneNumber" th:field="*{phoneNumber}" style="width: 200px;">
            <span class="error" th:errors="*{phoneNumber}"></span>
        </div>

        <!-- 邮箱 -->
        <div style="margin-bottom: 10px;">
            <label for="email">邮箱:</label>
            <input type="email" id="email" th:field="*{email}" style="width: 200px;">
            <span class="error" th:errors="*{email}"></span>
        </div>

        <!-- 密码 -->
        <div style="margin-bottom: 10px;">
            <label for="password">密码:</label>
            <input type="password" id="password" th:field="*{password}" style="width: 200px;">
            <span class="error" th:errors="*{password}"></span>
        </div>

        <!-- 生日 -->
        <div style="margin-bottom: 20px;">
            <label for="birthday">生日:</label>
            <input type="date" id="birthday" th:field="*{birthday}" style="width: 200px;">
            <span class="error" th:errors="*{birthday}"></span>
        </div>

        <button type="submit">注册</button>
    </form>
</div>
</body>
</html>
  • 当使用 th:errors="*{username}" 时,会查找 Model 中找到 BindingResult.user,然后取出 username 字段的错误信息。

3 测试

使用 http://localhost:8080/user-form/register 访问页面,直接点击保存,会显示出校验的错误信息。

但是在页面显示校验错误信息的时候,会将一个字段所有的错误信息都显示出来:

可以使用下面的写法,只显示一条:

java
<span class="error"
              th:if="${#fields.hasErrors('name')}"
              th:text="${#fields.errors('name')[0]}"></span>

17.3 单个参数校验

数据校验不仅可以用于复杂对象,还可以直接用于单个参数。

举个栗子:

java
package com.foooor.hellospringmvc.controller;

import com.foooor.hellospringmvc.common.ErrorCode;
import com.foooor.hellospringmvc.common.Result;
import com.foooor.hellospringmvc.dto.UserDto;
import jakarta.validation.constraints.Min;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.extern.slf4j.Slf4j;
import org.springframework.validation.BindingResult;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

@Slf4j
@RestController
// @Validated  // spring6以下需要在类上添加@Validated注解
@RequestMapping("/user")
public class UserController {

    // @RequestParam参数校验
    @GetMapping
    public String getUsers(@RequestParam("page") @NotNull @Min(1) Integer page,
                              @RequestParam("size") @NotNull @Min(1) Integer size) {
        return "分页查询用户,第" + page + "页,每页" + size + "条";
    }

    // @PathVariable参数校验
    @GetMapping("/{id}")
    public String getUserById(@PathVariable("id") @NotNull @Min(1) Long id) {
        return "查询用户ID:" + id;
    }

    // 字符串长度校验
    @GetMapping("/search")
    public String search(@RequestParam("keyword") @Size(min = 2, max = 10) String keyword) {
        return "搜索关键词:" + keyword;
    }

    // 其他代码...
}
  • 在方法的参数上添加相关的注解即可。

17.4 校验结果的详细处理

在上面 Restful API 的 例子中,通过 getDefaultMessage() 获取的是第一个错误信息:

java
// 获取第一个错误信息
String errorMsg = bindingResult.getFieldError().getDefaultMessage();

如果要获取所有的错误信息,可以通过如下方式。

1 返回所有错误信息

java
@PostMapping("/register")
public Result register(@Validated @RequestBody UserDto user, BindingResult bindingResult) {
    // 检查是否有校验错误
    if (bindingResult.hasErrors()) {
        // 获取所有错误信息
        List<String> errorMessages = bindingResult.getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.toList());
        return Result.error(ErrorCode.PARAM_ERROR, String.join(",", errorMessages));
    }

    // 校验通过,进行注册逻辑
    return Result.success();
}
  • 使用 Java 8 的Stream API将所有错误信息收集到一个列表中,当然你也可以使用普通的 for 循环遍历。
  • 使用String.join将所有错误信息用分号连接起来,返回结果如下:

返回的 JSON 格式如下:

json
{
    "code": 1001,
    "message": "生日不能为空,密码不能为空,手机号不能为空,用户名不能为空,邮箱不能为空",
    "data": null
}

2 按字段返回错误信息

有时候,我们需要按字段返回错误信息,以便前端能够更精确地在对应的输入框旁显示错误提示:

java
@PostMapping("/register")
public Result register(@Validated @RequestBody UserDto user, BindingResult bindingResult) {
    // 检查是否有校验错误
    if (bindingResult.hasErrors()) {
        // 按字段收集错误信息
        Map<String, String> errorMap = bindingResult.getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,  // 字段名
                        FieldError::getDefaultMessage  // 错误信息
                ));
        return Result.error(ErrorCode.PARAM_ERROR, errorMap);
    }

    // 校验通过,进行注册逻辑
    return Result.success();
}

这样返回的 JSON 格式如下:

json
{
    "code": 1001,
    "message": "参数错误",
    "data": {
        "birthday": "生日不能为空",
        "password": "密码不能为空",
        "phoneNumber": "手机号不能为空",
        "email": "邮箱不能为空",
        "username": "用户名不能为空"
    }
}

17.5 分组校验

在实际开发中,我们可能会遇到这样的情况:同一个实体类在不同的场景下需要不同的校验规则。比如,创建用户的时候不需要ID(自动生成),但更新用户信息时需要ID。

这时候,我们可以使用分组校验来解决这个问题。

1 定义分组接口

首先,我们需要定义一些分组接口:

java
package com.foooor.hellospringmvc.validation;

public class UserGroup {

    // 创建分组
    public interface CreateGroup {}

    // 更新分组
    public interface UpdateGroup {}
}
  • 为了简单,我将多个分组放在一个类中,也可以单独定义类文件;
  • 分组接口只是一个标记接口,不需要定义任何方法。
  • 另外分组是可以继承的,父类相当于囊括了所有子分组。

2 在实体类中指定分组

然后,我们在实体类的校验注解中指定分组:

java
package com.foooor.hellospringmvc.dto;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.foooor.hellospringmvc.validation.UserGroup;
import jakarta.validation.constraints.*;
import lombok.Data;

import java.time.LocalDate;

@Data
public class UserDto {

    @NotNull(message = "学生ID不能为空", groups = UserGroup.UpdateGroup.class)  // 使用更新分组
    private Long id;

    @NotBlank(message = "用户名不能为空", groups = UserGroup.CreateGroup.class)  // 使用创建分组
    @Size(min = 6, max = 20, message = "用户名长度必须在6-20位之间")
    private String username;

    @NotBlank(message = "手机号不能为空")
    @Pattern(regexp = "^[0-9]{11}$", message = "手机号必须是11位数字")
    private String phoneNumber;

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

    @NotBlank(message = "密码不能为空")
    @Size(min = 6, max = 20, message = "密码长度必须在6-20位之间")
    private String password;

    @NotNull(message = "生日不能为空")
    @Past(message = "生日必须是过去的日期")
    @JsonFormat(pattern = "yyyy-MM-dd")  // 告诉Jackson序列化时使用的日期格式
    private LocalDate birthday;
}
  • id 字段只在 UpdateGroup 分组中需要校验;username 字段只在 CreateGroup 分组中需要校验;
  • 其他字段没有设置分组,Spring/Bean Validation 默认会使用 jakarta.validation.groups.Default 分组

3 在Controller中指定使用的分组

最后,在Controller中使用 @Validated 注解时指定要使用的分组:

java
import jakarta.validation.groups.Default;
import com.foooor.hellospringmvc.validation.UserGroup;


@PostMapping("/register")
public Result register(@Validated({Default.class, UserGroup.CreateGroup.class}) @RequestBody UserDto user, BindingResult bindingResult) {
    // 检查是否有校验错误
    if (bindingResult.hasErrors()) {
        // 获取所有错误信息
        List<String> errorMessages = bindingResult.getFieldErrors().stream()
                .map(FieldError::getDefaultMessage)
                .collect(Collectors.toList());
        return Result.error(ErrorCode.PARAM_ERROR, String.join(",", errorMessages));
    }

    // 校验通过,进行注册逻辑
    return Result.success();
}

@PutMapping
public Result update(@Validated({Default.class, UserGroup.UpdateGroup.class}) @RequestBody UserDto user, BindingResult bindingResult) {
    // 检查是否有校验错误
    if (bindingResult.hasErrors()) {
        // 按字段收集错误信息
        Map<String, String> errorMap = bindingResult.getFieldErrors().stream()
                .collect(Collectors.toMap(
                        FieldError::getField,  // 字段名
                        FieldError::getDefaultMessage  // 错误信息
                ));
        return Result.error(ErrorCode.PARAM_ERROR, errorMap);
    }

    // 更新逻辑...

    // 校验通过,进行注册逻辑
    return Result.success();
}
  • @Validated({Default.class, UserGroup.CreateGroup.class}) 指定使用注册分组的校验规则,同时指定了默认的校验规则,这样可以对没有添加分组的属性也进行校验;
  • @Validated({Default.class, UserGroup.UpdateGroup.class} 指定使用更新分组的校验规则;
  • 这样在更新的时候才检查用户 id 和其他默认分组的属性是否为空,创建的时候不检查。

17.6 自定义校验注解

有时候,系统提供的校验注解不能满足我们的需求,这时候我们可以自定义校验注解。

比如,我们需要校验手机号码的格式是否正确。

1 创建校验注解

先创建一个校验器注解,后面可以用在字段或参数上面。

java
package com.foooor.hellospringmvc.validation;

import jakarta.validation.Constraint;
import jakarta.validation.Payload;

import java.lang.annotation.*;

@Documented
@Constraint(validatedBy = PhoneValidator.class)  // 指定校验器
@Target({ElementType.FIELD, ElementType.PARAMETER})  // 可以用在字段和参数上
@Retention(RetentionPolicy.RUNTIME)  // 运行时保留
public @interface Phone {
    // 默认错误信息
    String message() default "手机号码格式不正确";
    
    // 分组
    Class<?>[] groups() default {};
    
    // 负载
    Class<? extends Payload>[] payload() default {};
}
  • @Constraint(validatedBy = PhoneValidator.class) 指定了该注解使用的校验器,待会创建;
  • message() 定义了默认的错误信息;
  • groups()payload() 是Bean Validation规范要求的方法;

2 创建校验器

创建校验器,用来验证手机格式是否正确,这里使用正则表达式来验证。

java
package com.foooor.hellospringmvc.validation;

import jakarta.validation.ConstraintValidator;
import jakarta.validation.ConstraintValidatorContext;

public class PhoneValidator implements ConstraintValidator<Phone, String> {
    
    // 手机号码正则表达式
    private static final String PHONE_REGEX = "^1[3-9]\\d{9}$";
    
    @Override
    public void initialize(Phone constraintAnnotation) {
        // 初始化方法,可以获取注解的属性
    }
    
    @Override
    public boolean isValid(String phone, ConstraintValidatorContext context) {
        // 如果手机号为null,返回true(由@NotNull等注解处理非空校验)
        if (phone == null) {
            return true;
        }
        // 校验手机号格式
        return phone.matches(PHONE_REGEX);
    }
}
  • ConstraintValidator<Phone, String> 表示该校验器用于校验Phone注解,校验的数据类型是String
  • initialize() 方法用于初始化校验器,可以获取注解的属性;
  • isValid() 方法用于执行校验逻辑,返回 true 表示校验通过,false 表示校验失败。

3 使用自定义校验注解

现在,我们可以在实体类中使用自定义的 @Phone 注解了:

java
@Data
public class UserDto {
    // 其他字段...
    
    @NotBlank(message = "手机号不能为空")
    @Phone(message = "手机号码格式不正确")
    private String phoneNumber;
}
  • 按自己的需要,看是不是要指定分组。

17.7 嵌套校验

当实体类中包含其他实体类作为属性时,我们需要使用嵌套校验来验证嵌套对象的属性。

比如,在 User类,包含一个 Book 对象作为属性:

java
package com.foooor.hellospringmvc.pojo;

import com.fasterxml.jackson.annotation.JsonFormat;
import com.foooor.hellospringmvc.validation.Phone;
import com.foooor.hellospringmvc.validation.UserGroup;
import jakarta.validation.Valid;
import jakarta.validation.constraints.*;
import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import java.time.LocalDate;

@Data
public class UserDto {

    @NotNull(message = "学生ID不能为空", groups = UserGroup.UpdateGroup.class)
    private Long id;

    // 其他字段...

    @NotNull(message = "图书的信息不能为空")
    @Valid  // 嵌套校验
    private Book book;
}
  • @Valid 注解用于触发嵌套对象的校验。

同样也可以在嵌套的对象中,对属性添加校验规则,例如 Book 类如下:

java
package com.foooor.hellospringmvc.pojo;

import jakarta.validation.constraints.NotBlank;
import jakarta.validation.constraints.NotNull;
import jakarta.validation.constraints.Size;
import lombok.Data;

@Data
public class Book {

    @NotNull(message = "图书ID不能为空")
    private Long id;

    @NotBlank(message = "图书名称不能为空")
    @Size(min = 2, max = 20, message = "图书名称长度必须在2-20位之间")
    private String name;
  
}

在Controller中,和之前是一样的,还是对 User 正常使用@Validated注解即可,没有变化:

java
@PostMapping
public Result create(@Validated({Default.class, UserGroup.CreateGroup.class}) @RequestBody UserDto user, BindingResult bindingResult) {
}
内容未完......