java后端参数默认值添加枚举_利用自定义Validator和枚举类来限定接口的入参

本文介绍了如何在Java后端使用自定义Validator和枚举来限定接口入参的范围,避免业务代码和校验代码耦合。通过创建自定义注解`@EnumCheck`,配合枚举工具类`EnumUtil`,可以检查参数是否在预定义的枚举范围内,提高代码的优雅性和可维护性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

趁热记录下,给未来的自己

0. 前言

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

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

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

1. 架构图

192e66fe377a77209f9fcedb0be67dee.png

模块说明:

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成功后,进入后续的业务逻辑

2. 代码说明

2.1 JenkinsProcessBuildReqDTO.java

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

@Data

public class JenkinsProcessBuildReqDTO{

/** * 部署环境 */

@EnumCheck(message = "environment输入有误", enumClass = JenkinsProcessEnum.class)

private String environment;

}

复制代码

2.2 JenkinsProcessEnum.java

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

import lombok.Getter;

@Getter

public enum JenkinsProcessEnum{

/** * sit 环境 */

DEPLOY_SIT("0", "SIT", "sit 环境"),

/** * uat 环境 */

DEPLOY_UAT("1", "UAT", "uat 环境"),

/** * sit 和 uat 环境 */

DEPLOY_SIT_UAT("2", "SIT_UAT", "sit 和 uat 环境"),

;

private String code;

private String name;

private String desc;

JenkinsProcessEnum(String code, String name, String desc) {

this.code = code;

this.name = name;

this.desc = desc;

}

}

复制代码

2.3 EnumUtil.java

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

@Slf4j

public class EnumUtil{

/** * * @author arkMon * @date 14:22 2021/2/23 * @param clazz 传入的枚举类名 * @param getEnumMethodName 传入的枚举类clazz中的方法名称 * @param enumParameter 枚举参数 * @return T 具体的枚举值 或者 null */

public static > T getEnumByParameter(Class clazz, String getEnumMethodName, Object enumParameter){

T result = null;

try{

//Enum接口中没有values()方法,我们仍然可以通过Class对象取得所有的enum实例

T[] arr = clazz.getEnumConstants();

//获取定义的方法

Method targetMethod = clazz.getDeclaredMethod(getEnumMethodName);

if (targetMethod == null) {

log.error("getEnumMethodName=" + getEnumMethodName + " 不存在");

return null;

}

Object typeVal;

//遍历枚举定义

for(T entity:arr){

if (enumParameter instanceof Integer) {

typeVal = Integer.valueOf(String.valueOf(targetMethod.invoke(entity)));

} else if (enumParameter instanceof String) {

//获取传过来方法的

typeVal = String.valueOf(targetMethod.invoke(entity)).replace(" ","");

//执行的方法的值等于参数传过来要判断的值

enumParameter = ((String) enumParameter).replace(" ", "");

} else {

log.error("传入的enumType不是Integer也不是String类型");

return null;

}

if(typeVal.equals(enumParameter)){

//返回这个枚举

result = entity;

break;

}

}

} catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException | NoSuchMethodException | SecurityException e) {

e.printStackTrace();

}

return result;

}

}

复制代码

2.4 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 @interface EnumCheck {

String message() default "{enum.value.invalid}"; // 错误信息 Class extends Enum>> enumClass(); // 枚举类 String enumMethodCode() default "getCode"; // 枚举校验方法 String enumMethodName() default "getName"; // 枚举校验方法 boolean allowNull() default false; // 是否允许为空 class Validator implements ConstraintValidator { private Class extends Enum>> enumClass; private String enumMethodCode; private String enumMethodName; private boolean allowNull; @Override public void initialize(EnumCheck enumValue) { enumMethodCode = enumValue.enumMethodCode(); enumMethodName = enumValue.enumMethodName(); enumClass = enumValue.enumClass(); allowNull = enumValue.allowNull(); } @Override public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) { if (value == null) { return allowNull; } if (enumClass == null) { return Boolean.TRUE; } JenkinsProcessEnum enumByParameter = EnumUtil.getEnumByParameter(JenkinsProcessEnum.class, enumMethodCode, value); if (enumByParameter != null) { return true; } JenkinsProcessEnum enumByParameter1 = EnumUtil.getEnumByParameter(JenkinsProcessEnum.class, enumMethodName, value); if (enumByParameter1 != null) { return true; } return false; } } }复制代码

Ref

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值