文章目录
导出数据的流程
定义一个RowModel
/**
* @author lidelin.
*/
@Data
@Accessors(chain = true)
@ColumnWidth(value = 50)
@HeadRowHeight(value = 15)
@HeadFontStyle(fontHeightInPoints = 10)
//@ContentStyle(horizontalAlignment = HorizontalAlignment.RIGHT)
public class DemoModel {
@ExcelProperty("第一列")
private String col1;
@ExcelProperty("第二列")
private Long col2;
@ExcelProperty("第三列")
private Double col3;
@ExcelProperty("第四列")
@DateTimeFormat("yyyy-MM-dd HH:mm:ss")
private LocalDateTime col4;
}
解释一下各个注解的意义:
@ColumnWidth:定义了整个表的每个列的宽度,可以用在Class或者Field上
@HeadRowHeight:定义了表头的行高,只能用在Class上
@HeadFontStyle:定义表头的字体样式,可以用在Class或者Field上
@ExcelProperty:定义了表的一列,只能用在Field上
@DateTimeFormat:定义了列的日期格式,原只能用于Date类型,扩展Converter可以支持其他类型。
其他注解请参考包路径:com.alibaba.excel.annotation.write.style.*
调用方法写出excel
public static void main(String[] args) throws IOException {
List<DemoModel> modelList = new LinkedList<>();
DemoModel model = new DemoModel();
model.setCol1("col1").setCol2(2000000L).setCol3(3.2345678D).setCol4(LocalDateTime.now());
modelList.add(model);
try (OutputStream outputStream = Files.newOutputStream(Paths.get("/Users/admin/delin/test/excel/test.xls"))) {
EasyExcel.write(outputStream, DemoModel.class)
.sheet("sheet-1")
.doWrite(modelList);
}
}
特殊的格式化处理
Java8 LocalDateTime的格式化支持
我们只需要实现一个com.alibaba.excel.converters.Converter
即可(实现可以参考DateStringConverter):
/**
* @author lidelin.
*/
public class LocalDateTimeConverter implements Converter<LocalDateTime> {
private static final DateStringConverter DATE_STRING_CONVERTER = new DateStringConverter();
@Override
public Class<LocalDateTime> supportJavaTypeKey() {
return LocalDateTime.class;
}
@Override
public CellDataTypeEnum supportExcelTypeKey() {
return CellDataTypeEnum.STRING;
}
@Override
public LocalDateTime convertToJavaData(CellData cellData, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
Date date = DATE_STRING_CONVERTER.convertToJavaData(cellData, contentProperty, globalConfiguration);
if (date != null) {
return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
}
return null;
}
@Override
@SuppressWarnings("rawtypes")
public CellData convertToExcelData(LocalDateTime value, ExcelContentProperty contentProperty, GlobalConfiguration globalConfiguration) throws Exception {
String text = "";
if (value != null) {
if (contentProperty == null || contentProperty.getDateTimeFormatProperty() == null) {
text = value.toString();
} else {
text = DateTimeFormatter.ofPattern(contentProperty.getDateTimeFormatProperty().getFormat()).format(value);
}
}
return new CellData(text);
}
}
这个实现顺便支持的@DateTimeFormat注解,也就是我们可以跟@DateTimeFormat中设置的格式进行输出。
接着只需要修改一下EasyExcel的调用即可
public static void main(String[] args) throws IOException {
...
EasyExcel.write(outputStream, DemoModel.class)
.sheet("sheet-1")
.registerConverter(new LocalDateTimeConverter())
.doWrite(modelList);
...
}
格式化Excel单元格
我们可以通过重写com.alibaba.excel.write.handler.AbstractCellWriteHandler
设置单元格的格式
/**
* @author lidelin.
*/
public class DemoModelCellWriteHandler extends AbstractCellWriteHandler {
private static final String COL_2_FIELD = "col2";
private static final String COL_3_FIELD = "col3";
@Override
public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex, Boolean isHead) {
Workbook workbook = writeSheetHolder.getParentWriteWorkbookHolder().getWorkbook();
CellStyle cellStyle = workbook.createCellStyle();
DataFormat format = workbook.createDataFormat();
cellStyle.setAlignment(HorizontalAlignment.RIGHT);
if (COL_2_FIELD.equals(head.getFieldName())) {
cell.setCellType(CellType.NUMERIC);
cellStyle.setDataFormat(format.getFormat("#,##0"));
} else if (COL_3_FIELD.equals(head.getFieldName())) {
cell.setCellType(CellType.NUMERIC);
cellStyle.setDataFormat(format.getFormat("0.00000000"));
}
cell.setCellStyle(cellStyle);
}
}
该类实现了对第二列使用千分位分隔符,第三列保留8位小数的单元格样式。这里需要注意的是,由于我们在Model中可以通过@ContentStyle设置相关样式,这个样式会在最后覆写我们样式,所以为了避免冲突,我们应该只使用其中一种方式对样式进行设置。而且建议重写afterCellDispose方法,因为此时值已经设置好,我们只需要关注设置单元格样式即可。我们应该在Converter进行值的转化,在WriteHandler中进行单元格样式的修改。
设置导出文件名
response.setHeader("Content-Disposition", String.format("attachment; filename=%s", URLEncoder.encode(fileName, StandardCharsets.UTF_8.name())));
注意这里需要做URLEncode,主要针对一些HTTP的特殊字符或者中文进行处理
设置MIME
response.setContentType("application/xls");
多sheet处理
1、创建具体Model类对应的ExcelWriter
ExcelWriter writer = EasyExcel.write(out, Measure.class).build();
2、写入sheet
writer.write(dataList, EasyExcel.writerSheet(sheetName).build());
response.setContentType("application/xls");
3、结束写入
writer.finish();