Java实现将JSON文件导出到Excel

2023-11-14

文章目录

一、运行环境


  • windows10
  • IDEA 2022
  • JDK 8
  • Maven 3.8.6
  • Apache POI 5
  • fastjson2

二、需求描述


写一个功能,任意json生成excel,每个数组都单独生成一个sheet。

三、实现思路


参考资料:Apache POI 使用教程

主要实现思路: 使用支持Java对象与JSON对象、字符串互相转换的fastjson,以及支持Java将JSON转化Excel的库 apache-poi

Excel表格关键结构:

  • Workbook 工作台,相当于一个 excel文件
  • sheet,一个excel文件中的表格页面,可能有多个
    • row,所在sheet中的行
      • cel,所在sheet中所在行的列
        • value,所在单元格的值

在这里插入图片描述

JSON转换的几种情形与实现思路:

情形一:普通的单层结构,多个JSON对象

{
    "班级A" : [{
      "文章":"课文1",
      "作者":"李白"
    },
    {
      "文章":"课文2",
      "作者":"小李"
    },
    {
      "文章":"课文2",
      "作者": "小明"
    }]
}

导出结果:

在这里插入图片描述
当我们使用fastjson遍历JSONObject时,每次读取到的都是单个{ } 所包含的对象,比如:

{
  "文章":"课文1",
  "作者":"李白"
}

这种情况下,我们在Excel的Sheet中的行是确定的,比如这里就是第二行(第一行是列名),行根据遍历的顺序确定,而列则是不确定的,在这里有 “文章”,“作者” 这两个列,但是一开始这两个列是不存在的。这里则确定文章在第一列,作者按第二列(默认升序排序)。

当遍历下一个对象时,我们可能遇到旧的列,也可能遇到新的列,比如:

{
  "文章":"课文2",
  "作者":"李白",
  "出版日期": "2022年7月6日"
}

这时,我们需要知道"文章" 和 “作者” 在第几列,同时也要知道 “出版日期” 应该在第几列,否则就不能确定唯一的单元格,将 JSON的value存储进去。

这里可以使用 Map<String, Integer> map 来记录列名以及下标。

在遍历对象时,key是列名,value则是单元格该填的值,如果 map.get(key) 的结果是空的,说明该列不存在,则需要创建,如果存在,那么可以创建单元格的对象,将值填入即可。

情形二:嵌套结构,JSON数组的嵌套

{
  "班级A":[
    {
      "学号":"A01",
      "语文":[
        {
          "文章":"课文1",
          "作者":"李白"
        },
        {
          "文章":"课文2",
          "作者":"小李"
        },
        {
          "文章":"课文2",
          "作者": "小明"
        }
      ],
      "数学":"130"
    },
    {
      "学号":"A02",
      "语文":"130",
      "数学":"135"
    }
  ],
}

实现效果:

在这里插入图片描述

在这里插入图片描述

这里相比之前的情况复杂了一些,主要的就是需要再次创建一个新的 sheet,这意味着需要使用递归完成创建,于是我们可以将之前那种情形的代码实现封装成一个方法,比如createSubSheet(),在遍历JSON对象时,如果value值是一个JSONAarray,那么就再次调用createSubSheet()这个方法,只要使用同一个Workbook对象,表示同一个excel文件,就能满足这个需求了。

四、实现代码


pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>groupId</groupId>
    <artifactId>poi_demo</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.apache.poi</groupId>
            <artifactId>poi-ooxml</artifactId>
            <version>5.2.2</version>
        </dependency>

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.9</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.7</version>
        </dependency>

    </dependencies>
</project>
123456789101112131415161718192021222324252627282930313233343536
JSONToExcelUtil.java
package cn.uni;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.alibaba.fastjson2.JSONWriter;
import com.alibaba.fastjson2.schema.JSONSchema;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFCell;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.*;
import java.util.HashMap;
import java.util.Map;

/**
 *  uni
 *  2022/07/05~2022/07/06
 *  将 JSON 转化为 Excel的工具类
 */
public class JSONToExcelUtil {

