Alibaba easyExcel对Excel操作之复杂标题处理

easyExcle对poi进行二次封装优化,对外提供了更加方便的接入方式,如果对导出Excle的标题有比较复杂的业务需求,那么就要用到官方提供的2种方式(模版填充、自定义标题),如果自定义标题也不能满足我们的需求,例如我们需要在标题中切入图片需求,要么采用第一种比较简单的模版填充方式,但是如果你不想使用模版的方式,倾向于使用java代码来实现,那么本文可能对你有所帮助,我们采用自定义标题加上拦截器。

业务说明,根据业务需要我们需要生成如下截图的excel文件

对导出文件进行分析:

1、第一行合并单元格

2、第一行中间显示图片,图片是根据其中一个字段生成的条形码

3、第二行也是标题

4、从第三行开始才是数据

实现方案:

1、采用模版填充的方式,很好实现,将需要填充的单元格用变量替换,在程序中使用map进行数据封装

2、采用自定义标题,纯java代码,自定义标题加拦截器,第一步在自定义标题中填充除了图片以外的数据,第二步在拦截器中获取该字段将其转成图片,再次写入到excel中且调整格式

这篇文章我们采用第二种方案

controller层类 ExcelExportController

@GetMapping(value = "/exportExcel")
    public void exportExcel(@RequestParam(value = "id") Long id, HttpServletResponse response) throws IOException {
        //封装标题数据 省略
        ExcelTitle title = new ExcelTitle();
        //封装数据 省略
        List<Object> list = new ArrayList();
        
        ExcelUtils.writeExcel(response,new InboundCellWriteHandler(),head(title.getbBillNo(),title), list, "文件名称");
    }

封装复杂标题head方法

private static List<List<String>> head(String inboundNo , Exceltitle title) {
        List<List<String>> listHead = new ArrayList<>();
        List<String> head0 = new ArrayList<>();
        head0.add(inboundNo);
        head0.add("入库单号");
        head0.add("序号");
        listHead.add(head0);
        List<String> head1 = new ArrayList<>();
        head1.add("");
        head1.add(title.getInboundBillNo());
        head1.add("商品编码");
        listHead.add(head1);
        List<String> head2 = new ArrayList<>();
        head2.add("");
        head2.add("入库类型");
        head2.add("商品名称");
        listHead.add(head2);
        List<String> head3 = new ArrayList<>();
        head3.add("");
        head3.add(title.getBillType());
        head3.add("商品条码");
        listHead.add(head3);
        List<String> head4 = new ArrayList<>();
        head4.add("");
        head4.add("预计到仓日期");
        head4.add("预期数量");
        listHead.add(head4);
        List<String> head5 = new ArrayList<>();
        head5.add("");
        head5.add(title.getExpectArriveStoreTime());
        head5.add("清点数量");
        listHead.add(head5);
        //省略其他字段
        return listHead;
    }

咱们先看excle的工具类,比较简单,最后在处理拦截器的逻辑

public static void writeExcel(HttpServletResponse response,CellWriteHandler handler, List<List<String>> header, List list, String fileName) throws IOException {
        response.setContentType("application/vnd.ms-excel; charset=utf-8");
        response.setCharacterEncoding("utf-8");
        response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName, "utf-8") + ".xlsx");
        EasyExcel.write(response.getOutputStream()).head(header).registerWriteHandler(new LongestMatchColumnWidthStyleStrategy()).registerWriteHandler(handler).sheet("sheet1").doWrite(list);
    }

最后咱们看 InboundCellWriteHandler拦截器处理逻辑

public class InboundCellWriteHandler implements CellWriteHandler {
   //省略beforeCellCreate、afterCellCreate、afterCellDataConverted
    @Override
    public void afterCellDispose(WriteSheetHolder writeSheetHolder, WriteTableHolder writeTableHolder,
                                 List<CellData> cellDataList, Cell cell, Head head, Integer relativeRowIndex,
                                 Boolean isHead) {
        if (!isHead) {
            return;
        }
        if (cell.getRowIndex() == 0 && cell.getColumnIndex() == 0) {
            Sheet sheet = writeSheetHolder.getSheet();
            List<String> headNameList = head.getHeadNameList();
            if (CollectionUtils.isEmpty(headNameList)) {
                return;
            }
            String value = null;
            cell.setCellValue(value);
           //先移除合并第一行标题的单元格
            sheet.removeMergedRegion(0);
            sheet.removeMergedRegion(7);
            //再次合并单元格
            CellRangeAddress region = new CellRangeAddress(0,0, 0,11);
            sheet.addMergedRegionUnsafe(region);
            //图片的高
            short i1 = Integer.valueOf(cell.getRow().getHeight() * 4 + cell.getRow().getHeight() / 4).shortValue();
            cell.getRow().setHeight(i1);
            //根据第一行标题数据生成条形码图片
            byte[] generate = BarCodeUtils.generate(headNameList.get(0));
            int i = sheet.getWorkbook().addPicture(generate, 6);
            //生成画板
            Drawing<?> drawingPatriarch = sheet.getDrawingPatriarch();
            if (Objects.isNull(drawingPatriarch)){
                drawingPatriarch = sheet.createDrawingPatriarch();
            }
            CreationHelper creationHelper = sheet.getWorkbook().getCreationHelper();
            //锁定图片所在的位置
            ClientAnchor clientAnchor = creationHelper.createClientAnchor();
            clientAnchor.setCol1(3);
            clientAnchor.setCol2(5);
            clientAnchor.setRow1(0);
            clientAnchor.setRow2(0);
            clientAnchor.setDx1(0);
            clientAnchor.setDy1(0);
            clientAnchor.setDx2(0);
            clientAnchor.setDy2(1);
            clientAnchor.setAnchorType(ClientAnchor.AnchorType.DONT_MOVE_DO_RESIZE);
            Picture picture = drawingPatriarch.createPicture(clientAnchor, i);
            //这个字段必须设置,要不然图片显示不出来
            picture.resize(2d,1d);
        }

    }

总结:对第二种方式的一些思考

1、提高了代码的复杂性,而且要熟悉poi的一些接口

2、无需另外加载远程excle模版,如果是本地,可能会出现找不到文件的情况

3、使用拦截器,提高excel的格式改变的灵活性

4、使用拦截器,能够方便我们在后期excel的格式进行二次修改加工

 

  • 0
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值