springboot整合spring Validated

spring Validated是基于java JSR303进一步封装,具有校验功能的框架,封装了原本的@Valid,但不同于@Valid的是他具有分组功能

依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
   	 <groupId>org.springframework.boot</groupId>
     <artifactId>spring-boot-starter-validation</artifactId>
 </dependency>

代码

数据校验需要在两个位置用到spring Validated的注解,一个是在请求参数的位置,一个是在实体类的位置。

请求参数:

参数需要使用@Validated注解标注,表示该参数需要被校验

  @GetMapping("/getAll")
    public UserVo getAll(@Validated UserVo userVo) {
        return userVo;
    }

实体类:

在属性位置标注上对应的注解比如 @NotEmpty(message = “用户名不为空”),表示name不能为空,为空白字符,长度不能为0

@Data
public class UserVo {
    @NotEmpty(message = "用户名不为空")
    private String name;
    @Min(value = 18,message = "年龄必须大于18岁")
    private String age;
    @Email(regexp = "^\\w+([-+.]\\w+)*@\\w+([-.]\\w+)*\\.\\w+([-.]\\w+)*$",message = "邮箱格式错误")
    private String email;
}

那如果我们需要对某些字段进行校验,或者按照某种条件进行校验,我们该怎么做呢?
那么我们就需要分组校验来进行
下面我们进行分组校验测试

分组校验

分组接口

先创建两个接口,这两个接口不需要任何内容,就只是用于分组标记

public interface IGroupA {
}
public interface IGroupB {
}

请求参数

我们在请求参数出设置校验标记,
@Validated({IGroupB.class})表示只有分组为IGroupB.class才进行校验,否则不校验

    @GetMapping("/getAll")
    public UserVo getAll(@Validated({IGroupB.class}) UserVo userVo) {
        return userVo;
    }

实体类:

groups = IGroupB.class表示将这个校验标记为IGroupB分组,如果controller不是IGroupB就不进行校验。否则就校验

@Data
public class UserVo {
    @NotEmpty(message = "用户名不为空", groups = IGroupA.class)
    private String name;
    //只有分组为IGroupB才进行校验
    @NotBlank
    @Min(value = 18, message = "年龄必须大于18岁", groups = {IGroupB.class})
    private String age;
    @NotBlank
    @Email(message = "邮箱格式错误", groups = {IGroupB.class})
    private String email;
}

如果访问,上面的结果是:name不会校验,age和email会进行校验。

那如果在请求参数处同时标记IGroupA.class,IGroupB.class会怎么样呢?

 @GetMapping("/getAll")
    public UserVo getAll(@Validated({IGroupA.class,IGroupB.class}) UserVo userVo) {
        return userVo;
    }

答案就是:三个都会进行校验,那如果我们对一个进行校验后发现不通过,后面的就不需要进行校验该怎么办呢?
那么我们可以采用组序列,在使用组序列验证的时候,如果序列前边的组验证失败,则后面的组将不再给予验证。

组序列

创建一个接口:IGroup

在上面标注注解,@GroupSequence({Default.class, IGroupA.class, IGroupB.class})

import javax.validation.GroupSequence;
import javax.validation.groups.Default;

@GroupSequence({Default.class, IGroupA.class, IGroupB.class})
public interface IGroup {
}

实体类

对实体类的属性上同时标注上groups = IGroupB.class和groups = IGroupA.class)

@Data
public class UserVo {
    @NotEmpty(message = "用户名不为空", groups = IGroupA.class)
    private String name;
    //只有分组为IGroupB才进行校验
    @Min(value = 18, message = "年龄必须大于18岁", groups = {IGroupB.class})
    private String age;
    @Email(message = "邮箱格式错误", groups = {IGroupB.class})
    private String email;
}

请求参数

在请求参数处标注一个@Validated({IGroup.class})注解

	GetMapping("/getAll")
    public UserVo getAll(@Validated({IGroup.class}) UserVo userVo) {
        return userVo;
    }

再进行测试;
如果我们三个参数都填错,那么按照顺序,他只会校验name后就不再进行校验。
那如果我们实体类中是以另一个实体类为属性,我们能对他进行校验吗?
那当然可以。

嵌套校验

创建另一个实体类Teacher

import javax.validation.constraints.Min;
import javax.validation.constraints.NotEmpty;
@Data
public class Teacher {

    @NotEmpty(message = "老师姓名不能为空")
    private String teacherName;
    @Min(value = 1, message = "至少为1")
    private int type;
}

