溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務(wù)條款》

Java怎么優(yōu)雅的實現(xiàn)字典翻譯

發(fā)布時間:2023-04-27 14:34:41 來源:億速云 閱讀:122 作者:zzz 欄目:開發(fā)技術(shù)

這篇文章主要介紹了Java怎么優(yōu)雅的實現(xiàn)字典翻譯的相關(guān)知識,內(nèi)容詳細易懂,操作簡單快捷,具有一定借鑒價值,相信大家閱讀完這篇Java怎么優(yōu)雅的實現(xiàn)字典翻譯文章都會有所收獲,下面我們一起來看看吧。

什么是序列化

在Java中,序列化是將對象轉(zhuǎn)換為字節(jié)流的過程,可以將這些字節(jié)流保存到文件中或通過網(wǎng)絡(luò)進行傳輸。反序列化是將字節(jié)流轉(zhuǎn)換為原始對象的過程。通過序列化和反序列化,我們可以在不同的應(yīng)用程序之間傳遞對象,也可以將對象保存到文件中以便以后使用。

使用序列化實現(xiàn)字典值的翻譯

在Java中,我們可以使用序列化機制來實現(xiàn)編碼與其對應(yīng)的含義的對應(yīng)關(guān)系。具體步驟如下:

1.定義一個字典注解與,例如:

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

    /**
     * 字典類型
     * 比如在描述學生的時候,1代表小學生 2代表初中生 3代表高中生 4代表大學生
     * 同樣在描述老師的時候,1代表語文老師 2代表數(shù)學老師 3代表英語老師 4代表體育老師
     * 同樣的數(shù)值在不同類型下,代表含義不同,所以需要指定字典的類型
     */
    String dic();
}

2.自定義注解結(jié)合繼承JsonSerialize實現(xiàn)ContextualSerializer,實現(xiàn)返回結(jié)果轉(zhuǎn)譯:

@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 {
            // 因為序列化是每個對象都需要進行序列話操作,這里為了減少網(wǎng)絡(luò)IO,使用了 guava 的本地緩存(代碼在下面)
            Map<String, String> dictMap = DictionaryConstants.DICTIONARY_CACHE.get(dictCode);
            if (dictMap.containsKey("nullValue")) {
                // 當本地緩存中不存在該類型的字典時,就調(diào)用查詢方法,并且放入到本地緩存中(代碼在下面)
                dictMap = translateDictValue(dictCode);
                DictionaryConstants.DICTIONARY_CACHE.put(dictCode, dictMap);
            }
            // 通過數(shù)據(jù)字典類型和value獲取name
            String label = dictMap.get(value.toString());
            gen.writeObject(value);
            // 在需要轉(zhuǎn)換的字段上添加@Dict注解,注明需要引用的code,后端會在返回值中增加filedName_dictText的key,前端只需要取對應(yīng)的 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.將同類型的字典編碼和對應(yīng)的含義保存到一個Map中,例如:

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", "大學生");
  
    // 因為我們公司采用微服務(wù),然后字典模塊單獨拆分成一個服務(wù),所以這里使用Feign方式調(diào)用
    DictionaryFeignClient dictionaryFeign = SpringUtil.getBean(DictionaryFeignClient.class);
    return dictionaryFeign.dictionary(code);
}

4.因為序列化是需要每個對象都進行序列話操作,如果返回的是集合的話,就會進行很多次序列化操作,此時就需要對相同類型的字典進行緩存,我這里使用了guava 的 LoadingCache 進行本地緩存(這里可能有人會說了,如果這個時候字典值對應(yīng)的含義修改了,你這個緩存豈不是會導(dǎo)致數(shù)據(jù)不正確,首先字典功能一般是管理端進行增刪改操作,而且字典一旦定好了是不會輕易修改的,如果你要硬杠,你贏了)。

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;
                }
            });
}

這里額外補充一個小知識:

  • expireAfterWrite和expireAfterAccess都是Google Guava緩存庫中的緩存過期策略。

  • expireAfterWrite表示緩存項在指定時間后過期,無論緩存項是否被訪問過。例如,如果我們將緩存項的expireAfterWrite設(shè)置為10分鐘,則緩存項在被添加到緩存中10分鐘后過期,無論它是否被訪問過。

  • 這兩種過期策略可以單獨或組合使用,以實現(xiàn)更靈活的緩存策略。例如,我們可以將緩存項的expireAfterWrite設(shè)置為10分鐘,同時將expireAfterAccess設(shè)置為5分鐘,這樣緩存項將在10分鐘后過期,或者在最近5分鐘內(nèi)沒有被訪問時過期,以先到者為準。

  • 使用expireAfterWrite和expireAfterAccess可以避免緩存中的數(shù)據(jù)過期時間過長或過短,從而提高緩存的效率和可靠性。

5.相比于使用 aop 切面的方式,使用序列化的方式能更好的進行字典的翻譯(因為 aop 方式很難處理對象中的屬性的屬性),例如:

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

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

在這種場景中,如果返回的是 Company 集合,使用 aop 切面方式就很難達到(開發(fā)難度與開發(fā)成本)與序列化方式同樣的效果。

通過以上步驟,我們可以使用Java中的序列化機制來優(yōu)雅地實現(xiàn)字典編碼與其對應(yīng)的含義的對應(yīng)關(guān)系,從而簡化編碼數(shù)據(jù)的管理和維護。

關(guān)于“Java怎么優(yōu)雅的實現(xiàn)字典翻譯”這篇文章的內(nèi)容就介紹到這里,感謝各位的閱讀!相信大家對“Java怎么優(yōu)雅的實現(xiàn)字典翻譯”知識都有一定的了解,大家如果還想學習更多知識,歡迎關(guān)注億速云行業(yè)資訊頻道。

向AI問一下細節(jié)

免責聲明:本站發(fā)布的內(nèi)容(圖片、視頻和文字)以原創(chuàng)、轉(zhuǎn)載和分享為主,文章觀點不代表本網(wǎng)站立場,如果涉及侵權(quán)請聯(lián)系站長郵箱:is@yisu.com進行舉報,并提供相關(guān)證據(jù),一經(jīng)查實,將立刻刪除涉嫌侵權(quán)內(nèi)容。

相關(guān)推薦