文章目录

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

一、运行环境


  • 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>

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){// 创建新的 sheetXSSFSheet 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){// 遍历每个KVfor (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));// 获取 ValueString cellValue = JSON.toJSONString(jsonObject.get(cellName));// 如果V为数组则递归创建sheetif(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);// 遍历 objfor (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){// 创建新的 sheetXSSFSheet 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);// 遍历每个KVfor (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));// 获取 ValueString cellValue = JSON.toJSONString(jsonObject.get(cellName));// 如果V为对象则递归创建sheetif(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()){// 获取当前的SheetXSSFSheet sheet = workbook.createSheet("sheet");// 获取第一行XSSFRow firstRow = sheet.createRow(0);// 记录Key所在的列Map<String, Integer> map = new HashMap<>();// 记录列数int cellCount = 0;// 遍历 JSON的keyXSSFRow 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为数组 则创建新的 Sheetif(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");elsecurrentCell.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";// 测试1toExcelByLocalJSONFile(jsonPath, savePath, excelName + "1");String jsonStr = readJSONFile(jsonPath);JSONObject jsonObject = JSONObject.parseObject(jsonStr);Object object = JSON.parse(jsonStr);// 测试2toExcelByString(jsonStr, savePath, excelName + "2");// 测试3toExcelByObject(object, savePath, excelName + "3");// 测试4toExcelByJSONObject(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相关推荐

  1. JAVA实现数据库数据导入/导出到Excel(POI)

    原文地址为: JAVA实现数据库数据导入/导出到Excel(POI) 准备工作: 1.导入POI包:POI下载地址http://mirrors.tuna.tsinghua.edu.cn/apache/ ...

  2. IDEA Java解析GeoJson.json文件

    IDEA Java解析GeoJson.json文件 一.遇到的问题 1. 无法导入成功 2. org.geotools.StyleFactory is not an ImageIO SPI class ...

  3. java如何读写json文件

    java如何读写json文件 在实际项目开发中,有时会遇到一些全局的配置缓存,最好的做法是配置redis数据库作为数据缓存,而当未有配置redis服务器时,读取静态资源文件(如xml.json等)也是 ...

  4. java上传json文件

    java 上传json文件并解析 fastjson <dependency><groupId>com.alibaba</groupId><artifactId ...

  5. 使用java在后台将数据导出为excel文件

    本文主要讲的是怎么使用java将数据导出为Excel文件,xls格式的. 例如:我从前台查询到的数据,要把数据进行导出为excl格式的文件.需要将前台的查询条件(数据)传递到后台,后台拿到数据,写sq ...

  6. java基于easypoi实现对导出的excel文档加密

    **项目背景 随着项目日新月异的变化,对数据的安全性也越来越高,特别是政府类型的项目,数据安全往往是非常重要的,最近项目中导出的文件被要求需要密码才能打开,所以写下这篇文章,特此记录一下. 文章目录 ...

  7. Java 百万数据秒级导出到Excel中

    出自: 腾讯课堂 700多分钟干货实战Java多线程高并发高性能实战全集 , 我学习完了之后, 我给 老师在课上说的话做了个笔记,以及视频的内容,还有代码敲了一遍,然后添加了一些注释,把执行结果也整理 ...

  8. 纯JavaScript 实现JSON数据导出到Excel(支持多个Sheet页)

    核心思想: 拿到JSON 格式的数据后,使用JS逻辑生成符合 EXCEL格式规范的XML字符串 然后转字符串内容把换成一个Blob 实例对象 最后通过 临时创建的一个A标签通过触发它的点击事件模拟浏览 ...

  9. Java实现将表格数据导出成Excel

    1.添加maven依赖 <dependency> <groupId>com.alibaba</groupId> <artifactId>easyexce ...

最新文章

  1. 2019南昌网络赛 C题,Hello 2019
  2. [jQuery]10 Things I Learned from the jQuery Source
  3. 自定义parallelStream的thread pool
  4. 用户空间访问I2C设备驱动
  5. 回溯算法之购物车(0-1 背包问题)
  6. gulp 实现sass自动化 ,监听同步
  7. css3动画 --- Animation
  8. linux环境安装ffmepg,Linux centOS下安装FFmpeg
  9. 传统密码学(三)——转轮密码机
  10. 九峰影业创始人_《勇士之城》林永健扮演棠德县县长魏九峰
  11. C#利用控件拖拽技术制作拼图游戏
  12. android将两张图片合并为一张图片
  13. 云服务器BBC销售渠道,云服务器bbc
  14. git 报错:remote: Not Found fatal: repository ‘http://xxx/xxx.git/‘ not found
  15. 交换网络基础-交换机的工作原理
  16. 关于Safari的思考(转载)
  17. iPhone中将MP3设置为铃声
  18. Chrome广告屏蔽
  19. 程序员涨工资大多数靠跳槽吗?花费3个月整理的初出社会的“菜鸟”程序员跳槽攻略(学习篇)
  20. 4米乘以12米CAD图_简单四步,教你如何绘制好施工现场总平面布置图

热门文章

  1. C语言——结构体(入门详解)
  2. 【论文】网络安全与入门-ARP攻击
  3. 网页中播放FLV视频文件的代码
  4. 洛谷 P5707 上学迟到
  5. 2022下半场,Plug and Play 最关心的金融科技创新趋势是?
  6. Android动态创建快捷方式
  7. Quartus-II两种方式实现D触发器及时序仿真和波形验证
  8. 软件架构师的要求介绍
  9. 吃瓜(西瓜书-南瓜书)1、2章
  10. 统计虚词使用不同聚类方法判别红楼梦作者