【2023】Spring Validation中@NotNull注解、@NotBlank注解介绍以及使用

本文介绍了Spring框架中的@NotNull和@NotBlank注解在数据验证中的使用,以及如何在SpringValidation中集成JSR303规范,提供优雅的空值检查和错误处理。文章详细讲解了如何在SpringBoot项目中添加依赖并展示了实体类、Controller层和统一异常处理的示例。

前言

平常我们在编写代码的时候总需要很多if判空,防止出现很多空指针问题。如:

if(name!=null){
	return "账号不能为空,请重新输入";
}
else if(password!=null){
	return "密码不能为空,请重新输入";
}

这样就会显得特别low,而且极不美观,而使用@NotNull 注解就可以通过注解直接实现验证。

一、简介

而spring给我们提供的 @NotNull ,@NotEmpty 等注解以实现对于接口参数的自动验证。

它这个实现主要是基于JSR 303 (JSR(Java Specification Request)是指由Java社区中的一个或多个成员提交的一项Java技术规范请求)的规范
JSR 303 的主要目标是为开发者提供一种在应用程序中进行数据验证的通用机制,而无需编写大量的验证代码。它定义了一组用于验证 Java 对象的注解和 API,可以用于验证对象的属性、方法参数和返回值等。

  • 注解:JSR 303 定义了一组用于验证的注解,如 @NotNull@Size@Pattern@Min、@Max 等。通过在 Java 对象的属性上添加这些注解,可以指定验证的条件和约束。
  • 常见的使用 JSR 303 的框架包括 Hibernate ValidatorSpring Validation 等。

早期的 Spring Web 基于 Hibernate Validator 实现了这些校验规范。在后期,Spring 将这部分校验独立成为了一个模块spring-validation,需要额外引入依赖实现相关注解校验。

spring-validation框架的常用注解

