JAVA Json解析之json字符串转Map 左手的ㄟ右手 2022-05-21 09:12 331阅读 0赞 ### 前言 ### 昨天在修改订单这一块,因为我们可爱的产品大佬加了一个小小的新需求~~“首单”。 哟呵?首单?:针对用户A,如果这个用户有推荐人B,那么B就是A的直接上级。如果C有推荐人D,那么D是A的间接上级。 当用户存在上级(直接和间接),这一单均算是首单。。反正我刚开始是有点懵,一个用户居然可能会有两个首单,返利也不一样。 ### 问题 ### 因为订单走的是消息队列。订单支付完成,返利处理也是走的消息队列,这就难受了~~本地不能打断点调试,只能打日志,在测试服上面查看日志。然后就有一行报了`nullPointException`异常。反复调试,才发现原来是json字符串转Map出了问题。先看代码! ### 代码 ### /** * 支付完成时 - 根据用户ID - 检测该订单是否是此用户的首单 * 首单条件:1.该用户有上级(产生返利) 2.订单中包含RMB商品 3.满足1,2两条件的第一个订单 */ @Override public Boolean checkIsFirstOrder(Integer orderId, Integer userId) { Jedis jedis = RedisPool.getJedis(); try { Boolean firstOrder = Boolean.TRUE; // check 用户是否存在 BsUser user = userMapper.queryUserByInfoId(userId); if (user == null) { throw new BusiException(E.INVALID_PARAMETER, "用户不存在"); } // check 用户是否有上级 Integer directParentUserId = userMapper.queryParentId(userId); if (directParentUserId == null || directParentUserId == -1) { // 没有上级 一定不是首单 firstOrder = Boolean.FALSE; logger.info("checkIsFirstOrder: 用户ID:{},是否是首单:{},info:{}", userId, firstOrder, "没有上级 一定不是首单"); return firstOrder; } // 1.check redis中是否存有该用户首单数据 String firstOrderRedis = jedis.hget(Rkey.ORDER_IS_FIRST_ORDER, userId.toString()); if (!StringUtils.isEmpty(firstOrderRedis)) { // 下面这行代码有问题 Map<String, Object> info = JsonUtils.transBean2Map(firstOrderRedis); // Map<String, Object> info = JsonUtils.toBean(firstOrderRedis); Object firstOrderTypeRedis = info.get("firstOrderType"); if (firstOrderTypeRedis != null) { Integer firstOrderType = (Integer) firstOrderTypeRedis; logger.info("checkIsFirstOrder: 用户ID:{},firstOrderTypeRedis:{}", userId, firstOrderTypeRedis); if (firstOrderType.equals(OrderConst.IS_BOTH_FIRST_ORDER) || firstOrderType.equals(OrderConst.IS_INDIRECT_FIRST_ORDER)) { // 不是首单 firstOrder = Boolean.FALSE; logger.info("checkIsFirstOrder: 用户ID:{},是否是首单:{},info:{}", userId, firstOrder, "redis已存在 不是首单"); } else if (firstOrderType.equals(OrderConst.IS_DIRECT_FIRST_ORDER)) { // 是首单 firstOrder = Boolean.TRUE; logger.info("checkIsFirstOrder: 用户ID:{},是否是首单:{},info:{}", userId, firstOrder, "直接首单已存在 间接首单不存在"); } } } else { firstOrder = Boolean.TRUE; } if (firstOrder) { // 2.如果redis 判断是首单 查数据库,再判断一次是否存在首单 List<BsOrder> orderList = orderMapper.queryFirstOrderByUserId(userId); if (orderList != null && !orderList.isEmpty()) { for (BsOrder order : orderList) { if (order.getFirstOrderType().equals(OrderConst.IS_INDIRECT_FIRST_ORDER) || order.getFirstOrderType().equals(OrderConst.IS_BOTH_FIRST_ORDER)) { // 不是首单 firstOrder = Boolean.FALSE; logger.info("checkIsFirstOrder: 用户ID:{},是否是首单:{},info:{}", userId, firstOrder, "mysql 已存在 不是首单"); return firstOrder; } } } } logger.info("checkIsFirstOrder: 用户ID:{},是否是首单:{}", userId, firstOrder); return firstOrder; } finally { RedisPool.returnJedis(jedis); } } ### 分析 ### 1.上面代码第31行,变量`firstOrderRedis`是Json类型字符串,将字符串转Map,变量`info`的值是`null`: Map<String, Object> info = JsonUtils.transBean2Map(firstOrderRedis); // firstOrderRedis的值是取redis,值如下面截图: ![这里写图片描述][70] 即: { "directFirstOrder": { //直接首单信息 "userId": 3454, "orderId": 976, "firstOrderType": 1 }, "firstOrderType": 3, //最终首单类型 "inDirectFirstOrder": { // 间接首单信息 "userId": 3454, "orderId": 976, "firstOrderType": 2 } } 我也不成想,就是将这样一个json字符串转map,没成功。。。。。。。。。。。。。。。 百思不得其姐!! `JsonUtils`是公司封装的json解析工具类,具体是谁写的,我就不知道了~~ 该类完整代码见我这篇博客:[JAVA基础之HashMap转List][JAVA_HashMap_List] 我当时调用的是`JsonUtils`中的`transBean2Map`这个方法,源码如下: public static Map<String, Object> transBean2Map(Object obj) { if (obj == null) { return null; } Map<String, Object> map = new HashMap<String, Object>(); try { BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); for (PropertyDescriptor property : propertyDescriptors) { String key = property.getName(); if (!key.equals("class")) { Method getter = property.getReadMethod(); Object value = getter.invoke(obj); map.put(key, value); } } } catch (Exception e) { System.out.println("transBean2Map Error " + e); } return map; } 仔细一看`transBean2Map`这个方法才发现,原来他只是将一个bean,也就是一个有属性的类转成Map。而我调用时,看到这个方法传入的是一个object,以为字符串也可以转成map。字符串用这个方法,转出来是个null。 2.分析下`transBean2Map`这个方法: // 很明显,这行代码是得到传进来的这个bean的信息。 BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass()); `Introspector`类: Introspector类为访问目标Jave Bean支持的属性、事件和方法提供了标准方法。该方法可用于工具类(如BeanUtils)中。 对于属性、事件和方法中的每一类信息,Introspector会分别分析目标bean以及其父类,寻找显式或隐式信息并用其构建一个能够全面描述目标bean的BeanInfo对象。 通过调用`Introspector.getBeanInfo()`方法来获得指定类的bean信息。Java Bean规范允许通过实现BeanInfo接口,定义一个对象来描述bean。为了将BeanInfo与bean关联起来,须遵守如下命名模式:bean信息类的名字必须是将”BeanInfo”添加到bean名字的后面构成。 了解更多关于`Introspector`类,请阅读这篇博客[从Introspector谈Java内省机制][Introspector_Java] 咱们接着看: // 这里就是从刚刚得到的bean信息中,获取到这个类的属性 PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors(); // 遍历这个类的所有属性 for (PropertyDescriptor property : propertyDescriptors) { // 得到属性的名字:如name,sex String key = property.getName(); if (!key.equals("class")) { Method getter = property.getReadMethod(); Object value = getter.invoke(obj); // 将属性名,属性值放入map key就是属性名 map.put(key, value); } } 原来是这样将一个类转换为map的。而我把一个json字符串当做一个bean传入这个方法,相当于,先去获取并遍历`String`类的所有属性。当然就找不到对应的key - value。返回的值也就是一个null。 后面调用工具类`JsonUtils`中`toBean`这个方法: @SuppressWarnings("unchecked") public static HashMap<String, Object> toBean(String json) { return toBean(json, HashMap.class); } public static <T> T toBean(String json, Class<T> clazz) { try { T bean = (T) mapper.readValue(json, clazz); return bean; } catch (IOException e) { e.printStackTrace(); } return null; } 问题就这样解决了。。。`toBean()`??? 大哥,你取名字能取得再随意一点嘛!谁能想到`toBean()`返回的竟然是一个HashMap… ### 总结 ### 咳咳!这一次的总结真是令人感到尴尬呢! 1.不能断章取义,看到方法名理解,不一定这个方法作用就是那样。 2.这一次最老火的就是,因为订单这里走的消息队列。改一行代码,就得重启服务器,去测试。这样这是草鸡麻烦!!! 下次,可以将需要测试的方法独立出来,用postMan调用,手动传入需要传入的值,本地打断点测试。方便得多! 这次,测试花了我太多时间,其实本地打断点测试,几分钟就能找到问题。遇到过坑了,下一次才知道怎么去解决。QAQ 好了,这次的博客,主要是为了记录一下这次我遇到的坑。。可能对大家并没有什么帮助。 ### 收尾 ### 世界真奇怪,最陌生的人:快递、外卖、骗子和老板,反而最常给我们打电话。 [70]: /images/20220521/2d627153cbc54986b48dd79be07d1da8.png [JAVA_HashMap_List]: https://blog.csdn.net/qq_22638399/article/details/80670212 [Introspector_Java]: http://cwind.iteye.com/blog/2007496
相关 Java JSON解析问题:非JSON字符串转JSON失败 在Java中,如果你有一个非JSON的字符串,直接使用`org.json.JSONObject`或者其他JSON库进行解析通常会失败。这是因为非JSON字符串不符合JSON数据 谁借莪1个温暖的怀抱¢/ 2024年09月11日 20:30/ 0 赞/ 9 阅读
相关 map转Json字符串 Map<String, Object> params = new HashMap<>(); params.put("a","11111"); 今天药忘吃喽~/ 2022年12月15日 03:22/ 0 赞/ 180 阅读
相关 java解析json转Map 前段时间在做json报文处理的时候,写了一个针对不同格式json转map的处理工具方法,总结记录如下: 1、单节点单层级、单节点多层级json转map impo £神魔★判官ぃ/ 2022年06月09日 00:56/ 0 赞/ 828 阅读
相关 json字符串转map 现象: 将得到的json字符串转为map 方法: ![这里写图片描述][SouthEast] 方法二:json字符串 ![这里写图片描述][SouthEast àì夳堔傛蜴生んèń/ 2022年06月08日 00:07/ 0 赞/ 194 阅读
相关 map转json,json转map 1.String paramsMaps; Map<String, Object> mapTypes = JSON.parseObject(paramsMaps) àì夳堔傛蜴生んèń/ 2022年06月07日 00:48/ 0 赞/ 270 阅读
相关 JAVA Json解析之json字符串转Map 前言 昨天在修改订单这一块,因为我们可爱的产品大佬加了一个小小的新需求~~“首单”。 哟呵?首单?:针对用户A,如果这个用户有推荐人B,那么B就是A的直接上级。如果C 左手的ㄟ右手/ 2022年05月21日 09:12/ 0 赞/ 332 阅读
相关 Map转Json字符串 举栗: // 创建map Map<String, Object> map = new HashMap<String, Object>(); 男娘i/ 2022年03月02日 09:24/ 0 赞/ 353 阅读
相关 map转json字符串 Map<String, Object> params = new HashMap<>(); params.put("a","11111"); params.put("b", 「爱情、让人受尽委屈。」/ 2021年12月21日 02:55/ 0 赞/ 296 阅读
相关 json字符串转为map集合 map集合转json字符串 /json字符串转成map集合 private Map<String, Object> getMapFromJson(String message) \{ 男娘i/ 2021年12月14日 04:41/ 0 赞/ 481 阅读
还没有评论,来说两句吧...