首页 > 其他分享 >【实用技巧】JSON格式转换方式

【实用技巧】JSON格式转换方式

时间:2024-04-23 21:55:26浏览次数:26  
标签:newPath 实用技巧 String private JSON 格式 import new

1  前言

对接开发中,常遇到的就是报文转换。比如从淘宝或者京东拉取订单,亦或是各个公司内部的WMS、OMS等交互,都涉及到格式转换。而大多的格式基本上都是 JSON 格式,当然也有一些老的 SAP 交互用的是 XML格式的,还有一小部分 webService 接口也是用的 XML 格式。
那我们这节就看看JSON报文转换,当然最简单最直接的方式就是硬编码,直接写 set get 啥的,或者一些 JSON 网站上有那种 JSON 转 JavaBean 的,比如我们常用的 json.cn等,我这里主要是列两种不是那么硬的。

2  实践

2.1  测试准备

我这里有两种实体,比如左边是我们的第三方平台订单信息,右边我们自己系统的订单信息,那么当要拉取各种第三方平台的订单的时候,不可避免的就是我们中间的转换,也是我们本节要讲的。

第三方订单信息:

// 第三方订单主信息
@Data
public class ThirdOrderEntity {
    /**
     * 订单号
     */
    private String flowNo;
    /**
     * 订单类型
     */
    private Integer tradeType;
    /**
     * 下单时间
     */
    private LocalDateTime payTime;
    /**
     * 订单金额
     */
    private BigDecimal orderAmount;
    /**
     * 订单备注
     */
    private String remark;
    /**
     * 明细信息
     */
    private List<ThirdOrderDetailEntity> skuList;
}
// 第三方订单明细信息
@Data
public class ThirdOrderDetailEntity {
    /**
     * 商品编码
     */
    private String sku;
    /**
     * 数量
     */
    private BigDecimal num;
}

订单信息:

// 订单主信息
@Data
public class OrderEntity {
    /**
     * 订单号
     */
    private String orderNo;
    /**
     * 订单类型
     */
    private Integer orderType;
    /**
     * 下单时间
     */
    private LocalDateTime orderTime;
    /**
     * 订单金额
     */
    private BigDecimal totalAmount;
    /**
     * 订单备注
     */
    private String orderRemark;
    /**
     * 明细信息
     */
    private List<OrderDetailEntity> detailList;
}
// 订单明细信息
@Data
public class OrderDetailEntity {
    /**
     * 商品编码
     */
    private String skuCode;
    /**
     * 数量
     */
    private BigDecimal quantity;
}

2.2  JsonPath 正则转换

我这就直接贴代码了哈:

package com.example.demo.service;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.JSONPath;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.example.demo.entity.OrderEntity;
import com.example.demo.entity.third.ThirdOrderDetailEntity;
import com.example.demo.entity.third.ThirdOrderEntity;
import com.google.common.collect.Lists;

import java.io.BufferedReader;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.HashMap;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author: kuku
 * @description
 */
public class JsonConvert {
    /**
     * 从规则生成转换正则,主要针对目标jsonPath和源jsonPath
     * @param map
     * @return
     */
    private static Map<String, String> convertRules(Map<String, String> map) {
        Map<String,String> ruleMap = new HashMap<String, String>();
        for (Map.Entry<String,String> entry:map.entrySet()){
            //针对目标路径进行转换
            String key = "/"+ entry.getKey()
                    .replaceAll("\\[(\\d+)\\]","/\\$$1")
                    .replace(".","/");
            //针对源路径进行转换
            String value = "/"+ entry.getValue()
                    .replaceAll("\\[\\]","/(\\\\d+)")
                    .replace(".","/\\d*/*");
            ruleMap.put(key,value);
        }
        return ruleMap;
    }