实体类

将其封装到UserVo中

@Data
public class UserVo {
    @NotEmpty(message = "用户名不为空", groups = IGroupA.class)
    private String name;
    //只有分组为IGroupB才进行校验
    @Min(value = 18, message = "年龄必须大于18岁", groups = IGroupB.class)
    private String age;
    @Email(message = "邮箱格式错误", groups = IGroupB.class)
    private String email;
    @NotNull(message = "用户不能为空")
    @Size(min = 1,message = "至少有一个用户")
    private List<Teacher>  teachers;
}

请求参数

我们访问前端接口测试

@GetMapping("/getAll")
    public UserVo getAll(@Validated({IGroup.class}) UserVo userVo) {
        return userVo;
    }

参数为:
在这里插入图片描述
发现只校验了NotNull, 和 Size,并没有对teacher信息里面的字段进行校验,因为我们type给的0,那么应该校验发出校验,
这里teacher中的type明显是不符合约束要求的,但是能检测通过,是因为在student中并没有做 嵌套校验
在这里插入图片描述

解决办法

可以在teacherBeans中加上 @Valid,

@Data
public class UserVo {
    @NotEmpty(message = "用户名不为空", groups = IGroupA.class)
    private String name;
    //只有分组为IGroupB才进行校验
    @Min(value = 18, message = "年龄必须大于18岁", groups = IGroupB.class)
    private String age;
    @Email(message = "邮箱格式错误", groups = IGroupB.class)
    private String email;
    @Valid
    @NotNull(message = "用户不能为空")
    @Size(min = 1,message = "至少有一个用户")
    private List<Teacher>  teachers;
}

我们再次测试
发现结果对teacher类中的字段进行了校验。测试成功

将@Validated的返回信息通过全局异常类同意处理

先创建一个全局异常类

/**
 * 统一异常处理
 */
@RestControllerAdvice
public class GlobalExceptionHandler {
/**
     * jsr303校验异常
     * @param e
     * @return
     */
    @ExceptionHandler({MethodArgumentNotValidException.class})
    public R validatedException(MethodArgumentNotValidException e){
        BindingResult bindingResult = e.getBindingResult();
        String field = bindingResult.getFieldError().getField();
        if("mobile".equals(field)){
            return R.error().code("30").message(bindingResult.getFieldError().getDefaultMessage());
        }else{
            return R.error().code("31").message(bindingResult.getFieldError().getDefaultMessage());
        }
    }
}

参数vo实例类

@Data
public class RegisterVo implements Serializable {
    //手机号
    @NotBlank(message = "手机号码不能为空")
    @Pattern(regexp = "^[1][3,4,5,7,8,9][0-9]{9}$",message = "手机号码不正确")
    private String mobile;
    //密码

    @NotBlank(message = "密码不能为空")
    private String password;
    //@NotBlank校验字符不为null,不为空字符串(" "),字符长度不为0("")
    //@NotEmpty校验字符不为null,字符长度不为0("")
    @NotBlank(message = "昵称不能为空")
    private String nickname;
}
    @PostMapping("register")
    public R register(@RequestBody @Validated RegisterVo registerVo){
        memberService.register(registerVo);
        return R.ok().message("注册成功");
    }

可用注解说明

@Null 限制只能为null
@NotNull 限制必须不为null
@AssertFalse 限制必须为false
@AssertTrue 限制必须为true
@DecimalMax(value) 限制必须为一个不大于指定值的数字
@DecimalMin(value) 限制必须为一个不小于指定值的数字
@Digits(integer,fraction) 限制必须为一个小数,且整数部分的位数不能超过integer,小数部分的位数不能超过fraction
@Future 限制必须是一个将来的日期
@Max(value) 限制必须为一个不大于指定值的数字
@Min(value) 限制必须为一个不小于指定值的数字
@Past 限制必须是一个过去的日期
@Pattern(value) 限制必须符合指定的正则表达式
@Size(max,min) 限制字符长度必须在min到max之间
@Past 验证注解的元素值(日期类型)比当前时间早
@NotEmpty 验证注解的元素值不为null且不为空(字符串长度不为0、集合大小不为0)
@NotBlank 验证注解的元素值不为空(不为null、去除首位空格后长度为0),不同于@NotEmpty,@NotBlank只应用于字符串且在比较时会去除字符串的空格
@Email 验证注解的元素值是Email,也可以通过正则表达式和flag指定自定义的email格式

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值