在工作中,我们经常有这样的业务情况,实体间通过id实现数据业务上的关联 , 比如订单和用户,订单的创建人id、商品id等 , 在页面查询时我们需要将对应的id信息转换成对应的中文描述 , 比如用户中文名称,商品中文名称等 。如果是单条数据的展示还好,但是设计到列表查询,如何高效、优雅地实现这个效果呢?
现在接口返回的数据基本都是JSON格式,比如spring中使用了jackson,在controller层对结果进行json序列化,而我们要做的就是在序列化的过程中 , 实现id的转换
使用方式定义实体转换接口由于需要对订单实体中的创建人id进行转换
public interface UserConvert {String USER_CACHE = "USER_CACHE";String userId();default ConvertItem getUserConvert(){if( userId() == null ){return null;}return new ConvertItem(userId(), USER_CACHE);}}定义接口转换适配器基于上面UserConvert的处理,基于缓存实现,同时支持一个实体中多个,比如商品名称、商品分类等
【一招教你解决页面中关联id的转换】public class UserConvertProvider extends CacheItemConvertAdapter {private static String name = UserConvert.USER_CACHE;public UserConvertProvider() {super(name, User.class);}@Overridepublic boolean support(ConvertItem convertItem) {return convertItem != null && convertItem.getName().equals(name);}@Overridepublic String convert(ConvertItem convertItem) {if( convertItem == null ){return null;}User user = (User) fromCache(convertItem.getId());return user != null ? user.getCaption() : null;}}需要转换的数据缓存该实现依赖缓存,需要优先对需要转换的数据进行缓存,因此示例中添加了缓存示例
public void init(){Cache cache = cacheManager.getCache(UserConvert.USER_CACHE);if( cache != null ){cache.put("u1", new User("u1","Tom"));}}实体定义实体中需要通过实现接口UserConvert,这样对多个数据项转换时可以继续扩展
public class Order implements UserConvert {private String id;private String name;private LocalDateTime createTime = LocalDateTime.now();/*** 创建用户*/private String creator;@Overridepublic String userId() {return creator;}}实现效果可以看到 , 在输出json中,多了一列userConvert , 也就是接口中定义的get*方法
{"id": "1","name": "测试订单","createTime": "2024-05-08T21:55:51.5747507","creator": "u1","userConvert": "Tom"}实现原理上面说的,主要实现基于缓存,在web查询结果进行json序列化时,依赖于jackson的扩展,对输出结果匹配的类型进行转换 。
@EnableCaching@Configurationpublic class JacksonCustomConfiguration{@Beanpublic Jackson2ObjectMApperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){return jacksonObjectMapperBuilder -> configureMapperBuilder(jacksonObjectMapperBuilder);}private void configureMapperBuilder(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) {jackson2ObjectMapperBuilder.serializers(convertSerializer());}@Beanpublic ItemConvertSerializer convertSerializer(){return new ItemConvertSerializer(ConvertItem.class);}}
- 在配置文件中基于Jackson2ObjectMapperBuilderCustomizer对jackson进行扩展
- 定义ItemConvertSerializer对ConvertItem类型的属性进行处理 , 该类主要继承于StdSerializer
- 在ItemConvertSerializer中基于ConvertItem的name属性来匹配对应的缓存并进行转换
- 注意开启spring缓存*@EnableCaching*
- 最后基于spring特性,定义*/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports*来实现自动注入配置
- ConvertItem示例
@Getter@Setterpublic class ConvertItem {private String id;private String text;private String name;public ConvertItem() {}public ConvertItem(String id, String name) {this.id = id;this.name = name;}}- ItemConvertAdapter扩展适配器,主要于ConvertItem搭配扩展
public interface ItemConvertAdapter {/*** @param convertItem* @return*/boolean support(ConvertItem convertItem);/**** @param convertItem* @return*/String convert(ConvertItem convertItem);}- ItemConvertSerializer示例
public class ItemConvertSerializer extends StdSerializer<ConvertItem> implements ApplicationContextAware {private List<ItemConvertAdapter> itemConvertAdapters;public ItemConvertSerializer(Class<ConvertItem> t) {super(t);}@Overridepublic void serialize(ConvertItem value, JsonGenerator gen, SerializerProvider provider) throws IOException {String text = "";if(!CollectionUtils.isEmpty(itemConvertAdapters)){for (ItemConvertAdapter itemConvertAdapter : itemConvertAdapters) {if( itemConvertAdapter.support(value) ){text = itemConvertAdapter.convert(value);break;}}}gen.writeString(text);}@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throws BeansException {Map<String, ItemConvertAdapter> itemConvertAdapterMap= BeanFactoryUtils.beansOfTypeIncludingAncestors(applicationContext, ItemConvertAdapter.class, true, false);if( !itemConvertAdapterMap.isEmpty() ){itemConvertAdapters = new ArrayList<>(itemConvertAdapterMap.values());itemConvertAdapters.sort(OrderComparator.INSTANCE);}}}
推荐阅读
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- 人民的名义高小琴原型曝光:生了6个孩子3爹,一招抓龙手成为秘籍!
- 玉浩隐晦爆料的卢鑫80万才能解决的大事是什么?我猜是交通肇事
- 仅用一招让自己口碑暴增,这一次,把鹿晗送上热搜的不是关晓彤!
- 仅用一招让自己口碑暴增,这一次,把冯绍峰送上热搜的不是赵丽颖
- 鹿晗仅用一招口碑暴增,冲上热搜重回顶流,这次靠的不是关晓彤!
- 杨议“担心”的事还是发生了,郭德纲仅用一招,彰显德云社的魅力
- 吴京和郭帆的矛盾,要是再得不到解决,早晚会毁掉《流浪地球3》
- 《小巷人家》教你如何对付白眼狼,一针见血不内耗
- 仅用一招让自己再次“爆红”,这一次小沈阳最该感谢的不是赵本山
- 汽车空调慢漏怎么解决,汽车空调慢漏怎么处理
