EasyExcel——写文件
目录
easyExcel是阿里巴巴开源的一个excel处理框架,以使用简单、节省内存著称。
64M内存1分钟内读取75M(46W行25列)的Excel(当然还有急速模式能更快,但是内存占用会在100M多一点)
可有效避免OOM。
致敬阿里:
---参照官方文档进行编辑,主要记录了工作中用到的,用的少的就没有记录
---官方文档 : https://www.yuque.com/easyexcel
---官方github : https://github.com/alibaba/easyexcel
写入数据实体类
@Data
public class DemoData {
@ExcelProperty("字符串标题")
private String stringData;
@ExcelProperty("整型标题")
private Integer integerData;
@ExcelProperty("日期标题")
private Date dateData;
@NumberFormat("#.##%")
private Double dounleData;
}
- @ExcelProperty("***") 标题行名称
构造数据的方法
private List<DemoData> data() {
List<DemoData> list = new ArrayList<DemoData>();
for (int i = 0; i < 10; i++) {
DemoData data = new DemoData();
data.setStringData("字符串" + i);
data.setIntegerData(i);
data.setDateData(new Date());
data.setDounleData(0.56);
list.add(data);
}
return list;
}
创建对象的写
简单写入
//写法一
String fileName = "c://Users//****";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).sheet("模板").doWrite(data());
//写法二
String fileName = "c://Users//****";
// 这里 需要指定写用哪个class去写
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
excelWriter.write(data(), writeSheet);
// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
根据参数只导出指定列
String fileName = "c://Users//****";
//排除掉不想输出的列 假设我们要忽略 stringData
Set<String> excludeColumnFiledNames = new HashSet<String>();
excludeColumnFiledNames.add("stringData");
EasyExcel.write(fileName, DemoData.class).excludeColumnFiledNames(excludeColumnFiledNames).sheet("模板").doWrite(data());
//只输出实体类我们想要的字段 假设我们只要导出 stringData
Set<String> includeColumnFiledNames = new HashSet<String>();
includeColumnFiledNames.add("stringData");
EasyExcel.write(fileName, DemoData.class).includeColumnFiledNames(includeColumnFiledNames).sheet("模板").doWrite(data());
指定写入的列
修改实体类注解即可
@ExcelProperty(value = "数字标题", index =5)
private Integer integerData;
复杂头写入
修改实体类注解即可
@ExcelProperty({"主标题", "字符串标题"})
@ExcelProperty({"主标题", "日期标题"})
@ExcelProperty({"主标题", "数字标题"})
重复多次写入(写到单个或者多个Sheet)
同一个sheet多次写
String fileName = "c://Users//****";
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
//同一个sheet只要创建一次
WriteSheet writeSheet = EasyExcel.writerSheet("模板").build();
// 调用写入,实际使用时根据数据库分页的总的页数来
for (int i = 0; i < 5; i++) {
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
写到不同的sheet 同一个对象
String fileName = "c://Users//****";
ExcelWriter excelWriter = EasyExcel.write(fileName, DemoData.class).build();
// 去调用写入,实际使用时根据数据库分页的总的页数来。最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样
WriteSheet writeSheet = EasyExcel.writerSheet(i, "模板" + i).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
写到不同的sheet 不同的对象
String fileName = "c://Users//****";
//指定文件
ExcelWriter excelWriter = EasyExcel.write(fileName).build();
// 去调用写入,实际使用时根据数据库分页的总的页数来。这里最终会写到5个sheet里面
for (int i = 0; i < 5; i++) {
// 每次都要创建writeSheet 这里注意必须指定sheetNo 而且sheetName必须不一样。这里注意DemoData.class 可以每次都变,我这里为了方便 所以用的同一个class 实际上可以一直变
writeSheet = EasyExcel.writerSheet(i, "模板" + i).head(DemoData.class).build();
// 分页去数据库查询数据 这里可以去数据库查询每一页的数据
List<DemoData> data = data();
excelWriter.write(data, writeSheet);
}
/// 千万别忘记finish 会帮忙关闭流
excelWriter.finish();
日期、数字或者自定义格式转换
修改实体类注解即可
日期、数字
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期标题")
private Date dateData;
@NumberFormat("#.##%")
@ExcelProperty("浮点型标题")
private Double dounleData;
自定义格式转换
@ExcelProperty(converter = CustomStringStringConverter.class)
private String stringData;
public class CustomStringStringConverter implements Converter<String> {
@Override
public Class supportJavaTypeKey() {
return String.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
/**
* 这里读的时候会调用
*/
@Override
public String convertToJavaData(CellData cellData, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return "自定义:" + cellData.getStringValue();
}
/**
* 这里是写的时候会调用
*/
@Override
public CellData convertToExcelData(String value, ExcelContentProperty excelContentProperty, GlobalConfiguration globalConfiguration) throws Exception {
return new CellData(value);
}
}
指定列宽、行高
@Data
@ContentRowHeight(10)
@HeadRowHeight(20)
@ColumnWidth(25)
public class DemoData {
@ColumnWidth(50)
@ExcelProperty("字符串标题")
//@ExcelProperty(converter = CustomStringStringConverter.class)
private String stringData;
@ExcelProperty(value = "数字标题")
private Integer integerData;
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期标题")
private Date dateData;
@NumberFormat("#.##%")
@ExcelProperty("浮点型标题")
private Double dounleData;
}
注解形式自定义样式
@Data
// 头背景设置成红色 IndexedColors.RED.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 10)
// 头字体设置成20
@HeadFontStyle(fontHeightInPoints = 20)
// 内容的背景设置成绿色 IndexedColors.GREEN.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 17)
// 内容字体设置成20
@ContentFontStyle(fontHeightInPoints = 20)
public class DemoData {
@ColumnWidth(50)
@ExcelProperty("字符串标题")
// 字符串的头背景设置成粉红 IndexedColors.PINK.getIndex()
@HeadStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 14)
private String stringData;
// 字符串的头字体设置成20
@HeadFontStyle(fontHeightInPoints = 30)
@ExcelProperty(value = "数字标题")
private Integer integerData;
// 字符串的内容的背景设置成天蓝 IndexedColors.SKY_BLUE.getIndex()
@ContentStyle(fillPatternType = FillPatternType.SOLID_FOREGROUND, fillForegroundColor = 40)
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期标题")
private Date dateData;
// 字符串的内容字体设置成20
@ContentFontStyle(fontHeightInPoints = 30)
@NumberFormat("#.##%")
@ExcelProperty("浮点型标题")
private Double dounleData;
}
自定义样式
String fileName = "c://Users//****";
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
// 头的策略
WriteCellStyle headWriteCellStyle = new WriteCellStyle();
// 背景设置为红色
headWriteCellStyle.setFillForegroundColor(IndexedColors.RED.getIndex());
WriteFont headWriteFont = new WriteFont();
headWriteFont.setFontHeightInPoints((short)20);
headWriteCellStyle.setWriteFont(headWriteFont);
// 内容的策略
WriteCellStyle contentWriteCellStyle = new WriteCellStyle();
// 这里需要指定 FillPatternType 为FillPatternType.SOLID_FOREGROUND 不然无法显示背景颜色.头默认了 FillPatternType所以可以不指定
contentWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);
// 背景绿色
contentWriteCellStyle.setFillForegroundColor(IndexedColors.GREEN.getIndex());
WriteFont contentWriteFont = new WriteFont();
// 字体大小
contentWriteFont.setFontHeightInPoints((short)20);
contentWriteCellStyle.setWriteFont(contentWriteFont);
// 这个策略是 头是头的样式 内容是内容的样式 其他的策略可以自己实现
HorizontalCellStyleStrategy horizontalCellStyleStrategy =
new HorizontalCellStyleStrategy(headWriteCellStyle, contentWriteCellStyle);
// 这里 需要指定写用哪个class去写,然后写到第一个sheet,名字为模板 然后文件流会自动关闭
EasyExcel.write(fileName, DemoData.class).registerWriteHandler(horizontalCellStyleStrategy).sheet("模板")
.doWrite(data());
合并单元格
@Data
// 将第6-7行的2-3列合并成一个单元格
//@OnceAbsoluteMerge(firstRowIndex = 5, lastRowIndex = 6, firstColumnIndex = 1, lastColumnIndex = 2)
public class DemoData {
// 这一列 每隔2行 合并单元格
@ContentLoopMerge(eachRow = 2)
@ExcelProperty("字符串标题")
private String stringData;
@ExcelProperty(value = "数字标题")
private Integer integerData;
@DateTimeFormat("yyyy年MM月dd日HH时mm分ss秒")
@ExcelProperty("日期标题")
private Date dateData;
@NumberFormat("#.##%")
@ExcelProperty("浮点型标题")
private Double dounleData;
}
自动列宽(不太精确)
EasyExcel.write(fileName, DemoData.class).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).sheet("模板")
.doWrite(data());
不创建对象的写
String fileName = "c://Users//****";
EasyExcel.write(fileName).head(head()).sheet("模板").doWrite(dataList());
-------------------------------------------------------------------------
private List<List<String>> head() {
List<List<String>> list = new ArrayList<List<String>>();
List<String> head0 = new ArrayList<String>();
head0.add("字符串" + System.currentTimeMillis());
List<String> head1 = new ArrayList<String>();
head1.add("数字" + System.currentTimeMillis());
List<String> head2 = new ArrayList<String>();
head2.add("日期" + System.currentTimeMillis());
list.add(head0);
list.add(head1);
list.add(head2);
return list;
}
private List<List<Object>> dataList() {
List<List<Object>> list = new ArrayList<List<Object>>();
for (int i = 0; i < 10; i++) {
List<Object> data = new ArrayList<Object>();
data.add("字符串" + i);
data.add(new Date());
data.add(0.56);
list.add(data);
}
return list;
}
web的写(文件下载)
/**
* 文件下载(失败了会返回一个有部分数据的Excel)
*/
@GetMapping("download")
public void download(HttpServletResponse response) throws IOException {
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());
}
web中的写并且失败的时候返回json
@GetMapping("downloadFailedUsingJson")
public void downloadFailedUsingJson(HttpServletResponse response) throws IOException {
try {
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).autoCloseStream(Boolean.FALSE).sheet("模板")
.doWrite(data());
} catch (Exception e) {
// 重置response
response.reset();
response.setContentType("application/json");
response.setCharacterEncoding("utf-8");
Map<String, String> map = new HashMap<String, String>();
map.put("status", "failure");
map.put("message", "下载文件失败" + e.getMessage());
response.getWriter().println(JSON.toJSONString(map));
}
}
private List<DownloadData> data() {
List<DownloadData> list = new ArrayList<DownloadData>();
for (int i = 0; i < 10; i++) {
DownloadData data = new DownloadData();
data.setStringData("字符串" + i);
data.setIntegerData(i);
data.setDateData(new Date());
data.setDounleData(0.56);
list.add(data);
}
return list;
}