Java中枚举类型的校验

最近项目中用到了一些枚举类,而接口API中提供的是String类型来接收,这样的话,调用方随便传什么,如果传的并不是后台定义的枚举类型,那么处理起来肯定会有问题。所以我们需要对调用方传来的枚举进行校验。

简单粗暴的方法就是,拿传入的参数跟枚举类型一个个比较,直到找到相同的才认为输入的值合法。这样的话需要写很多的if else来判断。那有没有优雅点的处理方式呢?

之前写过一篇通过注解校验参数的博文,如下:

https://blog.csdn.net/Lieforlove/article/details/90271377

参考这种方式,我们可以自定义一个注解,用来校验枚举类型。具体做法如下:

package com.test.utils;

import javax.validation.Constraint;
import javax.validation.ConstraintValidator;
import javax.validation.ConstraintValidatorContext;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import javax.validation.Payload;
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 = EnumValue.Validator.class)
public @interface EnumValue {

    String message() default "{enum.value.invalid}"; // 错误信息

    Class<?>[] groups() default {};

    Class<? extends Payload>[] payload() default {};

    Class<? extends Enum<?>> enumClass(); // 枚举类

    String enumMethod() default "isValidEnum"; // 枚举校验方法

    boolean allowNull() default false; // 是否允许为空

    class Validator implements ConstraintValidator<EnumValue, Object> {

        private Class<? extends Enum<?>> enumClass;
        private String enumMethod;
        private boolean allowNull;

        @Override
        public void initialize(EnumValue enumValue) {
            enumMethod = enumValue.enumMethod();
            enumClass = enumValue.enumClass();
            allowNull = enumValue.allowNull();
        }

        @Override
        public boolean isValid(Object value, ConstraintValidatorContext constraintValidatorContext) {
            if (value == null) {
                return allowNull;
            }

            if (enumClass == null || enumMethod == null) {
                return Boolean.TRUE;
            }

            Class<?> valueClass = value.getClass();

            try {
                Method method = enumClass.getMethod(enumMethod, valueClass);
                if (!Boolean.TYPE.equals(method.getReturnType()) && !Boolean.class.equals(method.getReturnType())) {
                    throw new RuntimeException(String.format("%s method return is not boolean type in the %s class", enumMethod, enumClass));
                }

                if(!Modifier.isStatic(method.getModifiers())) {
                    throw new RuntimeException(String.format("%s method is not static method in the %s class", enumMethod, enumClass));
                }

                Boolean result = (Boolean)method.invoke(null, value);
                return result == null ? Boolean.FALSE : result;
            } catch (IllegalAccessException | IllegalArgumentException | InvocationTargetException e) {
                throw new RuntimeException(e);
            } catch (NoSuchMethodException | SecurityException e) {
                throw new RuntimeException(String.format("This %s(%s) method does not exist in the %s", enumMethod, valueClass, enumClass), e);
            }
        }

    }
}

在枚举类中增加一个校验枚举类型的方法:

package com.test.common;

public enum FundStatusEnum {

    SUBMITTED("Submitted", "已提交"),
    SETTLED("Settled", "已结算"),
    PENDING_SETTLEMENT("PS", "待结算"),
    PENDING_TOPUP("PT", "待充值"),
    CANCELLED("Cancelled", "已取消");

    private final String status;

    private final String description;

    FundStatusEnum(String status, String description) {
        this.status = status;
        this.description = description;
    }

    public String status() {
        return status;
    }

    public String description() {
        return description;
    }

    /**
     * 校验是否是该枚举
     *
     * @param code 枚举字符串
     * @return true or false
     */
    public static boolean isValidEnum(String code) {
        for (FundStatusEnum fundStatusEnum : FundStatusEnum.values()) {
            if (fundStatusEnum.status().equals(code)) {
                return true;
            }
        }
        return false;
    }

}

对外接口Request参数VO中定义如下:

package com.test.vo;

import com.test.common.FundStatusEnum;
import com.test.utils.EnumValue;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;

import javax.validation.constraints.NotBlank;

@ApiModel(value = "更新交易请求实体", description = "更新交易请求对象")
public class UpdateTxnReqVO {

    @NotBlank(message = "The field 'gsRefID' can't be empty.")
    @ApiModelProperty(value = "业务系统交易ID", name = "gsRefID", example = "TXN-REF-TEST-001")
    private String gsRefID;

    // 可选设置的参数 enumMethod = "isValidEnum", allowNull = false  
    /**因为这两个在我们自定义的枚举校验注解中用了默认值*/
    @EnumValue(enumClass = FundStatusEnum.class, message = "The field 'fundStatus' is missing or invalid.")
    @ApiModelProperty(value = "资金状态", name = "fundStatus", example = "Settled")
    private String fundStatus;

    public String getGsRefID() {
        return gsRefID;
    }

    public void setGsRefID(String gsRefID) {
        this.gsRefID = gsRefID;
    }

    public String getFundStatus() {
        return fundStatus;
    }

    public void setFundStatus(String fundStatus) {
        this.fundStatus = fundStatus;
    }
}

Controller中方法参数中,还是通过@Valid注解 + BindingResult来获取校验信息。如下:

    @PutMapping(value = "/record")
    public String update(@Valid @RequestBody UpdateTxnReqVO updateTxnReqVO, BindingResult bindingResult) {
        logger.debug("update txn starts------");
        if (bindingResult.hasErrors()) {
            // TODO 处理逻辑
        }
        return "OK";
    }

这样,我们在Call这个update API的时候,如果传入的fundStatus不是FundStatusEnum中的任意一个,都会报错。

错误信息就是我们自定义的message,即:The field 'fundStatus' is missing or invalid.

 

  • 0
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值