项目中加了一个excel导入导出的功能,之前用过POI,但是听说easyexcel 很快!
所以想试试他到底有多快!
首先导入依赖,刚开始用的3.1.0版本的,但是新版本用的人比较少,官方的手册又不是很完美,之后又降为2.x版本的
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.2.6</version>
</dependency>
首先咱们需要整一个监听
import com.alibaba.excel.context.AnalysisContext;
import com.alibaba.excel.event.AnalysisEventListener;
import java.util.ArrayList;
import java.util.List;
public class QdportReadListener extends AnalysisEventListener {
/**
* 可以通过实例获取该值获取,之后可以实现直接把dataList 存到数据库等等操作
*/
private List<Object> dataList = new ArrayList<>();
@Override
public void invoke(Object object, AnalysisContext context) {
//每一条数据都会循环,可以实现空数据,重复数据的检查,不建议在这里做太复杂的逻辑,这里
//不写也没关系
//数据存储到list,供批量处理,或后续自己业务逻辑处理。
dataList.add(object);
handleBusinessLogic();
/*
如数据过大,可以进行定量分批处理
if(dataList.size()>=200){
handleBusinessLogic();
dataList.clear();
}
*/
}
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
}
//根据业务自行实现该方法,例如将解析好的dataList存储到数据库中
private void handleBusinessLogic() {
}
public List<Object> getDataList() {
return dataList;
}
public void setDataList(List<Object> dataList) {
this.dataList = dataList;
}
}
对应的实体类(只是举个栗子)
@Data//lombok
@ExcelIgnoreUnannotated//这个注解的作用是属性只有加了@ExcelProperty才会参与读写。
public class Info {
/**
* 主键
*/
@TableId(type = IdType.AUTO)
private Integer id;
/**
* 名字
*/
@ExcelProperty(value = "名字")
private String name;
/**
* 类型
*/
@ExcelProperty(value = "类型", converter = CustomStringStringConverter.class)
private Integer type;
/**
* 是否
*/
@ExcelProperty(value = "是否", converter = CustomStringStringConverter.class)
private Integer status;
}
然后写接口
这是导出:因为用的是微服务gateway网关,不能用servlet ,只能用
import org.springframework.http.server.reactive.ServerHttpResponse;包下的ServerHttpResponse来代替
/**
* 导出查询数据
*/
@GetMapping("/export")
public Mono<Void> export(ServerHttpResponse response, Info info) {
response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=这里拼上文件的名字.xlsx");
//spring webflux文件下载零拷贝(Zero-copy)
ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
File file = new File("../文件先暂时放在本地.xlsx");//应该有文件流的方法,但我懒
// 分页查询数据
EasyExcel.write(file, DockInfo.class)
.sheet("这里是excel里面分页的名字")
.doWrite(infoService.getList(info));//这里放的就是需要处理的数据
return zeroCopyResponse.writeWith(file, 0, file.length()).doFinally(a -> {
boolean delete = file.delete();//处理完成之后把本地文件删除,这里建议做一下空值判断
});
}
这样,一个导出就完成了
然后做导入:
/**
* 导入数据
*/
@PostMapping(value = "/import")
public Result<Integer> importInfo(@RequestPart("file") FilePart filePart) throws IOException {
String strFileName = filePart.filename();
File file = new File("../" + strFileName);//文件暂时存到本地,应该有文件流的方法,但我懒
List<info> infos;
try {
filePart.transferTo(file);
ExcelReaderBuilder read = EasyExcel.read(file, Info.class, new QdportReadListener());
dockInfos = read.doReadAllSync();
} catch (Exception ignored) {
throw new ServerException("文件读取发生异常");
} finally {
boolean delete = file.delete();//读完了文件之后做删除
}
return infoService.addInfoList(infos);
}
之后加了一个导出模板的功能,要求导出的模板,字典类型的列是下拉列表选择的那种
就是这里让我放弃的3.1.0,没有文档,网上也没有资源,对于我这种菜狗来说不合适。
首先实现一个 写表的接口
import com.alibaba.excel.write.handler.SheetWriteHandler;
import com.alibaba.excel.write.metadata.holder.WriteSheetHolder;
import com.alibaba.excel.write.metadata.holder.WriteWorkbookHolder;
import org.apache.poi.ss.usermodel.DataValidation;
import org.apache.poi.ss.usermodel.DataValidationConstraint;
import org.apache.poi.ss.usermodel.DataValidationHelper;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.util.CellRangeAddressList;
import org.apache.poi.xssf.usermodel.XSSFDataValidation;
import java.util.HashMap;
import java.util.Map;
public class MySheetWriteHandler implements SheetWriteHandler {
/**
* 创建sheet页前的操作
* @param writeWorkbookHolder
* @param writeSheetHolder
*/
@Override
public void beforeSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
}
/**
* 创建sheet页后的操作
* @param writeWorkbookHolder
* @param writeSheetHolder
*/
@Override
public void afterSheetCreate(WriteWorkbookHolder writeWorkbookHolder, WriteSheetHolder writeSheetHolder) {
//定义选值范围
String[] strings1 = new String[]{"类型1","类型2"};
String[] strings2 = new String[]{"否","是"};
//根据index,形成map,可插入多个
Map<Integer,String []> mapDropDown = new HashMap<>();
mapDropDown.put(2,strings1);//第一个参数是在那一列加入,从0开始
mapDropDown.put(3,strings2);
//获取sheet页
Sheet sheet = writeSheetHolder.getSheet();
///开始设置下拉框
DataValidationHelper helper = sheet.getDataValidationHelper();
for (Map.Entry<Integer, String[]> entry : mapDropDown.entrySet()) {
/***起始行、终止行、起始列、终止列**/
CellRangeAddressList addressList = new CellRangeAddressList(1, 9999, entry.getKey(), entry.getKey());
/***设置下拉框数据**/
DataValidationConstraint constraint = helper.createExplicitListConstraint(entry.getValue());
DataValidation dataValidation = helper.createValidation(constraint, addressList);
/***处理Excel兼容性问题**/
if (dataValidation instanceof XSSFDataValidation) {
dataValidation.setSuppressDropDownArrow(true);
dataValidation.setShowErrorBox(true);
} else {
dataValidation.setSuppressDropDownArrow(false);
}
sheet.addValidationData(dataValidation);
}
}
}
写接口:
/**
* 导出模板
*/
@GetMapping("/exportTemplate")
public Mono<Void> exportTemplate(ServerHttpResponse response) {
response.getHeaders().setContentType(MediaType.APPLICATION_OCTET_STREAM);
response.getHeaders().set(HttpHeaders.CONTENT_DISPOSITION, "attachment;filename=模板.xlsx");
//spring webflux文件下载零拷贝(Zero-copy)
File file1 = new File("../模板.xlsx");
ZeroCopyHttpOutputMessage zeroCopyResponse = (ZeroCopyHttpOutputMessage) response;
EasyExcel.write(file1, DockInfo.class)
.sheet("模板")
.registerWriteHandler(new MySheetWriteHandler())//刚才实现的类在这个地方用上了
.doWrite(new ArrayList<>());
return zeroCopyResponse.writeWith(file1, 0, file1.length()).doFinally(a -> {
boolean delete = file1.delete();
});
}
这样,功能就完成了!
如果有什么问题,欢迎在评论区讨论!