EasyExcel实现自定义表头

最近在做Excel导出的时候遇到这样一个问题,有一个可以切换的列表,根据不同的维度去统计数量以及计算比例,其它的字段都是一样的,只有维度的字段不一样。而easyexcel是通过@ExcelProperty注解来指定表头的,如果要实现这个功能我就要创建好几个类,这时我就在想,能不能动态的实现表头呢?

打个比方来说,统计一个班级里面男女同学的数量以及比例,也可以切换成统计一个班级里面各个年龄段的同学的数量以及比例。这两个列表的导出模板如下图所示:

 能不能只用一个类来实现这个功能呢?答案是肯定可以的,下面我们来一起实现这个功能吧~

(1)在pom里面引入easyexcel依赖

<dependency>
    <groupId>com.alibaba</groupId>
    <artifactId>easyexcel</artifactId>
    <version>2.2.6</version>
</dependency>

(2)创建 StudentExcelBean类

@Data
@Builder
public class StudentExcelBean {

    @ExcelProperty(value = "序号", index = 0)
    private Integer serialNumber;

    @ExcelProperty(value = "${titleName}", index = 1)
    private String title;

    @ExcelProperty(value = "数量", index = 2)
    private Integer num;

    @ExcelProperty(value = "占比", index = 3)
    private String ratio;

}

 title字段的@ExcelProperty注解的value属性值是${titleName},因为后面可以将这个标识进行替换,用这种方式去实现动态表头。这里的${titleName}可以是任何标识符,只要在第三步里面按照特定的标识去替换即可。

(3)创建一个TitleCellWriteHandler类去实现CellWriteHandler接口,并重写beforeCellCreate方法

public class TitleCellWriteHandler implements CellWriteHandler {
    private final Map<String, String> titleMap;
    private final PropertyPlaceholderHelper propertyPlaceholderHelper = new PropertyPlaceholderHelper("${","}");

    public TitleCellWriteHandler(Map<String, String> titleMap) {
        this.titleMap = titleMap;
    }

    @Override
    public void beforeCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 Row row, Head head, Integer integer, Integer integer1, Boolean aBoolean) {
        if (head != null) {
            List<String> titleNameList = head.getHeadNameList();
            if (CollectionUtils.isNotEmpty(titleNameList)) {
               titleMap.forEach((k, v) -> {
                   Properties properties = new Properties();
                   properties.setProperty(k, v);
                   titleNameList.replaceAll(value -> propertyPlaceholderHelper.replacePlaceholders(value, properties));
               });
            }
        }
    }

    @Override
    public void afterCellCreate(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDataConverted(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, CellData cellData, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder, List<CellData> list, Cell cell, Head head, Integer integer, Boolean aBoolean) {

    }

}

 这里我们可以看到在重写的beforeCellCreate方法里面去遍历map,将包含key中关键字的都替换成了value。这里用map的好处就是,可以通过map传参就能实现多个字段的自定义替换。

(4)创建一个EasyExcelUtil工具类去实现导出的方法

public class EasyExcelUtil {

    public static void exportData(HttpServletResponse response, String excelName, String sheetName,
                                           Class clazz, List data, Map<String, String> headMap) throws Exception {
        OutputStream outputStream = response.getOutputStream();
        response.setContentType("application/vnd.ms-excel");
        response.setCharacterEncoding("utf-8");
        excelName = URLEncoder.encode(excelName, "UTF-8");
        response.setHeader("Content-disposition", "attachment;filename=" + excelName + ExcelTypeEnum.XLSX.getValue());

        EasyExcel.write(outputStream, clazz)
                .registerWriteHandler(new TitleCellWriteHandler(headMap))
                .sheet(sheetName)
                .doWrite(data);
        outputStream.flush();
    }

}

(5)创建一个EasyExcelController测试导出的方法

@RestController
@RequestMapping(value = "/easyExcelTest")
public class EasyExcelController {

    @SneakyThrows
    @PostMapping("exportSexStatistics")
    public void exportSexStatistics(HttpServletResponse response) {
        // 测试数据
        List<StudentExcelBean> dataList = new ArrayList<StudentExcelBean>(){{
            add(StudentExcelBean.builder().serialNumber(1).title("男").num(50).ratio("50%").build());
            add(StudentExcelBean.builder().serialNumber(2).title("女").num(50).ratio("50%").build());
        }};

        EasyExcelUtil.exportData(response, "导出",
                "sheet1",
                StudentExcelBean.class,
                dataList,
                new HashMap<String, String>() {{put("titleName", "性别");}});
    }

    @SneakyThrows
    @PostMapping("exportAgeStatistics")
    public void exportAgeStatistics(HttpServletResponse response) {
        // 测试数据
        List<StudentExcelBean> dataList = new ArrayList<StudentExcelBean>(){{
            add(StudentExcelBean.builder().serialNumber(1).title("11-12岁").num(20).ratio("20%").build());
            add(StudentExcelBean.builder().serialNumber(2).title("13-14岁").num(20).ratio("20%").build());
            add(StudentExcelBean.builder().serialNumber(3).title("15-16岁").num(20).ratio("20%").build());
            add(StudentExcelBean.builder().serialNumber(4).title("17-18岁").num(20).ratio("20%").build());
            add(StudentExcelBean.builder().serialNumber(5).title("19-20岁").num(20).ratio("20%").build());
        }};

        EasyExcelUtil.exportData(response, "导出",
                "sheet1",
                StudentExcelBean.class,
                dataList,
                new HashMap<String, String>() {{put("titleName", "年龄段");}});
    }

}

这里我们分别写了两个接口来测试不同的导出,下面是两个接口导出的excel截图

这里可以看到我们已经实现了这个效果,即调用导出方法的时候通过map传参的方式去修改指定的值,在实际开发中可以通过前端type传参来改变map中对应的值即可。 

点点关注不迷路,下期将带来更多实用的小技巧~

  • 4
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

沉默的良

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

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

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

打赏作者

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

抵扣说明:

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

余额充值