@valid分组校验,手动触发valid校验

业务场景:同一个接口,不同的操作的时候,校验的字段是不同的。比如更改状态,对于请假申请审批和撤销,校验的字段不同的时候。
但是呢,常规的通过@valid的注解是无法满足的(请求的时候参数拦截,触发校验规则)。而我的业务场景必须进行手动触发@valid校验

废话不多说,下面直接展示思路与核心相关代码

1.设计思路

本质来说,常规@Valid不满足需求的原因就是:
1.同一个接口,根据type字段来进行触发不同的分组字段校验;
2.手动触发valid分组校验。
补充:我所说的常规@valid是指@Validated(value = {People.Student.class}),代码如下:

    /**
     * <p>@Description: 请求拦截-根据分组进行参数校验 </p >
     * <p>@param [people]</p >
     * <p>@return com.lzq.learn.domain.CommonResult</p >
     * <p>@throws </p >
     * <p>@date 14:37 14:37</p >
     */
    @PostMapping("validByGroup")
    public CommonResult validByGroup(@RequestBody @Validated(value = {
    
    People.Student.class}) People people) {
    
    
        System.out.println("People 参数:" + people);
        CommonResult commonResult = CommonResult.success(people);
        return commonResult;
    }

2.完整代码展示

2.1 controller代码

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.lzq.learn.domain.CommonResult;
import com.lzq.learn.domain.People;
import com.lzq.learn.domain.User;
import org.apache.poi.ss.formula.functions.T;
import org.springframework.beans.factory.annotation.Autowired;
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.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.validation.*;
import javax.validation.groups.Default;
import java.util.List;
import java.util.Set;

@RestController
@RequestMapping("valid")
public class TestValidController {
    
    


    @Autowired
    private Validator validator;

    /**
     * <p>@Description: 测试手动触发valid分组校验</p >
     * <p>@param [userList]</p >
     * <p>@return com.lzq.learn.domain.CommonResult</p >
     * <p>@throws </p >
     * <p>@date 15:21 15:21</p >
     */
    @PostMapping("validByHand")
    public CommonResult validByHand(@RequestBody People people) {
    
    
        System.out.println("people  参数:" + people);
        String validResult = "";
        List<Class> groupList = CollUtil.newArrayList(Default.class);
        if (StrUtil.equals("student", people.getType())) {
    
    
            groupList.add(People.Student.class);
        }
        if (StrUtil.equals("teacher", people.getType())) {
    
    
            groupList.add(People.Teacher.class);
        }
        Class[] groupArray = groupList.toArray(new Class[groupList.size()]);
        // 写法1:使用ValidatorFactory 获取Validator对象
        Set<ConstraintViolation<People>> violations = Validation.buildDefaultValidatorFactory().getValidator().validate(people, groupArray);
        // 写法2:从springboot上下文 获取Validator对象
        // Set<ConstraintViolation<People>> violations = validator.validate(people, groupArray);
        validResult = getResultFromValidate(violations);
        CommonResult commonResult = CommonResult.success(validResult);
        return commonResult;
    }


    /**
     * <p>@Description: 对于valid校验结果进行转换结果</p >
     * <p>@param </p >
     * <p>@return </p >
     * <p>@throws </p >
     * <p>@date 13:43 13:43</p >
     */
    public static <T> String getResultFromValidate(Set<ConstraintViolation<T>> violations) {
    
    
        if (CollUtil.isEmpty(violations)) {
    
    
            return "pass";
        }
        StringBuilder sb = new StringBuilder();
        for (ConstraintViolation<T> violation : violations) {
    
    
            sb.append(violation.getPropertyPath()).append(": ").append(violation.getMessage()).append("\n");
        }
        return sb.toString();
    }
    
}

注意:我们需要手动触发,则在controller的接口中,不能加上@valid(或@validated)注解,不然又会走请求拦截,根本走不到我们的controller代码中!

2.2 实体类People代码


import lombok.*;

import javax.validation.constraints.NotBlank;
import javax.validation.constraints.NotNull;
import java.io.Serializable;

/**
 * @author x
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
@ToString
public class People implements Serializable {
    
    

    /**     自定义校验分组        **/
    public interface Student{
    
    }
    public interface Teacher{
    
    }

    private Long id;

    @NotNull(message = "年龄不能为空")
    private Integer age;

    @NotBlank(message = "个人名称不能为空")
    private String myName;

    @NotBlank(message = "学生名称不能为空", groups = Student.class)
    private String studentName;

    @NotBlank(message = "教师名称不能为空", groups = Teacher.class)
    private String teacherName;

    // dto 字段
    private String type;
}

注意:对于本实体类来说,age和myName字段没有指定分组,其实它们两个被指定到了Default.class分组(javax.validation.groups.Default)

3.postMan接口测试

为了简要概述,本文只针对于type=student的情况进行测试分析,按照上述代码,当type=student的时候,会进行Default和Student的分组校验,如下图postman接口测试

3.1 type=student,不传default分组字段

在这里插入图片描述

3.1 type=student,不传student分组字段

在这里插入图片描述

3.1 type=student,不传teacher分组字段

在这里插入图片描述

3.1 type=student,全部分组字段都传

在这里插入图片描述

如图,发现我们编写的代码是正确的,实现了在任意代码执行顺序中,根据type来进行自定义分组校验。但是controller接口一定不要加@valid或@validated注解,不然请求会被拦截,根本走不到我们的自定义方法处。

本博客也只是更改了valid参数校验的执行时机,其实上述代码只是提供最基本的解决方案,后续可以优化为在方法上加上自定义注解,实现aop参数校验拦截!抽象出来这种行为,避免重复的if else代码冗余。

猜你喜欢

转载自blog.csdn.net/lzq2357639195/article/details/131259458
今日推荐