在工作中,我們經常有這樣的業務情況,實體間通過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.tebozhan.com/showinfo-26-88739-0.html一招教你解決頁面中關聯id的轉換
聲明:本網頁內容旨在傳播知識,若有侵權等問題請及時與本網聯系,我們將在第一時間刪除處理。郵件:2376512515@qq.com
上一篇: React 中的國際化優秀實踐
下一篇: 怪不得這么多人學 React!