SpringBoot Hibernate Validation 分组校验

提出问题

  • 添加用户:不需要传 id,因为 id 是由后端生成的,所以添加时,不需要校验 id 是否为空

  • 删除用户、修改用户、根据id显示用户信息:必须传 id,否则无法实现修改用户,所以,需要校验 id 是否为空

问题:在接收参数的 User 实体类的 id 属性上添加 NotNull,无法实现上述功能:

  • 添加用户时,不校验 id
  • 删除用户、修改用户、根据id显示用户信息,校验 id

解决

可以 定义分组,如下:

  • Add 分组

  • Update 分组

在 Add 分组时,校验 id,在 Update 分组时,不需要校验 id

案例

定义分组

所谓分组,其实就是 接口

package top.malaoshi.netdisk.validation;

/**
 * 定义分组
 */
public class ValidGroup {

    // 新增分组
    public interface Insert  {}

    // 更新分组
    public interface Update {}

    // 删除分组
    public interface Delete {}

}

测试-对实体类进行校验

实体类

在校验注解上添加 groups 属性指定分组

package std;
import javax.validation.constraints.NotNull;
import javax.validation.constraints.Size;
public class User {
    // 关键:只有在 Delete、Update 分组时,才生效
    // 关键:必须为 Long 类型,包装类型才能是 null
    @NotNull(message = "ID不能为空",groups = {ValidGroup.Delete.class,ValidGroup.Update.class})
    private Long id;


    @NotNull(message = "登录名不能为空")
    @Size(min = 3, max = 16, message = "登录名长度必须在3-16之间")
    private String username;
    @NotNull(message = "密码不能为空")
    @Size(min = 5, max = 16, message = "密码长度必须在5-16之间")
    private String password;
    public Long getId() {
        return id;
    }
    public void setId(Long id) {
        this.id = id;
    }
    public String getUsername() {
        return username;
    }
    public void setUsername(String username) {
        this.username = username;
    }
    public String getPassword() {
        return password;
    }
    public void setPassword(String password) {
        this.password = password;
    }
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", username='" + username + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}

分组校验

校验生效方式1(推荐)

环境:springboot 2.2.2 版本

形参是 bean 类型,形参前面只需要加 @Validated 注解,并要指定 分组,否则 不会对该形参进行校验

package top.malaoshi.netdisk.ctrl;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.malaoshi.netdisk.service.LoginSrvImpl;
import top.malaoshi.netdisk.vo.JsonResult;
import top.malaoshi.netdisk.vo.User;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

@RestController
@RequestMapping("/user")
public class UserCtrl {

    @PostMapping("/delete")
    public JsonResult delete( @Validated(ValidGroup.Delete.class) @RequestBody User user) throws Exception {
        return JsonResult.success("删除成功!");
    }

}

校验生效方式2

环境:springboot 2.2.2 版本

同时满足下面两个条件,才会 对形参进行校验:

  • 类名上加 @Validated 注解,或者方法名上加 @Validated 注解,并要 指定分组
    注意:由于指定分组,所以不要在 类名上加 @Validated,因为表示整个类的方法都使用 该分组校验,会造成混乱

  • 形参是 bean 类型,前面加 @Valid 注解

package top.malaoshi.netdisk.ctrl;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.malaoshi.netdisk.service.LoginSrvImpl;
import top.malaoshi.netdisk.vo.JsonResult;
import top.malaoshi.netdisk.vo.User;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

@RestController
public class LoginCtrl {

    @PostMapping("/login")
    @Validated(ValidGroup.Delete.class)
    public JsonResult login(@Valid @RequestBody User user) throws Exception {
        return JsonResult.success("删除成功!");
    }

}

使用默认分组校验

登录时,必须输入用户名、密码,校验注解没有指定分组,如下:

@NotNull(message = "登录名不能为空")
@Size(min = 3, max = 16, message = "登录名长度必须在3-16之间")
private String username;
@NotNull(message = "密码不能为空")
@Size(min = 5, max = 16, message = "密码长度必须在5-16之间")
private String password;

所以在 @Validated 注解中,不指定分组,就会对这些注解进行校验,如下:

package top.malaoshi.netdisk.ctrl;

import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import top.malaoshi.netdisk.service.LoginSrvImpl;
import top.malaoshi.netdisk.vo.JsonResult;
import top.malaoshi.netdisk.vo.User;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;

@RestController
public class LoginCtrl {

    @PostMapping("/login")
    public JsonResult login(HttpSession session, @Validated @RequestBody User user) throws Exception {
        return JsonResult.success("登录成功!");
    }

}

Default分组

校验注解(如: @NotBlank ) 默认都属于 javax.validation.groups.Default.class 分组

所以校验时,不指定分组, @NotBlank 等校验注解也会生效

分组继承 Default

如果 分组接口 继承 javax.validation.groups.Default,在校验时,不指定分组,也会 进行校验

缺点: 校验时 不指定分组,不但会 校验未指定分组的字段,也会 校验指定分组的字段,可能会引发混乱

分组

分组都 extends Default

public class ValidGroup {

    // 新增分组
    public interface Insert extends Default {}

    // 更新分组
    public interface Update extends Default {}

    // 删除分组
    public interface Delete extends Default {}

}

校验注解

下面两个注解是等价的:

分组没有继承 Default(推荐)

如果 分组接口 没有继承 javax.validation.groups.Default,在校验时,不指定分组,就 不会进行校验

好处:不会引发混乱,更加灵活

校验时不指定分组

没有指定分组,会校验没有分组的 username、password,不会校验 指定分组的 id

@Validated

仅校验 Delete 分组

指定 Delete 分组,只id校验生效

@Validated(ValidGroup.Delete.class)

同时校验 Delete、Default 分组

指定 Delete、Default 分组,id校验生效,其他未指定分组的校验(username、password)也生效

@Validated(value = {ValidGroup.Delete.class,Default.class})

参考:
https://zhuanlan.zhihu.com/p/447694886
https://blog.csdn.net/u011738045/article/details/118539706


原文出处:/show_1IX76HjmvjIe.html