注解实现字典值转换

本文介绍了一种通过注解实现数据字典值转换的方法,旨在提高查询效率和提升新员工对业务的理解。文章详细阐述了设计思路,包括在需要转换的字段上添加注解,并利用Fastjson进行序列化处理。此外,还提供了注解结构、使用方法及实现过程的详细步骤。

注解实现字典值转换

1 背景

项目中对数据字典值、机构名称、创建人和更新人等编码值的转换方式一般通过关联特定表查询对应的name,

这样的查询效率低且对于不熟悉业务的新员工很不友好,因此想要开发通过注解实现编码值转换的功能

2 设计思路

通过在需要转换的字段上添加注解标识需要转换的字段,再通过fastjson的序列化完成对特定字段的处理

3 实现方式

通过继承WebMvcConfigurer进行统一的http请求信息管理,使用FastJsonHttpMessageConverter作为http消息转换类,

添加自定义的序列化类,完成注解字段的转换
maven依赖

      <!-- fastjson-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.76</version>
        </dependency>

		 <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>5.7.5</version>
        </dependency>

3.1 注解

3.1.1 注解结构

注解@CodeValue如下所示

public @interface CodeValue {


    /*** 编码类型 */
    CodeType type() default CodeType.DICT;

    /** 字典类型编码*/
    DictType dictType() default DictType.DEFAULT;

    /** 默认值*/
    String defaultValue() default "";
    
        /**
     * @Description
     *    扩展字段名,作为描述编码值的name字段,
     *    不填时默认为编码字段加Name后缀

     */
    String fieldName() default "";


}

type : 类型是CodeType ,代表的是编码值的类型,默认是字典类型

public enum CodeType {

    DICT,
    ORG,
    USER;

}

dictType:类型是DictType,当CodeValue是DICT字典类型时,该字段表示的是字典类型的编码值,如性别SEX

public enum DictType {

    DEFAULT("","空"),
    PROVINCE("province","省份"),
    SEX("sex","性别"),
    IS_START("is_start","是否启动");
    
      /** 字典类型编码 */
    private String code;
    /*** 描述*/
    private String description;
}

defaultValue: 类型是String,该字段表示的是当注解的字段值为空时的默认值

3.1.2 使用方法

注解直接在字段上使用,如下所示

public class BussinessDTO implements Serializable {

    // 转换字典类型不需要指定type字段,指定字典类型的枚举即可
    @CodeValue(dictType = DictType.SEX)
    private String sex;

	// 转换字典类型必须有默认值时,可以将默认值填写到defaultValue字段上
	@CodeValue(dictType = DictType.PROVINCE, defaultValue = "BEI_JING")
    private String province;

    // 转换用户id字段时,type字段使用USER枚举类
    @CodeValue(type = CodeType.USER)
    private String createUser;
    
    // 转换机构id字段时,type字段使用ORG枚举类,通过fieldName属性指定转换后的字段名
    @CodeValue(type = CodeType.ORG,fieldName="orgName")
    private String orgId;
    

}

3.1.3 返回样例

{
  
    "sex": "1",
    "sexName": "男",
    "province": "GUANG_DONG",
    "provinceName": "广东省",
    "createUser": "u123i1231oi23123i12o31",
    "createUserName": "张三",
    "orgId": "asdasfasfasfsafas",
    "orgName": "财政部"
}

3.2 实现过程

继承WebMvcConfigurer

@Configuration
public class WebMvcConfigurer implements WebMvcConfigurer {

    private static final String DATA_FORMAT = "yyyy-MM-dd HH:mm:ss";

    @Override
    public void configureMessageConverters(List<?>> converters) {
        converters.add(fastJsonHttpMessageConverter());
    }

