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的格式进行二次修改加工
本文地址:https://blog.csdn.net/zanpengfei/article/details/111884782