easyPoi使用遇到的坑
吐槽一下easypoi;最近在公司做一个excel的导入、导出功能,看到之前公司项目中用到了poi技术;为了方便,所以我直接选用了easyPoi来做这个功能,首先在导入maven依赖时没啥问题。在使用的时候,好家伙直接jar包冲突!后来在依赖上加上“-beta1”就好了
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>3.17-beta1</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi-ooxml</artifactId>
<version>3.17-beta1</version>
</dependency>
这里主要讲下导入字段校验、和读取文件效率的问题
一、字段校验:
在字段校验的时候,可直接在实体类添加注解做字段校验(相关注解可自己百度);然后在ImportParams中设置开启字段校验。
设置开启字段校验
ImportParams params = new ImportParams();
params.setNeedVerfiy(true);//是否开启校验
params.setHeadRows(1); //头行忽略的行数
ExcelImportResult<Object> objectExcelImportResult = ExcelImportUtil.importExcelMore(file.getInputStream(), CTourGuide.class, params);
//校验失败的数据
objectExcelImportResult.getFailList();
//校验成功的数据
objectExcelImportResult.getList();
二、读取效率问题
数据量大的话,ExcelImportUtil.importExcelMore这个方法真的会卡死,不知道是我代码的问题还是api的问题,咱也不敢说,咱也不敢问!在源码中断点看下是在哪卡住的,结果在这。。。
解决方法:给他里面的一些东西拎出来自己写(不知会不会发生其他问题哈)
//直接放到你的controller中
final ExcelImportService excelImportService = new ExcelImportService();
ExcelImportResult excelImportResult =excelImportService.importExcelByIs(file.getInputStream(), CTourGuide.class, params, false);
//校验成功数据
List<CTourGuide> list = excelImportResult.getList();
final Field failCollection = ExcelImportService.class.getDeclaredField("failCollection");
failCollection.setAccessible(true);
//校验失败数据
List<CTourGuide> failList = (List) failCollection.get(excelImportService);
批量插入最好是将一个List放到xml中遍历插入,若数据库对一次插入数据量有限制,还需要对list分割处理,再插入。提供下分割代码,xml里面的看下循环标签
public void addBath(List<CTourGuide> list, int splitSize) {
// List<CTourGuide> temp = new ArrayList<>();
// int size = 0;
// for (CTourGuide cTourGuide : list) {
// if(++size == splitSize){
// add(temp);
// temp.clear();
// size = 0;
// }else{
// temp.add(cTourGuide);
// }
// }
// if(temp.size() != 0){
// add(temp);
// }
int maxSize = (list.size() + splitSize - 1);
//分割list
List<List<CTourGuide>> collect = Stream.iterate(0, n -> n + 1)
.limit(maxSize)
.parallel()
.map(a -> list.parallelStream().skip(a * splitSize).limit(splitSize).collect(Collectors.toList()))
.filter(b -> !b.isEmpty())
.collect(Collectors.toList());
if(collect.size()>0){
for (int i = 0; i < collect.size(); i++) {
this.add(collect.get(i));
}
}
}
最后提供下我的controller;写的比较烂o(╥﹏╥)o
@RequestMapping("/importMonitor")
@ResponseBody
public Map<String, String> importMonitor(@RequestParam MultipartFile file) throws Exception {
HashMap<String, String> map = new HashMap<>();
if (file==null){
map.put("flag","1");
map.put("msg","导入失败,上传文件数据不能为空");
return map;
}
ImportParams params = new ImportParams();
params.setNeedVerfiy(true);//是否开启校验
params.setHeadRows(1); //头行忽略的行数
final ExcelImportService excelImportService = new ExcelImportService();
ExcelImportResult excelImportResult =excelImportService.importExcelByIs(file.getInputStream(), CTourGuide.class, params, false);
//校验成功数据
List<CTourGuide> list = excelImportResult.getList();
final Field failCollection = ExcelImportService.class.getDeclaredField("failCollection");
failCollection.setAccessible(true);
//校验失败数据
List<CTourGuide> failList = (List) failCollection.get(excelImportService);
if(list.size() == 0 && failList.size() == 0){
map.put("flag","1");
map.put("msg","导入失败,上传文件数据不能为空");
return map;
}
//失败数据入库
if (failList.size()>=0){
failList.stream().forEach(p ->{
p.setCreateTime(new Date());
p.setUpdateTime(new Date());
p.setSfzh(Base64.encode(p.getSfzh()));
p.setSxstatus(0);
});
cTourGuideService.addBath(failList,500);
}
//如果没有错误,可以存入数据库
if(list.size()>=0){
list.stream().forEach(p ->{
p.setCreateTime(new Date());
p.setUpdateTime(new Date());
p.setSfzh(Base64.encode(p.getSfzh()));
p.setSxstatus(2);
});
cTourGuideService.addBath(list,500);
}
map.put("flag","0");
map.put("msg","导入成功");
String num = Convert.toStr(failList.size()+list.size());
map.put("num",num);
return map;
}