From 5d896e90e36bfb6ec1da46877c85a09e5899bfb9 Mon Sep 17 00:00:00 2001 From: canonical Date: Thu, 18 Jul 2024 21:17:15 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0Excel=E5=8A=A8=E6=80=81sheet?= =?UTF-8?q?=E5=92=8C=E5=8A=A8=E6=80=81=E5=88=97=E6=BC=94=E7=A4=BA=E3=80=82?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E8=AF=BB=E5=8F=96Excel=E6=89=80=E6=9C=89shee?= =?UTF-8?q?t=E6=95=B0=E6=8D=AE=E7=9A=84=E5=BF=AB=E6=8D=B7=E6=96=B9?= =?UTF-8?q?=E6=B3=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/resources/nop-vfs-index.txt | 1 + .../io/nop/ooxml/xlsx/util/ExcelHelper.java | 22 +++++++++++++- .../nop/ooxml/xlsx/util/ExcelSheetData.java | 28 ++++++++++++++++++ .../nop/ooxml/xlsx/utils/TestExcelHelper.java | 17 ++++++++++- .../io/nop/ooxml/xlsx/utils/test-data.xlsx | Bin 0 -> 9398 bytes ...\212\250\346\200\201\345\210\227.xpt.xlsx" | Bin 0 -> 12885 bytes 6 files changed, 66 insertions(+), 2 deletions(-) create mode 100644 nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelSheetData.java create mode 100644 nop-ooxml/nop-ooxml-xlsx/src/test/resources/io/nop/ooxml/xlsx/utils/test-data.xlsx create mode 100644 "nop-report/nop-report-demo/src/main/resources/_vfs/nop/report/demo/base/12-\345\212\250\346\200\201Sheet\345\222\214\345\212\250\346\200\201\345\210\227.xpt.xlsx" diff --git a/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt b/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt index 7ee800b95..6792778cd 100644 --- a/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt +++ b/nop-demo/nop-quarkus-demo/src/main/resources/nop-vfs-index.txt @@ -565,6 +565,7 @@ /nop/report/demo/base/09-套打.xpt.xlsx /nop/report/demo/base/10-导出Excel公式.xpt.xlsx /nop/report/demo/base/11-打印条码和二维码.xpt.xlsx +/nop/report/demo/base/12-动态Sheet和动态列.xlsx /nop/report/demo/ext/report-with-params.xpt.xlsx /nop/report/demo/pages/demo.page.yaml /nop/report/demo/pages/report-with-params.page.yaml diff --git a/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelHelper.java b/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelHelper.java index fe1c99825..ac58a0348 100644 --- a/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelHelper.java +++ b/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelHelper.java @@ -12,6 +12,7 @@ import io.nop.commons.util.StringHelper; import io.nop.core.resource.IResource; import io.nop.core.resource.impl.FileResource; +import io.nop.core.resource.impl.UnknownResource; import io.nop.core.resource.record.csv.CsvResourceRecordIO; import io.nop.core.resource.record.list.HeaderListRecordOutput; import io.nop.excel.model.ExcelWorkbook; @@ -22,6 +23,7 @@ import io.nop.xlang.api.XLang; import java.io.File; +import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -44,7 +46,25 @@ public static Object loadXlsxObject(String impModelPath, IResource resource) { return new XlsxObjectLoader(impModelPath).parseFromResource(resource); } - public static List> readXlsx(IResource xlsx, String selectedSheetName) { + public static List readAllSheets(IResource xlsx) { + List ret = new ArrayList<>(); + + new XlsxToRecordOutput((r, e) -> new HeaderListRecordOutput<>(xlsx, null, CollectionHelper::toMap) { + @Override + public void close() { + ExcelSheetData data = new ExcelSheetData(); + data.setName(r.getName()); + data.setData(this.getResult()); + ret.add(data); + } + }, + null, sheetName -> { + return new UnknownResource("/" + sheetName); + }).parseFromResource(xlsx); + return ret; + } + + public static List> readSheet(IResource xlsx, String selectedSheetName) { HeaderListRecordOutput> output = new HeaderListRecordOutput<>(xlsx, null, CollectionHelper::toMap); MutableInt index = new MutableInt(); diff --git a/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelSheetData.java b/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelSheetData.java new file mode 100644 index 000000000..4dd9dcb8b --- /dev/null +++ b/nop-ooxml/nop-ooxml-xlsx/src/main/java/io/nop/ooxml/xlsx/util/ExcelSheetData.java @@ -0,0 +1,28 @@ +package io.nop.ooxml.xlsx.util; + +import io.nop.api.core.annotations.data.DataBean; + +import java.util.List; +import java.util.Map; + +@DataBean +public class ExcelSheetData { + private String name; + private List> data; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List> getData() { + return data; + } + + public void setData(List> data) { + this.data = data; + } +} diff --git a/nop-ooxml/nop-ooxml-xlsx/src/test/java/io/nop/ooxml/xlsx/utils/TestExcelHelper.java b/nop-ooxml/nop-ooxml-xlsx/src/test/java/io/nop/ooxml/xlsx/utils/TestExcelHelper.java index 3e9a67fca..b34ff50cb 100644 --- a/nop-ooxml/nop-ooxml-xlsx/src/test/java/io/nop/ooxml/xlsx/utils/TestExcelHelper.java +++ b/nop-ooxml/nop-ooxml-xlsx/src/test/java/io/nop/ooxml/xlsx/utils/TestExcelHelper.java @@ -2,6 +2,7 @@ import io.nop.api.core.time.CoreMetrics; import io.nop.core.initialize.CoreInitialization; +import io.nop.core.lang.json.JsonTool; import io.nop.core.resource.IResource; import io.nop.core.unittest.BaseTestCase; import io.nop.excel.model.ExcelCell; @@ -9,11 +10,15 @@ import io.nop.excel.model.ExcelTable; import io.nop.excel.model.ExcelWorkbook; import io.nop.ooxml.xlsx.util.ExcelHelper; +import io.nop.ooxml.xlsx.util.ExcelSheetData; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; import java.io.File; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; public class TestExcelHelper extends BaseTestCase { @BeforeAll @@ -61,9 +66,19 @@ public void testXlsxToCsv() { System.out.println("xlsxToCsv:" + (endTime - beginTime) + "ms"); beginTime = CoreMetrics.currentTimeMillis(); - ExcelHelper.readXlsx(xlsx, null); + ExcelHelper.readSheet(xlsx, null); endTime = CoreMetrics.currentTimeMillis(); // 1M => 16312ms System.out.println("readXlsx:" + (endTime - beginTime) + "ms"); } + + @Test + public void readAllSheets() { + IResource xlsx = attachmentResource("test-data.xlsx"); + List sheets = ExcelHelper.readAllSheets(xlsx); + System.out.println(JsonTool.serialize(sheets, true)); + assertEquals(2, sheets.size()); + assertEquals("Sheet2", sheets.get(1).getName()); + assertEquals("[{c=5, d=6}, {c=7, d=8}]", sheets.get(1).getData().toString()); + } } diff --git a/nop-ooxml/nop-ooxml-xlsx/src/test/resources/io/nop/ooxml/xlsx/utils/test-data.xlsx b/nop-ooxml/nop-ooxml-xlsx/src/test/resources/io/nop/ooxml/xlsx/utils/test-data.xlsx new file mode 100644 index 0000000000000000000000000000000000000000..ea920f3c63d725a2017ef06af346314257db924b GIT binary patch literal 9398 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 S=cj5G9byH{KO?4}-~I>mGvWyV literal 0 HcmV?d00001