Spring Boot | 一种优雅的参数校验方案(个人总结)

简介: 一种优雅的参数校验方案(个人总结)

首发链接:掘金 —— 汪小成

1、前言

在平时的开发工作中,我们通常需要对接口进行参数格式验证。当参数个数较少(个数小于3)时,可以使用if ... else ...手动进行参数验证。当参数个数大于3个时,使用if ... else ...进行参数验证就会让代码显得臃肿,这个时候推荐使用注解来进行参数验证。

2、常用注解

下面列举一些常用的验证注解:

  1. @NotNull:值不能为null;
  2. @NotEmpty:字符串、集合或数组的值不能为空,即长度大于0;
  3. @NotBlank:字符串的值不能为空白,即不能只包含空格;
  4. @Size:字符串、集合或数组的大小是否在指定范围内;
  5. @Min:数值的最小值;
  6. @Max:数值的最大值;
  7. @DecimalMin:数值的最小值,可以包含小数;
  8. @DecimalMax:数值的最大值,可以包含小数;
  9. @Digits:数值是否符合指定的整数和小数位数;
  10. @Pattern:字符串是否匹配指定的正则表达式;
  11. @Email:字符串是否为有效的电子邮件地址;
  12. @AssertTrue:布尔值是否为true;
  13. @AssertFalse:布尔值是否为false;
  14. @Future:日期是否为将来的日期;
  15. @Past:日期是否为过去的日期;

3、实现示例

3.1 创建项目,添加依赖

本示例中使用的spring boot 版本为2.7.7

使用IDEA创建一个spring boot项目。在项目的pom.xml文件中添加如下依赖:

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

3.2 创建示例实体类

创建一个User实体类,在实体类中需要对属性进行如下验证:

  • name - 用户姓名,不能为空;
  • password - 密码,不能为空,长度不能小于6;
  • age - 年龄,大于0小于150;
  • phone - 手机号,满足手机号格式;

User实体类具体代码如下:

 import lombok.Data;
 import javax.validation.constraints.*;
 ​
 @Data
 public class User {
 ​
   @NotBlank(message = "用户姓名不能为空")
   private String name;
 ​
   @NotBlank(message = "密码不能为空")
   @Size(min = 6, message = "密码长度不能少于6位")
   private String password;
 ​
   @Min(value = 0, message = "年龄不能小于0岁")
   @Max(value = 150, message = "年龄不应超过150岁")
   private Integer age;
 ​
   @Pattern(regexp = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-9])|(147))\d{8}$", message = "手机号格式不正确")
   private String phone;
 ​
 }
 ​

3.3 创建控制器类

创建一个简单的控制器类,用于演示参数验证功能。

控制器代码如下:

 import cn.ddcherry.springboot.demo.util.R;
 import cn.ddcherry.springboot.demo.entity.User;
 import org.springframework.web.bind.annotation.PostMapping;
 import org.springframework.web.bind.annotation.RequestBody;
 import org.springframework.web.bind.annotation.RequestMapping;
 import org.springframework.web.bind.annotation.RestController;
 ​
 import javax.validation.Valid;
 ​
 @RestController
 @RequestMapping("/user")
 public class UserController {
 ​
   @PostMapping("/save")
   public R save(@Valid @RequestBody User user) {
     return R.ok(user);
   }
 }

我们在参数user前添加@Valid注解,表示验证该参数。

其中R是封装的一个简易工具类,用于统一返回结果格式。代码如下:

 import lombok.Data;
 ​
 import java.io.Serializable;
 ​
 @Data
 public class R<T> implements Serializable {
   private int code;
   private boolean success;
   private T data;
   private String msg;
 ​
   private R(int code, T data, String msg) {
     this.code = code;
     this.data = data;
     this.msg = msg;
     this.success = code == 200;
   }
 ​
   public static <T> R<T> ok(T data) {
     return new R<>(200, data, null);
   }
 ​
   public static <T> R<T> error(String msg) {
     return new R<>(500, null, msg);
   }
 }

3.4 定义全局异常处理类

全局异常处理类代码如下:

 import cn.ddcherry.springboot.demo.util.R;
 import org.springframework.validation.BindException;
 import org.springframework.validation.BindingResult;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.RestControllerAdvice;
 ​
 @RestControllerAdvice
 public class GlobalExceptionHandler {
 ​
   @ExceptionHandler(BindException.class)
   public R handleError(BindException e) {
     BindingResult bindingResult = e.getBindingResult();
     return R.error(bindingResult.getFieldError().getDefaultMessage());
   }
 }

我们在全局异常处理类中使用ExceptionHandler捕获BindException异常,获取参数验证异常信息,最后返回统一的异常结果格式。

3.5 测试

在接口测试工具中测试接口。

以密码长度不足6位为例,返回的结果如下图所示:

image-20230925143558493

3.6 小结

至此,我们就简单地讲述了Spring Boot项目使用@Valid注解进行参数验证的实现步骤。示例的验证逻辑流程如下图所示:

Snipaste_2023-11-11_16-52-58.png

4、进阶

4.1 @Valid与@Validated的区别

用于参数校验的注解通常有两个:@Valid@Validated。它们的区别有如下几点:

区别 @Valid @Validated
来源 @Valid是Java标准注解 @Validated是Spring框架定义的注解。
是否支持分组验证 不支持 支持
使用位置 构造函数、方法、方法参数、成员属性 类、方法、方法参数,不能用于成员属性
是否支持嵌套校验 支持 不支持