    /**
     * json映射转换,返回转换后的json数据
     * @param jobj 源json数据
     * @param map  map的key为目标jsonPath,value为源jsonPath,需要换为实际的映射对象,并传入类型和值集转换相关信息
     * @return
     */
    private static JSONObject exchangeJson(JSONObject jobj,Map<String,String> map) {
        Map<String, String> ruleMap = convertRules(map);
        JSONObject newJson = new JSONObject();
        Map<String,Object> paths = JSONPath.paths(jobj);
        for (Map.Entry<String,Object> pathEntry : paths.entrySet()){
            for (Map.Entry<String,String> ruleEntry:ruleMap.entrySet()){
                if(pathEntry.getKey().matches(ruleEntry.getValue())){
                    String newPath = pathEntry.getKey().replaceAll(ruleEntry.getValue(),ruleEntry.getKey());
                    //获取转换后的value。此处进行类型转换和值集映射转换
                    Object newValue = pathEntry.getValue();
                    if(JSONPath.contains(newJson,newPath) && JSONPath.size(newJson,newPath) < 0){
                        //path下已经存在一个值,则需要将类型转换为jsonArray并添加第二个值
                        Object tmp = JSONPath.eval(newJson,newPath);
                        Object[] tArray = {tmp,newValue};
                        JSONPath.set(newJson, newPath, tArray);
                    }else if(JSONPath.size(newJson,newPath) > 1){
                        //path下已经存在数组对象,直接追加
                        JSONPath.arrayAdd(newJson, newPath, newValue);
                    }else{
                        //path不存在,直接添加对象
                        JSONPath.set(newJson, newPath, newValue);
                    }
                }
            }
        }
        return newJson;
    }

    public static void main(String[] args) {
        // 平台订单信息
        ThirdOrderEntity thirdOrderEntity = new ThirdOrderEntity();
        thirdOrderEntity.setFlowNo("1111");
        thirdOrderEntity.setOrderAmount(new BigDecimal("111.2"));
        thirdOrderEntity.setPayTime(LocalDateTime.now());
        thirdOrderEntity.setRemark("我是订单备注");
        thirdOrderEntity.setTradeType(2);

        ThirdOrderDetailEntity one = new ThirdOrderDetailEntity();
        one.setSku("PE-OEF-WER-002");
        one.setNum(new BigDecimal("2"));
        ThirdOrderDetailEntity two = new ThirdOrderDetailEntity();
        two.setSku("WER-OEF-WER-002");
        two.setNum(new BigDecimal("99"));
        thirdOrderEntity.setSkuList(Lists.newArrayList(one, two));

        // 第三方平台的 JSNO
        String sourceJson = JSON.toJSONString(thirdOrderEntity);
        // JSON转换规则
        InputStream resourceAsStream = JsonConvert.class.getResourceAsStream("/testfile/changeOrder.json");
        String changeRule = new BufferedReader(new InputStreamReader(resourceAsStream)).lines().collect(Collectors.joining(System.lineSeparator()));
        JSONArray array = JSON.parseArray(changeRule);
        // 规则放进 map
        Map<String,String> map = new HashMap<>(16);
        for (Object o : array) {
            JSONObject jsonObject = (JSONObject) o;
            String oldPath = jsonObject.getString("oldPath");
            String newPath = jsonObject.getString("newPath");
            if (StringUtils.isNotBlank(oldPath) && StringUtils.isNotBlank(newPath)) {
                map.put(newPath, oldPath);
            }
        }
        JSONObject jobj = JSON.parseObject(sourceJson);
        String res = exchangeJson(jobj, map).toJSONString();
        System.out.println(res);
        
        OrderEntity orderEntity = JSON.parseObject(res, OrderEntity.class);
        System.out.println(orderEntity);
    }
}

转换规则:

[
  {
    "newPath":"orderNo",
    "oldPath":"flowNo"
  },
  {
    "newPath":"totalAmount",
    "oldPath":"orderAmount"
  },
  {
    "newPath":"orderTime",
    "oldPath":"payTime"
  },
  {
    "newPath":"orderRemark",
    "oldPath":"remark"
  },
  {
    "newPath":"orderType",
    "oldPath":"tradeType"
  },
  {
    "newPath":"detailList[1].skuCode",
    "oldPath":"skuList[].sku"
  },
  {
    "newPath":"detailList[1].quantity",
    "oldPath":"skuList[].num"
  }
]

效果:

2.3  json-convertor

另外一中方式是我在 gitee上找的一个:json-convertor,我们来试试:

package com.example.demo.service;

import io.shmilyhe.convert.JsonConvertor;
import io.shmilyhe.convert.tools.ResourceReader;

/**
 * @author: kuku
 * @description
 */
