在之前的文章中 easypoi 导入 Excel 最佳实践 详细介绍了如何使用 EasyPoi 来进行数据的导入与多重校验,但是 EasyPoi 更擅长与比较规整的表格输入导入,如果遇到不规则的表格时,可能就没那么轻松搞定导入了。本文主要介绍如何实现不规则表格数据导入。

本文源码地址:

首先来看一下,不规则的表格长什么样子。如图所示,这种表格如果继续使用 EasyPoi 其实比较困难做到很便捷的导入,但是这种表格一般格式相对固定,只有个别值的位置不规则(蓝色框内),而中间位置的数据格式比较规整(红色框内)。
我们可以取长补短,不规则的地方数据特殊处理读取,而有规则的地方依然使用 EasyPoi 进行读取。

读取示例

红色框内的数据读取本文就不再展示了,可以参考上文的链接。本文主要讲解如何提取蓝色框内的数据。为了方便使用,笔者参考了网上的文章,抽取了一个工具类,基于所见即所得的方式去获取对应单元格的值。

使用示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class ExcelReadHelperTest {

@Test
public void testImport() {
InputStream in = getClass().getResourceAsStream("/excel/示例 Excel3.xlsx");
ExcelReadHelper readHelper = new ExcelReadHelper(in);
// 获取 B4 单元格的数据,以下同理
String b4 = readHelper.getValueAt("B", 4);
String c23 = readHelper.getValueAt("C", 23);
String c24 = readHelper.getValueAt("C", 24);
String m4 = readHelper.getValueAt("M", 4);
String m5 = readHelper.getValueAt("M", 5);
Assert.assertEquals("一众科技有限公司", b4);
Assert.assertEquals("13112345678", c23);
Assert.assertEquals("370827198801021000", c24);
Assert.assertEquals("XH-HZHY-20170504", m4);
Assert.assertEquals("2017.5.4", m5);
readHelper.close();
}
}

如图所示,如果要读取联系人电话,先找到数据所在单元格,C23,代码中直接通过 readHelper.getValueAt("C", 23); 即可获取对应的值。

工具类源码

需要依赖 POI 相关依赖,如果引入了 EasyPoi 的话,就无需重复引入了。

EasyPoi 的依赖:

1
2
3
4
5
<dependency>
<groupId>cn.afterturn</groupId>
<artifactId>easypoi-web</artifactId>
<version>3.2.0</version>
</dependency>

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
import org.apache.poi.hssf.util.CellReference;
import org.apache.poi.ss.usermodel.*;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;

import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;

public class ExcelReadHelper {
private Workbook workbook;
private Sheet sheet;
//Sheet 总数
private int sheetCount;
//当前行
private Row row;

public ExcelReadHelper(InputStream is) {
try {
// 只支持 xlsx,如果要支持 xls,自行修改下一行代码
workbook = new XSSFWorkbook(is);
} catch (Exception e) {
throw new RuntimeException(e);
}
sheetCount = workbook.getNumberOfSheets();
setSheetAt(0);
}

/**
* 关闭工作簿
*
* @throws IOException
*/
public void close() {
if (workbook != null) {
try {
workbook.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

/**
* 获取单元格真实位置
*
* @param row 行索引
* @param col 列索引
* @return [行, 列 ]
*/
public String getCellLoc(Integer row, Integer col) {
return String.format("[%s,%s]", row + 1, CellReference.convertNumToColString(col));
}

/**
* 根据标签设置 Sheet
*
* @param labels
*/
public void setSheetByLabel(String... labels) {
Sheet sheet = null;
for (String label : labels) {
sheet = workbook.getSheet(label);
if (sheet != null) {
break;
}
}
if (sheet == null) {
StringBuilder sheetStr = new StringBuilder();
for (String label : labels) {
sheetStr.append(label).append(",");
}
sheetStr.deleteCharAt(sheetStr.lastIndexOf(","));
throw new RuntimeException(sheetStr.toString() + "Sheet does not exist");
}
this.sheet = sheet;
}

/**
* 根据索引设置 Sheet
*
* @param index
*/
public void setSheetAt(Integer index) {
Sheet sheet = workbook.getSheetAt(index);
if (sheet == null) {
throw new RuntimeException(index + "Sheet does not exist");
}
this.sheet = sheet;
}

/**
* 获取单元格内容并转为 String 类型
*
* @param row 行号,从 1 开始
* @param colName 列号
* @return
*/
@SuppressWarnings("deprecation")
public String getValueAt(String colName, int row) {
int colIdx = CellReference.convertColStringToIndex(colName);
int rowIdx = row < 0 ? 0 : row - 1;
Cell cell = sheet.getRow(rowIdx).getCell(colIdx);
String value = null;
if (cell != null) {
switch (cell.getCellType()) {
case Cell.CELL_TYPE_STRING:
value = cell.getStringCellValue() + "";
break;
case Cell.CELL_TYPE_NUMERIC:
if (DateUtil.isCellDateFormatted(cell)) {
value = cell.getDateCellValue().getTime() + "";
} else {
DecimalFormat df = new DecimalFormat("0");
return df.format(cell.getNumericCellValue());
}
break;
case Cell.CELL_TYPE_FORMULA:
value = cell.getNumericCellValue() + "";
break;
case Cell.CELL_TYPE_BOOLEAN:
value = cell.getBooleanCellValue() + "";
break;
}
}
return (value == null || value.isEmpty()) ? null : value.trim();
}

/**
* 获取当前行指定列内容
*
* @param col 列号,从 1 开始
* @return
*/
public String getValue(Integer col) {
return getValueAt(CellReference.convertNumToColString(col + 1), col);
}

/**
* 获取 Sheet 名称
*
* @return
*/
public String getSheetLabel() {
String label = null;
if (sheet != null) {
label = sheet.getSheetName();
}
return label;
}

/**
* 行偏移
*
* @param offset 偏移量
* @return
*/
public Boolean offsetRow(Integer offset) {
boolean state = true;
if (row == null) {
row = sheet.getRow(offset - 1);
} else {
row = sheet.getRow(row.getRowNum() + offset);
if (row == null) {
state = false;
}
}
return state;
}

/**
* 设置行
*
* @param index 索引
* @return
*/
public Boolean setRow(Integer index) {
row = sheet.getRow(index);
return row != null;
}

/**
* 偏移一行
*
* @return
*/
public Boolean nextRow() {
return offsetRow(1);
}

/**
* 偏移到下一个 Sheet
*
* @return
*/
public Boolean nextSheet() {
boolean state = true;
if (sheet == null) {
sheet = workbook.getSheetAt(0);
} else {
int index = workbook.getSheetIndex(sheet) + 1;
if (index >= sheetCount) {
sheet = null;
} else {
sheet = workbook.getSheetAt(index);
}

if (sheet == null) {
state = false;
}
}
row = null;
return state;
}

}

源码地址

参考