4.2 自定义验证注解

除了框架自带的注解,平时的工作中可能需要我们自定义验证注解处理特定的业务需求。这里汪小成将上面User类中的手机号格式验证改成使用自定义注解的验证方式。

4.2.1 定义注解

 @Documented
 @Retention(RUNTIME)
 @Constraint(validatedBy = {PhoneValidator.class})
 @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE})
 public @interface Phone {
 ​
   String message() default "手机号格式错误";
 ​
   Class<?>[] groups() default {};
 ​
   Class<? extends Payload>[] payload() default {};
 }

说明:

  • @Constraint(validatedBy = {PhoneValidator.class}):用于指定验证器类;
  • @Target({METHOD, FIELD, ANNOTATION_TYPE, CONSTRUCTOR, PARAMETER, TYPE_USE}):指定@Phone注解可以作用在方法、字段、构造函数、参数以及类型上;

4.2.2 定义验证器类

 public class PhoneValidator implements ConstraintValidator<Phone, String> {
   private static final Logger LOGGER = LoggerFactory.getLogger(PhoneValidator.class);
   private static final String REGEX = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-9])|(147))\d{8}$";
 ​
   @Override
   public boolean isValid(String s, ConstraintValidatorContext context) {
     boolean result = false;
     try {
       result = Pattern.matches(REGEX, s);
     } catch (Exception e) {
       LOGGER.error("验证手机号格式时发生异常,异常信息:", e);
     }
     return result;
   }
 }

4.2.3 使用注解

 @Data
 public class User {
 ​
   // 省略其它代码
 ​
 - //  @Pattern(regexp = "^((13[0-9])|(15[^4])|(18[0-9])|(17[0-9])|(147))\d{8}$", message = "手机号格式不正确")
 + @Phone
   private String phone;
 ​
 }
 ​

这样我们就成功地使用自定义注解@Phone验证手机号格式了。

使用自定义注解实现业务验证的一个比较大的优点是可以复用。所有需要进行手机号格式验证的属性,只需要添加上@Phone注解就可以了。如果后期我们需要修改手机号的验证规则,只需要修改PhoneValidator类中的验证逻辑,就可以作用于所有添加了@Phone注解的字段了。

目录
相关文章
|
20天前
|
JSON 前端开发 Java
Spring MVC——获取参数和响应
本文介绍了如何在Spring框架中通过不同的注解和方法获取URL参数、上传文件、处理cookie和session、以及响应不同类型的数据。具体内容包括使用`@PathVariable`获取URL中的参数,使用`MultipartFile`上传文件,通过`HttpServletRequest`和`@CookieValue`获取cookie,通过`HttpSession`和`@SessionAttribute`获取session,以及如何返回静态页面、HTML代码片段、JSON数据,并设置HTTP状态码和响应头。
38 1
Spring MVC——获取参数和响应
|
26天前
|
easyexcel Java UED
SpringBoot中大量数据导出方案:使用EasyExcel并行导出多个excel文件并压缩zip后下载
在SpringBoot环境中,为了优化大量数据的Excel导出体验,可采用异步方式处理。具体做法是将数据拆分后利用`CompletableFuture`与`ThreadPoolTaskExecutor`并行导出,并使用EasyExcel生成多个Excel文件,最终将其压缩成ZIP文件供下载。此方案提升了导出效率,改善了用户体验。代码示例展示了如何实现这一过程,包括多线程处理、模板导出及资源清理等关键步骤。
|
25天前
|
JSON NoSQL Java
springBoot:jwt&redis&文件操作&常见请求错误代码&参数注解 (九)
该文档涵盖JWT(JSON Web Token)的组成、依赖、工具类创建及拦截器配置,并介绍了Redis的依赖配置与文件操作相关功能,包括文件上传、下载、删除及批量删除的方法。同时,文档还列举了常见的HTTP请求错误代码及其含义,并详细解释了@RequestParam与@PathVariable等参数注解的区别与用法。
|
30天前
|
前端开发 Java Spring
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
【Spring】“请求“ 之传递单个参数、传递多个参数和传递对象
95 2
|
2月前
|
JSON Java 数据格式
springboot 参数统一处理
springboot 参数统一处理
|
23天前
|
监控 Java Maven
springboot学习二:springboot 初创建 web 项目、修改banner、热部署插件、切换运行环境、springboot参数配置,打包项目并测试成功
这篇文章介绍了如何快速创建Spring Boot项目,包括项目的初始化、结构、打包部署、修改启动Banner、热部署、环境切换和参数配置等基础操作。
97 0
|
1月前
|
存储 NoSQL Java
Spring Boot项目中使用Redis实现接口幂等性的方案
通过上述方法,可以有效地在Spring Boot项目中利用Redis实现接口幂等性,既保证了接口操作的安全性,又提高了系统的可靠性。
32 0
|
2月前
|
Java Spring
spring boot 启动项目参数的设定
spring boot 启动项目参数的设定
|
2月前
|
SQL 监控 druid
springboot-druid数据源的配置方式及配置后台监控-自定义和导入stater(推荐-简单方便使用)两种方式配置druid数据源
这篇文章介绍了如何在Spring Boot项目中配置和监控Druid数据源,包括自定义配置和使用Spring Boot Starter两种方法。
|
Java Spring 前端开发
spring 3.2 自定义参数绑定--日期格式转换器
springmvc配置文件 &lt;!-- 代替org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping 和org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter --&gt;
2437 0