SpringBoot系列之自定义枚举类的数据校验注解

SpringBoot系列之自定义枚举类的数据校验注解,第1张

SpringBoot系列之自定义枚举类的数据校验注解

SpringBoot系列之自定义枚举类的数据校验注解
业务场景:数据校验,需要对枚举类型的数据传参,进行数据校验,不能随便传参。拓展,支持多个参数的枚举数据校验

在网上找到很多参考资料,所以本博客基于这些博客进行拓展补充,ok,先建一个springboot项目

项目环境:

  • JDK 1.8
  • SpringBoot2.2.1
  • Maven 3.2+
  • 开发工具
    • IntelliJ IDEA
    • smartGit
      创建一个SpringBoot Initialize项目

      选择jdk8

      选择lombok和spring web

      项目建好之后,在maven配置文件加上:

     javax.validation
     validation-api
     2.0.1.Final
 

这里可以先写个例子进行验证,写个枚举类,表示多种支付类型,比如支付宝执法,微信支付等等

package com.example.common.util.validator.sample.enums;

public enum PayTypeEnum {

    Cash("1","现金"),
    Alipay("2","支付宝"),
    WeChatPay("3","微信支付"),
    BankCard("4","yhk支付"),
    CreditCard("5","xyk支付");

    PayTypeEnum(String code , String desc) {
        this.code = code;
        this.desc = desc;
    }

    private String code;
    private String desc;

    public String getCode() {
        return code;
    }
    public void setCode(String code) {
        this.code = code;
    }
    public String getDesc() {
        return desc;
    }
    public void setDesc(String desc) {
        this.desc = desc;
    }

}

因为要校验传入参数是否为枚举类里的类型,可以在PayTypeEnum类里新增一个校验方法

public static boolean isValuevalid(String value) {
    if(!StringUtils.isEmpty(value)){
        for (PayTypeEnum enumObj : PayTypeEnum.values()) {
            if (enumObj.getCode().equals(value)) {
                return true;
            }
        }
        return false;
    }
    return true;
}

这里是加一下自定义的元注解类,然后通过@Constraint指定具体的校验类,通过反射机制获取对应的方法,比如isValuevalid这个方法

package com.example.common.util.validator;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import javax.validation.Payload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;


@Target({ ElementType.METHOD, ElementType.FIELD, ElementType.ANNOTATION_TYPE })
@Retention(RetentionPolicy.RUNTIME)
@Constraint(validatedBy = EnumValuevalidator.Validator.class)
public @interface EnumValuevalidator {

    Logger log = LoggerFactory.getLogger(EnumValuevalidator.class);

    String message() default "参数有误";

    Class> enumClass();

    String enumMethod();
    
    class Validator implements ConstraintValidator {
        private Class> enumClass;
        private String enumMethod;

        @Override
        public void initialize(EnumValuevalidator constraintAnnotation) {
            enumMethod = constraintAnnotation.enumMethod();
            enumClass = constraintAnnotation.enumClass();
        }
        @Override
        public boolean isValid(Object o, ConstraintValidatorContext constraintValidatorContext) {
          // 值没传的情况,直接返回true
            if (StringUtils.isEmpty(o)) return Boolean.TRUE;
            if (enumClass == null || StringUtils.isEmpty(enumMethod)) return Boolean.TRUE;
            Class vclass = o.getClass();
            try {
            // 反射机制获取具体的校验方法
                Method method = enumClass.getMethod(enumMethod,vclass);
                if (!Boolean.TYPE.equals(method.getReturnType()) &&
                        !Boolean.class.equals(method.getReturnType())) {
                    throw new RuntimeException("校验方法不是布尔类型!");
                }
                if (!Modifier.isStatic(method.getModifiers())) {
                    throw new RuntimeException("校验方法不是静态方法!");
                }
                method.setAccessible(true);
                // 调用具体的方法
                Boolean res = (Boolean) method.invoke(null,o);
                return res != null ? res : false;
            } catch (NoSuchMethodException e) {
                log.error("NoSuchMethodException:{}" ,e);
                throw new RuntimeException(e);
            } catch (IllegalAccessException e) {
                log.error("IllegalAccessException:{}" ,e);
                throw new RuntimeException(e);
            } catch (InvocationTargetException e) {
                log.error("InvocationTargetException:{}" ,e);
                throw new RuntimeException(e);
            }
        }
    }

}

