EasyExcel是一个基于Java的简单、省内存的读写Excel的开源项目。在尽可能节约内存的情况下支持读写百M的Excel。
EasyExcel官方文档地址
需要导入数据时,我们一定需要先制定模板,通过模板导入数据。接下来描述的是springBoot读取resource下的文件并下载。templatePath应该是从resource下开始,需要文件名需要加后缀。如"导入律师库模板.xlsx"
//读取文件
try (InputStream resourceAsStream = Thread.currentThread().getContextClassLoader().getResourceAsStream(templatePath)) {
// //fast-fail原则
HttpServletResponse response = context.getHttpServletResponse();
assert resourceAsStream != null;
try (BufferedInputStream fis = new BufferedInputStream(resourceAsStream); OutputStream toClient = new BufferedOutputStream(response.getOutputStream())) {
//获取文件名
String name = FileUtil.getName(templatePath);
int available = fis.available();
byte[] buffer = new byte[4096];
int r;
while (-1 != (r = fis.read(buffer))) {
toClient.write(buffer, 0, r);
}
// 清空response
//response.reset();
// 设置response的Header
response.setHeader("Content-Disposition", "attachment;filename=" + java.net.URLEncoder.encode(name, "utf-8"));
response.addHeader("Content-Length", "" + available);
//response.setContentType("application/octet-stream");
toClient.flush();
}
}
下载的模板可能会出现乱码,因为编译时也编译了模板文件,需要在pom.xml文件中配置不编译模板文件类型的文件。
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<configuration>
<encoding>UTF-8</encoding>
<nonFilteredFileExtensions>
<nonFilteredFileExtension>xls</nonFilteredFileExtension>
<nonFilteredFileExtension>xlsx</nonFilteredFileExtension>
</nonFilteredFileExtensions>
</configuration>
</plugin>
</plugins>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>3.0.5</version>
</dependency>
//参数依次是文件流、接收参数的class类【类中通过@ExcelProperty(value = "案件名称")将excel列表头与类对应。】、指定监听器,读取的sheet页,从execl第几行开始读取。
EasyExcel.readread(InputStream inputStream, Class head, ReadListener readListener).sheet().headRowNumber(headRowNumber).doRead();
// 有个很重要的点 DemoDataListener 不能被spring管理,要每次读取excel都要new,然后里面用到spring可以构造方法传进去
@Slf4j
public class DemoDataListener implements ReadListener<DemoData> {
/**
* 每隔5条存储数据库,实际使用中可以100条,然后清理list ,方便内存回收
*/
private static final int BATCH_COUNT = 100;
/**
* 缓存的数据
*/
private List<DemoData> cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
/**
* 假设这个是一个DAO,当然有业务逻辑这个也可以是一个service。当然如果不用存储这个对象没用。
*/
private DemoDAO demoDAO;
public DemoDataListener() {
// 这里是demo,所以随便new一个。实际使用如果到了spring,请使用下面的有参构造函数
demoDAO = new DemoDAO();
}
/**
* 如果使用了spring,请使用这个构造方法。每次创建Listener的时候需要把spring管理的类传进来
*
* @param demoDAO
*/
public DemoDataListener(DemoDAO demoDAO) {
this.demoDAO = demoDAO;
}
/**
* 这个每一条数据解析都会来调用
*
* @param data one row value. Is is same as {@link AnalysisContext#readRowHolder()}
* @param context
*/
@Override
public void invoke(DemoData data, AnalysisContext context) {
log.info("解析到一条数据:{}", JSON.toJSONString(data));
cachedDataList.add(data);
// 达到BATCH_COUNT了,需要去存储一次数据库,防止数据几万条数据在内存,容易OOM
if (cachedDataList.size() >= BATCH_COUNT) {
saveData();
// 存储完成清理 list
cachedDataList = ListUtils.newArrayListWithExpectedSize(BATCH_COUNT);
}
}
/**
* 所有数据解析完成了 都会来调用
*
* @param context
*/
@Override
public void doAfterAllAnalysed(AnalysisContext context) {
// 这里也要保存数据,确保最后遗留的数据也存储到数据库
saveData();
log.info("所有数据解析完成!");
}
/**
* 加上存储数据库
*/
private void saveData() {
log.info("{}条数据,开始存储数据库!", cachedDataList.size());
demoDAO.save(cachedDataList);
log.info("存储数据库成功!");
}
}
一定要在获取response后立即写,不同格式的文件浏览器需要使用不同的解析
EasyExcel会自动关闭输出流
try {
HttpServletResponse response = getHttpServletResponse(context, excelName);
EasyExcel.write(response.getOutputStream(), ExportTraderBaseInfoVo.class).includeColumnFiledNames(includeColumnFiledNames).sheet("交易商基础信息表").doWrite(vos);
} catch (Exception e) {
e.printStackTrace();
}
private HttpServletResponse getHttpServletResponse(ServiceHandlerContext context, String excelName) throws UnsupportedEncodingException {
HttpServletResponse response = context.getHttpServletResponse();
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman测试
//浏览器解析页面的方式,"application/octet-stream"支持所有格式的文件
response.setContentType("application/octet-stream");
告知客户端响应正文类型
response.setHeader("content-type", "application/octet-stream");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码
String fileName = URLEncoder.encode(excelName, "UTF-8").replaceAll("\\+", "%20")+".xlsx";
//attachment表示以附件方式下载,如果在页面中打开,应该修改为Inline
response.setHeader("Content-disposition", "attachment;filename=" + fileName);
return response;
}
文件类型 | 解析方式 |
---|---|
application/pdf | |
jpe | image/jpeg |
jpeg | image/jpeg |
jpg | image/jpeg |
htm | text/html |
* | application/octet-stream |
xls | application/vnd.ms-excel |