Home  >  Article  >  Java  >  How to elegantly implement dictionary translation in Java

How to elegantly implement dictionary translation in Java

PHPz
PHPzforward
2023-05-12 17:31:061447browse

What is serialization

In Java, serialization is the process of converting objects into byte streams that can be saved to files or transmitted over the network. Deserialization is the process of converting a byte stream into a raw object. Through serialization and deserialization, we can pass objects between different applications and also save objects to files for later use.

Use serialization to realize translation of dictionary values

In Java, we can use the serialization mechanism to realize the correspondence between encoding and its corresponding meaning. The specific steps are as follows:

1. Define a dictionary annotation, for example:

@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@JacksonAnnotationsInside
@JsonSerialize(using = DictSerializer.class)
public @interface Dict {

    /**
     * 字典类型
     * 比如在描述学生的时候,1代表小学生 2代表初中生 3代表高中生 4代表大学生
     * 同样在描述老师的时候,1代表语文老师 2代表数学老师 3代表英语老师 4代表体育老师
     * 同样的数值在不同类型下,代表含义不同,所以需要指定字典的类型
     */
    String dic();
}

2. Combine the custom annotation with inheriting JsonSerialize to implement ContextualSerializer, and realize the translation of the returned result:

@Slf4j
public class DictSerializer extends StdSerializer<Object> implements ContextualSerializer {

    private transient String dictCode;

    @Override
    public JsonSerializer<?> createContextual(SerializerProvider prov, BeanProperty beanProperty){
        Dict dict = beanProperty.getAnnotation(Dict.class);
        return createContextual(dict.dic());
    }

    private JsonSerializer<?> createContextual(String dicCode) {
        DictSerializer serializer = new DictSerializer();
        serializer.setDictCode(dicCode);
        return serializer;
    }

    @Override
    public void serialize(Object value, JsonGenerator gen, SerializerProvider provider){

        String dictCode = getDictCode();
        if (StrUtil.isBlank(dictCode)) {
            return;
        }
        if (Objects.isNull(value)) {
            return;
        }
        try {
            // 因为序列化是每个对象都需要进行序列话操作,这里为了减少网络IO,使用了 guava 的本地缓存(代码在下面)
            Map<String, String> dictMap = DictionaryConstants.DICTIONARY_CACHE.get(dictCode);
            if (dictMap.containsKey("nullValue")) {
                // 当本地缓存中不存在该类型的字典时,就调用查询方法,并且放入到本地缓存中(代码在下面)
                dictMap = translateDictValue(dictCode);
                DictionaryConstants.DICTIONARY_CACHE.put(dictCode, dictMap);
            }
            // 通过数据字典类型和value获取name
            String label = dictMap.get(value.toString());
            gen.writeObject(value);
            // 在需要转换的字段上添加@Dict注解,注明需要引用的code,后端会在返回值中增加filedName_dictText的key,前端只需要取对应的 filedName_dictText 就可以直接使用
            gen.writeFieldName(gen.getOutputContext().getCurrentName() + DictionaryConstants.DICT_TEXT_SUFFIX);
            gen.writeObject(label);
        } catch (Exception e) {
            log.error("错误信息:{}", e.getMessage(), e);
        }
    }

    private String getDictCode() {
        return dictCode;
    }

    private void setDictCode(String dictCode) {
        this.dictCode = dictCode;
    }

    protected DictSerializer() {
        super(Object.class);
    }
}

3. Save dictionary codes and corresponding meanings of the same type into a Map, for example:

private Map<String, String> translateDictValue(String code) {
    if (StrUtil.isBlank(code)) {
      return null;
    }
    // Map<String, String> map = new HashMap<>();
    // map.put("1", "小学生");
    // map.put("2", "初中生");
    // map.put("3", "高中生");
    // map.put("4", "大学生");
  
    // 因为我们公司采用微服务,然后字典模块单独拆分成一个服务,所以这里使用Feign方式调用
    DictionaryFeignClient dictionaryFeign = SpringUtil.getBean(DictionaryFeignClient.class);
    return dictionaryFeign.dictionary(code);
}

4. Because serialization requires each object to perform a sequence operation, if a collection is returned, Many serialization operations will be performed. At this time, dictionaries of the same type need to be cached. I used guava's LoadingCache for local caching (someone may say here that if the meaning of the dictionary value is modified at this time, Wouldn't your cache lead to incorrect data? First of all, the dictionary function is usually added, deleted, and modified on the management side, and once the dictionary is set, it will not be easily modified. If you want to force a fight, you win).

public class DictionaryConstants {

    /**
     * 字典翻译文本后缀
     */
    public static final String DICT_TEXT_SUFFIX = "_dictText";

    public static final LoadingCache<String, Map<String, String>> DICTIONARY_CACHE = CacheBuilder.newBuilder()
            .maximumSize(1000)
            .expireAfterWrite(30, TimeUnit.SECONDS)
            .expireAfterAccess(10, TimeUnit.SECONDS)
            .build(new CacheLoader<String, Map<String, String>>() {
                @Override
                public Map<String, String> load(String key) {
                    Map<String, String> map = new HashMap<>();
                    map.put("nullValue", "nullValue");
                    return map;
                }
            });
}

Here is an additional little knowledge:

  • expireAfterWrite and expireAfterAccess are both cache expiration strategies in the Google Guava cache library.

  • expireAfterWrite indicates that the cache item expires after the specified time, regardless of whether the cache item has been accessed. For example, if we set the cache item's expireAfterWrite to 10 minutes, the cache item expires 10 minutes after it is added to the cache, regardless of whether it has been accessed.

  • These two expiration strategies can be used alone or in combination to achieve a more flexible caching strategy. For example, we can set the cache item's expireAfterWrite to 10 minutes and also set the expireAfterAccess to 5 minutes, so that the cache item will expire after 10 minutes, or expire when it has not been accessed in the last 5 minutes, whichever comes first .

  • Using expireAfterWrite and expireAfterAccess can avoid the data expiration time in the cache from being too long or too short, thereby improving the efficiency and reliability of the cache.

5. Compared with using the aop aspect method, using the serialization method can better translate the dictionary (because the aop method is difficult to process the attributes of the object) , For example:

public class Company {
  private List<Staff> staffs;
}

public class Staff {
  private Integer age;
  private String name;
  @Dic(dic = "position")
  private String position;
  
}

In this scenario, if the Company collection is returned, it will be difficult to achieve the same effect (development difficulty and development cost) as the serialization method using the aop aspect method.

Through the above steps, we can use the serialization mechanism in Java to elegantly realize the correspondence between dictionary encoding and its corresponding meaning, thereby simplifying the management and maintenance of encoded data.

The above is the detailed content of How to elegantly implement dictionary translation in Java. For more information, please follow other related articles on the PHP Chinese website!

Statement:
This article is reproduced at:yisu.com. If there is any infringement, please contact admin@php.cn delete