    @Bean
    public FastJsonHttpMessageConverter fastJsonHttpMessageConverter() {
        FastJsonHttpMessageConverter converter = new FastJsonHttpMessageConverter();
        converter.setFastJsonConfig(defaultFastJsonConfig());
        converter.setDefaultCharset(StandardCharsets.UTF_8);
        converter.setSupportedMediaTypes(defaultMediaTypes());
        return converter;
    }

    // 默认fastjson配置
    private FastJsonConfig defaultFastJsonConfig() {
        FastJsonConfig fastJsonConfig = new FastJsonConfig();
        //日期格式转换
        fastJsonConfig.setDateFormat(DATA_FORMAT);
        fastJsonConfig.setSerializerFeatures(
                SerializerFeature.DisableCircularReferenceDetect,
                SerializerFeature.WriteMapNullValue,
                SerializerFeature.WriteNullBooleanAsFalse,
                SerializerFeature.WriteNullListAsEmpty,
                SerializerFeature.WriteNullStringAsEmpty
        );
        // 设置自定义的序列化配置类
        FastJsonSerializeConfig fastJsonSerializeConfig = new FastJsonSerializeConfig();
        fastJsonConfig.setSerializeConfig(fastJsonSerializeConfig);
        return fastJsonConfig;
    }


    // 默认媒体类型列表
    private List defaultMediaTypes() {
       ...
    }
}    
    

自定义序列化配置类FastJsonSerializeConfig

public class FastJsonSerializeConfig extends SerializeConfig {

    @Override
    public ObjectSerializer getObjectWriter(Class<?> clazz) {
        ObjectSerializer writer = super.get(clazz);
        if (writer != null) {
            return writer;
        }
Map codeValueAnnotationFields = ReflectUtil.listAnnotationCode v a lueField(clazz);
        if (!CollectionUtils.isEmpty(codeValueAnnotationFields)) {
           // 包含自定义字典转换注解,返回自定义序列化类
            writer = new CodeValueSerializer(clazz);
        }
        if (writer == null) {
            return super.getObjectWriter(clazz);
        }
        put(clazz, writer);
        return writer;
    }
}

ReflectUtil

public class ReflectUtil {


    /**
     * 注解字段集合
     * 以类为key,
     */
    private static final Map<?>, Map> annotationFieldMap = new ConcurrentHashMap<>();

    /**
     * 根据类获取带{Link @CodeValue}注解的字段列表,以字段名为key
     *
     * @param clazz 类型
     */
    public static Map listAnnotationCodevalueField(Class<?> clazz) {
        if (clazz == null) {
            return null;
        }
        // 存在直接返回
        if (annotationFieldMap.containsKey(clazz)) {
            return annotationFieldMap.getOrDefault(clazz, null);
        }
        Map fieldList = getFieldMap(clazz);
        annotationFieldMap.put(clazz, fieldList);
        return fieldList;
    }


    /**
     * @Description 获取字段集合, 以字段名为key
     */
    public static Map getFieldMap(Class<?> clazz) {
        Map fieldMap = new HashMap<>();
        Field[] _fields = clazz.getDeclaredFields();
        for (Field field : _fields) {
            // 静态修饰的字段忽略
            if (Modifier.isFinal(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) {
                continue;
            }
            if (field.isAnnotationPresent(CodeValue.class)) {
                fieldMap.put(field.getName(), field);
            }
        }
        Class<?> superClass = clazz.getSuperclass();
        if (Objects.nonNull(superClass)) {
            fieldMap.putAll(getFieldMap(superClass));
        }
        return fieldMap;
    }



}

自定义序列化类CodeValueSerializer

public class CodeValueSerializer extends JavaBeanSerializer {

    private static final String SUFFIX_VALUE = "Name";
    private static final char JSON_FIELD_SEPARATOR = ',';

    public CodeValueSerializer(Class<?> beanType) {
        super(beanType);
    }


