JAVA使用hutool poi工具读取Excel表格指定行列范围的数据

java

1.pom.xml依赖配置

        <!-- huTool工具箱 -->

<dependency>

<groupId>cn.hutool</groupId>

<artifactId>hutool-all</artifactId>

<version>5.7.19</version>

</dependency>

<!-- poi -->

<dependency>

<groupId>org.apache.poi</groupId>

<artifactId>poi-ooxml</artifactId>

<version>5.1.0</version>

</dependency>

2.代码

单元格数据模型对象

package com.hdwang.exceltest;

import cn.hutool.json.JSONUtil;

/**

* 单元格数据

*/

public class CellData {

/**

* 行号

*/

private int rowIndex;

/**

* 列号

*/

private int cellIndex;

/**

* 单元格数值

*/

private Object value;

public int getRowIndex() {

return rowIndex;

}

public void setRowIndex(int rowIndex) {

this.rowIndex = rowIndex;

}

public int getCellIndex() {

return cellIndex;

}

public void setCellIndex(int cellIndex) {

this.cellIndex = cellIndex;

}

public Object getValue() {

return value;

}

public void setValue(Object value) {

this.value = value;

}

@Override

public String toString() {

return JSONUtil.toJsonStr(this);

}

}

Bean对象属性赋值注解

package com.hdwang.exceltest;

import java.lang.annotation.ElementType;

import java.lang.annotation.Retention;

import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Target;

/**

* 列号,用于给bean对象的属性赋指定列的值

*/

@Retention(RetentionPolicy.RUNTIME)

@Target(value = {ElementType.FIELD})

public @interface ColIndex {

/**

* 列索引号(从0开始),与name二者填一个即可,优先级高于name

*

* @return

*/

int index() default -1;

/**

* 列名称(从A开始),与index二者填一个即可,优先级低于index

*

* @return

*/

String name() default "";

}

表格数据对象

package com.hdwang.exceltest;

import cn.hutool.json.JSONUtil;

/**

* 证券月报

*/

public class ZhenquanReport {

/**

* 名称

*/

@ColIndex(name = "B")

private String name;

/**

* 数值

*/

@ColIndex(index = 2)

private String value;

public String getName() {

return name;

}

public void setName(String name) {

this.name = name;

}

public String getValue() {

return value;

}

public void setValue(String value) {

this.value = value;

}

@Override

public String toString() {

return JSONUtil.toJsonStr(this);

}

}

读取方法代码

package com.hdwang.exceltest;

import cn.hutool.poi.excel.ExcelReader;

import cn.hutool.poi.excel.ExcelUtil;

import cn.hutool.poi.excel.ExcelWriter;

import cn.hutool.poi.excel.cell.CellHandler;

import org.apache.commons.collections4.CollectionUtils;

import org.apache.poi.ss.usermodel.*;

import java.io.File;

import java.lang.reflect.Field;

import java.util.*;

import java.util.concurrent.atomic.AtomicInteger;

