Java 通过反射获取注解属性信息以及状态中字典

发布时间 2023-12-07 14:50:18作者: 爱学习的疯倾

一、创建存储对象

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 *  属性对象存储类*/
public class MetadataField {
    /**
     * key 对应对象中间的属性
     */
    private String key;
    /**
     * 字段标签
     */
    private String label;
    /**
     * 列表形式的字典
     */
    private List<Map<String, String>> dictionaries;

    public MetadataField(String key, String label) {
        this.key = key;
        this.label = label;
        this.dictionaries = new ArrayList<>();
    }

    public String getKey() {
        return key;
    }

    public String getLabel() {
        return label;
    }

    public void setKey(String key) {
        this.key = key;
    }

    public void setLabel(String label) {
        this.label = label;
    }

    public List<Map<String, String>> getDictionaries() {
        return dictionaries;
    }

    public void setDictionaries(List<Map<String, String>> dictionaries) {
        this.dictionaries = dictionaries;
    }

    // 添加一个方法,用于往 dictionaries 中添加字典项
    public void addDictionaryItem(String key, String value) {
        Map<String, String> dictionaryItem = new HashMap<>();
        dictionaryItem.put("key", key);
        dictionaryItem.put("value", value);
        this.dictionaries.add(dictionaryItem);
    }
}

 

二、工具类(通过ApiModelProperty注解获取字段属性信息)

/**
 * 对象属性封装类*/
public class ReflectionUtils {

    /**
     * 获取指定类的属性元数据列表,包括字段名称、中文标签和字典信息。
     *
     * @param clazz 要获取元数据的类
     * @param <T>   类型参数
     * @return 包含属性元数据的列表
     */
    public static <T> List<MetadataField> getField(Class<T> clazz) {
        List<MetadataField> propertyMetadataList = new ArrayList<>();
        Field[] fields = clazz.getDeclaredFields();

        // 处理字段
        for (Field field : fields) {
            ApiModelProperty annotation = field.getAnnotation(ApiModelProperty.class);
            if (annotation != null) {
                String propertyName = field.getName();
                String chineseName = annotation.value();

                // 将驼峰命名转换为下划线命名
                String underscoredName = camelToUnderscore(propertyName);
                propertyMetadataList.add(new MetadataField(underscoredName, chineseName));
            }
        }

        // 获取所有的 getter 方法
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            if (isGetter(method)) {
                try {
                    // 调用 getter 方法获取属性值
                    Object value = method.invoke(clazz.getDeclaredConstructor().newInstance());

                    // 处理返回字典的方法
                    if (value instanceof Map) {
                        Map<?, ?> dictionary = (Map<?, ?>) value;
                        // 查找对应的 MetadataField
                        MetadataField metadataField = findMetadataFieldByPropertyName(propertyMetadataList, getPropertyNameFromGetter(method));
                        if (metadataField != null) {
                            for (Map.Entry<?, ?> entry : dictionary.entrySet()) {
                                metadataField.addDictionaryItem(entry.getKey().toString(), entry.getValue().toString());
                            }
                        }
                    }
                } catch (Exception e) {
                    handleReflectionException(e);
                }
            }
        }

        return propertyMetadataList;
    }

    /**
     * 将驼峰命名转换为下划线命名。
     *
     * @param propertyName 驼峰命名的字符串
     * @return 下划线命名的字符串
     */
    private static String camelToUnderscore(String propertyName) {
        StringBuilder result = new StringBuilder();
        for (char ch : propertyName.toCharArray()) {
            if (Character.isUpperCase(ch)) {
                result.append("_").append(Character.toLowerCase(ch));
            } else {
                result.append(ch);
            }
        }
        return result.toString();
    }

    /**
     * 判断方法是否为 getter 方法。
     *
     * @param method 要检查的方法
     * @return 如果是 getter 方法则返回 true,否则返回 false
     */
    private static boolean isGetter(Method method) {
        return method.getName().startsWith("get") && method.getParameterCount() == 0;
    }

    /**
     * 从 getter 方法中获取属性名称。
     *
     * @param method getter 方法
     * @return 属性名称
     */
    private static String getPropertyNameFromGetter(Method method) {
        String methodName = method.getName();
        return methodName.substring(3, 4).toLowerCase() + methodName.substring(4);
    }

    /**
     * 根据属性名称查找对应的 MetadataField。
     *
     * @param fields       属性元数据列表
     * @param propertyName 要查找的属性名称
     * @return 匹配的 MetadataField,如果找不到则返回 null
     */
    private static MetadataField findMetadataFieldByPropertyName(List<MetadataField> fields, String propertyName) {
        for (MetadataField field : fields) {
            if (propertyName.equals(field.getKey())) {
                return field;
            }
        }
        return null;
    }

    /**
     * 处理反射异常。
     *
     * @param e 反射异常
     */
    private static void handleReflectionException(Exception e) {
        // 处理反射异常
        e.printStackTrace();
    }
}

 

三、构建 ApiModelProperty注解对象

import com.fasterxml.jackson.annotation.JsonFormat;
import com.yf.mybatis.entity.BaseEntity;
import io.swagger.annotations.ApiModelProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.time.LocalDateTime;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class DeductionDTO{

 
    @ApiModelProperty("总负责人")
    private String head;

 
    /**
     * 状态(0推进中 1已停滞 2已完成)
     */
    @ApiModelProperty("状态")
    private Map<String, Integer> status;

    // 获取 status 字段的 getter 方法
    public Map<String, Integer> getStatus() {
        Map<String, Integer> statusMapping = new HashMap<>();
        statusMapping.put("推进中", 0);
        statusMapping.put("已停滞", 1);
        statusMapping.put("已完成", 2);
        return statusMapping;
    }

    /**
     * 分类(0退税 1抵扣 2退税到账)
     */
    @ApiModelProperty("分类")
    private String type;

    public Map<String, Integer> getType() {
        Map<String, Integer> statusMapping = new HashMap<>();
        statusMapping.put("退税", 0);
        statusMapping.put("抵扣", 1);
        statusMapping.put("退税到账", 2);
        return statusMapping;
    }

    @ApiModelProperty("创建时间")
    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss")
    private LocalDateTime createTime;
}

 

四、前端控制器调用

 

 @PostMapping("/testField")
    public R<List<MetadataField>> testField(){
        // 获取属性名和中文描述的映射
        List<MetadataField> field = ReflectionUtils.getField(DeductionDTO.class);
        return R.data(field);
    }

 

返回结果如下:

{
    "code": 0,
    "msg": "操作成功",
    "data": [
        {
            "key": "head",
            "label": "总负责人",
            "dictionaries": []
        },
        {
            "key": "type",
            "label": "分类",
            "dictionaries": [
                {
                    "value": "1",
                    "key": "抵扣"
                },
                {
                    "value": "2",
                    "key": "退税到账"
                },
                {
                    "value": "0",
                    "key": "退税"
                }
            ]
        },
        {
            "key": "status",
            "label": "状态",
            "dictionaries": [
                {
                    "value": "2",
                    "key": "已完成"
                },
                {
                    "value": "0",
                    "key": "推进中"
                },
                {
                    "value": "1",
                    "key": "已停滞"
                }
            ]
        },
        {
            "key": "create_time",
            "label": "创建时间",
            "dictionaries": []
        }
    ]
}