From 009bf63478c8ca6fe12e4e7944940de0e3e33dd0 Mon Sep 17 00:00:00 2001 From: codering Date: Fri, 10 Jan 2025 18:15:14 +0800 Subject: [PATCH 1/3] =?UTF-8?q?excel-reader=20=E8=AF=BB=E5=8F=96=E6=8C=87?= =?UTF-8?q?=E5=AE=9A=E7=9A=84=20headers?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../resource/record/list/HeaderListRecordOutput.java | 9 +++++++-- .../java/io/nop/report/core/record/ExcelRecordInput.java | 1 + 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/nop-core/src/main/java/io/nop/core/resource/record/list/HeaderListRecordOutput.java b/nop-core/src/main/java/io/nop/core/resource/record/list/HeaderListRecordOutput.java index 7651b0e56..5c8e9c6cb 100644 --- a/nop-core/src/main/java/io/nop/core/resource/record/list/HeaderListRecordOutput.java +++ b/nop-core/src/main/java/io/nop/core/resource/record/list/HeaderListRecordOutput.java @@ -18,12 +18,13 @@ import java.util.List; import java.util.function.BiFunction; public class HeaderListRecordOutput implements IRecordOutput> { - private List headers; + private final List records = new ArrayList<>(); private final BiFunction, List, R> rowBuilder; private boolean headersWritten; private long writeCount; private int headerRowCount; + private List headers; private List headerLabels; private IEvalFunction headersNormalizer; @@ -34,6 +35,10 @@ public class HeaderListRecordOutput implements IRecordOutput> { this.rowBuilder = rowBuilder; } + public void setHeaders(List headers) { + this.headers = headers; + } + public void setHeaderLabels(List headerLabels) { this.headerLabels = headerLabels; } @@ -98,4 +103,4 @@ public class HeaderListRecordOutput implements IRecordOutput> { @Override public void close() { } -} \ No newline at end of file +} diff --git a/nop-report/nop-report-core/src/main/java/io/nop/report/core/record/ExcelRecordInput.java b/nop-report/nop-report-core/src/main/java/io/nop/report/core/record/ExcelRecordInput.java index d0e6d533c..fde962851 100644 --- a/nop-report/nop-report-core/src/main/java/io/nop/report/core/record/ExcelRecordInput.java +++ b/nop-report/nop-report-core/src/main/java/io/nop/report/core/record/ExcelRecordInput.java @@ -86,6 +86,7 @@ public class ExcelRecordInput implements IRecordInput { @Override public void beforeRead(Map map) { HeaderListRecordOutput> collector = new HeaderListRecordOutput<>(config.getHeaderRowCount(), CollectionHelper::toNonEmptyKeyMap); + collector.setHeaders(headers); collector.setHeaderLabels(headerLabels); collector.setHeadersNormalizer(headersNormalizer); -- Gitee From 67c79fecea2c445e98338e204ac7e5bb5218731a Mon Sep 17 00:00:00 2001 From: codering Date: Fri, 10 Jan 2025 18:21:51 +0800 Subject: [PATCH 2/3] =?UTF-8?q?excel-reader=20=E5=A4=84=E7=90=86=20header?= =?UTF-8?q?=20=E5=92=8C=20record=20=E7=9A=84=E5=AF=B9=E5=BA=94=E5=85=B3?= =?UTF-8?q?=E7=B3=BB=E6=97=B6=EF=BC=8C=E4=B8=A4=E8=80=85=E7=9A=84=E7=B4=A2?= =?UTF-8?q?=E5=BC=95=E5=BA=94=E8=AF=A5=E4=B8=80=E8=B5=B7=E7=A7=BB=E5=8A=A8?= =?UTF-8?q?=EF=BC=8C=E8=BF=99=E6=A0=B7=E5=B0=B1=E8=83=BD=E5=A4=84=E7=90=86?= =?UTF-8?q?=20header=20=E4=B8=BA=20null=E7=9A=84=E6=83=85=E5=86=B5?= =?UTF-8?q?=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../src/main/java/io/nop/commons/util/CollectionHelper.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/nop-commons/src/main/java/io/nop/commons/util/CollectionHelper.java b/nop-commons/src/main/java/io/nop/commons/util/CollectionHelper.java index c50954f35..a802281d9 100644 --- a/nop-commons/src/main/java/io/nop/commons/util/CollectionHelper.java +++ b/nop-commons/src/main/java/io/nop/commons/util/CollectionHelper.java @@ -250,9 +250,9 @@ public class CollectionHelper { while (kIt.hasNext() && vIt.hasNext()) { K key = kIt.next(); + V value = vIt.next(); if (StringHelper.isEmptyObject(key)) continue; - V value = vIt.next(); ret.put(key, value); } return ret; @@ -1071,4 +1071,4 @@ public class CollectionHelper { list.add(0, item); return list; } -} \ No newline at end of file +} -- Gitee From 3c36e9f55003c13248df046dc33075d80466a86a Mon Sep 17 00:00:00 2001 From: codering Date: Fri, 10 Jan 2025 18:22:18 +0800 Subject: [PATCH 3/3] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=20excel-reader=20?= =?UTF-8?q?=E5=8D=95=E5=85=83=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../core/record/TestExcelResourceIO.java | 45 ++++++++++++++++++ .../io/nop/report/core/excel-input.xlsx | Bin 7756 -> 9006 bytes 2 files changed, 45 insertions(+) diff --git a/nop-report/nop-report-core/src/test/java/io/nop/report/core/record/TestExcelResourceIO.java b/nop-report/nop-report-core/src/test/java/io/nop/report/core/record/TestExcelResourceIO.java index 87755a304..1370dcd6d 100644 --- a/nop-report/nop-report-core/src/test/java/io/nop/report/core/record/TestExcelResourceIO.java +++ b/nop-report/nop-report-core/src/test/java/io/nop/report/core/record/TestExcelResourceIO.java @@ -18,6 +18,7 @@ import java.util.List; import java.util.Map; import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; public class TestExcelResourceIO extends BaseTestCase { @@ -44,6 +45,50 @@ public class TestExcelResourceIO extends BaseTestCase { input.close(); } + @Test + public void testReadSpecifiedHeader() throws IOException { + ExcelResourceIO> io = new ExcelResourceIO<>(); + ExcelIOConfig config = new ExcelIOConfig(); + io.setIOConfig(config); + // 指定 headers + io.setHeaders(Arrays.asList("a","b","c")); + + IRecordInput> input = io.openInput(new ClassPathResource("classpath:io/nop/report/core/excel-input.xlsx"), null); + input.beforeRead(new HashMap<>()); + + List> list = input.readAll(); + System.out.println(JSON.serialize(list, true)); + assertEquals(1, list.get(0).get("a")); + assertEquals(1, list.get(0).get("b")); + assertEquals(1, list.get(0).get("c")); + assertEquals(10, list.get(9).get("a")); + assertEquals(901, list.get(9).get("b")); + assertEquals(9001, list.get(9).get("c")); + input.close(); + } + + @Test + public void testReadHeaderWithNull() throws IOException { + ExcelResourceIO> io = new ExcelResourceIO<>(); + ExcelIOConfig config = new ExcelIOConfig(); + // header 为空的列,就不会处理 + io.setHeaders(Arrays.asList("a",null/*b*/,"c",null/*d*/,null/*e*/,"f")); + io.setIOConfig(config); + + IRecordInput> input = io.openInput(new ClassPathResource("classpath:io/nop/report/core/excel-input.xlsx"), null); + input.beforeRead(new HashMap<>()); + + List> list = input.readAll(); + System.out.println(JSON.serialize(list, true)); + assertEquals(1, list.get(0).get("a")); + assertNull(list.get(0).get("b")); + assertEquals(1, list.get(0).get("c")); + assertNull(list.get(0).get("d")); + assertNull(list.get(0).get("e")); + assertEquals(11, list.get(0).get("f")); + input.close(); + } + @Test public void testReadMultiHeader() throws IOException { ExcelResourceIO> io = new ExcelResourceIO<>(); diff --git a/nop-report/nop-report-core/src/test/resources/io/nop/report/core/excel-input.xlsx b/nop-report/nop-report-core/src/test/resources/io/nop/report/core/excel-input.xlsx index 2c53d75e2108976e71987fff50ab2ffb1f6613ba..e2a7169ed8ef141e6a9ce44c71790f5454cff22b 100644 GIT binary patch literal 9006 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 jKeC`@{+FN;{*L`s^i_ZeKO+ST1`8$#awI