easyExcel导出复杂表头,且自定义样式

实现效果如下

在这里插入图片描述

具体代码:

动态表头数据
    /**
     * 导出房租物业表头
     *
     * @return
     */
 public List<List<String>> buildHead() {
        R<List<RentalProperty>> rentalPropertyR = smartPropertyClient.getRentalPropertyListByTenantId(AuthUtil.getTenantId());
        List<String> feeProjectNameList = new ArrayList<>();
        if (rentalPropertyR.isSuccess() && rentalPropertyR.getData().size() > 0) {
            for (RentalProperty rentalProperty : rentalPropertyR.getData()) {
                feeProjectNameList.add(rentalProperty.getName());
            }
        }
        List<List<String>> head = new ArrayList<>();
        String headFirst = "历史账单导入模版\n(统计起始时间:2018年5月 截止时间:填表月的上一个月)";
        String headSecond = "填表须知:\n" +
                "1.带*的为必填项,每个公司下的合同单独存一个文件\n" +
                "2.此数据为示例,缴费周期:按月\n" +
                "3.每个起始时间、终止时间为合同缴费周期的账单日期:如按季,则起始时间为2023/1/5 终止时间为历时月,以此类推。\n" +
                "4.支持批量导入,直接在表格中将所有合同的账单内容填写完成即可\n" +
                "5.请务必确认合同号及账单内容填写无误";
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*合同号", "*合同号"));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "所属楼盘", "所属楼盘"));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "房屋描述", "房屋描述"));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*起始时间", "*起始时间"));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*终止时间", "*终止时间"));
        feeProjectNameList.stream()
                .forEach(temp -> head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*应收项目", temp)));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*实收项目", "转账实收(元)"));
        head.add(Lists.newArrayList(headFirst, headFirst, headSecond, "*未收租金(元)", "*未收租金(元)"));
        return head;
    }

下载方法
    /**
     * 导出execl
     *
     * @param response 输出流
     * @param fileName 文件名
     * @param headList 表头
     * @param data     数据
     * @throws IOException
     */
 public static void download2(HttpServletResponse response, String fileName, List<List<String>> headList,
                                 List data) throws IOException {
        String excelName = StringUtil.isNotBlank(fileName) ? fileName : "" + DateUtil.format(new java.util.Date(), "yyyy-MM");
        response.addHeader("Access-Control-Expose-Headers", "Content-Disposition");
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        excelName = URLEncoder.encode(excelName, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-Disposition", "attachment;filename*=utf-8''" + excelName + ".xlsx");
        //主标题和副标题在excel中是0-4,一共五行
        List<Integer> columnIndexes = IntStream.range(0, 4).boxed().collect(Collectors.toList());

        //自定义标题和内容策略(具体定义在下文)
        CellStyleStrategy cellStyleStrategy = new CellStyleStrategy(columnIndexes, new WriteCellStyle(), new WriteCellStyle());
        EasyExcel.write(response.getOutputStream())
                .registerWriteHandler(getData2Style())
                .registerWriteHandler(cellStyleStrategy)
                .inMemory(true) // 富文本
                .registerWriteHandler(new WriteHandlerStrategy())
                .registerWriteHandler(new CellRowHeightStyleStrategy())
                .head(headList).excelType(ExcelTypeEnum.XLSX)
                .sheet("sheet1")
                .doWrite(data);
    }

    public static HorizontalCellStyleStrategy getData2Style() {
        // 创建一个样式,用于设置带有边框的内容单元格
        WriteCellStyle borderedCellStyle = new WriteCellStyle();
        borderedCellStyle.setBorderTop(BorderStyle.THIN);
        borderedCellStyle.setBorderBottom(BorderStyle.THIN);
        borderedCellStyle.setBorderLeft(BorderStyle.THIN);
        borderedCellStyle.setBorderRight(BorderStyle.THIN);
        borderedCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);
        return new HorizontalCellStyleStrategy(borderedCellStyle, borderedCellStyle);
    }
最主要的方法
/**
 * Description: - 设置表头和填充内容的样式
 *
 * @author 林李
 * @date 2023/10/13 16:17
 */
public class CellStyleStrategy extends HorizontalCellStyleStrategy {

    private final WriteCellStyle headWriteCellStyle;
    private final WriteCellStyle contentWriteCellStyle;

    private final List<Integer> columnIndexes;

    public CellStyleStrategy(List<Integer> columnIndexes, WriteCellStyle headWriteCellStyle, WriteCellStyle contentWriteCellStyle) {
        this.columnIndexes = columnIndexes;
        this.headWriteCellStyle = headWriteCellStyle;
        this.contentWriteCellStyle = contentWriteCellStyle;
    }

    @Override
    protected void setHeadCellStyle(CellWriteHandlerContext context) {
        WriteFont headWriteFont = new WriteFont();
        headWriteFont.setFontName("宋体");
        headWriteFont.setFontHeightInPoints((short) 11);
        headWriteCellStyle.setBorderTop(BorderStyle.THIN);
        headWriteCellStyle.setBorderBottom(BorderStyle.THIN);
        headWriteCellStyle.setBorderLeft(BorderStyle.THIN);
        headWriteCellStyle.setBorderRight(BorderStyle.THIN);
        headWriteCellStyle.setVerticalAlignment(VerticalAlignment.CENTER);


        // 设置表头样式
        // 设置表头字体为粗体
        headWriteFont.setBold(false);
        headWriteCellStyle.setWriteFont(headWriteFont);
        headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
        headWriteCellStyle.setFillPatternType(FillPatternType.SOLID_FOREGROUND);

        // 根据行索引为不同级别的表头应用不同样式
        if (context.getRowIndex() == 1 || (context.getRowIndex() >= 3 && context.getRowIndex() <= 4)) {
            // 一级、三级和四级表头样式(居中对齐)
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); // 居中对齐


        } else if (context.getRowIndex() == 2) {
            // 二级表头样式(居左对齐)
            headWriteCellStyle.setWriteFont(headWriteFont);
            headWriteCellStyle.setFillForegroundColor(IndexedColors.WHITE.getIndex());
            headWriteCellStyle.setHorizontalAlignment(HorizontalAlignment.LEFT); // 居左对齐
        }

