业务常用解法:EasyExcel导出数据

导出数据的流程

定义一个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();
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

木子的木木

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值