注解说明
@Null被注释的元素必须为null
@NotNull被注释的元素不能为null
@AssertTrue被注释的元素必须为true
@AssertFalse被注释的元素必须为false
@Min(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@Max(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@DecimalMin(value)被注释的元素必须是一个数字,其值必须大于等于指定的最小值
@DecimalMax(value)被注释的元素必须是一个数字,其值必须小于等于指定的最大值
@Size(max,min)被注释的元素的大小必须在指定的范围内
@Digits(integer,fraction)被注释的元素必须是一个数字,其值必须在可接受的范围内
@Past被注释的元素必须是一个过去的日期
@Future被注释的元素必须是一个将来的日期
@Pattern(value)被注释的元素必须符合指定的正则表达式

注意:

  • 下面的注解都可以使用message 属性做异常错误返回的。 如: @NotNull(message = "name不能为空")

  • 在进行请求参数的验证时,需要在controller方法的需要验证的参数前面加上@Valid或者@Validated注解,否则Form中的验证注解不起作用。

  • 如果是内层对象需要验证的话,需要在里面对象前也加上@valid,这样,无论嵌套多少,都可以验证(包括对象泛型)。

@Valid与@Validated的区别

  • @Valid:可以用在方法、构造函数、方法参数和成员属性(字段)上
  • @Validated:可以用在类型、方法和方法参数上。但是不能用在成员属性(字段)上,并且@Validated提供了一个分组功能,可以在入参验证时,根据不同的分组采用不同的验证机制

二、代码实现

添加依赖

springboot 2.3.0 以前可以直接使用,而在2.3.0之后的版本不会自动引入jar包,所以要添加以下maven

<dependency>
	<groupId>org.springframework.boot</groupId>
	<artifactId>spring-boot-starter-validation</artifactId>
</dependency>

1、实体举例

import lombok.Data;
import org.springframework.format.annotation.DateTimeFormat;
import javax.validation.Valid;
import javax.validation.constraints.*;
import java.util.Date;

@Data
public class User {
    @NotBlank(message = "姓名不能为空")
    private String name;

    @Max(value = 30,message = "姓名不能超过30岁")
    private Integer age;
    
    private Integer password;

    private String sex;

    @Past(message = "只能是过去的时间!")
    @DateTimeFormat(pattern = "yyyy-MM-dd")
    private Date date;

    @Email(message = "邮箱格式错误")
    private String email;
    /**如果引用了其他的对象要想其他的对象的生效,需要在引用时加上注解*/
    @Valid
    private School school;
}

2、Controller层:

import org.springframework.validation.BindingResult;
import org.springframework.validation.FieldError;
import org.springframework.web.bind.annotation.*;
import javax.validation.Valid;

/**
 * @author zhengfuping
 * @version 1.0
 * @description: TODO 测试 validation
 */
@RestController
@RequestMapping("/test")
public class TestController {
    
    /**
     * @Param * @param u 实例对象
     * @param result validation提供的异常处理类
     * @return * @return Object
     */
    @PostMapping("/save_user")
    @ResponseBody
    public Object saveUser(@Valid @RequestBody User u , BindingResult result) {
//        判断是否有异常,进行返回
        if (result.hasErrors()){
            FieldError fieldError = result.getFieldError();
            System.out.println(fieldError);
            return fieldError;
        }
//          没有异常打印日志返回
        System.out.println(u);
        return u;
    }
}

3、统一异常处理

如果不想每个Controller层的方法里面都要写一个判断方法,可以定义一个全局异常类进行统一处理

import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import java.util.Objects;

/**
 * @author zhengfuping
 * @version 1.0
 * @description: TODO统一处理实体字段验证错误返回
 */
@ControllerAdvice
@Slf4j
public class ControllerException {
    
    @ResponseBody
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Object handleValidException(MethodArgumentNotValidException e){
        log.error(Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
//            正常开发会有统一返回对象
//         return Result.error(500, Objects.requireNonNull(e.getBindingResult().getFieldError()).getDefaultMessage());
        return e.getBindingResult().getFieldError().getDefaultMessage();
    }
}

添加统一异常处理后Controller代码则可以简化为(为了区分重新写了一个)

    @PostMapping("/save_user2")
    @ResponseBody
    public Object saveUser2(@Valid @RequestBody User u) {
        System.out.println(u);
        return "验证通过";
    }

4、结果返回

验证通过返回

在这里插入图片描述

验证失败返回

在这里插入图片描述

<think>好的,用户想了解Java中的@NotNull注解的用法或相关技术问题的解决方案。首先,我需要确认用户的具体需求。他们可能是在开发过程中遇到了指针异常,想通过注解来预防这类问题,或者是在代码审查中发现需要更明确的值约束,想了解如何正确使用@NotNull。 接下来,我需要回顾@NotNull注解的基本作用。它通常用于标记方法参数、返回值或字段,表示这些元素不能为null。这样可以在编译时或运行时进行校验,避免指针异常。但要注意,不同的框架和工具可能有不同的实现,比如JetBrains的@NotNull和JSR 305的@Nonnull,还有Jakarta Validation@NotNull,它们的用法和效果可能略有不同。 然后,用户可能需要知道具体的使用场景和示例。比如在方法参数中使用@NotNull,让调用者明确不能传入null;在返回值中使用,确保方法不会返回null;或者在实体类字段上使用,结合校验框架进行数据验证。需要给出具体的代码示例,说明如何在不同位置应用注解。 还需要考虑如何集成校验框架,比如Hibernate Validator,以及如何在Spring的Controller层使用@Validated进行参数校验。同时,要提到相关的依赖配置,比如Maven的依赖项,确保用户能够正确配置环境。 此外,用户可能会遇到注解不生效的问题,需要提供常见解决方案。比如检查依赖是否正确引入、是否在需要校验的地方添加了@Valid或@Validated注解,或者确认注解的来源是否与使用的框架匹配。还要提到IDE的静态分析工具,如IntelliJ IDEA的支持,帮助用户在编码时发现问题。 最后,要区分不同注解的来源和适用场景,避免混淆。例如,JetBrains的注解主要用于IDE提示,而Jakarta的注解用于运行时校验。可能还需要引用站内的参考资料,比如引用[1]和[2],说明父类与子类方法中@NotNull和@Nullable的继承关系,以及@Nullable的用法对比。 总结下来,回答需要涵盖@NotNull的作用、使用场景、示例代码、框架集成、常见问题解决和不同注解的区别,确保用户能够全面理解并正确应用该注解。</think>### Java @NotNull 注解使用说明及解决方案 #### 一、@NotNull 注解的作用 `@NotNull` 是用于标记方法参数、返回值或字段**不可为 null** 的注解,主要帮助开发者在以下场景中避免指针异常: 1. **编译时静态检查**:IDE(如 IntelliJ IDEA)或静态分析工具(如 Checker Framework)会基于注解提示潜在的指针风险[^1]。 2. **运行时校验**:结合校验框架(如 Hibernate Validator)在方法调用或数据传输时验证非约束[^3]。 --- #### 二、使用场景与示例 ##### 1. 方法参数校验 ```java public void processUser(@NotNull String username) { // 若传入 null,校验框架或 IDE 会抛出异常/警告 System.out.println(username.length()); } ``` ##### 2. 返回值校验 ```java public @NotNull String getUserName() { // 若返回 null,编译工具或运行时校验会报错 return "Alice"; } ``` ##### 3. 实体类字段校验 ```java public class User { @NotNull(message = "用户ID不能为") private Long id; // Getter/Setter } ``` ##### 4. Controller 层参数校验(Spring) ```java @PostMapping("/create") public ResponseEntity<?> createUser(@RequestBody @Valid User user) { // 自动触发 @NotNull 校验,失败时返回 message } ``` --- #### 三、依赖配置(以 Hibernate Validator 为例) ```xml <!-- Maven 依赖 --> <dependency> <groupId>org.hibernate.validator</groupId> <artifactId>hibernate-validator</artifactId> <version>8.0.1.Final</version> </dependency> ``` --- #### 四、常见问题与解决 ##### 问题1:注解不生效 - **原因**:未启用校验框架或缺少 `@Valid` 注解。 - **解决**: ```java // Spring 中需在 Controller 方法参数前添加 @Valid public ResponseEntity<?> save(@RequestBody @Valid User user) { ... } ``` ##### 问题2:IDE 不提示警告 - **原因**:未启用注解的静态分析功能。 - **解决**:在 IntelliJ IDEA 中,开启 `Annotations -> Configure Annotations`,绑定 `@NotNull` 到 `javax.validation.constraints.NotNull`[^2]。 ##### 问题3:与父类方法冲突 - **规则**:子类重写父类方法时,若父类方法参数有 `@Nullable`,子类可标记为 `@NotNull`;反之若父类为 `@NotNull`,子类必须保持相同或更严格约束[^1]。 --- #### 五、注解对比 | 注解来源 | 适用场景 | 典型框架 | |----------------------|----------------------------|--------------------| | `javax.validation.NotNull` | 运行时校验 | Hibernate Validator| | `org.jetbrains.annotations.NotNull` | IDE 静态检查 | IntelliJ IDEA | | `jakarta.annotation.Nonnull` | JAX-RS/Jakarta EE | Jakarta EE | ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值