Browse Source

修改tools-poi,增加ExcelReader读取指定sheet支持,可以指定序号或者名称

Signed-off-by: luoshi <luoshi@qmth.com.cn>
luoshi 10 tháng trước cách đây
mục cha
commit
732db6a495

+ 25 - 5
tools-poi/src/main/java/com/qmth/boot/tools/excel/ExcelReader.java

@@ -1,6 +1,7 @@
 package com.qmth.boot.tools.excel;
 
 import com.qmth.boot.tools.excel.enums.ExcelType;
+import com.qmth.boot.tools.excel.filter.SheetFilter;
 import com.qmth.boot.tools.excel.handler.impl.DataArrayHandler;
 import com.qmth.boot.tools.excel.handler.impl.DataMapHandler;
 import com.qmth.boot.tools.excel.handler.impl.ObjectHandler;
@@ -20,6 +21,8 @@ public class ExcelReader {
 
     private InputStream ins;
 
+    private SheetFilter sheetFilter;
+
     private int columnNameRow;
 
     /**
@@ -31,13 +34,29 @@ public class ExcelReader {
      * @return
      */
     public static ExcelReader create(ExcelType type, InputStream ins, int columnNameRow) {
-        return new ExcelReader(type, ins, columnNameRow);
+        return new ExcelReader(type, ins, SheetFilter.first(), columnNameRow);
     }
 
-    private ExcelReader(ExcelType type, InputStream ins, int columnNameRow) {
+    /**
+     * 初始化带表头的Excel解析工具,读取指定的sheet
+     *
+     * @param type          文件格式,XLSX或XLS
+     * @param ins           文件输入流
+     * @param sheetFilter   sheet过滤工具
+     * @param columnNameRow 表头所在行号,0表示第一行
+     * @return
+     */
+    public static ExcelReader create(ExcelType type, InputStream ins, SheetFilter sheetFilter, int columnNameRow) {
+        return new ExcelReader(type, ins, sheetFilter, columnNameRow);
+    }
+
+    private ExcelReader(ExcelType type, InputStream ins, SheetFilter sheetFilter, int columnNameRow) {
         if (ins == null) {
             throw new IllegalArgumentException("Excel InputStream is required");
         }
+        if (sheetFilter == null) {
+            throw new IllegalArgumentException("Excel SheetFilter is required");
+        }
         if (columnNameRow < 0) {
             throw new IllegalArgumentException("Excel column name row should >= 0");
         }
@@ -49,6 +68,7 @@ public class ExcelReader {
             throw new IllegalArgumentException("Excel type is required");
         }
         this.ins = ins;
+        this.sheetFilter = sheetFilter;
         this.columnNameRow = columnNameRow;
     }
 
@@ -97,7 +117,7 @@ public class ExcelReader {
      * @throws Exception
      */
     public <E> void readObject(Class<E> objectType, ObjectListener<E> listener) throws Exception {
-        parser.parse(ins, new ObjectHandler<>(objectType, columnNameRow, listener));
+        parser.parse(ins, sheetFilter, new ObjectHandler<>(objectType, columnNameRow, listener));
     }
 
     /**
@@ -107,7 +127,7 @@ public class ExcelReader {
      * @throws Exception
      */
     public void readDataMap(ObjectListener<DataMap> listener) throws Exception {
-        parser.parse(ins, new DataMapHandler(columnNameRow, listener));
+        parser.parse(ins, sheetFilter, new DataMapHandler(columnNameRow, listener));
     }
 
     /**
@@ -117,7 +137,7 @@ public class ExcelReader {
      * @throws Exception
      */
     public void readDataArray(ObjectListener<String[]> listener) throws Exception {
-        parser.parse(ins, new DataArrayHandler(columnNameRow, listener));
+        parser.parse(ins, sheetFilter, new DataArrayHandler(columnNameRow, listener));
     }
 
     /**

+ 61 - 0
tools-poi/src/main/java/com/qmth/boot/tools/excel/filter/SheetFilter.java

@@ -0,0 +1,61 @@
+package com.qmth.boot.tools.excel.filter;
+
+import java.util.HashSet;
+import java.util.Set;
+
+/**
+ * 针对Excel读取过程中的sheet过滤器
+ */
+public class SheetFilter {
+
+    private Integer index;
+
+    private Set<String> names;
+
+    private SheetFilter() {
+    }
+
+    /**
+     * 只读取第一个sheet
+     *
+     * @return
+     */
+    public static SheetFilter first() {
+        SheetFilter filter = new SheetFilter();
+        filter.index = 0;
+        return filter;
+    }
+
+    /**
+     * 读取指定序号的sheet,从0开始
+     *
+     * @return
+     */
+    public static SheetFilter ofIndex(int index) {
+        SheetFilter filter = new SheetFilter();
+        filter.index = index;
+        return filter;
+    }
+
+    /**
+     * 读取指定名称的sheet
+     *
+     * @return
+     */
+    public static SheetFilter ofName(String name) {
+        SheetFilter filter = new SheetFilter();
+        filter.names = new HashSet<>();
+        filter.names.add(name);
+        return filter;
+    }
+
+    public boolean match(int index, String name) {
+        if (this.index != null) {
+            return this.index == index;
+        } else if (names != null) {
+            return names.contains(name);
+        } else {
+            return false;
+        }
+    }
+}

+ 2 - 1
tools-poi/src/main/java/com/qmth/boot/tools/excel/parser/ExcelParser.java

@@ -1,12 +1,13 @@
 package com.qmth.boot.tools.excel.parser;
 
+import com.qmth.boot.tools.excel.filter.SheetFilter;
 import com.qmth.boot.tools.excel.handler.RowDataHandler;
 
 import java.io.InputStream;
 
 public interface ExcelParser {
 
-    void parse(InputStream ins, RowDataHandler handler) throws Exception;
+    void parse(InputStream ins, SheetFilter sheetFilter, RowDataHandler handler) throws Exception;
 
     String[] getColumnNames();
 }

+ 42 - 18
tools-poi/src/main/java/com/qmth/boot/tools/excel/parser/impl/XlsParser.java

@@ -1,5 +1,6 @@
 package com.qmth.boot.tools.excel.parser.impl;
 
+import com.qmth.boot.tools.excel.filter.SheetFilter;
 import com.qmth.boot.tools.excel.handler.RowDataHandler;
 import com.qmth.boot.tools.excel.model.RowData;
 import com.qmth.boot.tools.excel.parser.ExcelParser;
@@ -9,6 +10,8 @@ import org.apache.poi.hssf.record.*;
 import org.apache.poi.poifs.filesystem.POIFSFileSystem;
 
 import java.io.InputStream;
+import java.util.ArrayList;
+import java.util.List;
 
 public class XlsParser implements HSSFListener, ExcelParser {
 
@@ -20,10 +23,19 @@ public class XlsParser implements HSSFListener, ExcelParser {
 
     private RowData rowData;
 
+    private SheetFilter sheetFilter;
+
+    private int sheetIndex = -1;
+
+    private boolean sheetAccept = false;
+
+    private List<String> sheetNames = new ArrayList<>();
+
     private int maxRowIndex = 0;
 
-    public void parse(InputStream inputStream, RowDataHandler handler) throws Exception {
+    public void parse(InputStream inputStream, SheetFilter sheetFilter, RowDataHandler handler) throws Exception {
         this.handler = handler;
+        this.sheetFilter = sheetFilter;
 
         MissingRecordAwareHSSFListener listener = new MissingRecordAwareHSSFListener(this);
         formatListener = new FormatTrackingHSSFListener(listener);
@@ -45,41 +57,53 @@ public class XlsParser implements HSSFListener, ExcelParser {
         switch (record.getSid()) {
         // the BOFRecord can represent either the beginning of a sheet or the workbook
         case BOFRecord.sid:
-            // BOFRecord bof = (BOFRecord) record;
-            // if (bof.getType() == BOFRecord.TYPE_WORKBOOK) {
-            // System.out.println("Encountered workbook");
-            // assigned to the class level member
-            // } else if (bof.getType() == BOFRecord.TYPE_WORKSHEET) {
-            // System.out.println("Encountered sheet reference");
-            // }
+            BOFRecord bof = (BOFRecord) record;
+            if (bof.getType() == BOFRecord.TYPE_WORKBOOK) {
+                //System.out.println("Encountered workbook");
+                //assigned to the class level member
+            } else if (bof.getType() == BOFRecord.TYPE_WORKSHEET) {
+                sheetIndex++;
+                sheetAccept = sheetFilter.match(sheetIndex, sheetNames.get(sheetIndex));
+                if (sheetAccept) {
+                    maxRowIndex = 0;
+                    rowData = null;
+                }
+                //System.out.println("Encountered sheet reference");
+            }
             break;
         case BoundSheetRecord.sid:
-            // BoundSheetRecord bsr = (BoundSheetRecord) record;
-            // System.out.println("New sheet named: " + bsr.getSheetname());
+            BoundSheetRecord bsr = (BoundSheetRecord) record;
+            sheetNames.add(bsr.getSheetname());
             break;
         case RowRecord.sid:
-            RowRecord rowrec = (RowRecord) record;
-            maxRowIndex = Math.max(maxRowIndex, rowrec.getRowNumber());
+            if (sheetAccept) {
+                RowRecord rowrec = (RowRecord) record;
+                maxRowIndex = Math.max(maxRowIndex, rowrec.getRowNumber());
+            }
             break;
         case BlankRecord.sid:
             //BlankRecord brec = (BlankRecord) record;
             //rowData.addValue(brec.getColumn(), null);
             break;
         case NumberRecord.sid:
-            NumberRecord numrec = (NumberRecord) record;
-            getRowData(numrec.getRow()).addValue(numrec.getColumn(), formatListener.formatNumberDateCell(numrec));
+            if (sheetAccept) {
+                NumberRecord numrec = (NumberRecord) record;
+                getRowData(numrec.getRow()).addValue(numrec.getColumn(), formatListener.formatNumberDateCell(numrec));
+            }
             break;
         // SSTRecords store a array of unique strings used in Excel.
         case SSTRecord.sid:
             sstRecord = (SSTRecord) record;
             break;
         case LabelRecord.sid:
-            LabelRecord lrec = (LabelRecord) record;
-            getRowData(lrec.getRow()).addValue(lrec.getColumn(), lrec.getValue());
+            if (sheetAccept) {
+                LabelRecord lrec = (LabelRecord) record;
+                getRowData(lrec.getRow()).addValue(lrec.getColumn(), lrec.getValue());
+            }
             break;
         case LabelSSTRecord.sid:
             LabelSSTRecord lsrec = (LabelSSTRecord) record;
-            if (sstRecord != null) {
+            if (sheetAccept && sstRecord != null) {
                 getRowData(lsrec.getRow())
                         .addValue(lsrec.getColumn(), sstRecord.getString(lsrec.getSSTIndex()).toString());
             }
@@ -94,7 +118,7 @@ public class XlsParser implements HSSFListener, ExcelParser {
         // Handle end of row
         if (record instanceof LastCellOfRowDummyRecord) {
             //End the row
-            if (rowData != null) {
+            if (sheetAccept && rowData != null) {
                 handler.handle(rowData);
                 rowData = null;
             }

+ 10 - 5
tools-poi/src/main/java/com/qmth/boot/tools/excel/parser/impl/XlsxParser.java

@@ -1,5 +1,6 @@
 package com.qmth.boot.tools.excel.parser.impl;
 
+import com.qmth.boot.tools.excel.filter.SheetFilter;
 import com.qmth.boot.tools.excel.handler.RowDataHandler;
 import com.qmth.boot.tools.excel.parser.ExcelParser;
 import org.apache.poi.openxml4j.opc.OPCPackage;
@@ -17,7 +18,7 @@ public class XlsxParser implements ExcelParser {
 
     private XlsxSheetContentHandler contentHandler;
 
-    public void parse(InputStream inputStream, RowDataHandler handler) throws Exception {
+    public void parse(InputStream inputStream, SheetFilter sheetFilter, RowDataHandler handler) throws Exception {
         OPCPackage pkg = OPCPackage.open(inputStream);
         XSSFReader reader = new XSSFReader(pkg);
 
@@ -27,11 +28,15 @@ public class XlsxParser implements ExcelParser {
                 new XSSFSheetXMLHandler(reader.getStylesTable(), new ReadOnlySharedStringsTable(pkg), contentHandler,
                         new DataFormatter(), false));
         XSSFReader.SheetIterator sheets = (XSSFReader.SheetIterator) reader.getSheetsData();
-        if (sheets.hasNext()) {
+        int sheetIndex = -1;
+        while (sheets.hasNext()) {
+            sheetIndex++;
             InputStream ins = sheets.next();
-            InputSource sheetSource = new InputSource(ins);
-            parser.parse(sheetSource);
-            ins.close();
+            if (sheetFilter.match(sheetIndex, sheets.getSheetName())) {
+                InputSource sheetSource = new InputSource(ins);
+                parser.parse(sheetSource);
+                ins.close();
+            }
         }
     }
 

+ 25 - 1
tools-poi/src/test/java/com/qmth/boot/test/tools/excel/read/ExcelReadTest.java

@@ -4,6 +4,7 @@ import com.qmth.boot.test.tools.excel.model.ExcelTestEntity;
 import com.qmth.boot.test.tools.excel.model.GenderEnum;
 import com.qmth.boot.tools.excel.ExcelReader;
 import com.qmth.boot.tools.excel.enums.ExcelType;
+import com.qmth.boot.tools.excel.filter.SheetFilter;
 import com.qmth.boot.tools.excel.listener.ObjectCollector;
 import com.qmth.boot.tools.models.ByteArray;
 import org.apache.commons.lang3.time.DateUtils;
@@ -27,11 +28,25 @@ public class ExcelReadTest {
         Assert.assertFalse(list.get(1).isEnable());
         Assert.assertEquals(list.get(1).getGender(), GenderEnum.FEMALE);
         Assert.assertEquals(list.get(1).getTime(), DateUtils.parseDate("2023-11-30", "yyyy-MM-dd"));
+
+        listener = new ObjectCollector<>();
+        ExcelReader
+                .create(ExcelType.XLSX, ByteArray.fromResource("test.xlsx").toInputStream(), SheetFilter.ofIndex(1), 0)
+                .readObject(ExcelTestEntity.class, listener);
+        list = listener.getObjectList();
+        Assert.assertEquals(2, list.size());
+        Assert.assertEquals(list.get(1).getId(), Long.valueOf(3));
+        Assert.assertEquals(list.get(1).getName(), "李四");
+        Assert.assertEquals(list.get(1).getScore(), Double.valueOf(100.6));
+        Assert.assertFalse(list.get(1).isEnable());
+        Assert.assertEquals(list.get(1).getGender(), GenderEnum.FEMALE);
+        Assert.assertEquals(list.get(1).getTime(), DateUtils.parseDate("2023-11-01", "yyyy-MM-dd"));
     }
 
     @Test
     public void testDataArrayRead() throws Exception {
-        List<String[]> list = ExcelReader.create(ExcelType.XLS, ByteArray.fromResource("test.xls").toInputStream(), 1)
+        List<String[]> list = ExcelReader
+                .create(ExcelType.XLS, ByteArray.fromResource("test.xls").toInputStream(), SheetFilter.first(), 1)
                 .getDataArrayList();
         Assert.assertEquals(4, list.size());
         Assert.assertEquals(list.get(0)[0], "1");
@@ -40,6 +55,15 @@ public class ExcelReadTest {
         Assert.assertEquals(list.get(2)[3], "否");
         Assert.assertNull(list.get(3)[4]);
         Assert.assertEquals(list.get(3)[5], "2023/01/01");
+
+        list = ExcelReader
+                .create(ExcelType.XLS, ByteArray.fromResource("test.xls").toInputStream(), SheetFilter.ofIndex(1), 0)
+                .getDataArrayList();
+        Assert.assertEquals(3, list.size());
+        Assert.assertEquals(list.get(0)[3], "男");
+        Assert.assertEquals(list.get(0)[1], "0.56");
+        Assert.assertEquals(list.get(1)[1], "100.6");
+        Assert.assertEquals(list.get(2)[2], "是");
     }
 
 }

BIN
tools-poi/src/test/resources/test.xls


BIN
tools-poi/src/test/resources/test.xlsx