具体的bean类,加上@EnumValuevalidator(enumClass = PayTypeEnum.class , enumMethod = "isStrsValid" , message = "支付类型校验有误")指向具体的枚举类和校验方法

package com.example.common.util.validator.sample.model;

import com.example.common.util.validator.EnumValuevalidator;
import com.example.common.util.validator.sample.enums.PayTypeEnum;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.ToString;
import lombok.experimental.SuperBuilder;

import javax.validation.constraints.NotNull;

@Data
@AllArgsConstructor
@NoArgsConstructor
@SuperBuilder(toBuilder = true)
@ToString
public class ShopOrder {

    @EnumValuevalidator(enumClass = PayTypeEnum.class , enumMethod = "isStrsValid" , message = "支付类型校验有误")
    @NotNull(message = "支付类型必须传")
    private String payType;

}

加上@Validated开启校验

package com.example.common.util.validator.sample.controller;

import com.example.common.util.validator.sample.model.ShopOrder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api/orders")
public class SampleController {

    @PostMapping
    public String saveOrder(@Validated ShopOrder shopOrder) {
        return shopOrder.toString();
    }
}

校验出错返回:

{
    "timestamp": "2021-12-16T10:01:27.801+0000",
    "status": 400,
    "error": "Bad Request",
    "errors": [
        {
            "codes": [
                "EnumValuevalidator.shopOrder.payType",
                "EnumValuevalidator.payType",
                "EnumValuevalidator.java.lang.String",
                "EnumValuevalidator"
            ],
            "arguments": [
                {
                    "codes": [
                        "shopOrder.payType",
                        "payType"
                    ],
                    "arguments": null,
                    "defaultMessage": "payType",
                    "code": "payType"
                },
                "com.example.common.util.validator.sample.enums.PayTypeEnum",
                {
                    "defaultMessage": "isStrsValid",
                    "arguments": null,
                    "codes": [
                        "isStrsValid"
                    ]
                }
            ],
            "defaultMessage": "支付类型校验有误",
            "objectName": "shopOrder",
            "field": "payType",
            "rejectedValue": "2,111",
            "bindingFailure": false,
            "code": "EnumValuevalidator"
        }
    ],
    "message": "Validation failed for object='shopOrder'. Error count: 1",
    "path": "/api/orders"
}

拓展,这里要求传payType类型,也就是支持多选的情况,参数payType=2,111,这里要修改校验方法:

public static boolean isStrsValid(String value) {
    if (!value.contains(","))
        return isValuevalid(value);
    String[] arr = StringUtils.split(value , ",");
    for (String s : arr) {
        if (!isValuevalid(s)) {
            return false;
        }
    }
   return true;
}

加上注解,enumMethod 改成isStrsValid

@EnumValuevalidator(enumClass = PayTypeEnum.class , enumMethod = "isStrsValid" , message = "支付类型校验有误")

调用这个接口:

http://127.0.0.1:8080/api/orders?payType=2,111
  • https://www.baeldung.com/javax-validations-enums
  • https://blog.csdn.net/xiaojin21cen/article/details/102622771

欢迎分享,转载请注明来源:内存溢出

原文地址: http://outofmemory.cn/zaji/5671480.html

(0)
打赏 微信扫一扫 微信扫一扫 支付宝扫一扫 支付宝扫一扫
上一篇 2022-12-16
下一篇 2022-12-16

发表评论

登录后才能评论

评论列表(0条)

保存