主要区别
注解 | 适用类型 | 校验规则 | 示例说明 |
---|---|---|---|
@NotNull | 任何类型 | 检查对象引用是否为 null (不检查内容是否为空) | null → 无效 “” → 有效 " " → 有效 [] → 有效 |
@NotEmpty | 字符串、集合、数组、Map | 1. 检查对象不为 null 2. 长度/大小 > 0 | null → 无效 “” → 无效 " " → 有效 [] → 无效 |
@NotBlank | 字符串 | 1. 检查不为 null 2. 去除首尾空格后长度 > 0 (专门针对空白字符校验) | null → 无效 “” → 无效 " " → 无效 " a " → 有效 |
详解
1. @NotNull - 基础空值检查
public class User {
@NotNull(message = "ID不能为空")
private Long id; // 只检查是否为null
@NotNull
private String name; // 接受 "" 或 " "
}
- 适用场景:任何非原始类型(对象引用)
- 特点:最宽松,只检查是否为 null,不验证内容
2. @NotEmpty - 非空内容检查
public class Request {
@NotEmpty(message = "用户名不能为空")
private String username; // 拒绝 null 和 ""
@NotEmpty(message = "角色列表不能为空")
private List<String> roles; // 拒绝 null 和 空列表
}
- 适用场景:
- 字符串(长度 > 0)
- 集合/数组(size > 0)
- Map(size > 0)
- 特点:比 @NotNull 更严格,要求有实际内容
3. @NotBlank - 严格字符串检查
public class LoginForm {
@NotBlank(message = "密码不能为空或空白")
private String password; // 拒绝 null、"" 和纯空格
@NotBlank
@Email
private String email;
}
- 适用场景:字符串类型(会调用 trim() 检查)
- 特点:专门针对空白字符设计,最严格的字符串校验
组合使用示例
public class Product {
@NotNull(message = "产品ID必填")
private Long id;
@NotBlank(message = "产品名称不能为空")
private String name;
@NotEmpty(message = "标签不能为空")
private List<@NotBlank String> tags; // 嵌套校验:非空列表 + 非空白标签
}
核心区别总结
场景 | @NotNull | @NotEmpty | @NotBlank |
---|---|---|---|
null | ❌ 无效 | ❌ 无效 | ❌ 无效 |
空字符串 “” | ✅ 有效 | ❌ 无效 | ❌ 无效 |
纯空格 " " | ✅ 有效 | ✅ 有效 | ❌ 无效 |
带内容的字符串 “a” | ✅ 有效 | ✅ 有效 | ✅ 有效 |
空集合 [] | ✅ 有效 | ❌ 无效 | N/A |
非空集合 [“a”] | ✅ 有效 | ✅ 有效 | N/A |
使用注意事项
1.依赖要求:需添加验证依赖
<!-- Spring Boot 验证 starter -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
2.触发验证:在 Controller 中使用 @Valid
@PostMapping("/users")
public ResponseEntity createUser(@Valid @RequestBody User user) {
// ...
}
3.错误处理:捕获 MethodArgumentNotValidException
@ExceptionHandler
public ResponseEntity handleValidationException(MethodArgumentNotValidException ex) {
// 提取错误信息: ex.getBindingResult().getAllErrors()
}
最佳实践建议
- 数据库字段 → 优先用 @NotNull(避免 null 值)
- 必填文本字段 → 使用 @NotBlank(避免空白输入)
- 集合类参数 → 使用 @NotEmpty(确保有内容)
- 组合校验:集合内元素可嵌套 @NotBlank
@NotEmpty
private List<@NotBlank String> items;
根据实际业务需求选择:
- 只需防 null → @NotNull
- 需要内容存在 → @NotEmpty
- 文本需真实内容 → @NotBlank
注意
想要实现不同场景应用不同的校验规则,可以分组校验(Group Validation) ,通过定义校验组(Validation Groups)来实现。
1.核心解决方案:使用 groups 属性
在约束注解中指定 groups 参数,定义校验组接口
// 1. 定义分组接口(空接口作为标记)
public interface CreateGroup {} // 创建操作校验组
public interface UpdateGroup {} // 更新操作校验组
public interface SearchGroup {} // 查询操作校验组
2.实体类配置分组校验
public class User {
// 创建时必须提供ID,更新时ID不能为空
@Null(groups = CreateGroup.class, message = "创建时ID必须为空")
@NotNull(groups = UpdateGroup.class, message = "更新时ID不能为空")
private Long id;
// 创建和更新时都需要校验用户名
@NotBlank(groups = {CreateGroup.class, UpdateGroup.class},
message = "用户名不能为空")
private String username;
// 仅创建时需要校验密码
@Size(min = 6, max = 20, groups = CreateGroup.class,
message = "密码长度6-20位")
private String password;
// 查询时专用校验
@Pattern(regexp = "\\d{4}-\\d{2}", groups = SearchGroup.class,
message = "日期格式必须为 yyyy-MM")
private String queryMonth;
}
3.控制器中使用分组校验
使用 Spring 的 @Validated 注解指定校验组(注意:不是 @Valid),只有对应分组中的属性才会被校验
@RestController
@RequestMapping("/users")
public class UserController {
// 创建操作:使用 CreateGroup
@PostMapping
public ResponseEntity createUser(
@Validated(CreateGroup.class) @RequestBody User user) {
// 业务逻辑
}
// 更新操作:使用 UpdateGroup
@PutMapping("/{id}")
public ResponseEntity updateUser(
@PathVariable Long id,
@Validated(UpdateGroup.class) @RequestBody User user) {
// 业务逻辑
}
// 查询操作:使用 SearchGroup
@GetMapping("/search")
public ResponseEntity searchUsers(
@Validated(SearchGroup.class) @ModelAttribute UserQuery query) {
// 业务逻辑
}
}