Java实现将JSON文件导出到Excel

文章目录

  • 一、运行环境
  • 二、需求描述
  • 三、实现思路
  • 四、实现代码

一、运行环境


  • 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,所在单元格的值

Java实现将JSON文件导出到Excel_第1张图片

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

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

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

导出结果:

Java实现将JSON文件导出到Excel_第2张图片
当我们使用fastjson遍历JSONObject时,每次读取到的都是单个{ } 所包含的对象,比如:

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

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

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

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

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

这里可以使用 Map map 来记录列名以及下标。

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

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

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

实现效果:

Java实现将JSON文件导出到Excel_第3张图片

Java实现将JSON文件导出到Excel_第4张图片

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

四、实现代码


pom.xml


<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.0modelVersion>

    <groupId>groupIdgroupId>
    <artifactId>poi_demoartifactId>
    <version>1.0-SNAPSHOTversion>

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

    <dependencies>
        <dependency>
            <groupId>org.apache.poigroupId>
            <artifactId>poi-ooxmlartifactId>
            <version>5.2.2version>
        dependency>

        <dependency>
            <groupId>org.apache.commonsgroupId>
            <artifactId>commons-lang3artifactId>
            <version>3.9version>
        dependency>

        <dependency>
            <groupId>com.alibabagroupId>
            <artifactId>fastjsonartifactId>
            <version>2.0.7version>
        dependency>

    dependencies>
project>

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结果是一致的,主要是为了测试不同方法的正确性。

Java实现将JSON文件导出到Excel_第5张图片
Java实现将JSON文件导出到Excel_第6张图片
Java实现将JSON文件导出到Excel_第7张图片
Java实现将JSON文件导出到Excel_第8张图片

你可能感兴趣的:(实习记录,java,json,开发语言)