Java-Validation

欢迎你来读这篇博客,这篇博客主要是关于Validation
其中包括了关于我的见解和收集的知识分享。

序言

@Validated 是 Spring 提供的一个注解,用于启用方法参数的校验。在 Spring Boot 中,@Validated 通常结合 JSR-303/JSR-380
规范(例如
Hibernate Validator)中的注解使用,比如 @NotNull@Size@Min@Max 等,用于对控制器、服务方法的参数进行验证,特别是处理用户输入时常见的有效性校验需求。

正文

基本用法

@Validated可以放在类、方法上,用于校验请求对象的属性值是否符合约束。通常搭配以下三类注解一起使用:

  • 字段级注解:如 @NotNull、@Size、@Email 等,放在对象的属性上。
  • 分组校验:通过不同的校验组,可以实现对不同场景的校验。
  • 级联校验:用于嵌套对象的校验。

常见注解

  • @NotNull:字段不能为 null。
  • @NotEmpty:集合、数组、字符串不能为 null 且不能为空。
  • @NotBlank:字符串必须包含非空白字符。
  • @Size(min=, max=):指定集合、数组、字符串的长度范围。
  • @Min(value=) / @Max(value=):指定数值的最小/最大值。
  • @Email:邮箱格式校验。
  • @Pattern(regexp=):正则表达式校验,适用于字符串。

以下是简要示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import javax.validation.constraints.Email;
import javax.validation.constraints.NotBlank;
import javax.validation.constraints.Size;

public class UserDTO {
@NotBlank(message = "用户名不能为空")
@Size(min = 3, max = 20, message = "用户名长度必须在3到20之间")
private String username;

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

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.validation.Valid;

@RestController
@RequestMapping("/api/users")
@Validated // 启用参数校验
public class UserController {

@PostMapping("/register")
// @Valid:用于启用 UserDTO 对象的字段校验。校验触发:如果 UserDTO 对象中的字段不满足校验条件,将返回错误信息,而不会进入 registerUser 方法。
public String registerUser(@Valid @RequestBody UserDTO userDTO) {
// 校验通过后才会进入此方法
return "用户注册成功: " + userDTO.getUsername();
}
}

分组校验

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// 自定义分组 支持继承,校验判断是否需要触发的时候,会触发只标注父类,但是没标注子类的
public interface CreateGroup extends DefaultGroup {}
public interface UpdateGroup extends DefaultGroup {}

// 在实体类上指定分组
public class UserDTO {

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

@NotBlank(groups = {CreateGroup.class, UpdateGroup.class}, message = "邮箱不能为空")
@Email(groups = {CreateGroup.class, UpdateGroup.class}, message = "邮箱格式不正确")
private String email;

@NotBlank(groups = DefaultGroup.class, message = "C/U全都会校验")
private String description;
}

// 指定分组
@PostMapping("/create")
public String createUser(@Validated(CreateGroup.class) @RequestBody UserDTO userDTO) {
return "创建用户成功";
}

@PutMapping("/update")
public String updateUser(@Validated(UpdateGroup.class) @RequestBody UserDTO userDTO) {
return "更新用户成功";
}

自定义校验器

示例 @UniqueUsername

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// 构造注解
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Target({ ElementType.FIELD })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = UniqueUsernameValidator.class)
public @interface UniqueUsername {
String message() default "用户名已存在";
Class<?>[] groups() default {};
Class<? extends Payload>[] payload() default {};
}

// 实现校验逻辑
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;

public class UniqueUsernameValidator implements ConstraintValidator<UniqueUsername, String> {

@Override
public boolean isValid(String username, ConstraintValidatorContext context) {
// 模拟用户名已存在的校验逻辑,例如检查数据库
return !username.equalsIgnoreCase("existingUser"); // 返回false表示无效
}
}

// 使用自定义校验注解
public class UserDTO {
@UniqueUsername
private String username;

@Email
private String email;
}

示例 @IsLeek

定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
import javax.validation.Constraint;
import javax.validation.Payload;
import java.lang.annotation.*;

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
@Documented
@Constraint(validatedBy = IsLeekValidator.class) // 指定我们自定义的校验类
public @interface IsLeek {

/**
* 是否强制校验
*
* @return 是否强制校验的boolean值
*/
boolean required() default true;

/**
* 校验不通过时的报错信息
*
* @return 校验不通过时的报错信息
*/
String message() default "此用户不是韭零后,无法开户!";

/**
* 将validator进行分类,不同的类group中会执行不同的validator操作
*
* @return validator的分类类型
*/
Class<?>[] groups() default {};

/**
* 主要是针对bean,很少使用
*
* @return 负载
*/
Class<? extends Payload>[] payload() default {};

}

定义校验器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import org.springframework.util.StringUtils;

public class IsLeekValidator implements ConstraintValidator<IsLeek, String> {

/**
* 是否强制校验
*/
private boolean required;

@Override
public void initialize(IsLeek constraintAnnotation) {
this.required = constraintAnnotation.required();
}

@Override
public boolean isValid(String name, ConstraintValidatorContext constraintValidatorContext) {
if (required) {
// 名字以"新韭菜"开头的则校验通过
return !StringUtils.isEmpty(name) && name.startsWith("新韭菜");
}
return false;
}
}

参考资料

启示录

富贵岂由人,时会高志须酬。

能成功于千载者,必以近察远。


Java-Validation
https://allendericdalexander.github.io/2025/08/06/java_validated/
作者
AtLuoFu
发布于
2025年8月6日
许可协议