public class JsonTest {
    public static void main(String[] args) {
        String json = ResourceReader.read("testfile/test1.json");
        String commands =ResourceReader.read("testfile/test1.script");
        //一个脚本需只初始化一次,初始化脚本会做一次内存的编译,比较耗时。脚本初始化后执行的效率很高。
        JsonConvertor jc = new JsonConvertor(commands);
        String dest = jc.convert(json);
        System.out.println(dest);
    }
}

效果是一样的:

3  小结

感谢两位铁子的文章,JsonPath转换以及json-convertor,性能还有待考量哈。

标签:newPath,实用技巧,String,private,JSON,格式,import,new
From: https://www.cnblogs.com/kukuxjx/p/18153784

相关文章

  • Fastjson的toString链分析
    前言之前分析过Fastjson的getter链,忽略了toString链,现在补上,最终也是任意调用getter攻击测试packageorg.example;importcom.alibaba.fastjson.JSONObject;importcom.sun.org.apache.xalan.internal.xsltc.runtime.AbstractTranslet;importcom.sun.org.apache.xalan.inte......
  • 详细分析Java中的@JsonFormat注解和@DateTimeFormat注解
    @DateTimeFormat(pattern="yyyy-MM-ddHH:mm:ss")@JsonFormat(pattern="yyyy-MM-ddHH:mm:ss",timezone="GMT+8")privateDatecreated_on;在前后端数据交互的过程中,Data类型的数据经常会出现类型映射转换的错误,为了达到业务的目标时间格式,通常会使用@JsonFormat和@DateTi......
  • 系统——MP3格式的背景音乐处理
    目标*创建MP3格式的文件处理*主菜单音乐调用*关卡音乐调用*切换安全屋和关卡的音乐调用1.创建MP3格式的文件处理将MP3格式的文件拖入到UE中会是这种格式的文件为每个MP3文件创建一个媒体播放列表,方便存放不同关卡或场景的BGM创建一个媒体播放器便于BGM播放蓝图的......
  • Python 字符串格式化指南
    前言在Python中,字符串格式化是一种常见且重要的操作,用于将变量或值插入到字符串中,并控制输出的格式。本文将介绍几种常见的字符串格式化方法,帮助大家掌握在Python中有效地处理字符串的技巧。方法一:使用%操作符格式化字符串使用%操作符是一种传统的字符串格式化方法,可......
  • Everything搜索非NTFS格式文件
    Everything是一款非常优秀的文件搜索软件,但是普通用户只是通过它来进行文件名的搜索。其实该软件还隐藏了很多的搜索功能,用户只要熟练的使用这些功能,就可以快速查询到自己需要的文件内容。搜索非NTFS格式文件Everything软件在默认情况下只能对NTFS格式的文件进行搜索,但是由于现......
  • 使用digital amp时通过mtkparser从cfg音频文件转成ini格式
    针对digitalamp主要利用ini里的内容。drivercode会依据iniformattype去parser内容给digitalamp。下面是mtkparser的格式[INIT_TABLE]IniFormatType=x//MtkParser目前固定填0即可count=xx;//xx是后面部分index总数index_x=AA,BB,CC;//x:命令index值......
  • 原生js base64格式数据 下载
    原生jsbase64格式数据下载/***封装base64Strblob对象**/functionbase64toBlob(base64Str){varbstr=atob(base64Str),n=bstr.length,u8arr=newUint8Array(n);while(n--){u8arr[n]=bstr.charCodeAt(n);}returnnewBlob([u8arr]);}/......
  • error 对象,格式化信息处理方式
    处理场景是来自使用elementui的上传组件的时候,有时会因为某些原因导致上传失败,而这时候非接口端的报错,所以抛回的error的message需要前端解析,这种解析方式适用定义抛出的异常是Error对象的情况;参考文档是来自:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/......
  • JS基础(二)运算符、流程控制语句、数组对象、JSON对象、Date对象、Math对象、Function对
    一运算符<script>//算数运算符//(1)自加运算varx=10;//x=x+1;//x+=2;varret=x++;//先赋值再计算:x+=1//varret=++x;//先计算再赋值:x+=1console.log(x)......
  • 模块与包、json模块
    【一】模块与包介绍【1】什么是模块在Python中,一个py文件就是一个模块,文件名为xxx.py,模块名则是xxx,导入模块可以引入模块中已经写好的功能。如果把开发程序比喻成制造一台电脑编写模块就像是在制造电脑的零部件准备好零件后,剩下的工作就是按照逻辑把它们组装到一起。将......