SpringBoot系列之自定义枚举类的数据校验注解
业务场景:数据校验,需要对枚举类型的数据传参,进行数据校验,不能随便传参。拓展,支持多个参数的枚举数据校验
在网上找到很多参考资料,所以本博客基于这些博客进行拓展补充,ok,先建一个springboot项目
项目环境:
JDK 1.8
SpringBoot2.2.1
Maven 3.2+
开发工具
IntelliJ IDEA
smartGit
创建一个SpringBoot Initialize项目
选择jdk8
选择lombok和spring web
项目建好之后,在maven配置文件加上:
<dependency>
<groupId>javax.validation</groupId>
<artifactId>validation-api</artifactId>
<version>2.0.1.Final</version>
</dependency>
这里可以先写个例子进行验证,写个枚举类,表示多种支付类型,比如支付宝执法,微信支付等等
package com.example.common.util.validator.sample.enums;
public enum PayTypeEnum {
Cash("1","现金"),
Alipay("2","支付宝"),
WeChatPay("3","微信支付"),
BankCard("4","银行卡支付"),
CreditCard("5","信用卡支付");
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<? extends Enum<?>> enumClass();
String enumMethod();
class Validator implements ConstraintValidator<EnumValueValidator , Object> {
private Class<? extends Enum<?>> 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://blog.csdn.net/u014427391/article/details/121980957
内容来源于网络,如有侵权,请联系作者删除!