Java8 Map 示例:一个略复杂的数据映射聚合例子及代码重构

栏目: Java · 发布时间: 6年前

内容简介:Java8 Map 示例:一个略复杂的数据映射聚合例子及代码重构

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

问题

给定一个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);
    }

java 8 中可使用 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);
    newItemI

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 = "{\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);
  }

}

以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持 码农网

查看所有标签

猜你喜欢:

本站部分资源来源于网络,本站转载出于传递更多信息之目的,版权归原作者或者来源机构所有,如转载稿涉及版权问题,请联系我们

Convergence Culture

Convergence Culture

Henry Jenkins / NYU Press / 2006-08-01 / USD 30.00

"Convergence Culture" maps a new territory: where old and new media intersect, where grassroots and corporate media collide, where the power of the media producer, and the power of the consumer intera......一起来看看 《Convergence Culture》 这本书的介绍吧!

随机密码生成器
随机密码生成器

多种字符组合密码

HTML 编码/解码
HTML 编码/解码

HTML 编码/解码

RGB HSV 转换
RGB HSV 转换

RGB HSV 互转工具