        if (stopProcessing(context)) {
            return;
        }

        WriteCellData<?> cellData = context.getFirstCellData();
        WriteCellStyle.merge(headWriteCellStyle, cellData.getOrCreateStyle());
    }

设置*号为红色
/**
 * Description:
 *
 * @author 林李
 * @date 2023/10/16 16:14
 */
public class WriteHandlerStrategy implements CellWriteHandler {

    @Override
    public void beforeCellCreate(final WriteSheetHolder writeSheetHolder, final WriteTableHolder writeTableHolder,
                                 final Row row, final Head head, final Integer columnIndex,
                                 final Integer relativeRowIndex, final Boolean isHead) {

    }

    @Override
    public void afterCellCreate(final WriteSheetHolder writeSheetHolder, final WriteTableHolder writeTableHolder,
                                final Cell cell, final Head head, final Integer relativeRowIndex, final Boolean isHead) {

    }


    public void afterCellDispose(final WriteSheetHolder writeSheetHolder, final WriteTableHolder writeTableHolder,
                                 final List<WriteCellData<?>> list, final Cell cell, final Head head, final Integer integer,
                                 final Boolean aBoolean) {
        if (cell.getStringCellValue().contains("*")) {
            Sheet sheet = writeSheetHolder.getSheet();
            Workbook workbook = sheet.getWorkbook();
            // xlsx格式,如果是老版本格式的话就用 HSSFRichTextString
            XSSFRichTextString richString = new XSSFRichTextString(cell.getStringCellValue());
            Font font = workbook.createFont();
            font.setColor(Font.COLOR_RED);
            // 从哪到哪,你想设置成什么样的字体都行startIndex,endIndex
            richString.applyFont(0, 1, font);
            // 再设置回每个单元格里
            cell.setCellValue(richString);
        }

    }

}

设置行高
public class CellRowHeightStyleStrategy extends AbstractRowHeightStyleStrategy {

    @Override
    protected void setContentColumnHeight(Row row, int relativeRowIndex) {

    }

    @Override
    protected void setHeadColumnHeight(Row row, int relativeRowIndex) {
        //设置主标题行高为17.7
        if (relativeRowIndex == 2) {
            //如果excel需要显示行高为15,那这里就要设置为15*20=300
            row.setHeight((short) (3200));
        }
    }
}
对于复杂自定义表头导出,可以使用EasyExcel的注解`@ExcelProperty`来实现。具体步骤如下: 1. 创建表头实体类,使用`@ExcelProperty`注解来定义表头名称和对应的字段。 ```java public class ComplexHeadData { @ExcelProperty({"主标题", "名称"}) private String name; @ExcelProperty({"主标题", "数量"}) private Integer number; @ExcelProperty({"主标题", "价格"}) private Double price; @ExcelProperty({"次标题", "子名称"}) private String subName; @ExcelProperty({"次标题", "子数量"}) private Integer subNumber; @ExcelProperty({"次标题", "子价格"}) private Double subPrice; // 省略getter和setter方法 } ``` 2. 创建导出数据集合,并将数据集合和表头实体类传入`EasyExcel.write()`方法中,使用`Sheet`对象来设置表头。 ```java List<ComplexHeadData> data = ... Sheet sheet = new Sheet(1, 0, ComplexHeadData.class); // 设置主标题行 List<List<String>> head = new ArrayList<>(); head.add(Arrays.asList("主标题", "名称", "数量", "价格")); // 设置次标题行 head.add(Arrays.asList("次标题", "子名称", "子数量", "子价格")); // 设置表头样式 WriteCellStyle headStyle = new WriteCellStyle(); // ... 设置样式 // 设置主标题行的样式 WriteCellStyle mainHeadStyle = new WriteCellStyle(headStyle); mainHeadStyle.setFillForegroundColor(IndexedColors.BLUE_GREY.getIndex()); // 设置次标题行的样式 WriteCellStyle subHeadStyle = new WriteCellStyle(headStyle); subHeadStyle.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex()); // 设置主标题行和次标题行的样式 WriteCellStyle headCellStyle = new WriteCellStyle(); headCellStyle.setWrapped(true); headCellStyle.setHorizontalAlignment(HorizontalAlignment.CENTER); headCellStyle.setVerticalAlignment(VerticalAlignment.CENTER); headCellStyle.setMainHeadStyle(mainHeadStyle); headCellStyle.setSubHeadStyle(subHeadStyle); // 设置表头 sheet.setHead(head); sheet.setHeadStyle(headCellStyle); // 写入数据到Excel EasyExcel.write(outputStream, ComplexHeadData.class).sheet().doWrite(data); ``` 通过以上步骤,即可实现复杂自定义表头导出。需要注意的是,`@ExcelProperty`注解中的数组参数表示表头的层级关系,数组的第一个元素为主标题,第二个元素为次标题,以此类推。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

江南_烟雨.

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

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

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

打赏作者

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

抵扣说明:

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

余额充值