本文內容來自真實的工做案例,因其轉換略複雜,且有必定意義,故記錄之。java
給定一個JSON串json
{ "item:s_id:18006666": "1024", "item:s_id:18008888": "1024", "item:g_id:18006666": "6666", "item:g_id:18008888": "8888", "item:num:18008888": "8", "item:num:18006666": "6", "item:item_core_id:18006666": "9876666", "item:item_core_id:18008888": "9878888", "item:order_no:18006666": "E20171013174712025", "item:order_no:18008888": "E20171013174712025", "item:id:18008888": "18008888", "item:id:18006666": "18006666", "item_core:num:9878888": "8", "item_core:num:9876666": "6", "item_core:id:9876666": "9876666", "item_core:id:9878888": "9878888", "item_price:item_id:1000": "9876666", "item_price:item_id:2000": "9878888", "item_price:price:1000": "100", "item_price:price:2000": "200", "item_price:id:2000": "2000", "item_price:id:1000": "1000", "item_price_change_log:id:1111": "1111", "item_price_change_log:id:2222": "2222", "item_price_change_log:item_id:1111": "9876666", "item_price_change_log:item_id:2222": "9878888", "item_price_change_log:detail:1111": "haha1111", "item_price_change_log:detail:2222": "haha2222", "item_price_change_log:id:3333": "3333", "item_price_change_log:id:4444": "4444", "item_price_change_log:item_id:3333": "9876666", "item_price_change_log:item_id:4444": "9878888", "item_price_change_log:detail:3333": "haha3333", "item_price_change_log:detail:4444": "haha4444" }
這是一個訂單的兩個商品的基本信息、價格信息以及計價變動信息,是從DB裏的結構獲取到的記錄。爲了企業保密性,對錶、字段以及值作了簡化的特殊處理。目標是將這個訂單的各個商品的信息聚合在一塊兒。 即獲得:app
{1024_E20171013174712025_18006666={item:id=18006666, item_price:price=100, item_price:id=1000, item_price_change_log:id=[3333, 1111], item_core:num=6, item:g_id=6666, item:item_core_id=9876666, item_price:item_id=9876666, item:order_no=E20171013174712025, item_core:id=9876666, item_price_change_log:item_id=[9876666, 9876666], item:s_id=1024, item:num=6, item_price_change_log:detail=[haha3333, haha1111]}, 1024_E20171013174712025_18008888={item:id=18008888, item_price:price=200, item_price:id=2000, item_price_change_log:id=[2222, 4444], item_core:num=8, item:g_id=8888, item:item_core_id=9878888, item_price:item_id=9878888, item:order_no=E20171013174712025, item_price_change_log:item_id=[9878888, 9878888], item:s_id=1024, item_core:id=9878888, item:num=8, item_price_change_log:detail=[haha2222, haha4444]}}
細心的讀者會發現,一個商品 item 對應一個 item_core, 一個 item_price ,可能對應多個 item_price_change_log 。這三個表都是經過 item:item_core_id 來關聯的,在 item 表是 item:item_core_id 字段, 在 item_price 表是 item_price:item_id 字段, 在 item_price_change_log 表是 item_price_change_log:item_id 字段。函數
基本思路是:ui
STEP1: 對於含有表 item, item_core, item_price, item_price_change_log 數據的指定JSON,構建一個總的 itemIndexMap[table:id, Map[table:field, value]],其中 key 是 table:id, value 是一個 valMap, valMap 的鍵是 table:field, 值是對應的最後面的值。 table: 做爲名字空間的前綴,是爲了不不一樣表之間的ID和field相互重合覆蓋。 見方法 buildItemIndexMap 的實現。設計
STEP2: 從 itemIndexMap 構建 item:id 與 item:item_core_id 的映射 itemCoreId2originItemIdMap;在實際應用中, originItemId 爲 oldItemId (item:id), itemCoreId 爲 newItemId (item:item_core_id);code
STEP3: 對於每個 [table:id, Map[table:field, value]], 經過 itemCoreId2originItemIdMap 拿到對應的 originitemId , 而後使用 originitemId 爲鍵替換itemIndexMap中對應的 item_core:id, item_price:id, item_price_change_log:id,將具備相同的 originItemId 的不一樣的 Map[table:field, value] 進行合併後,添加到新的newItemIndexMap 中。orm
ItemUtil.java對象
package zzz.study.utils; /** * Created by shuqin on 17/11/10. */ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.HashMap; import java.util.Map; import java.util.Set; import static zzz.study.utils.NewMapUtil.merge; /** * Created by shuqin on 17/10/23. */ public class ItemUtil { private static Logger logger = LoggerFactory.getLogger(ItemUtil.class); /** * 構建一個訂單的全部商品級別的信息以及映射 * @param multiItemInfoMapForOneOrder 一個訂單下多個商品的信息 * @return 一個訂單的全部商品級別的信息以及映射 * * key 是 sID + order_no + item_id ; item_id 對應 item.id, 對應 item_core.item_core_id */ public static Map<String, Map<String,Object>> buildFinalOrderItemMap(Map<String,String> multiItemInfoMapForOneOrder) { try { return mergeOrderItemMap(buildItemIndexMap(multiItemInfoMapForOneOrder)); } catch (Exception ex) { logger.error("failed to buildFinalOrderItemMap for: " + multiItemInfoMapForOneOrder, ex); return new HashMap<>(); } } /** * 構建一個訂單的全部商品級別的信息以及映射 * @param itemInfoMap 商品級別的信息 * @return 一個訂單的全部商品的信息 * * NOTE: itemInfoMap 是對應一個訂單的全部商品的信息的映射,不要傳多個訂單的信息進來,可能重複 * * key = table:table_unique_id , value = map [ table:field, value ] * * eg. map [ item:goods_type:1800888 = 0 , item:num:1800888 = 8 ] * will be transformed into map[item:1800888 = map[item:goods_type=0 , item:num=8]] */ public static Map<String,Map<String,String>> buildItemIndexMap(Map<String, String> itemInfoMap) { Map<String, Map<String,String>> itemIndexMap = new HashMap<>(); itemInfoMap.forEach( (key, value) -> { String[] keyparts = key.split(":"); // 只考慮三段式 tablename:field:id if (keyparts != null && keyparts.length == 3) { String table = keyparts[0]; String field = keyparts[1]; String index = keyparts[2]; String indexKey = table+ ":" + index; String fieldKey = table+":"+field; if (itemIndexMap.get(indexKey) == null) { itemIndexMap.put(indexKey, new HashMap<>()); } itemIndexMap.get(indexKey).put(fieldKey, String.valueOf(value)); } } ); return itemIndexMap; } /** * 聚合一個訂單下的全部商品信息 * @param itemIndexMap 一個訂單全部商品的信息映射 * @return 一個訂單下的全部商品信息 * * key 是 sID + order_no + item_id ; item_id 對應 item.id, item_core.item_core_id */ private static Map<String, Map<String,Object>> mergeOrderItemMap(Map<String, Map<String,String>> itemIndexMap) { if (itemIndexMap == null || itemIndexMap.isEmpty()) { return new HashMap<>(); } // Map[oldItemId, newItemId] Map<String,String> old2newItemIdMap = new HashMap<>(); Map<String,String> new2oldItemIdMap = new HashMap<>(); Set<Map.Entry<String,Map<String,String>>> entries = itemIndexMap.entrySet(); String orderNo = ""; String sID = ""; for (Map.Entry<String,Map<String,String>> entry: entries) { String indexKey = entry.getKey(); Map<String,String> value = entry.getValue(); if (indexKey.startsWith("item:")) { old2newItemIdMap.put(indexKey, value.get("item:item_core_id")); new2oldItemIdMap.put(value.get("item:item_core_id"), indexKey); orderNo = value.get("item:order_no"); sID = value.get("item:s_id"); } } Map<String, Map<String,Object>> newItemIndexMap = new HashMap<>(); for (Map.Entry<String,Map<String,String>> entry: entries) { String indexKey = entry.getKey(); Map<String,String> value = entry.getValue(); if (indexKey.startsWith("item:")) { if (newItemIndexMap.get(indexKey) == null) { newItemIndexMap.put(indexKey, new HashMap<>()); } newItemIndexMap.get(indexKey).putAll(value); } else if (indexKey.startsWith("item_core:")) { String itemCoreId = indexKey.split(":")[1]; String oldItemId = new2oldItemIdMap.get(itemCoreId); if (newItemIndexMap.get(oldItemId) == null) { newItemIndexMap.put(oldItemId, new HashMap<>()); } newItemIndexMap.get(oldItemId).putAll(value); } else if (indexKey.startsWith("item_price:")) { // item_price 與 item_id 一對一關係 String itemCoreId = itemIndexMap.get(indexKey).get("item_price:item_id"); String oldItemId = new2oldItemIdMap.get(itemCoreId); if (newItemIndexMap.get(oldItemId) == null) { newItemIndexMap.put(oldItemId, new HashMap<>()); } newItemIndexMap.get(oldItemId).putAll(value); } else if (indexKey.startsWith("item_price_change_log:")) { // item_price_change_log 與 item_id 多對一關係 String itemCoreId = itemIndexMap.get(indexKey).get("item_price_change_log:item_id"); String oldItemId = new2oldItemIdMap.get(itemCoreId); if (newItemIndexMap.get(oldItemId) == null) { newItemIndexMap.put(oldItemId, new HashMap<>()); } Map<String,Object> srcMap = newItemIndexMap.get(oldItemId); newItemIndexMap.get(oldItemId).putAll(merge(srcMap, value)); } } return buildFinalOrderItemMap(newItemIndexMap, old2newItemIdMap, orderNo, sID); } /** * 構建最終的訂單商品信息 * @param itemIndexMap 商品信息 * @param old2newItemIdMap 新老itemId映射 * @param orderNo 訂單號 * @param sID 店鋪號 * @return 訂單商品擴展信息 */ private static Map<String, Map<String,Object>> buildFinalOrderItemMap(Map<String, Map<String,Object>> itemIndexMap, Map<String,String> old2newItemIdMap, String orderNo, String sID) { Map<String, Map<String,Object>> finalResult = new HashMap<>(); Set<Map.Entry<String,Map<String,Object>>> entries = itemIndexMap.entrySet(); for (Map.Entry<String,Map<String,Object>> entry: entries) { String indexKey = entry.getKey(); Map<String,Object> value = entry.getValue(); String itemId = indexKey.split(":")[1]; String itemKey = sID + "_" + orderNo + "_" + itemId; finalResult.put(itemKey, value); } return finalResult; } }
NewMapUtil.java字符串
package zzz.study.utils; import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; /** * Created by shuqin on 17/11/10. */ public class NewMapUtil { /** * 將 map 的值轉爲字符串類型 */ public static Map<String,String> transMap(Map<String,Object> map) { if (map == null) { return null; } Map<String,String> result = new HashMap<>(); map.forEach( (k,v) -> result.put(k, v != null ? v.toString(): null) ); return result; } /** * 將兩個 Map 裏相同 key 的值合併爲列表 * * eg. src = ["id": 1, "detail": "haha111", "extra":"extra111"] , * dest = ["id": 2, "detail": "haha222", "another": "another222"] * merge 以後返回 ["id": [1,2], "detail": ["haha111", "haha222"], "extra":"extra111", "another": "another222"] ` */ public static Map<String, ? extends Object> merge(Map<String,? extends Object> src, Map<String, ? extends Object> dest) { if (src == null || src.size() == 0) { return dest; } if (dest == null || dest.size() == 0) { return src; } Map<String, Object> result = new HashMap<>(); src.forEach( (key, value) -> { Object valueDesc = dest.get(key); if (valueDesc != null) { result.put(key, mergeToList(value, valueDesc)); } else { result.put(key, value); } } ); dest.forEach( (key, value) -> { if (result.get(key) == null) { result.put(key, value); } } ); return result; } public static List mergeToList(Object src, Object... args) { List valList = new ArrayList(); add(valList, src); for (Object arg: args) { add(valList, arg); } return valList; } public static List add(List valList, Object src) { if (src == null) { return valList; } if (src instanceof List) { valList.addAll((List)src); } else { valList.add(src); } return valList; } }
能夠看到,初步實現雖然實現了功能,但是代碼比較亂,尤爲是 mergeOrderItemMap 方法,混雜了業務表的邏輯,理解和擴展起來比較麻煩。須要仔細重構下。另外,Map的遍歷訪問比較囉嗦,能夠更簡潔一些。
重構從簡單作起。原來使用了
Set<Map.Entry<String,Map<String,Object>>> entries = itemIndexMap.entrySet(); for (Map.Entry<String,Map<String,Object>> entry: entries) { String indexKey = entry.getKey(); Map<String,Object> value = entry.getValue(); String itemId = indexKey.split(":")[1]; String itemKey = sID + "_" + orderNo + "_" + itemId; finalResult.put(itemKey, value); }
在 java8 中可以使用 forEach 語法簡潔表達:
itemIndexMap.forEach( (indexKey,value) -> { String itemId = indexKey.split(":")[1]; String itemKey = sID + "_" + orderNo + "_" + itemId; finalResult.put(itemKey, value); } );
裏面有不少以下重複代碼
if (newItemIndexMap.get(oldItemId) == null) { newItemIndexMap.put(oldItemId, new HashMap<>()); } newItemIndexMap.get(oldItemId).putAll(value);
實際上就是將新的item_core_id 映射成 item.id ,而後填充到新的Map,能夠抽離出一個函數,而後複用。
private static void putNewIndexMap(Map<String, Map<String,Object>> newItemIndexMap, String indexKey, Map<String,String> value, Function<String, String> getOriginItemIdFunc) { String originItemId = getOriginItemIdFunc.apply(indexKey); if (newItemIndexMap.get(originItemId) == null) { newItemIndexMap.put(originItemId, new HashMap<>()); } Map<String,Object> srcMap = newItemIndexMap.get(originItemId); newItemIndexMap.get(originItemId).putAll(merge(srcMap, value)); } 調用: putNewIndexMap(newItemIndexMap, indexKey, value, key -> key);
看以下代碼,裏面含有 item_price: , item_price:item_id 這樣的業務信息,破壞了方法的通用性。
if (indexKey.startsWith("item_price:")) { // item_price 與 item_id 一對一關係 String itemCoreId = itemIndexMap.get(indexKey).get("item_price:item_id"); }
能夠抽離出來作成配置。好的配置可讓代碼大大簡化。仔細思考下整個過程:當 indexKey 包含某個表的前綴時,取它對應的 itemCoreId 的字段,而後獲得 itemCoreId ,再根據 putNewIndexMap 方法將對應的 Map 添加到最終的Map中。見以下代碼:
private static Map<String,String> itemIdConf = new HashMap() { { put("item", "item:item_core_id"); put("item_core", "item_core:id"); put("item_price", "item_price:item_id"); put("item_price_change_log", "item_price_change_log:item_id"); } }; String table = indexKey.split(":")[0]; if (itemIdConf.containsKey(table)) { String itemCoreIdField = itemIdConf.get(table); String itemCoreId = itemIndexMap.get(indexKey).get(itemCoreIdField); putNewIndexMap(newItemIndexMap, indexKey, value, key -> new2oldItemIdMap.get(itemCoreId)); }
哈!if-elseif-elseif 語句消失了!此時,才說真正抓住了設計重點:將itemId 的映射抽離出來作成配置,而後其它的依此解析。
// 這個配置含有新老itemId映射的信息以及獲取orderNo, sID 的字段信息 private static List<String> itemBaseDataConf = Arrays.asList("item:", "item:item_core_id", "item:order_no", "item:s_id"); private static Map<String,String> itemIdConf = new HashMap() { { put("item", "item:item_core_id"); put("item_core", "item_core:id"); put("item_price", "item_price:item_id"); put("item_price_change_log", "item_price_change_log:item_id"); } }; /** * 聚合一個訂單下的全部商品信息 * @param itemIndexMap 一個訂單全部商品的信息映射 * @return 一個訂單下的全部商品信息 * * key 是 sID + order_no + item_id ; */ private static Map<String, Map<String,Object>> mergeOrderItemMap(Map<String, Map<String,String>> itemIndexMap) { if (itemIndexMap == null || itemIndexMap.isEmpty()) { return new HashMap<>(); } // Map[oldItemId, newItemId] Map<String,String> old2newItemIdMap = new HashMap<>(); Map<String,String> new2oldItemIdMap = new HashMap<>(); Set<Map.Entry<String,Map<String,String>>> entries = itemIndexMap.entrySet(); String orderNo = ""; String kdtId = ""; // 構建itemID映射 for (Map.Entry<String,Map<String,String>> entry: entries) { String indexKey = entry.getKey(); Map<String,String> value = entry.getValue(); if (indexKey.startsWith(itemBaseDataConf.get(0))) { old2newItemIdMap.put(indexKey, value.get(itemBaseDataConf.get(1))); new2oldItemIdMap.put(value.get(itemBaseDataConf.get(1)), indexKey); orderNo = value.get(itemBaseDataConf.get(2)); kdtId = value.get(itemBaseDataConf.get(3)); } } Map<String, Map<String,Object>> newItemIndexMap = aggregationAllInfoOfEachItem(itemIndexMap, new2oldItemIdMap); return buildFinalOrderItemMap(newItemIndexMap, old2newItemIdMap, orderNo, kdtId); } /* * 聚合每一個商品的全部信息 * * Map[item:id, Map[table:field, value]] */ private static Map<String, Map<String,Object>> aggregationAllInfoOfEachItem(Map<String, Map<String,String>> itemIndexMap, Map<String,String> new2oldItemIdMap) { Map<String, Map<String,Object>> newItemIndexMap = new HashMap<>(); itemIndexMap.forEach( (indexKey, value) -> { String table = indexKey.split(":")[0]; if (itemIdConf.containsKey(table)) { String itemCoreIdField = itemIdConf.get(table); String itemCoreId = itemIndexMap.get(indexKey).get(itemCoreIdField); putNewIndexMap(newItemIndexMap, indexKey, value, key -> new2oldItemIdMap.get(itemCoreId)); } } ); return newItemIndexMap; } /* * 將各商品信息聚合到相應的原itemId的鍵下 */ private static void putNewIndexMap(Map<String, Map<String,Object>> newItemIndexMap, String indexKey, Map<String,String> value, Function<String, String> getOriginItemIdFunc) { String originItemId = getOriginItemIdFunc.apply(indexKey); if (newItemIndexMap.get(originItemId) == null) { newItemIndexMap.put(originItemId, new HashMap<>()); } Map<String,Object> srcMap = newItemIndexMap.get(originItemId); newItemIndexMap.get(originItemId).putAll(merge(srcMap, value)); }
能夠看到,putNewIndexMap 使用了 Function 做爲參數,讓調用方指定如何去獲取 originItemId,而後根據獲取的originItemId進行通用處理。這裏 Function 實現了模板方法模式。
注意到這個方法簽名使用了 [ ? extends Object ]。 這裏使用了協變特性。即對應參數 Map[String, ? extend Object],既能夠傳入 Map[String, Object], 也能夠傳入 Map[String, String] ,或 Map[String, Entity] ,避免從 Map[String, Entity] 到 Map[String, Object] 的無聊轉換。
public static Map<String, ? extends Object> merge(Map<String,? extends Object> src, Map<String, ? extends Object> dest)
ItemUtilTest.java
package cc.lovesq.study.test.datastructure; import org.junit.Test; import java.util.Arrays; import java.util.Map; import cc.lovesq.study.test.CommonForTest; import zzz.study.utils.ItemUtil; import zzz.study.utils.JsonUtil; import zzz.study.utils.NewMapUtil; /** * Created by shuqin on 17/11/10. */ public class ItemUtilTest extends CommonForTest { String newItemInfoStr = "{\n" + " \"item:s_id:18006666\": \"1024\",\n" + " \"item:s_id:18008888\": \"1024\",\n" + " \"item:g_id:18006666\": \"6666\",\n" + " \"item:g_id:18008888\": \"8888\",\n" + " \"item:num:18008888\": \"8\",\n" + " \"item:num:18006666\": \"6\",\n" + " \"item:item_core_id:18006666\": \"9876666\",\n" + " \"item:item_core_id:18008888\": \"9878888\",\n" + " \"item:order_no:18006666\": \"E20171013174712025\",\n" + " \"item:order_no:18008888\": \"E20171013174712025\",\n" + " \"item:id:18008888\": \"18008888\",\n" + " \"item:id:18006666\": \"18006666\",\n" + " \"item_core:num:9878888\": \"8\",\n" + " \"item_core:num:9876666\": \"6\",\n" + " \"item_core:id:9876666\": \"9876666\",\n" + " \"item_core:id:9878888\": \"9878888\",\n" + " \"item_price:item_id:1000\": \"9876666\",\n" + " \"item_price:item_id:2000\": \"9878888\",\n" + " \"item_price:price:1000\": \"100\",\n" + " \"item_price:price:2000\": \"200\",\n" + " \"item_price:id:2000\": \"2000\",\n" + " \"item_price:id:1000\": \"1000\",\n" + " \"item_price_change_log:id:1111\": \"1111\",\n" + " \"item_price_change_log:id:2222\": \"2222\",\n" + " \"item_price_change_log:item_id:1111\": \"9876666\",\n" + " \"item_price_change_log:item_id:2222\": \"9878888\",\n" + " \"item_price_change_log:detail:1111\": \"haha1111\",\n" + " \"item_price_change_log:detail:2222\": \"haha2222\",\n" + " \"item_price_change_log:id:3333\": \"3333\",\n" + " \"item_price_change_log:id:4444\": \"4444\",\n" + " \"item_price_change_log:item_id:3333\": \"9876666\",\n" + " \"item_price_change_log:item_id:4444\": \"9878888\",\n" + " \"item_price_change_log:detail:3333\": \"haha3333\",\n" + " \"item_price_change_log:detail:4444\": \"haha4444\"\n" + "}"; @Test public void testBuildItemIndexMapForNew() { Map<String,Object> itemInfoMap = JsonUtil.readMap(newItemInfoStr); Map<String,Map<String,String>> itemIndexMap = ItemUtil .buildItemIndexMap(NewMapUtil.transMap(itemInfoMap)); System.out.println(itemIndexMap); eq("18006666", itemIndexMap.get("item:18006666").get("item:id")); eq("6666", itemIndexMap.get("item:18006666").get("item:g_id")); eq("1024", itemIndexMap.get("item:18006666").get("item:s_id")); eq("E20171013174712025", itemIndexMap.get("item:18006666").get("item:order_no")); eq("9876666", itemIndexMap.get("item:18006666").get("item:item_core_id")); eq("18008888", itemIndexMap.get("item:18008888").get("item:id")); eq("8888", itemIndexMap.get("item:18008888").get("item:g_id")); eq("1024", itemIndexMap.get("item:18008888").get("item:s_id")); eq("E20171013174712025", itemIndexMap.get("item:18008888").get("item:order_no")); eq("9878888", itemIndexMap.get("item:18008888").get("item:item_core_id")); eq("9876666", itemIndexMap.get("item_core:9876666").get("item_core:id")); eq("6", itemIndexMap.get("item_core:9876666").get("item_core:num")); eq("9878888", itemIndexMap.get("item_core:9878888").get("item_core:id")); eq("8", itemIndexMap.get("item_core:9878888").get("item_core:num")); eq("9876666", itemIndexMap.get("item_price:1000").get("item_price:item_id")); eq("1000", itemIndexMap.get("item_price:1000").get("item_price:id")); eq("100", itemIndexMap.get("item_price:1000").get("item_price:price")); eq("9878888", itemIndexMap.get("item_price:2000").get("item_price:item_id")); eq("2000", itemIndexMap.get("item_price:2000").get("item_price:id")); eq("200", itemIndexMap.get("item_price:2000").get("item_price:price")); eq("9876666", itemIndexMap.get("item_price_change_log:1111").get("item_price_change_log:item_id")); eq("haha1111", itemIndexMap.get("item_price_change_log:1111").get("item_price_change_log:detail")); eq("9878888", itemIndexMap.get("item_price_change_log:2222").get("item_price_change_log:item_id")); eq("haha2222", itemIndexMap.get("item_price_change_log:2222").get("item_price_change_log:detail")); eq("9876666", itemIndexMap.get("item_price_change_log:3333").get("item_price_change_log:item_id")); eq("haha3333", itemIndexMap.get("item_price_change_log:3333").get("item_price_change_log:detail")); eq("9878888", itemIndexMap.get("item_price_change_log:4444").get("item_price_change_log:item_id")); eq("haha4444", itemIndexMap.get("item_price_change_log:4444").get("item_price_change_log:detail")); } @Test public void testBuildFinalOrderItemMapForNew() { Map<String,Object> itemInfoMap = JsonUtil.readMap(newItemInfoStr); Map<String, Map<String,Object>> finalOrderItemMap = ItemUtil .buildFinalOrderItemMap(NewMapUtil.transMap(itemInfoMap)); System.out.println(finalOrderItemMap); eq("18006666", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item:id")); eq("6666", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item:g_id")); eq("1024", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item:s_id")); eq("E20171013174712025", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item:order_no")); eq("9876666", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item_core:id")); eq("6", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item_core:num")); eq("9876666", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item_price:item_id")); eq("100", finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item_price:price")); eq("18008888", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item:id")); eq("8888", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item:g_id")); eq("1024", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item:s_id")); eq("E20171013174712025", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item:order_no")); eq("9878888", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item_core:id")); eq("8", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item_core:num")); eq("9878888", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item_price:item_id")); eq("200", finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item_price:price")); eq(Arrays.asList("haha3333", "haha1111"), finalOrderItemMap.get("1024_E20171013174712025_18006666").get("item_price_change_log:detail")); eq(Arrays.asList("haha2222", "haha4444"), finalOrderItemMap.get("1024_E20171013174712025_18008888").get("item_price_change_log:detail")); } }
CommonForTest.java
package cc.lovesq.study.test; import org.junit.Assert; import java.util.List; import static org.junit.Assert.assertEquals; /** * Created by shuqin on 17/11/10. */ public class CommonForTest { public static final String NOT_THROW_EXCEPTION = "Not Throw Exception"; public void eq(Object expected, Object actual) { assertEquals(expected, actual); } public <T> void eq(T[] expected, T[] actual) { Assert.assertArrayEquals(expected, actual); } public <T> void eq(List<T> expectedList, List<T> actualList) { if (expectedList == null && actualList == null) { return ; } assertEquals(expectedList.size(), actualList.size()); for (int i=0; i< expectedList.size(); i++) { assertEquals(expectedList.get(i), actualList.get(i)); } } public void fail(String message) { Assert.fail(message); } }
package zzz.study.utils; import org.codehaus.jackson.map.DeserializationConfig; import org.codehaus.jackson.map.ObjectMapper; import org.codehaus.jackson.map.annotate.JsonSerialize; import java.text.SimpleDateFormat; import java.util.HashMap; import java.util.Map; public class JsonUtil { private static final ObjectMapper MAPPER = new ObjectMapper(); static { // 爲保持對象版本兼容性,忽略未知的屬性 MAPPER.configure(DeserializationConfig.Feature.FAIL_ON_UNKNOWN_PROPERTIES, false); // 序列化的時候,跳過null值 MAPPER.getSerializationConfig().setSerializationInclusion(JsonSerialize.Inclusion.NON_NULL); // date類型轉化 SimpleDateFormat fmt = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); MAPPER.setDateFormat(fmt); } /** * 將一個json字符串解碼爲java對象 * * 注意:若是傳入的字符串爲null,那麼返回的對象也爲null * * @param json json字符串 * @param cls 對象類型 * @return 解析後的java對象 * @throws RuntimeException 若解析json過程當中發生了異常 */ public static <T> T toObject(String json, Class<T> cls) { if (json == null) { return null; } try { return MAPPER.readValue(json, cls); } catch (Exception e) { return null; } } /** * 讀取JSON字符串爲MAP */ @SuppressWarnings("unchecked") public static Map<String, Object> readMap(String json) { return toObject(json, HashMap.class); } }