avatar

Spring Boot参数校验

Spring Boot参数校验

前言

在web开发中,前端的参数校验可以提高用户的体验,后端的参数校验为了数据的安全。
在之前的开发中参数校验一般如下图


没有任何问题,只有有些不简洁不优雅
使用 hibernate-validator 来进行参数校验

示例

导入依赖

版本自由选择

1
2
3
4
5
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-validator</artifactId>
<version>6.1.0.Final</version>
</dependency>

常用的校验注解

  • @AssertFalse 所注解的元素必须是Boolean类型,且值为false
  • @AssertTrue 所注解的元素必须是Boolean类型,且值为true
  • @DecimalMax 所注解的元素必须是数字,且值小于等于给定的值
  • @DecimalMin 所注解的元素必须是数字,且值大于等于给定的值
  • @Digits 所注解的元素必须是数字,且值必须是指定的位数
  • @Future 所注解的元素必须是将来某个日期
  • @Max 所注解的元素必须是数字,且值小于等于给定的值
  • @Min 所注解的元素必须是数字,且值小于等于给定的值
  • @Range 所注解的元素需在指定范围区间内
  • @NotNull 所注解的元素值不能为null
  • @NotBlank 所注解的元素值有内容
  • @Null 所注解的元素值为null
  • @Past 所注解的元素必须是某个过去的日期
  • @PastOrPresent 所注解的元素必须是过去某个或现在日期
  • @Pattern 所注解的元素必须满足给定的正则表达式
  • @Size 所注解的元素必须是String、集合或数组,且长度大小需保证在给定范围之内
  • @Email 所注解的元素需满足Email格式

@NotNull 验证对象是否不为null, 无法查检长度为0的字符串: 不能为null,但可以为空字符串
@NotBlank 检查约束 (字符串) 是不是Null还有被Trim的长度是否大于0,只对字符串,且会去掉前后空格.: 只能作用在String上,不能为null,而且调用trim()后,长度必须大于0
@NotEmpty 检查(集合)约束元素是否为NULL或者是EMPTY. : 不能为null,并且长度必须大于0
@NotEmpty修饰的String类、Collection、Map、数组,是不能为null或者长度为0的(String Collection Map的isEmpty()方法)

参数校验的两种场景

单个参数校验

在参数前加上校验注解,前提要在类上加入注解@Validated
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
@ResponseBody
@PostMapping("/user")
public Object login2(@RequestParam("email")
@NotBlank(message = "邮箱号不能为空")
@Email(message = "邮箱格式不正确")
String email,
@RequestParam("password")
@NotBlank(message = "密码不能为空")
@Size(min = 5,max = 20,message = "密码应该在5~20之间")
String password){

User user = new User(email,password);
return loginService.login(user);
}
实体类参数校验

在类的属性上添加校验注解
例如

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.example.springboot.dto;

import lombok.Data;
import javax.validation.constraints.Email;
import javax.validation.constraints.NotNull;

@Data
public class LoginUserDTO {

@Email(message = "必须是邮箱格式啊!!")
@NotNull(message = "邮箱不能为空啊!!")
private String email;

@NotNull(message = "密码不能为空啊!!")
private String password;
}
实体类中的分组处理

思考:当我有一个方法也要校验LoginUserDTO,但是校验的参数和message不同时,怎么办?
解决一:再去定义一个类,编写参数和注解 。 这样很不优雅
解决二:使用参数分组
注册一个接口

1
2
public interface Login {
}

然后对LoginUserDTO中的参数进行分组,Default.class是validation-api自带的默认分组类

1
2
3
4
5
6
7
8
9
10
@Data
public class LoginUserDTO {

@Email(message = "必须是邮箱格式啊!!",groups = Default.class)
@NotBlank(message = "邮箱不能为空啊!!",groups = Login.class)
private String email;

@NotBlank(message = "密码不能为空啊!!",groups = Default.class)
private String password;
}

然后定义两个方法,在@Validated注解中加入分组即可

1
2
3
4
5
6
7
8
9
10
11
12
13
@ResponseBody
@PostMapping("/login")
public Object login(@RequestBody @Validated(Login.class) LoginUserDTO user){
System.out.println(user);
return loginService.login(user);
}

@ResponseBody
@PostMapping("/login2")
public Object login2(@RequestBody @Validated(Default.class) LoginUserDTO user){
System.out.println(user);
return loginService.login(user);
}

login方法只校验 email的@NotBlank
login2方法只校验 email的@Email和password的NotBlank

全局异常处理

当校验不成功时产生的异常通过全局异常处理,在有@ControllerAdvice注解的异常处理类中加入以下方法,将其拦截,再将错误信息传输到页面当中

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
@ExceptionHandler({MethodArgumentNotValidException.class,ConstraintViolationException.class})
@ResponseBody
public Object resolveMethodArgumentNotValidException(Exception e){
String defaultMessage = null;
//处理在类校验产生的异常
if (e instanceof MethodArgumentNotValidException) {
MethodArgumentNotValidException me = (MethodArgumentNotValidException) e;
defaultMessage = me.getBindingResult().getFieldError().getDefaultMessage();
}
//处理参数校验产生的异常
if (e instanceof ConstraintViolationException) {
ConstraintViolationException ce = (ConstraintViolationException) e;
Set<ConstraintViolation<?>> constraintViolations = ce.getConstraintViolations();
if(!CollectionUtils.isEmpty(constraintViolations)){
StringBuilder msgBuilder = new StringBuilder();
for(ConstraintViolation constraintViolation :constraintViolations){
msgBuilder.append(constraintViolation.getMessage()).append(",");
}
defaultMessage = msgBuilder.toString();
if(defaultMessage.length()>1){
defaultMessage = defaultMessage.substring(0,defaultMessage.length()-1);
}
return ResultDTO.errorOf(defaultMessage);
}
}
return ResultDTO.errorOf(defaultMessage);
}
文章作者: Hobo
文章链接: https://hobo-clh.github.io/2020/05/18/Validated%E5%8F%82%E6%95%B0%E6%A0%A1%E9%AA%8C/
版权声明: 本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来自 Hobo's blog
打赏
  • 微信
    微信
  • 支付宝
    支付宝

评论