在工作中,我们经常有这样的业务情况,实体间通过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的处理,基于缓存实现,同时支持一个实体中多个,比如商品名称、商品分类等
public class UserConvertProvider extends CacheItemConvertAdapter { private static String name = UserConvert.USER_CACHE; public UserConvertProvider() { super(name, User.class); } @Override public boolean support(ConvertItem convertItem) { return convertItem != null && convertItem.getName().equals(name); } @Override public 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; @Override public 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{ @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer(){ return jacksonObjectMapperBuilder -> configureMapperBuilder(jacksonObjectMapperBuilder); } private void configureMapperBuilder(Jackson2ObjectMapperBuilder jackson2ObjectMapperBuilder) { jackson2ObjectMapperBuilder.serializers(convertSerializer()); } @Bean public ItemConvertSerializer convertSerializer(){ return new ItemConvertSerializer(ConvertItem.class); }}
@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; }}
public interface ItemConvertAdapter { /** * @param convertItem * @return */ boolean support(ConvertItem convertItem); /** * * @param convertItem * @return */ String convert(ConvertItem convertItem);}
public class ItemConvertSerializer extends StdSerializer<ConvertItem> implements ApplicationContextAware { private List<ItemConvertAdapter> itemConvertAdapters; public ItemConvertSerializer(Class<ConvertItem> t) { super(t); } @Override public 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); } @Override public 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); } }}
本文链接:http://www.28at.com/showinfo-26-88739-0.html一招教你解决页面中关联id的转换
声明:本网页内容旨在传播知识,若有侵权等问题请及时与本网联系,我们将在第一时间删除处理。邮件:2376512515@qq.com
上一篇: React 中的国际化优秀实践
下一篇: 怪不得这么多人学 React!