EasyExcel
- 1 EasyExcel的集成
- 1.1 引入依赖
- 1.2 模型映射
- 1.3 读Excel
- 1.4 写Excel
- 1.5 web上传、下载
- 2 自定义多Sheet页下载
- 2.1 工具类
- 2.2 方法入参
- 3 优点
Java解析、生成Excel比较有名的框架有Apache poi、jxl。但他们都存在一个严重的问题就是非常的耗内存,poi有一套SAX模式的API可以一定程度的解决一些内存溢出的问题,但POI还是有一些缺陷,比如07版Excel解压缩以及解压后存储都是在内存中完成的,内存消耗依然很大。easyexcel重写了poi对07版Excel的解析,能够原本一个3M的excel用POI sax依然需要100M左右内存降低到几M,并且再大的excel不会出现内存溢出,03版依赖POI的sax模式。在上层做了模型转换的封装,让使用者更加简单方便。
1 EasyExcel的集成
1.1 引入依赖
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>easyexcel</artifactId>
<version>2.0.5</version>
</dependency>
1.2 模型映射
import com.alibaba.excel.annotation.ExcelProperty;
import lombok.Data;
import java.util.Date;
@Data
public class DemoData {
/**
* 编号
*/
@ExcelProperty(index = 0)
private String code;
/**
* 时间
*/
@ExcelProperty(format = "yyyy/MM/dd",value = "时间")
private Date reportTime;
/**
* 姓名
*/
@ExcelProperty({"姓名"})
private String name;
}
该实体相当于跟Excel解析出来的列一一对应,其中ExcelProperty注解的属性中index表示指定的列,注意是从0开始的,format是定义的格式,value是名称。
1.3 读Excel
/**
* 最简单的读
* <p>1. 创建excel对应的实体对象 参照{@link DemoData}
* <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link DemoDataListener}
* <p>3. 直接读即可
*/
@Test
public void simpleRead() {
String fileName = TestFileUtil.getPath() + "demo" + File.separator + "demo.xlsx";
// 这里 需要指定读用哪个class去读,然后读取第一个sheet 文件流会自动关闭
EasyExcel.read(fileName, DemoData.class, new DemoDataListener()).sheet().doRead();
}
1.4 写Excel
/**
* 最简单的写
* <p>1. 创建excel对应的实体对象 参照{@link com.alibaba.easyexcel.test.demo.write.DemoData}
* <p>2. 直接写即可
*/
@Test
public void simpleWrite() {
String fileName = TestFileUtil.getPath() + "write" + System.currentTimeMillis() + ".xlsx";
// 这里 需要指定写用哪个class去读,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 如果这里想使用03 则 传入excelType参数即可
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
}
1.5 web上传、下载
* 文件下载(失败了会返回一个有部分数据的Excel)
* <p>1. 创建excel对应的实体对象 参照{@link DownloadData}
* <p>2. 设置返回的 参数
* <p>3. 直接写,这里注意,finish的时候会自动关闭OutputStream,当然你外面再关闭流问题不大
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
// 这里注意 有同学反应使用swagger 会导致各种问题,请直接用浏览器或者用postman
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
String fileName = URLEncoder.encode("测试", "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + ".xlsx");
EasyExcel.write(response.getOutputStream(), DownloadData.class).sheet("模板").doWrite(data());
}
/**
* 文件上传
* <p>1. 创建excel对应的实体对象 参照{@link UploadData}
* <p>2. 由于默认一行行的读取excel,所以需要创建excel一行一行的回调监听器,参照{@link UploadDataListener}
* <p>3. 直接读即可
*/
@PostMapping("upload")
@ResponseBody
public String upload(MultipartFile file) throws IOException {
EasyExcel.read(file.getInputStream(), UploadData.class, new UploadDataListener(uploadDAO)).sheet().doRead();
return "success";
}
2 自定义多Sheet页下载
2.1 工具类
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.write.metadata.WriteSheet;
import com.alibaba.excel.write.metadata.style.WriteCellStyle;
import com.alibaba.excel.write.metadata.style.WriteFont;
import com.alibaba.excel.write.style.HorizontalCellStyleStrategy;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.ss.usermodel.BorderStyle;
import org.apache.poi.ss.usermodel.HorizontalAlignment;
import org.apache.poi.ss.usermodel.IndexedColors;
import org.apache.poi.ss.usermodel.VerticalAlignment;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.List;
/**
* @Description 多sheet页下载
* @Author zhangxu
* @Date 2020/5/11 14:46
**/
@Slf4j
public class EasyExcelUtils {
/**
* 下载文件类型
*/
private static final String FILE_TYPE = ".xlsx";
/**
* 多sheet页导出
* @param response
* @param fileName
* @param list
* @param sheetNameList
*/
public static void exportWebExcel(HttpServletResponse response, String fileName, List<List<?>> list, List<String> sheetNameList) {
response.setContentType("application/vnd.ms-excel");
response.setCharacterEncoding("utf-8");
ExcelWriter excelWriter = null;
try {
// 这里URLEncoder.encode可以防止中文乱码 当然和easyexcel没有关系
fileName = URLEncoder.encode(fileName, "UTF-8");
response.setHeader("Content-disposition", "attachment;filename=" + fileName + FILE_TYPE);
excelWriter = EasyExcel.write(response.getOutputStream()).registerWriteHandler(EasyExcelUtils.setHorizontalCellStyleStrategy()).build();
//这里 需要指定写用哪个class去写
for (int i = 0; i <= list.size() - 1; i++) {
WriteSheet writeSheet;
for (int j = 0; j <= list.get(i).size() - 1; j++) {
List<Object> list0 = new ArrayList<>();
list0.add(list.get(i).get(j));
writeSheet = EasyExcel.writerSheet(i, sheetNameList.get(i)).head(list.get(i).get(0).getClass()).build();
excelWriter.write(list0, writeSheet);
}
}
} catch (IOException e) {
e.printStackTrace();
} finally {
excelWriter.finish();
}
}
/**
* 设置样式
*
* @return
*/
public static HorizontalCellStyleStrategy setHorizontalCellStyleStrategy() {
/*******自定义列标题和内容的样式******/
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short) 11);
headWriteFont.setBold(false);
headWriteCellStyle.setWrapped(false);
headWriteCellStyle.setWriteFont(headWriteFont);
headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 背景色
// contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
WriteFont contentWriteFont = new WriteFont();
// 字体大小
contentWriteFont.setFontHeightInPoints((short) 11);
contentWriteFont.setFontName("宋体");
contentWriteCellStyle.setWriteFont(contentWriteFont);
//设置 自动换行
contentWriteCellStyle.setWrapped(false);
//设置 垂直居中
contentWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
//设置 水平居中
contentWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER);
// 这个策略是 头是头的样式 内容是内容的样式
HorizontalCellStyleStrategy horizontalCellStyleStrategy = new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
return horizontalCellStyleStrategy;
}
}
如果单个sheet页的下载满足不了你的需求,那么上边的多sheet页的导出可以供你参考,下边的方法是用来自定义样式的。其中该类上的@Slf4j是用来操作日志的,如果你不需要可以直接干掉。
2.2 方法入参
如果你有多sheet页下载的需求,可以直接拷贝该工具类就可以使用,当然,具体的接下来介绍一下该方法的入参:
- HttpServletResponse response: 响应的response对 象
- String fileName: 下载的文件的名称
- List<List<?>> list : 这个list用到了无边界通配符,可以传入任意的实体,想要了解泛型的也可以看下之前的文章 java中的泛型(基础篇)
- List sheetNameList: 每个sheet页的名称
3 优点
- 读Excel自动通过注解,把结果映射为java模型
- 读写Excel支持多sheet
- 写任意大07版Excel不会OOM
- 写Excel通过注解将表头自动写入Excel
- 写Excel可以自定义Excel样式 如:字体,加粗,表头颜色,数据内容颜色
- 写Excel时候自定义是否需要写表头