詳解Java如何優(yōu)雅的實現(xiàn)字典翻譯
什么是序列化
在Java中,序列化是將對象轉(zhuǎn)換為字節(jié)流的過程,可以將這些字節(jié)流保存到文件中或通過網(wǎng)絡(luò)進(jìn)行傳輸。反序列化是將字節(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 {
?
/**
* 字典類型
* 比如在描述學(xué)生的時候,1代表小學(xué)生 2代表初中生 3代表高中生 4代表大學(xué)生
* 同樣在描述老師的時候,1代表語文老師 2代表數(shù)學(xué)老師 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 {
// 因為序列化是每個對象都需要進(jìn)行序列話操作,這里為了減少網(wǎng)絡(luò)IO,使用了 guava 的本地緩存(代碼在下面)
Map<String, String> dictMap = DictionaryConstants.DICTIONARY_CACHE.get(dictCode);
if (dictMap.containsKey("nullValue")) {
// 當(dāng)本地緩存中不存在該類型的字典時,就調(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", "小學(xué)生");
// map.put("2", "初中生");
// map.put("3", "高中生");
// map.put("4", "大學(xué)生");
// 因為我們公司采用微服務(wù),然后字典模塊單獨拆分成一個服務(wù),所以這里使用Feign方式調(diào)用
DictionaryFeignClient dictionaryFeign = SpringUtil.getBean(DictionaryFeignClient.class);
return dictionaryFeign.dictionary(code);
}4.因為序列化是需要每個對象都進(jìn)行序列話操作,如果返回的是集合的話,就會進(jìn)行很多次序列化操作,此時就需要對相同類型的字典進(jìn)行緩存,我這里使用了guava 的 LoadingCache 進(jìn)行本地緩存(這里可能有人會說了,如果這個時候字典值對應(yīng)的含義修改了,你這個緩存豈不是會導(dǎo)致數(shù)據(jù)不正確,首先字典功能一般是管理端進(jìn)行增刪改操作,而且字典一旦定好了是不會輕易修改的,如果你要硬杠,你贏了)。
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)沒有被訪問時過期,以先到者為準(zhǔn)。
- 使用expireAfterWrite和expireAfterAccess可以避免緩存中的數(shù)據(jù)過期時間過長或過短,從而提高緩存的效率和可靠性。
5.相比于使用 aop 切面的方式,使用序列化的方式能更好的進(jìn)行字典的翻譯(因為 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 切面方式就很難達(dá)到(開發(fā)難度與開發(fā)成本)與序列化方式同樣的效果。
通過以上步驟,我們可以使用Java中的序列化機制來優(yōu)雅地實現(xiàn)字典編碼與其對應(yīng)的含義的對應(yīng)關(guān)系,從而簡化編碼數(shù)據(jù)的管理和維護(hù)。
總結(jié)
在本文中,我們介紹了如何使用Java中的序列化機制來實現(xiàn)編碼與其對應(yīng)的含義的對應(yīng)關(guān)系,從而簡化編碼數(shù)據(jù)的管理和維護(hù)。通過序列化和反序列化,我們可以高效地傳遞和保存對象,提高應(yīng)用程序的效率和可維護(hù)性。
到此這篇關(guān)于詳解Java如何優(yōu)雅的實現(xiàn)字典翻譯的文章就介紹到這了,更多相關(guān)Java字典翻譯內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實現(xiàn)圖片轉(zhuǎn)ascii字符畫的方法示例
這篇文章主要介紹了java實現(xiàn)圖片轉(zhuǎn)ascii字符畫的方法示例,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧2018-08-08
java可變參數(shù)當(dāng)做數(shù)組處理的方法示例
這篇文章主要介紹了java可變參數(shù)當(dāng)做數(shù)組處理的方法,結(jié)合實例形式分析了java可變參數(shù)當(dāng)做數(shù)組處理相關(guān)原理、步驟與操作注意事項,需要的朋友可以參考下2019-09-09
Java使用備忘錄模式實現(xiàn)過關(guān)類游戲功能詳解
這篇文章主要介紹了Java使用備忘錄模式實現(xiàn)過關(guān)類游戲功能,結(jié)合實例形式詳細(xì)分析了java備忘錄模式的概念、原理及其在過關(guān)類游戲中的具體應(yīng)用方法,需要的朋友可以參考下2018-04-04
Spring Boot + thymeleaf 實現(xiàn)文件上傳下載功能
最近同事問我有沒有有關(guān)于技術(shù)的電子書,我打開電腦上的小書庫,但是郵件發(fā)給他太大了,公司又禁止用文件夾共享,于是花半天時間寫了個小的文件上傳程序,部署在自己的Linux機器上,需要的朋友可以參考下2018-01-01
Java 8對LinkedHashSet元素進(jìn)行排序的操作方法
LinkedHashSet 是 Java 集合框架中的一個類,它繼承自 HashSet,并實現(xiàn)了 Set 接口,然而,LinkedHashSet 不支持元素的排序,它僅僅保持插入順序,所以本文給大家介紹了Java 8 如何對 LinkedHashSet 元素進(jìn)行排序,需要的朋友可以參考下2024-11-11