public class Main {

public static void main(String[] args) {

try {

File templateFile = new File("C:\\Users\\hdwang\\Desktop\\test.xlsx");

List<List<CellData>> rowDataList = readExcelData(templateFile, 2, Integer.MAX_VALUE, 1, Integer.MAX_VALUE);

System.out.println(rowDataList);

List<ZhenquanReport> reports = convertExcelDataToBeanList(rowDataList, ZhenquanReport.class);

System.out.println(reports);

} catch (Exception ex) {

ex.printStackTrace();

}

}

/**

* 读取表格数据

*

* @param templateFile 文件

* @param startRowIndex 起始行号(从0开始)

* @param endRowIndex 结束行号(从0开始)

* @param startCellIndex 起始列号(从0开始)

* @param endCellIndex 结束列号(从0开始)

* @return 表格数据

*/

private static List<List<CellData>> readExcelData(File templateFile, int startRowIndex, int endRowIndex, int startCellIndex, int endCellIndex) {

ExcelReader excelReader = ExcelUtil.getReader(templateFile, 0);

List<List<CellData>> rowDataList = new ArrayList<>();

AtomicInteger rowIndex = new AtomicInteger(-1);

excelReader.read(startRowIndex, endRowIndex, new CellHandler() {

@Override

public void handle(Cell cell, Object value) {

if (cell == null) {

//无单元格跳过

return;

}

if (cell.getColumnIndex() < startCellIndex || cell.getColumnIndex() > endCellIndex) {

//列号不在范围内跳过

return;

}

//新行的数据

if (cell.getRowIndex() != rowIndex.get()) {

rowDataList.add(new ArrayList<>());

}

rowIndex.set(cell.getRowIndex());

//取出新行数据对象存储单元格数据

List<CellData> cellDataList = rowDataList.get(rowDataList.size() - 1);

CellData cellData = new CellData();

cellData.setRowIndex(cell.getRowIndex());

cellData.setCellIndex(cell.getColumnIndex());

cellData.setValue(value);

cellDataList.add(cellData);

}

});

return rowDataList;

}

/**

* 转换表格数据为bean对象列表

*

* @param rowDataList 表格数据

* @param tClass bean类型

* @param <T>

* @return bean对象列表

*/

private static <T> List<T> convertExcelDataToBeanList(List<List<CellData>> rowDataList, Class<T> tClass) {

if (CollectionUtils.isEmpty(rowDataList)) {

return new ArrayList<>();

}

List<T> beanList = new ArrayList<>();

for (List<CellData> rowData : rowDataList) {

try {

//实例化bean对象

T bean = tClass.newInstance();

//遍历字段并赋值

Field[] fields = tClass.getDeclaredFields();

for (Field field : fields) {

if (field.isAnnotationPresent(ColIndex.class)) {

ColIndex colIndex = field.getAnnotation(ColIndex.class);

int index = colIndex.index();

String name = colIndex.name();

if (index != -1) {

//do nothing

} else if (!"".equals(name)) {

//列名转索引号(补0为了适应下述方法)

index = ExcelUtil.colNameToIndex(name + "0");

} else {

throw new RuntimeException("请设置列号(ColIndex注解值必须配置一个)");

}

//从行数据中找到指定单元格数据给字段赋值

final int i = index;

CellData cellData = rowData.stream().filter(x -> x.getCellIndex() == i).findFirst().orElse(null);

if (cellData != null) {

Object value = cellData.getValue();

if (field.getType().getName().equals(String.class.getName())) {

value = String.valueOf(value);

}

field.setAccessible(true);

field.set(bean, value);

}

}

}

beanList.add(bean);

} catch (Exception ex) {

throw new RuntimeException("实例化对象失败", ex);

}

}

return beanList;

}

}

3.表格

4.输出结果

表格数据对象

[

[

{

"cellIndex": 1,

"rowIndex": 2,

"value": "净资产"

},

{

"cellIndex": 2,

"rowIndex": 2,

"value": 10000

},

{

"cellIndex": 3,

"rowIndex": 2,

"value": " "

},

{

"cellIndex": 4,

"rowIndex": 2,

"value": 1

}

],

[

{

"cellIndex": 1,

"rowIndex": 3,

"value": "市值"

},

{

"cellIndex": 2,

"rowIndex": 3,

"value": 20000

},

{

"cellIndex": 4,

"rowIndex": 3,

"value": 2

}

],

[

{

"cellIndex": 1,

"rowIndex": 4,

"value": "标题"

}

],

[

{

"cellIndex": 1,

"rowIndex": 5,

"value": "净利润"

},

{

"cellIndex": 2,

"rowIndex": 5,

"value": 1000

},

{

"cellIndex": 4,

"rowIndex": 5,

"value": 3

}

]

]

 转成bean对象列表

[{"name":"净资产","value":"10000"}, {"name":"市值","value":"20000"}, {"name":"标题"}, {"name":"净利润","value":"1000"}]

5.原理总结

hutool poi 工具对POI进行了包装,实现了很多功能函数。可是在项目实践中发现还是有所不足。现在自己编写自定义取行列范围的数据并实现模型转换功能,从而方便对表格实现数据读取与单元格定位操作等。相关实现技术原理如下:

(1) 基于 public void read(int startRowIndex, int endRowIndex, CellHandler cellHandler)  函数实现行过滤,在CellHandler内部实现列过滤,这样便实现了行列过滤,且取出了行列信息,便于对单元格定位等。

(2) 将CellData转换为Bean对象的时候,采用反射技术读取bean对象字段的注解配置的列号信息,从而找到指定的CellData取值并赋值到字段上去。

6.附录

最新源码文件:https://github.com/hdwang123/exceltest

以上是 JAVA使用hutool poi工具读取Excel表格指定行列范围的数据 的全部内容, 来源链接: utcz.com/z/390348.html

回到顶部