News:三分天注定,七分靠打拼,爱拼才会赢!致力打造专业IT博客。如果你对本博客有任何意见或建议请联系作者,邮箱:blog@caokuan.cn

Java 如何实现枚举型字段值的校验

逝水无痕 955 0 条

在最近开发的产品中用到了自定义注解来校验字段的值,其中有一项是校验一个字符串或者数字是否是某个枚举里的值。整体实现不难,关键点是指定字段需要使用哪个枚举类校验和反射枚举类进行值校验。下面我写了一个小例子来简单说明实现方式。

java-enum.jpg

1. 自定义校验注解 @FieldCheck

/**
 * 字段校验枚举
 * 
 * 作者:caokk
 */
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FieldCheck {

    /**
     * 是否是枚举型数据
     */
    boolean isEnumType() default false;
    
    /**
     * 对应的枚举类
     */
    Class<?> enumClass() default Class.class;
}

2. 自定义枚举和枚举接口

/**
 * 枚举接口,方便统一管理
 * 
 * 作者:caokk
 */
public interface IEnum {

    /**
     * 枚举编码
     */
    String getCode();
    
    /**
     * 枚举名称
     */
    String getName();
}

/**
 * 枚举类示例
 * 
 * 作者:caokk
 */
public enum TypeEnum implements IEnum {

    Type_a("1", "类型1"),
    Type_b("2", "类型2"),
    Type_c("3", "类型3");
    
    private String code;
    
    private String name;

    private TypeEnum(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public String getName() {
        return name;
    }
}

自定义 DTO

/**
 * 数据传输对象
 * 
 * 作者:caokk
 */
public class TestDto {

    @FieldCheck(isEnumType = true, enumClass = TypeEnum.class)
    private String type;

    public String getType() {
        return type;
    }

    public void setType(String type) {
        this.type = type;
    }
}

编写测试类

/**
 * 测试代码
 * 
 * 作者:caokk
 */
public class Test {

    public static void main(String[] args) {
        
        TestDto testDto1 = new TestDto();
        testDto1.setType("1"); // type 枚举值正确
        doCheck(testDto1);
        
        TestDto testDto2 = new TestDto();
        testDto2.setType("2"); // type 枚举值正确
        doCheck(testDto2);
        
        TestDto testDto3 = new TestDto();
        testDto3.setType("3"); // type 枚举值正确
        doCheck(testDto3);
        
        TestDto testDto4 = new TestDto();
        testDto4.setType("4"); // type 枚举值正确
        doCheck(testDto4);
    }
    
    /**
     * 执行校验
     * 
     * @param testDto
     */
    private static void doCheck(TestDto testDto) {
        try {
            Field[] fields = testDto.getClass().getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                if (field.isAnnotationPresent(FieldCheck.class)) {
                    // 获取校验注解
                    FieldCheck fieldCheck = field.getAnnotation(FieldCheck.class);
                    // 如果需要校验的字段是枚举值字段
                    if (fieldCheck.isEnumType()) {
                        // 获取枚举类
                        Class<?> enumClass = fieldCheck.enumClass();
                        if (enumClass.isEnum()) {
                            // 强转为接口类型
                            IEnum[] enums = (IEnum[]) enumClass.getEnumConstants();
                            field.setAccessible(true);
                            // 获取待校验的字段的值
                            Object fieldValue = field.get(testDto);
                            // 以下为比较字段值是否包含在枚举类的值集合中
                            boolean contains = false;
                            for (IEnum iEnum : enums) {
                                if (iEnum.getCode().equals(fieldValue)) {
                                    contains = true;
                                    break;
                                }
                            }
                            if (!contains) {
                                System.out.println(field.getName() + " 不在枚举值范围内");
                            } else {
                                System.out.println(field.getName() + " 枚举值正确");
                            }
                        }
                    }
                }
            }
        } catch (SecurityException | IllegalArgumentException | IllegalAccessException e) {
            e.printStackTrace();
        }
    }
}

代码运行结果:

type 枚举值正确
type 枚举值正确
type 枚举值正确
type 不在枚举值范围内

其他

除了以上的思路之外,枚举反射也可以使用其他方式实现。比如反射获取枚举类的 values 方法。下面是示例代码:

/**
 * 测试代码2
 * 
 * 作者:caokk
 */
public class Test2 {

    public static void main(String[] args) {
        
        TestDto testDto = new TestDto();
        testDto.setType("1");
        
        try {
            Field[] fields = testDto.getClass().getDeclaredFields();
            for (int i = 0; i < fields.length; i++) {
                Field field = fields[i];
                if (field.isAnnotationPresent(FieldCheck.class)) {
                    // 获取校验注解
                    FieldCheck fieldCheck = field.getAnnotation(FieldCheck.class);
                    // 如果需要校验的字段是枚举值字段
                    if (fieldCheck.isEnumType()) {
                        // 获取枚举类
                        Class<?> enumClass = fieldCheck.enumClass();
                        // 反射获取values方法 (values()方法是编译器插入到enum定义中的static方法)
                        Method method = enumClass.getDeclaredMethod("values");
                        // 强转为接口类型
                        IEnum[] enums = (IEnum[]) method.invoke(null, null);
                        field.setAccessible(true);
                        // 获取待校验的字段的值
                        Object fieldValue = field.get(testDto);
                        // 以下为比较字段值是否包含在枚举类的值集合中
                        boolean contains = false;
                        for (IEnum iEnum : enums) {
                            if (iEnum.getCode().equals(fieldValue)) {
                                contains = true;
                                break;
                            }
                        }
                        if (!contains) {
                            System.out.println(field.getName() + " 不在枚举值范围内");
                        } else {
                            System.out.println(field.getName() + " 枚举值正确");
                        }
                    }
                }
            }
        } catch (SecurityException | IllegalArgumentException | NoSuchMethodException 
                | IllegalAccessException | InvocationTargetException e) {
            e.printStackTrace();
        }
    }
}

执行结果:

type 枚举值正确
发表我的评论
icon_mrgreen.gificon_neutral.gificon_twisted.gificon_arrow.gificon_eek.gificon_smile.gificon_confused.gificon_cool.gificon_evil.gificon_biggrin.gificon_idea.gificon_redface.gificon_razz.gificon_rolleyes.gificon_wink.gificon_cry.gificon_surprised.gificon_lol.gificon_mad.gificon_sad.gificon_exclaim.gificon_question.gif

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址