springboot form-data传参数_使用SpringBoot进行优雅的数据验证

本文详细介绍了如何在Spring Boot中使用JSR-303规范进行数据验证,包括内置约束、Hibernate Validator的附加约束,以及Spring Boot的校验功能。通过实例展示了直接参数校验、实体类DTO校验、Service层方法参数校验、分组校验、嵌套校验和集合校验。同时,还涵盖了自定义校验器、编程式校验和异常处理,最后讨论了@Validated和@Valid的区别及联系。
摘要由CSDN通过智能技术生成

JSR-303 规范

在程序进行数据处理之前,对数据进行准确性校验是我们必须要考虑的事情。尽早发现数据错误,不仅可以防止错误向核心业务逻辑蔓延,而且这种错误非常明显,容易发现解决。

JSR303 规范(Bean Validation 规范)为 JavaBean 验证定义了相应的元数据模型和 API。在应用程序中,通过使用 Bean Validation 或是你自己定义的 constraint,例如 @NotNull, @Max, @ZipCode , 就可以确保数据模型(JavaBean)的正确性。constraint 可以附加到字段,getter 方法,类或者接口上面。对于一些特定的需求,用户可以很容易的开发定制化的 constraint。Bean Validation 是一个运行时的数据验证框架,在验证之后验证的错误信息会被马上返回。

关于 JSR 303 – Bean Validation 规范,可以参考 官网

对于 JSR 303 规范,Hibernate Validator 对其进行了参考实现 . Hibernate Validator 提供了 JSR 303 规范中所有内置 constraint 的实现,除此之外还有一些附加的 constraint。如果想了解更多有关 Hibernate Validator 的信息,请查看 官网 。

validation-api 内置的 constraint 清单

7c2155529ef8798288313b609cf3be4b.png

Hibernate Validator 附加的 constraint

a485de0f217e35e1baccd16504b4dedf.png

Hibernate Validator 不同版本附加的 Constraint 可能不太一样,具体还需要你自己查看你使用版本。Hibernate 提供的 Constraint 在 org.hibernate.validator.constraints 这个包下面。

一个 constraint 通常由 annotation 和相应的 constraint validator 组成,它们是一对多的关系。也就是说可以有多个 constraint validator 对应一个 annotation。在运行时,Bean Validation 框架本身会根据被注释元素的类型来选择合适的 constraint validator 对数据进行验证。

有些时候,在用户的应用中需要一些更复杂的 constraint。Bean Validation 提供扩展 constraint 的机制。可以通过两种方法去实现,一种是组合现有的 constraint 来生成一个更复杂的 constraint,另外一种是开发一个全新的 constraint。

使用Spring Boot进行数据校验

Spring Validation 对 hibernate validation 进行了二次封装,可以让我们更加方便地使用数据校验功能。这边我们通过 Spring Boot 来引用校验功能。

如果你用的 Spring Boot 版本小于 2.3.x,spring-boot-starter-web 会自动引入 hibernate-validator 的依赖。如果 Spring Boot 版本大于 2.3.x,则需要手动引入依赖:

<dependency>
<groupId>org.hibernategroupId>
<artifactId>hibernate-validatorartifactId>
<version>6.0.1.Finalversion>
dependency>

直接参数校验

有时候接口的参数比较少,只有一个活着两个参数,这时候就没必要定义一个DTO来接收参数,可以直接接收参数。

@Validated
@RestController
@RequestMapping("/user")
public class UserController {

private static Logger logger = LoggerFactory.getLogger(UserController.class);

@GetMapping("/getUser")
@ResponseBody
// 注意:如果想在参数中使用 @NotNull 这种注解校验,就必须在类上添加 @Validated;
public UserDTO getUser(@NotNull(message = "userId不能为空") Integer userId){
logger.info("userId:[{}]",userId);
UserDTO res = new UserDTO();
res.setUserId(userId);
res.setName("程序员自由之路");
res.setAge(8);
return res;
}
}

下面是统一异常处理类

@RestControllerAdvice
public class GlobalExceptionHandler {

private static final Logger logger = LoggerFactory.getLogger(GlobalExceptionHandler.class);

@ExceptionHandler(value = ConstraintViolationException.class)public Response handle1(ConstraintViolationException ex){
StringBuilder msg = new StringBuilder();
Set> constraintViolations = ex.getConstraintViolations();for (ConstraintViolation> constraintViolation : constraintViolations) {
PathImpl pathImpl = (PathImpl) constraintViolation.getPropertyPath();
String paramName = pathImpl.getLeafNode().getName();
String message = constraintViolation.getMessage();
msg.append("[").append(message).append("]");
}
logger.error(msg.toString(),ex);// 注意:Response类必须有get和set方法,不然会报错return new Response(RCode.PARAM_INVALID.getCode(),msg.toString());
}@ExceptionHandler(value = Exception.class)public Response handle1(Exception ex){
logger.error(ex.getMessage(),ex);return new Response(RCode.ERROR.getCode(),RCode.ERROR.getMsg());
}
}

调用结果

# 这里没有传userId
GET http://127.0.0.1:9999/user/getUser

HTTP/1.1 200
Content-Type: application/json
Transfer-Encoding: chunked
Date: Sat, 14 Nov 2020 07:35:44 GMT
Keep-Alive: timeout=60
Connection: keep-alive

{
"rtnCode": "1000",
"rtnMsg": "[userId不能为空]"
}

实体类DTO校验

定义一个DTO

import org.hibernate.validator.constraints.Range;
import javax.validation.constraints.NotEmpty;

public class UserDTO {

private Integer userId;

@NotEmpty(message = "姓名不能为空")
private String name;
@Range(min = 18,max = 50,message = "年龄必须在18和50之间")
private Integer age;
//省略get和set方法
}

接收参数时使用@Validated进行校验

@PostMapping("/saveUser")
@ResponseBody
//注意:如果方法中的参数是对象类型,则必须要在参数对象前面添加 @Valida
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值