Springboot如何优雅的进行数据校验
基于 Spring Boot ,如何“优雅”的进行数据校验呢?
引入依赖
首先只需要给项目添加上 spring-boot-starter-web 依赖就够了,它的子依赖包含了我们所需要的东西。
注意:
Spring Boot 2.3 1 之后,spring-boot-starter-validation 已经不包括在了 spring-boot-starter-web 中,需要我们手动加上!
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-validation</artifactId>
</dependency>
验证 Controller 的输入
一定一定不要忘记在类上加上 @ Validated 注解了,这个参数可以告诉 Spring 去校验方法参数。
验证请求体
验证请求体即使验证被 @RequestBody 注解标记的方法参数。
PersonController
我们在需要验证的参数上加上了@Valid注解,如果验证失败,它将抛出MethodArgumentNotValidException。默认情况下,Spring 会将此异常转换为 HTTP Status 400(错误请求)。
@RestController
@RequestMapping("/api/person")
@Validated
public class PersonController {
@PostMapping
public ResponseEntity<PersonRequest> save(@RequestBody @Valid PersonRequest personRequest) {
return ResponseEntity.ok().body(personRequest);
}
}
@Data
@Builder
@AllArgsConstructor
@NoArgsConstructor
public class PersonRequest {
@NotNull(message = "classId 不能为空")
private String classId;
@Size(max = 33)
@NotNull(message = "name 不能为空")
private String name;
@Pattern(regexp = "(^Man$|^Woman$|^UGM$)", message = "sex 值不在可选范围")
@NotNull(message = "sex 不能为空")
private String sex;
}
使用 Postman 验证
验证请求参数
验证请求参数(Path Variables 和 Request Parameters)即是验证被 @PathVariable 以及 @RequestParam 标记的方法参数。
PersonController
@RestController
@RequestMapping("/api/persons")
@Validated
public class PersonController {
@GetMapping("/{id}")
public ResponseEntity<Integer> getPersonByID(@Valid @PathVariable("id") @Max(value = 5, message = "超过 id 的范围了") Integer id) {
return ResponseEntity.ok().body(id);
}
@PutMapping
public ResponseEntity<String> getPersonByName(@Valid @RequestParam("name") @Size(max = 6, message = "超过 name 的范围了") String name) {
return ResponseEntity.ok().body(name);
}
}
使用 Postman 验证
嵌套校验
在一个校验A对象里另一个B对象里的参数
需要在B对象上加上@Valid注解
常用校验注解总结
JSR303 定义了 Bean Validation(校验)的标准 validation-api,并没有提供实现。Hibernate Validation是对这个规范/规范的实现 hibernate-validator,并且增加了 @Email、@Length、@Range 等注解。Spring Validation 底层依赖的就是Hibernate Validation。
JSR 提供的校验注解:
- @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(regex=,flag=) 被注释的元素必须符合指定的正则表达式
Hibernate Validator 提供的校验注解:
- @NotBlank(message =) 验证字符串非 null,且长度必须大于 0
- @Email 被注释的元素必须是电子邮箱地址
- @Length(min=,max=) 被注释的字符串的大小必须在指定的范围内
- @NotEmpty 被注释的字符串的必须非空
- @Range(min=,max=,message=) 被注释的元素必须在合适的范围内
@JsonFormat与@DateTimeFormat注解的使用
@JsonFormat用于后端传给前端的时间格式转换,@DateTimeFormat用于前端传给后端的时间格式转换
JsonFormat
1、使用maven引入@JsonFormat所需要的jar包
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>org.codehaus.jackson</groupId>
<artifactId>jackson-mapper-asl</artifactId>
<version>1.9.13</version>
</dependency>
2、在需要查询时间的数据库字段对应的实体类的属性上添加@JsonFormat
@JsonFormat(timezone = "GMT+8", pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime updateDate;
注: timezone:是时间设置为东八区,避免时间在转换中有误差,pattern:是时间转换格式
DataTimeFormat
1、添加依赖
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.3</version>
</dependency>
2、我们在对应的接收前台数据的对象的属性上加@DateTimeFormat
@DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
private LocalDateTime acquireDate;
3.这样我们就可以将前端获取的时间转换为一个符合自定义格式的时间格式存储到数据库了
全局异常统一处理:拦截并处理校验出错的返回数据
写一个全局异常处理类
@ControllerAdvice
public class GlobalExceptionHandler{
/**
* 处理参数校验异常
*/
@ExceptionHandler({MethodArgumentNotValidException.class})
@ResponseBody
public ErrorResponseData validateException(MethodArgumentNotValidException e) {
log.error("参数异常"+e.getBindingResult().getFieldError().getDefaultMessage(),e);
return new ErrorResponseData(10001,e.getBindingResult().getFieldError().getDefaultMessage());
}
/**
* 处理json转换异常(比如 @DateTimeFormat注解转换日期格式时)
*/
@ExceptionHandler({HttpMessageNotReadableException.class})
@ResponseBody
public ErrorResponseData jsonParseException(HttpMessageNotReadableException e) {
log.error("参数异常"+e.getLocalizedMessage(),e);
return new ErrorResponseData(10001,e.getCause().getMessage());
}
}
来源:juejin.cn/post/7241114001324228663