zoukankan      html  css  js  c++  java
  • 一个略复杂的数据映射聚合例子及代码重构

    本文内容来自真实的工作案例,因其转换略复杂,且有一定意义,故记录之。

    问题###

    给定一个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里的结构获取到的记录。为了企业保密性,对表、字段以及值做了简化的特殊处理。目标是将这个订单的各个商品的信息聚合在一起。 即得到:

    {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 字段。

    基本思路是:

    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);

    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 中。

    程序实现###

    初步实现####

    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的遍历访问比较啰嗦,可以更简洁一些。

    使用forEach进行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 的映射抽离出来做成配置,然后其它的依此解析。

    重构后的ItemUtil####

    // 这个配置含有新老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));
      }
    

    Java8特性###

    Function####

    可以看到,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 = "{
    "
                              + "    "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"
    "
                              + "}";
    
      @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);
      }
    
    }
    
  • 相关阅读:
    @WebFilter注解
    Value '0000-00-00' can not be represented as java.sql.Date解决办法
    项目配置 xml文件时 报错提示(The reference to entity "useSSL" must end with the ';' delimiter.)
    eclipse中取消自动生成的TODO Auto-generated method stub
    eclipse中把选中的代码全部变成大写或者小写的快捷键
    在浏览器访问Tomcat的时候报错java.lang.IllegalArgumentException: Control character in cookie value or attribute.
    Tomcat报错,内存溢出的错误Exception in thread "http-bio-8080-exec-13" java.lang.OutOfMemoryError: PermGen space
    java.io.Serializable的作用
    idea快捷键总结
    MYSQL分页limit速度太慢优化方法
  • 原文地址:https://www.cnblogs.com/lovesqcc/p/7812875.html
Copyright © 2011-2022 走看看