    /**
     * @Description 重写应用方法,添加字段填充方法
     */
    @Override
    public boolean apply(JSONSerializer jsonBeanDeser, Object object, String key, Object propertyValue) {
        try {
            addFieldHandler(jsonBeanDeser, object, key, propertyValue);
        } catch (IOException e) {
            log.error("编码值翻译失败:{}", e);
        }
        return super.apply(jsonBeanDeser, object, key, propertyValue);
    }


    /**
     * @Description 新增字段After过滤器
     */
    public void addFieldHandler(JSONSerializer serializer, Object object, String key, Object propertyValue) throws IOException {
        if (object == null) {
            return;
        }
        Map fieldMap = ReflectUtil.listAnnotationCodeValueField(object.getClass());
        if (CollectionUtils.isEmpty(fieldMap) || fieldMap.get(key) == null) {
            return;
        }
        CodeValue codeValue = fieldMap.get(key).getAnnotation(Code v a lue.class);
        String fillFieldName = getFillFieldName(codeValue, key);
        String fillFieldValue = getFillFieldValue(codeValue,propertyValue);
        Field Field = ClassUtil.getDeclaredField(object.getClass(), fillFieldName);
        if (Field != null) {
            // 有相同的字段名,重新赋值
            BeanUtil.setFieldValue(object, fillFieldName, fillFieldValue);
            return;
        }
        if (isFirstField(serializer, key)) {
            // 如果是首字符进行特殊处理
            serializer.out.writeFieldValue(' ', fillFieldName, fillFieldValue);
            // 在填充字段fieldName:FieldValue后,补充逗号',' 防止逗号丢失
            serializer.out.write(JSON_FIELD_SEPARATOR);
            return;
        }
        // 不是首字母,直接写键值对
        serializer.out.writeFieldValue(JSON_FIELD_SEPARATOR, fillFieldName, fillFieldValue);
    }


    /**
     * @Description 是否是首字符
     */
    public boolean isFirstField(JSONSerializer serializer, String key) {
        FieldSerializer[] getters;
        if (serializer.out.isSortField()) {
            getters = this.sortedGetters;
        } else {
            getters = this.getters;
        }
        FieldSerializer fieldSerializer = getters[0];
        String startFiledName = fieldSerializer.fieldInfo.name;
        if (key.equals(startFiledName)) {
            return true;
        }
        return false;
    }

    /**
     * @Description 获取编码名称字段的字段名
     */
    public String getFillFieldName(CodeValue codeValue, String fieldName) {
        String newFieldName = fieldName + SUFFIX_VALUE;
        String defaultFieldName = codeValue.fieldName();
        if (!StringUtils.isEmpty(defaultFieldName)) {
            newFieldName = defaultFieldName;
        }
        return newFieldName;
    }

