数据校验

109 阅读3分钟

自己想做什么?

当前端传入的数据会进入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使用步骤

  1. 导入相关包
<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常见注解

图片.png

项目开发中常见校验注解使用:

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;
}

注意

    1. 在controller层会对所以对vo层的属性进行校验,比如用户名没有传入值,则会报错
    1. 在controller层必需加入@valid注解才会对vo层参数进行校验
    1. 推荐使用统一的结果集返回,会更加规范,方便前端工作 减轻前端压力与工作量