首页>>后端>>Spring->利用自定义Validator和枚举类来限定接口的入参

利用自定义Validator和枚举类来限定接口的入参

时间:2023-11-29 本站 点击:0

前言

Spring Validation 作为一个参数验证框架,本身提供的注解已经很强大了,能覆盖大部分业务场景需求,比如:@NotNull, @NotBlank, @Min, @Max, @Size, @Email等等。

但是对于更加复杂的业务场景,Spring Validation 自带的这些注解就无能为力了,比如,假设有个接口,其中的一个入参是 String 类型,由于业务需要,该入参值的范围只能在一个允许的 list 中,不在范围中的传入值,直接返回异常。

常规做法是在业务代码里对入参做一层逻辑判断,但是这样做会导致业务代码和校验代码耦合,且开发效率不高,代码十分不美观。 更加优雅的做法是自定义一个 validator 配合枚举类,来实现这个需求。

架构图

模块说明:

1: DTO - 接收入参的DTO类,使得收到的参数变成一个对象

1-1: private String para 对象加了 @EnumCheck 注解,表示 para 需要被校验

1-2: private String para1 对象未加 @EnumCheck 注解,表示 para1 不需要被校验

2: EnumCheck - 是一个注解类,需要在该类里实现自定义注解

3: EnumUtil - 枚举工具类,通过传入一个枚举参数,判断该参数是否在指定的枚举里,存在则返回枚举,不存在返回null

4: Enum Class - 用户定义的枚举类,用于存放入参的范围

5: 异常逻辑 - 当EnumCheck失败后,进入异常逻辑

6: 后续业务逻辑 - 当EnumCheck成功后,进入后续的业务逻辑

代码说明

JenkinsProcessBuildReqDTO.java

入参用该DTO类接收,在该类中定义需要被自定义validate的一个或者多个字段。

@DatapublicclassJenkinsProcessBuildReqDTO{/***部署环境*/@EnumCheck(message="environment输入有误",enumClass=JenkinsProcessEnum.class)privateStringenvironment;}

JenkinsProcessEnum.java

用户自定义的枚举类,用于存放入参的范围,如该枚举类中,限定了 JenkinsProcessBuildReqDTO.environment 的范围在 DEPLOY_SIT, DEPLOY_UAT, DEPLOY_SIT_UAT 这三个枚举里。

importlombok.Getter;@GetterpublicenumJenkinsProcessEnum{/***sit环境*/DEPLOY_SIT("0","SIT","sit环境"),/***uat环境*/DEPLOY_UAT("1","UAT","uat环境"),/***sit和uat环境*/DEPLOY_SIT_UAT("2","SIT_UAT","sit和uat环境"),;privateStringcode;privateStringname;privateStringdesc;JenkinsProcessEnum(Stringcode,Stringname,Stringdesc){this.code=code;this.name=name;this.desc=desc;}}

EnumUtil.java

该类中提供了一个方法getEnumByParameter: 通过传入一个枚举参数 enumParameter,判断该参数是否在指定的枚举 clazz 里。存在则返回 enumParameter 对应的枚举,不存在返回 null

@Slf4jpublicclassEnumUtil{/****@authorarkMon*@date14:222021/2/23*@paramclazz传入的枚举类名*@paramgetEnumMethodName传入的枚举类clazz中的方法名称*@paramenumParameter枚举参数*@returnT具体的枚举值或者null*/publicstatic<TextendsEnum<T>>TgetEnumByParameter(Class<T>clazz,StringgetEnumMethodName,ObjectenumParameter){Tresult=null;try{//Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有的enum实例T[]arr=clazz.getEnumConstants();//获取定义的方法MethodtargetMethod=clazz.getDeclaredMethod(getEnumMethodName);if(targetMethod==null){log.error("getEnumMethodName="+getEnumMethodName+"不存在");returnnull;}ObjecttypeVal;//遍历枚举定义for(Tentity:arr){if(enumParameterinstanceofInteger){typeVal=Integer.valueOf(String.valueOf(targetMethod.invoke(entity)));}elseif(enumParameterinstanceofString){//获取传过来方法的typeVal=String.valueOf(targetMethod.invoke(entity)).replace("","");//执行的方法的值等于参数传过来要判断的值enumParameter=((String)enumParameter).replace("","");}else{log.error("传入的enumType不是Integer也不是String类型");returnnull;}if(typeVal.equals(enumParameter)){//返回这个枚举result=entity;break;}}}catch(IllegalAccessException|IllegalArgumentException|InvocationTargetException|NoSuchMethodException|SecurityExceptione){e.printStackTrace();}returnresult;}}

EnumCheck.java

自定义验证器的注解。在该注解下的validator类中的isValid方法里,实现自定义验证器的逻辑:

判断传入的参数是否可以通过枚举里的code或者name,用getEnumByParameter方法找到其对应的枚举,能找到返回true,不能找到返回false

@Target({ElementType.METHOD,ElementType.FIELD,ElementType.ANNOTATION_TYPE})@Retention(RetentionPolicy.RUNTIME)@Constraint(validatedBy=EnumCheck.Validator.class)public@interfaceEnumCheck{Stringmessage()default"{enum.value.invalid}";//错误信息Class<?extendsEnum<?>>enumClass();//枚举类Class<?>[]groups()default{};Class<?extendsPayload>[]payload()default{};StringenumMethodCode()default"getCode";//枚举校验方法StringenumMethodName()default"getName";//枚举校验方法booleanallowNull()defaultfalse;//是否允许为空classValidatorimplementsConstraintValidator<EnumCheck,Object>{privateClass<?extendsEnum<?>>enumClass;privateStringenumMethodCode;privateStringenumMethodName;privatebooleanallowNull;@Overridepublicvoidinitialize(EnumCheckenumValue){enumMethodCode=enumValue.enumMethodCode();enumMethodName=enumValue.enumMethodName();enumClass=enumValue.enumClass();allowNull=enumValue.allowNull();}@OverridepublicbooleanisValid(Objectvalue,ConstraintValidatorContextconstraintValidatorContext){if(value==null){returnallowNull;}if(enumClass==null){returnBoolean.TRUE;}JenkinsProcessEnumenumByParameter=EnumUtil.getEnumByParameter(JenkinsProcessEnum.class,enumMethodCode,value);if(enumByParameter!=null){returntrue;}JenkinsProcessEnumenumByParameter1=EnumUtil.getEnumByParameter(JenkinsProcessEnum.class,enumMethodName,value);if(enumByParameter1!=null){returntrue;}returnfalse;}}}

Ref

使用spring validation完成数据后端校验

Java Bean Validation 最佳实践

作者:arkMon


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:/Spring/309.html