    /**
     * 读取绝对路径下的json文件
     * @param resourcePath json文件的绝对路径
     * @return json文件格式化后的字符串
     */
    public static String readJSONFile(String resourcePath) {
        try{
            // 1. 创建文件流
            File file = new File(resourcePath);
            // 2. 使用 common-lang3工具包, 以 UTF-8 格式读取文件, 转为字符串
            String str = FileUtils.readFileToString(file, "UTF-8");
            JSONObject jsonObject = JSONObject.parseObject(str);
            // 3. 将字符串转为标准的JSON格式的字符串
            return JSONObject.toJSONString(jsonObject, JSONWriter.Feature.WriteMapNullValue);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }

    /**
     * 创建 Sheet
     * @param layer 当前Sheet所在JSON中的层级
     * @param workbook 工作台 ( excel表格的主体 )
     * @param sheetName 当前页的名称
     * @param jsonArray JSON数组
     */
    public static void createSubSheet(int layer, XSSFWorkbook workbook, String sheetName, JSONArray jsonArray){
        // 创建新的 sheet
        XSSFSheet sheet = workbook.createSheet(sheetName);
        // 存储每个字段
        Map<String, Integer> map = new HashMap<>();
        // 统计当前的列
        int cellCount = 0;
        // 创建第一行
        XSSFRow firstRow = sheet.createRow(0);
        // 获取每一项
        for (int row = 1; row <= jsonArray.size(); row++) {
            JSONObject jsonObject = jsonArray.getJSONObject(row - 1);
            // 创建行
            XSSFRow currentRow = sheet.createRow(row);
            if(jsonObject != null){
                // 遍历每个KV
                for (String cellName : jsonObject.keySet()) {
                    // 列不存在时, 则创建列
                    if (!map.containsKey(cellName)) {
                        // 第一行创建列
                        XSSFCell firstRowCell = firstRow.createCell(cellCount);
                        firstRowCell.setCellValue(cellName);
                        map.put(cellName, cellCount++);
                    }
                    // 设置单元格
                    XSSFCell cell = currentRow.createCell(map.get(cellName));
                    // 获取 Value
                    String cellValue = JSON.toJSONString(jsonObject.get(cellName));

                    // 如果V为数组则递归创建sheet
                    if(JSON.isValidArray(cellValue)){
                        String subCellName = sheetName + "-" + cellName;
                        cell.setCellValue(subCellName);
                        createSubSheet(layer + 1, workbook,subCellName, jsonObject.getJSONArray(cellName));
                    }
                    else{
                        cell.setCellValue(jsonObject.getString(cellName));
                    }
                }
            } else{ // Value为一个数组
                JSONArray array = jsonArray.getJSONArray(row - 1);
                // 遍历数组
                if(array != null && array.size() > 0){
                    for (int i = 1; i <= array.size(); i++) {
                        JSONObject obj = array.getJSONObject(i - 1);
                        // 遍历 obj
                        for (String cellName : obj.keySet()) {
                            // 若列不存在则添加
                            if(!map.containsKey(cellName)){
                                XSSFCell cell = firstRow.createCell(cellCount);
                                map.put(cellName, cellCount++);
                                cell.setCellValue(cellName);
                            }
                            // 分情况讨论
                            String cellValue = obj.getString(cellName);
                            XSSFCell cell = currentRow.createCell(map.get(cellName));
                            // 如果值是JSON对象, 则递归创建
                            if(JSON.isValidObject(cellValue)){
                                String subSheetName = sheetName + "-" + cellName;
                                cell.setCellValue(subSheetName);
                                createSubSheet(layer+1, workbook, subSheetName , JSONObject.parseObject(cellValue));
                            } else if(JSON.isValidArray(cellValue)){
                                String subSheetName = sheetName + "-" + cellName;
                                cell.setCellValue(subSheetName);
                                createSubSheet(layer+1, workbook, subSheetName , JSONArray.parseArray(cellValue));
                            } else {
                                cell.setCellValue(cellValue);
                            }
                        }
                    }
                } else {
                    firstRow.createCell(0).setCellValue(sheetName);
                    XSSFCell cell = currentRow.createCell(cellCount);
                    cell.setCellValue(jsonArray.getString(row-1));
                }
            }
        }
    }

    /**
     * 创建 Sheet
     * @param layer 当前Sheet所在JSON中的层级
     * @param workbook 工作台 ( excel表格的主体 )
     * @param sheetName 当前页的名称
     * @param jsonObject JSON对象
     */
    public static void createSubSheet(int layer, XSSFWorkbook workbook, String sheetName, JSONObject jsonObject){
        // 创建新的 sheet
        XSSFSheet sheet = workbook.createSheet(sheetName);
        // 存储每个字段
        Map<String, Integer> map = new HashMap<>();
        // 统计当前的列
        int cellCount = 0;
        // 创建第一行
        XSSFRow fistRow = sheet.createRow(0);
        // 记录行数
        int row = 1;
        // 获取每一项
        // 创建行
        XSSFRow currentRow = sheet.createRow(row);
        // 遍历每个KV
        for (String cellName : jsonObject.keySet()) {
            // 列不存在时, 则创建列
            if (!map.containsKey(cellName)) {
                // 第一行创建列
                XSSFCell firstRowCell = fistRow.createCell(cellCount);
                firstRowCell.setCellValue(cellName);
                map.put(cellName, cellCount++);
            }
            // 设置单元格
            XSSFCell cell = currentRow.createCell(map.get(cellName));
            // 获取 Value
            String cellValue = JSON.toJSONString(jsonObject.get(cellName));
            // 如果V为对象则递归创建sheet
            if(JSON.isValidObject(cellValue)){
                String subCellName = "Sheet" + layer + "-" + sheetName + "-" + cellName;
                cell.setCellValue(subCellName);
                createSubSheet(layer + 1, workbook,subCellName, JSON.parseObject(cellValue));

            } else if(JSON.isValidArray(cellValue)){
                String subCellName = "Sheet" + layer + "-" + sheetName + "-" + cellName;
                cell.setCellValue(subCellName);
                createSubSheet(layer + 1, workbook,subCellName, JSON.parseArray(cellValue));
            }
            else{
                cell.setCellValue(jsonObject.getString(cellName));
            }
        }
    }

    /**
     * 将格式化的JSON字符串导出为Excel
     * @param jsonStr 格式化后的JSON字符串
     * @param savePath Excel保存路径
     * @param excelName Excel名称
     */
    public static void toExcelByString(String jsonStr, String savePath, String excelName){
        assert JSON.isValid(jsonStr) : "字符串: " + jsonStr + " 不是标准的JSON字符串";
        toExcelByJSONObject(JSONObject.parseObject(jsonStr),savePath, excelName);
    }

    /**
     * 将普通的Java对象导出为JSON文件
     * @param obj   Java对象
     * @param savePath  Excel保存路径
     * @param excelName Excel名称
     */
    public static void toExcelByObject(Object obj, String savePath, String excelName){
        String jsonStr = JSON.toJSONString(obj, JSONWriter.Feature.WriteMapNullValue);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        toExcelByJSONObject(jsonObject, savePath, excelName);
    }

    /**
     * 将本地的JSON文件导出为 Excel
     * @param resourcePath JSON文件的绝对路径
     * @param savePath  保存的路径
     * @param excelName 保存的Excel名称
     */
    public static void toExcelByLocalJSONFile(String resourcePath, String savePath, String excelName){
        // 1. 获取标准的 JSON 字符串
        String jsonStr = readJSONFile(resourcePath);
        // 验证字符串是否合法
        assert JSON.isValid(jsonStr) : "路径:[" + resourcePath + "] 的json文件不符合标准的JSON格式";
        toExcelByString(jsonStr, savePath, excelName);
    }

    /**
     * 将JSONObject转化导出到 Excel
     * 这里遵循递归导出,当遇到数组时会调用 createSheet创建新的页面。
     * @param jsonObject    JSON对象
     * @param savePath      Excel保存路径
     * @param excelName     Excel名称
     */
    public static void toExcelByJSONObject(JSONObject jsonObject,  String savePath, String excelName){
        try(XSSFWorkbook workbook = new XSSFWorkbook()){
            // 获取当前的Sheet
            XSSFSheet sheet = workbook.createSheet("sheet");
            // 获取第一行
            XSSFRow firstRow = sheet.createRow(0);
            // 记录Key所在的列
            Map<String, Integer> map = new HashMap<>();
            // 记录列数
            int cellCount = 0;
            // 遍历 JSON的key
            XSSFRow currentRow = sheet.createRow(1);
            for (String key : jsonObject.keySet()) {
                // 先处理列
                if(!map.containsKey(key)){  // 当列不存在则添加
                    map.put(key, cellCount);
                    XSSFCell cell = firstRow.createCell(cellCount++);
                    cell.setCellValue(key);
                }
                XSSFCell currentCell = currentRow.createCell(map.get(key));
                String jsonStr = jsonObject.getString(key);
                // 如果 Value为数组 则创建新的 Sheet
                if(JSON.isValidArray(jsonStr)){
                    String subSheetName = "Sheet-" + key;
                    createSubSheet(1, workbook, subSheetName, jsonObject.getJSONArray(key));
                    currentCell.setCellValue(subSheetName);
                } else if(JSON.isValidObject(jsonStr)){ // 如果当前 value 仍然是一个JSON对象
                    String subSheetName = "Sheet-" + key;
                    createSubSheet(1, workbook, subSheetName, jsonObject.getJSONObject(key));
                    currentCell.setCellValue(subSheetName);
                }
                else {
                    // 特殊处理空值
                    if(StringUtils.isEmpty(jsonStr))
                        currentCell.setCellValue("null");
                    else
                        currentCell.setCellValue(jsonStr);
                }
            }
            save(workbook, savePath, excelName);
        } catch (IOException ex) {
            throw new RuntimeException(ex);
        }
    }
    /**
     * 将 Excel对象保存到本地
     * @param workbook Excel对象
     * @param path Excel文件路径
     * @param excelName excel名称
     */
    public static void save(Workbook workbook, String path, String excelName){
        try {
            FileOutputStream fileOutputStream = new FileOutputStream(path +"/" + excelName +".xlsx");
            workbook.write(fileOutputStream);
            fileOutputStream.close();
            System.out.println("保存完毕. 保存位置为[ " + path + "/" + excelName + " ]");
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    public static void main(String[] args) {
        String jsonPath = "C:\\Users\\unirithe\\IdeaProjects\\poi_demo\\src\\main\\resources\\data.json";
        String savePath = "C:\\Users\\unirithe\\Desktop";
        String excelName = "demo";
        // 测试1
        toExcelByLocalJSONFile(jsonPath, savePath, excelName + "1");
        String jsonStr = readJSONFile(jsonPath);
        JSONObject jsonObject = JSONObject.parseObject(jsonStr);
        Object object = JSON.parse(jsonStr);
        // 测试2
        toExcelByString(jsonStr, savePath, excelName + "2");
        // 测试3
        toExcelByObject(object, savePath, excelName + "3");
        // 测试4
        toExcelByJSONObject(jsonObject, savePath, excelName + "4");
    }
}

测试的JSON数据:

{
  "班级A":[
    {
      "学号":"A01",
      "语文":[
        {
          "文章":"课文1",
          "作者":"李白"
        },
        {
          "文章":"课文2",
          "作者":"小李"
        },
        {
          "文章":"课文2",
          "作者": "小明"
        }
      ],
      "数学":"130"
    },
    {
      "学号":"A02",
      "语文":"130",
      "数学":"135"
    }
  ],
  "班级B":[
    {
      "学号":"B01",
      "语文":"128",
      "数学":"135"
    },
    {
      "学号":"B02",
      "语文":"133",
      "数学":"140"
    }
  ]
}

测试结果如下,这里保存的demo1、demo2、demo3和demo4结果是一致的,主要是为了测试不同方法的正确性。

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java实现将JSON文件导出到Excel 的相关文章

随机推荐

  • android开发Java调用C语言_Android使用jni调用c++/c方法详解

    1 下载ndk 2 编写jni的加载类 参考例子 public class JniTest public native String append String str1 String str2 static System loadLibr
  • C++ sort 排序(降序、升序)使用总结

    一 升序 C sort 函数十分方便 可以对内置类型也可对自定义类型进行快速排序 内置类型的使用比较简单 下面主要讨论自定义类型的排序 一般有如下几种使用方法 1 1 重载比较操作符 比如 我们现有一批学生 要根据他们的成绩进行升序排序 成
  • 基于epoll实现简单的web服务器

    1 简介 epoll 是 Linux 平台下特有的一种 I O 复用模型实现 于 2002 年在 Linux kernel 2 5 44 中被引入 在 epoll 之前 Unix Linux 平台下的 I O 复用模型包含 select 和
  • Excel使用多窗口打开(分屏幕的福音)

    1 材料 Office2010 其他不知道 2 注册表 2 1 Shett 8 2 2 Sheet 12如法炮制 照着图来就行了 话不多说
  • 鸿蒙系统是手机系统还是电脑系统,鸿蒙系统能兼容手机电脑和智能设备,这是怎样实现的?...

    鸿蒙系统它本身支持两种模式 一种是手机模式 一种是电脑模式 就比如现在华为 荣耀的高端手机 单独使用就是手机模式 通过HDMI线连接显示器或者电视屏幕的时候 它就变成了一台电脑 再配合蓝牙或者无线鼠标和键盘 使用体验上和普通的电脑并没有太大
  • 前端面试:如何修改overflow:scroll 滚动条的默认样式-如背景色以及宽度

    如何修改overflow scroll 滚动条的默认背景色以及宽度 使用 webkit scrolbar 自定义样式 复制代码 talk is cheap show me the code Title 所有主流浏览器都支持 overflow
  • 【Python】np.log

    此处先介绍log常用的两个底数计算 以10为底和以e为底 以后再补充完毕 1以10为底 import numpy as np np log10 x 如 gt gt gt np log10 100 2 0 gt gt gt 2 e为底 log
  • Kettle中使用JavaScrip调用jar包对文件内容进行MD5加密

    Kettle中使用JavaScript调用jar包对文件内容进行MD5加密 1 本文主要知识点 JavaScript调用jar包对文件内容进行MD5加密 返回加密md5值 Kettle实现对文件内容的加密 返回加密md5值 2 使用方法 1
  • 多元函数求极值,万能函数——fmincon讲解

    matlab中的函数fmincon可用于求可以求取多元函数的极值 其约束包括五种 1 线性不等式 约束 2 线性等式约束 3 变量约束 4 非线性不等式约束 5 非线性等式约束 其形式如下 x fmincon fun x0 A b Aeq
  • Acrobat里面直接截取部分页面(转存一页或者几页)为独立PDF

    不需要使用foxit福昕reader 在完整版acrobat里面 进入页面缩略图 右键 提取页面 出现如下对话框 1 直接确定 可以得到从214页至219页的独立pdf 2 勾选 提取页面为单独文件 则会有6个pdf
  • 校园网服务器系统需求分析,校园网需求及分析.doc

    校园网需求及分析 校园网络规划与设计 一 毕业设计课题名称 校园网络规划与设计 二 毕业设计任务 1 需求分析 2 系统设计原则和实现目标 1 网络系统设计原则 系统建设目标 2 网络性能分析 3 系统的总体设计 1 网络拓扑结构设计 2
  • 计算机主板上的fan,通用解决方案:计算机主板上的CPU_FAN,SYS_FAN,CHA_FAN,CPU_OPT接口知识...

    在组装计算机的过程中 尽管安装过程很简单 但经常会遇到接线问题 用户经常错误地将CPU散热器的电源线插入SYS FAN 尽管风扇可以旋转 但是在引导时可能会出现F1错误 CPU Fan Error 这也会导致CPU散热器无法智能调节速度 让
  • javafx开发- ImageView标签设置图片不显示

    图片不显示的原因没找到 但是找到了解决办法 嘿嘿 解决问题代码如下
  • flutter之Provider(一)

    网上有不少介绍Provider的文章 但是感觉大部分对于初学者而言不够友好 很多在文章开始就写了大片的代码或者是一通的状态管理的介绍 但是实际上根本不需要那么复杂 本篇文章当然也会简单的介绍Provider的使用 但是我们更多还是通俗的介绍
  • 新手教程!设置PDF文件的页面大小

    设置文档的页面大小是办公一族经常遇到的一种操作 如果是word文档 那简直就是so easy 但在日常工作中 我们偶尔会遇到PDF格式的文件 由于对它不熟悉 想要对PDF文档的页面大小进行修改 又该如何操作呢 这时我们就需要借助一款非常专业
  • 客户价值预测:线性回归模型与诊断(概念)

    客户生命周期可分为四个阶段 潜在客户阶段 响应客户阶段 既得客户阶段 流失客户阶段 本章整体是一个客户价值预测的案例 背景是某信用卡公司在地推活动之后 获取了大量客户的信用卡申请信息 其中一个部分客户顺利开卡 并且有月消费记录 而另外一部分
  • C语言结构体应用-通讯录

    这里写目录标题 总体介绍 一 数据的定义及数据初始化 二 增加联系人 三 删除联系人 四 修改某个联系人 五 显示所有联系人 六 删除所有联系人 七 按名字首字母排序联系人 八 查找联系人 九 代码展示 总体介绍 本文主要介绍一个结构体的应
  • vue 点击事件失效

    点击事件失效的情况 总共有三种 1 没有点到那个元素 比如说div gt span 事件绑定在div上 但是它可能点来点去是在span标签上面 这种情况 把 click点击事件绑定到span上测试一下就好了 如果是被覆盖了 加个这个 sto
  • error while loading shared libraries: libcublasLt.so.11 解决方法

    在运行cuda程序的时候 有时候会遇到此类错误 error while loading shared libraries libcublasLt so 11 问题是两个 确实没有此类库文件 有此库文件 不过没有放在正确的地方 针对第一类 如
  • Java实现将JSON文件导出到Excel

    文章目录 一 运行环境 二 需求描述 三 实现思路 四 实现代码 一 运行环境 windows10 IDEA 2022 JDK 8 Maven 3 8 6 Apache POI 5 fastjson2 二 需求描述 写一个功能 任意json