别再乱用校验注解!@NotNull、@NotEmpty和@NotBlank的正确使用姿势

主要区别

注解适用类型校验规则示例说明
@NotNull任何类型检查对象引用是否为 null
(不检查内容是否为空)
null → 无效
“” → 有效
" " → 有效
[] → 有效
@NotEmpty字符串、集合、数组、Map1. 检查对象不为 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) {
        // 业务逻辑
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值