【2023】Spring Validation中@NotNull注解、@NotBlank注解介绍以及使用
- 前言
- 一、简介
- `spring-validation`框架的常用注解
- 二、代码实现
- 添加依赖
- 1、实体举例
- 2、Controller层:
- 3、统一异常处理
- 4、结果返回
- 验证通过返回
- 验证失败返回
前言
平常我们在编写代码的时候总需要很多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 Validator
、Spring 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 "验证通过";
}