前言
需求:完成10万+记录行Excel上传分析与数据落库。
问题:后台读取Excel方式,JVM堆空间是否足够
使用Apache Poi完成文档解析 文档地址
过程
引入pom文件,注意版本号的一致
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>4.1.0</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml-schemas</artifactId>
<version>4.1.0</version>
</dependency>
读取excel文件
private static Workbook readExcel(String filePath){
Workbook wb = null;
if(filePath==null){
return null;
}
String extString = filePath.substring(filePath.lastIndexOf("."));
InputStream is = null;
try {
is = new FileInputStream(filePath);
if(".xls".equals(extString)){
return wb = new HSSFWorkbook(is);
}else if(".xlsx".equals(extString)){
return wb = new XSSFWorkbook(is);
}else{
return wb = null;
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
return wb;
}
分析单元格数据
private static String getCellFormatValue(Cell cell){
if(cell!=null){
switch(cell.getCellTypeEnum()){
case NUMERIC:
return String.valueOf((long)cell.getNumericCellValue());
case STRING:
return cell.getRichStringCellValue().getString();
default:
return null;
}
}
return null;
}
Main方法验证
public static void main(String[] args) {
Workbook wb =null;
Sheet sheet = null;
Row row = null;
String cellData = null;
List<Map<String,String>> list = null;
String filePath = "D:\\test.xlsx";
String columns[] = {"user_tel","template_id","sms_template_url","replace_para"};
wb = readExcel(filePath);
if(wb != null){
//用来存放表中数据
list = new ArrayList<Map<String,String>>();
//获取第一个sheet
sheet = wb.getSheetAt(0);
//获取最大行数
int rownum = sheet.getPhysicalNumberOfRows();
//获取第一行
row = sheet.getRow(0);
//获取最大列数
int colnum = row.getPhysicalNumberOfCells();
row = sheet.getRow(1);
String value = getCellFormatValue(row.getCell(0));
System.out.println(value);
}
}
问题与思考
通用性
底层工具类关心Excel文件流读取与解析。
服务层只关心业务模型与数据的映射,因此通过抽象类完成通用性改造。
定义抽象方法与通用模型获取方法
public abstract T transfer(String[] rows);
public List<T> getResource(String filePath){
Workbook wb = readExcel(filePath);
List<T> resList = new ArrayList<>();
if(wb != null){
Sheet sheet = wb.getSheetAt(0);
int rows = sheet.getPhysicalNumberOfRows();
int cols = sheet.getRow(0).getPhysicalNumberOfCells();
for (int i = 1;i < rows;i++){
Row row = sheet.getRow(i);
String[] strRow = new String[cols];
for(int j = 0;j < strRow.length;j++){
strRow[j] = getCellFormatValue(row.getCell(j));
}
resList.add(transfer(strRow));
}
}
return resList;
}
方法类使用
ExcelTransfer<T> excelTransfer = new ExcelTransfer<T>() {
@Override
public SMSCrowdDTO transfer(String[] rows) {
//构造方法
T t = new T();
return t;
}
};
return excelTransfer.getResource(url);
JVM内存
模拟2万数据行的Excel文件,
不同场景的数据量不同,实际用量要根据实际数据模型模拟
设置启动参数 -Xms256m -Xmx256m ,无报错
设置启动参数 -Xms128m -Xmx128m,内存不足
线上服务器为4C8G,参数为-Xms6144m -Xmx6144m -Xmn3072m
eden与survivor使用未超过一半,高峰期可能会导致youngGC,不会有内存溢出的风险。
响应时间
校验采用同步解析,插入库采用异步。
接口响应时间不超过2s左右,10万数据预计响应时间在10s左右,需要前端加载等待进度。