    public String getFillFieldValue(CodeValue codeValue, Object propertyValue) {
        String fieldValue = "";
        CodeType codeType = codeValue.type();
        DictType dictType = codeValue.dictType();
        String typeCode = dictType.getCode();
        // 如果是空字段枚举类,返回空字符串,防止忘记赋值字典类型
        if (CodeType.DICT.equals(codeType) && DictType.DEFAULT.equals(dictType)) {
            return "";
        }
        String defaultValue = codeValue.value();
        String value = propertyValue == null ? defaultValue : String.valueOf(propertyValue);
        fieldValue = CodeValueTranslateUtil.getName(codeType, value, typeCode);
        if (fieldValue == null) {
            fieldValue = "";
        }
        return fieldValue;
    }


}

CodeValueTranslateUtil

class CodeValueTranslateUtil {
// 编码值转换方法
public static getName(String codeType,String  value,String  typeCode){
CacheManager cacheManager = SpringContextHolder.getBean(CacheManager.class);
if(CacheManager==null){
return "";
}
return CacheManager.getName(codeType, value, typeCode);
}

CacheManager的使用方式见redisson + CacheManager缓存管理

<think>好的,我现在需要帮助用户了解如何在Python中使用字典实现某些功能,并且需要结合提供的引用内容来生成相关问题和回答。首先,我需要仔细分析用户的查询和提供的引用资料。 用户的问题是关于如何用Python字典实现具体功能,并请求使用示例。他们提供的四个引用分别涉及字典视图、item()方法遍历字典、四则运算用字典实现,以及字典的基本操作和例题。我需要将这些引用内容整合到回答中,确保覆盖用户的需求。 首先,我应该回顾每个引用的内容。引用1提到字典视图,包括键、和元素的动态视图,这可能用于展示如何实时获取字典的键对。引用2讨论使用item()方法遍历字典,这可能作为遍历字典的一个有效方法。引用3提到用字典实现四则运算,这可能是一个具体的应用示例,比如将运算符作为键,对应的函数作为。引用4提到了返回字典信息,可能与获取或处理有关。 接下来,我需要确定如何组织这些信息。用户需要具体的功能示例,因此我应该分点列出不同的应用场景,每个场景结合一个或多个引用,并给出代码示例。例如,可以包括动态同步的字典视图、遍历字典实现四则运算、数据统计等。 然后,我需要确保每个功能点都正确引用了对应的资料。比如,在讲解字典视图时引用[^1],在遍历字典时引用[^2],四则运算引用[^3],数据统计可能引用[^4]中的操作部分。 另外,用户要求生成相关问题,我需要根据内容提出相关问题,比如字典视图的动态特性、其他遍历方法、四则运算的扩展、字典的其他应用等。 需要注意的是,回答的结构要清晰,使用中文,并且代码示例要正确,符合LaTeX格式要求。例如,行内公式用$...$,独立公式用$$...$$,但在这个问题中可能较少涉及数学公式,但代码块需要用反引号包裹,并标明语言为Python。 现在,我需要检查是否有遗漏的功能点,或者是否有引用中的信息未被利用。例如,引用4提到了返回字典信息,可能在数据统计或处理使用values()方法,这部分可以作为一个示例。 最后,确保生成的相关问题与内容相关,并且能够引导用户进一步探索字典的不同应用和特性。</think>### 如何用Python字典实现具体功能? Python字典是一种高效的键对数据结构,广泛应用于数据映射、动态配置和快速查询等场景。以下是几个具体功能的实现示例: --- #### 1. **动态同步的字典视图(引用) 字典视图(`keys()`、`values()`、`items()`)会实时反映字典的修改,适合需要动态监控数据的场景。 ```python data = {"name": "Alice", "age": 30} keys = data.keys() values = data.values() data["city"] = "Beijing" # 动态添加键对 print(list(keys)) # 输出: ['name', 'age', 'city'] print(list(values)) # 输出: ['Alice', 30, 'Beijing'] ``` --- #### 2. **遍历字典对(引用[^2]) 使用`items()`方法遍历字典,可直接获取键和: ```python scores = {"Math": 90, "English": 85, "History": 78} for subject, score in scores.items(): print(f"科目: {subject}, 分数: {score}") ``` --- #### 3. **实现四则运算映射(引用[^3]) 将运算符作为键,对应的函数作为实现动态计算: ```python import operator operations = { "+": operator.add, "-": operator.sub, "*": operator.mul, "/": operator.truediv } a, b = 10, 5 for op in operations: result = operations[op](a, b) print(f"{a} {op} {b} = {result}") # 输出: 10 + 5 = 15, 10 - 5 = 5, ... ``` --- #### 4. **数据统计与分组(引用[^4]) 通过字典统计词频或分组数据: ```python text = "apple banana apple orange banana" words = text.split() word_count = {} for word in words: word_count[word] = word_count.get(word, 0) + 1 print(word_count) # 输出: {'apple': 2, 'banana': 2, 'orange': 1} ``` --- #### 5. **配置管理(引用) 用字典存储程序配置参数,便于动态修改: ```python config = { "debug_mode": True, "max_connections": 100, "timeout": 30 } if config["debug_mode"]: print("调试模式已开启") ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值