自己想做什么?
当前端传入的数据会进入vo层进行自动数据校验,然后将数据校验不通过的原因(message)返回给前端,将校验不通过原因返回给前端对我来说是难点!
当我直接使用@valid注解时,当校验不通过时,后端返回给前端的数据为如下:
{
"timestamp": "2022-03-22T02:00:22.290+00:00",
"status": 400,
"error": "Bad Request",
"path": "/login"
}
解决方案
使用 @Valid 注解 + @RestControllerAdvice全局异常处理器处理参数验证
Valid理解
JSR303 是一套JavaBean参数校验的标准,它定义了很多常用的校验注解,我们可以直接将这些注解加在我们JavaBean的属性上面,就可以在需要校验的时候进行校验了。注解如下:
Hibernate validator 在JSR303的基础上对校验注解进行了扩展,扩展注解如下:
Spring validtor 同样扩展了jsr303,并实现了方法参数和返回值的校验
Spring 提供了MethodValidationPostProcessor类,用于对方法的校验
Valid使用步骤
- 导入相关包
<dependency>
<groupId>org.hibernate.validator</groupId>
<artifactId>hibernate-validator</artifactId>
</dependency>
2.在VO层的类中属性加入校验注解
必需加入@Valid注解,校验才会生效
@Data
public class UserVO {
@NotNull(message = "用户名不能为空")
@Size(min = 4, max = 10, message = "用户名长度4-10之间")
private String userName;
@NotNull(message = "密码不能为空")
@Size(min = 4, max = 10, message = "密码长度4-20之间")
private String password;
}
3.在controller层请求参数中加入 @RequestBody @Valid 对VO层闯入参数进行校验
@PostMapping("/login")
public UserVO login(@RequestBody @Valid UserVO userVO){
return userVO;
}
4.全局异常处理
@RestControllerAdvice
public class GlobalExceptionHandler {
@ResponseStatus(HttpStatus.BAD_REQUEST) //设置状态码为 400
@ExceptionHandler({MethodArgumentNotValidException.class})
public String paramExceptionHandler(MethodArgumentNotValidException e) {
BindingResult exceptions = e.getBindingResult();
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
// 判断异常中是否有错误信息,如果存在就使用异常中的消息,否则使用默认消息
if (exceptions.hasErrors()) {
//返回第一条错误信息
return exceptions.getAllErrors().get(0).getDefaultMessage();
}
}
return "请求参数错误";
}
}
Valid常见注解
项目开发中常见校验注解使用:
public class UserVo {
/**
* _id
*/
@Size(max = 24, min = 1, message = "用户id长度在1-24位之间")
private String id;
/**
* 用户名 1-10位 只能字母、数字、下划线、减号组成
*/
@Pattern(regexp = "^[a-zA-Z0-9_-]{1,10}$", message = "用户名由1-10位字母、数字、下划线、减号组成")
private String username;
/**
* 密码 密码6-50位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符
*/
@Pattern(regexp = "^.*(?=.{6,50})(?=.*\d)(?=.*[A-Z])(?=.*[a-z])(?=.*[!@#$%^&*? ]).*$",
message = "密码6-50位,包括至少1个大写字母,1个小写字母,1个数字,1个特殊字符")
private String password;
/**
* 性别
*/
@NotEmpty(message = "性别不能为空")
private GenderType gender;
/**
* 年龄 当数据库中年龄为空时,输出0
*/
@Min(value = 0, message = "年龄最小不能低于0岁")
@Max(value = 200, message = "年龄最大不能超过200岁")
private Integer age;
/**
* 电话号码
*/
@Pattern(regexp = "1[3578]\d{9} ")
private String phone;
/**
* 人生格言 长度在1-50之间
*/
@Size(min = 1, max = 50, message = "长度在1-50之间")
private String motto;
/**
* 邮箱
*/
@Email(message = "邮箱格式不正确")
private String email;
}
注意
-
- 在controller层会对所以对vo层的属性进行校验,比如用户名没有传入值,则会报错
-
- 在controller层必需加入@valid注解才会对vo层参数进行校验
-
- 推荐使用统一的结果集返回,会更加规范,方便前端工作 减轻前端压力与工作量