Java怎么优雅的实现字典翻译
什么是序列化
在Java中,序列化是将对象转换为字节流的过程,可以将这些字节流保存到文件中或通过网络进行传输。反序列化是将字节流转换为原始对象的过程。通过序列化和反序列化,我们可以在不同的应用程序之间传递对象,也可以将对象保存到文件中以便以后使用。
使用序列化实现字典值的翻译
在Java中,我们可以使用序列化机制来实现编码与其对应的含义的对应关系。具体步骤如下:
1.定义一个字典注解与,例如:
@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.自定义注解结合继承JsonSerialize实现ContextualSerializer,实现返回结果转译:
@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.将同类型的字典编码和对应的含义保存到一个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", "大学生"); // 因为我们公司采用微服务,然后字典模块单独拆分成一个服务,所以这里使用Feign方式调用 DictionaryFeignClient dictionaryFeign = SpringUtil.getBean(DictionaryFeignClient.class); return dictionaryFeign.dictionary(code); }
4.因为序列化是需要每个对象都进行序列话操作,如果返回的是集合的话,就会进行很多次序列化操作,此时就需要对相同类型的字典进行缓存,我这里使用了guava 的 LoadingCache 进行本地缓存(这里可能有人会说了,如果这个时候字典值对应的含义修改了,你这个缓存岂不是会导致数据不正确,首先字典功能一般是管理端进行增删改操作,而且字典一旦定好了是不会轻易修改的,如果你要硬杠,你赢了)。
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设置为10分钟,则缓存项在被添加到缓存中10分钟后过期,无论它是否被访问过。
这两种过期策略可以单独或组合使用,以实现更灵活的缓存策略。例如,我们可以将缓存项的expireAfterWrite设置为10分钟,同时将expireAfterAccess设置为5分钟,这样缓存项将在10分钟后过期,或者在最近5分钟内没有被访问时过期,以先到者为准。
使用expireAfterWrite和expireAfterAccess可以避免缓存中的数据过期时间过长或过短,从而提高缓存的效率和可靠性。
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 切面方式就很难达到(开发难度与开发成本)与序列化方式同样的效果。
通过以上步骤,我们可以使用Java中的序列化机制来优雅地实现字典编码与其对应的含义的对应关系,从而简化编码数据的管理和维护。
以上是Java怎么优雅的实现字典翻译的详细内容。更多信息请关注PHP中文网其他相关文章!

热AI工具

Undresser.AI Undress
人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover
用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool
免费脱衣服图片

Clothoff.io
AI脱衣机

AI Hentai Generator
免费生成ai无尽的。

热门文章

热工具

记事本++7.3.1
好用且免费的代码编辑器

SublimeText3汉化版
中文版,非常好用

禅工作室 13.0.1
功能强大的PHP集成开发环境

Dreamweaver CS6
视觉化网页开发工具

SublimeText3 Mac版
神级代码编辑软件(SublimeText3)

热门话题

Java 8引入了Stream API,提供了一种强大且表达力丰富的处理数据集合的方式。然而,使用Stream时,一个常见问题是:如何从forEach操作中中断或返回? 传统循环允许提前中断或返回,但Stream的forEach方法并不直接支持这种方式。本文将解释原因,并探讨在Stream处理系统中实现提前终止的替代方法。 延伸阅读: Java Stream API改进 理解Stream forEach forEach方法是一个终端操作,它对Stream中的每个元素执行一个操作。它的设计意图是处

胶囊是一种三维几何图形,由一个圆柱体和两端各一个半球体组成。胶囊的体积可以通过将圆柱体的体积和两端半球体的体积相加来计算。本教程将讨论如何使用不同的方法在Java中计算给定胶囊的体积。 胶囊体积公式 胶囊体积的公式如下: 胶囊体积 = 圆柱体体积 两个半球体体积 其中, r: 半球体的半径。 h: 圆柱体的高度(不包括半球体)。 例子 1 输入 半径 = 5 单位 高度 = 10 单位 输出 体积 = 1570.8 立方单位 解释 使用公式计算体积: 体积 = π × r2 × h (4
