最新在使用easypoi,使用注解导出和模板导出的方式,现在主要就模板导出合并单元格一些坑和解决方法。

首先我建议刚接触的同学看这篇文章,很详细,功能也比较全面,比较感谢这篇文章的原创作者,网站1:easyPOI基本用法 - 钟小嘿 - 博客园

然后模板导出一些坑,可以看这篇文章,作者写的很详细,目前模板导出存在的一些问题,网站2:springboot集成easypoi并使用其模板导出功能和遇到的坑_巴中第一皇子的博客-CSDN博客_springboot的poi

这几天因为最后一个问题捣鼓了好久,最后写了一个临时方案来处理:

我目前需要处理的报表样式如下:

公司 项目 姓名 有效工作日 合计 人数
寿险 社保平台 张三 12 12000.0 2
李四 13 12000.0 2
王五 14 12000.0 2
合计 4 120000 120000 240000 2
           
产险 公积金平台 赵六 13 12000.0 2
僧其 16 12000.0 2
合计 8 120000 120000 240000 2

上面是一个excel报表,上下分成两部分,分别是两个list(easypoi模板可以允许多list的)

这里的坑,可以看网站2中第四条中的说明,两种方法,即一个使用$fe , 一个使用fe (汗,第一次使用这个,我都没发现这两个不一样), 但是都存在缺陷,

这种多层循环,使用$fe会产生空白行, 使用fe会覆盖循环的数据以下的内容, 如我需求里有 “合计” 行,必定会覆盖。

尝试了很多次后,我的想法是,先把 以人员为维度的所有数据全部查出来,比如上面这个excel表,我查询的数据总共就是5条(这里分成两个list,上面一个3条,下面是2条),这时可能有人疑惑,但是“公司”和“项目” 我是要相同的合并在一起呀,不错,我先以“人员”为粒度查出所有,然后导出前对需要合并的列进行合并。

首先这里两个list都必须使用$fe,因为这样才不会有覆盖的情况产生。

下面是我的模板,分成zkr和bat两个map,里面各自有对应的list:

公司 项目 姓名 有效工作日 合计 人数
{{$fe:zkr.list t.companyName t.projectName t.name t.effectDays t.totalAmount t.emplNum}}
合计 {{zkr.projectNum}} 120000 120000 240000 2
           
{{$fe:bat.list t.companyName t.projectName t.name t.effectDays t.totalAmount t.emplNum}}
合计 {{bat.projectNum}} 120000 120000 240000 2

下面是我封装了下模板导出兼容合并单元格的方法,先贴网站1原始方法:

 /*** 根据模板生成excel后导出** @param templatePath  模板路径* @param map 数据集合* @param fileName 文件名* @param response* @throws IOException*/public static void exportExcel(TemplateExportParams templatePath, Map<String, Object> map, String fileName, HttpServletResponse response) throws IOException {Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map);downLoadExcel(fileName, response, workbook);}

新兼容合并单元格方法:

/*** @Description: 合并指定列单元格并导出(合并行)* @Date: 2021/5/24 9:42* @Param templatePath: 模板路径* @Param map: 需要导出的数据map* @Param fileName: 导出文件名称* @Param response: response* @Param sheetMergeParamList: sheet参数集合* @return: void* @Version: 1.0**/public static void exportMergeExcel(TemplateExportParams templatePath, Map<String, Object> map, String fileName, HttpServletResponse response, List<SheetMergeParam> sheetMergeParamList) throws IOException {Workbook workbook = ExcelExportUtil.exportExcel(templatePath, map);//合并单元格mergeExcel(workbook,sheetMergeParamList);downLoadExcel(fileName, response, workbook);}/*** @Description: 合并单元格具体执行方法* @Date: 2021/5/24 14:58* @Param workbook: 工作薄* @Param sheetMergeParamList: sheet集合* @return: void* @Version: 1.0**/private static void mergeExcel(Workbook workbook, List<SheetMergeParam> sheetMergeParamList){for(SheetMergeParam sheetMergeParam : sheetMergeParamList){Sheet sheet = workbook.getSheetAt(sheetMergeParam.getSheetIndex());int lastRowNum = sheet.getLastRowNum();int i;for(i = 0;i < lastRowNum;i++){//获取每行第一个单元格if(null == sheet.getRow(i) || null == sheet.getRow(i).getCell(0)){continue;}Cell cell = sheet.getRow(i).getCell(0);if(sheetMergeParam.getIgnoreCellValues().contains(cell.getStringCellValue()) || StringUtils.isEmpty(cell.getStringCellValue()) ){continue;}//定义合并终止行数int endRowNum = 0;for(int j = i + 1 ;j < lastRowNum;j++){Cell desColumn = sheet.getRow(i).getCell(sheetMergeParam.getDesColumnIndex());Cell nextDesColumn = sheet.getRow(j).getCell(sheetMergeParam.getDesColumnIndex());if(!desColumn.getStringCellValue().equals(nextDesColumn.getStringCellValue())){//值不同,终止此层循环break;}endRowNum ++;}//判断是否有合并项if(endRowNum == 0){continue;}//合并单元格操作for(int z = 0; z < sheetMergeParam.getMergeColumnIndexs().length; z++){//合并起始行,终止行,起始列,终止列int firstRow = i;int lastRow = i + endRowNum;int firstCol = sheetMergeParam.getMergeColumnIndexs()[z];int lastCol = sheetMergeParam.getMergeColumnIndexs()[z];PoiMergeCellUtil.addMergedRegion(sheet,firstRow,lastRow,firstCol,lastCol);}//合并后行号下移i = i + endRowNum;}}}

下面是我的测试类:

@GetMapping("/testExport")public void testExport(HttpServletResponse response) throws Exception{test(response);}private void test(HttpServletResponse response) throws Exception{//中科软Map zkr = Maps.newHashMap();zkr.put("projectNum",4);ContractTest contractTestZkr = new ContractTest("寿险","社保平台",12000,2,"张三",12);ContractTest contractTestZkr1 = new ContractTest("寿险","社保平台",12000,2,"李四",13);ContractTest contractTestZkr2 = new ContractTest("寿险","社保平台",12000,2,"王五",14);zkr.put("list",Lists.newArrayList(contractTestZkr,contractTestZkr1,contractTestZkr2));//博奥特Map bat = Maps.newHashMap();bat.put("projectNum",8);ContractTest contractTestBat = new ContractTest("产险","公积金平台",12000,2,"赵六",13);ContractTest contractTestBat1 = new ContractTest("产险","公积金平台",12000,2,"僧其",16);bat.put("list",Lists.newArrayList(contractTestBat,contractTestBat1));Map map = Maps.newHashMap();map.put("zkr",zkr);map.put("bat",bat);TemplateExportParams templatePath = new TemplateExportParams("template/当月结算考勤汇总测试.xlsx",true);SheetMergeParam sheetMergeParam = new SheetMergeParam(0,0,new int[]{0,1},Lists.newArrayList("公司","合计"));ExcelUtils.exportMergeExcel(templatePath,map,"当月结算考勤汇总测试daochu",response, Lists.newArrayList(sheetMergeParam));}@Data
@AllArgsConstructor
@NoArgsConstructor
public class SheetMergeParam implements Serializable{/**** sheet下标*/private int sheetIndex;/**** 合并参考列列号*/private int desColumnIndex;/**** 合并单元格列列号数组*/private int[] mergeColumnIndexs;/**** 忽略行内容(如标题行,合计行等)*/private List<String> ignoreCellValues;
}

这个是我的解决方案,如有不正确的地方,欢迎各位指正。

附加

关于导出的样式需要更改的,我贴一篇样式是实例:

/*** @Description: 导出表格样式类* @Date: 2021/4/22 18:02* @Param null:* @return: null* @Version: 1.0**/
public class ExcelStyleUtil implements IExcelExportStyler {private static final short STRING_FORMAT = (short) BuiltinFormats.getBuiltinFormat("TEXT");private static final short FONT_SIZE_TEN = 9;private static final short FONT_SIZE_ELEVEN = 10;private static final short FONT_SIZE_TWELVE = 10;/*** 大标题样式*/private CellStyle headerStyle;/*** 每列标题样式*/private CellStyle titleStyle;/*** 数据行样式*/private CellStyle styles;public ExcelStyleUtil(Workbook workbook) {this.init(workbook);}/*** 初始化样式** @param workbook*/private void init(Workbook workbook) {this.headerStyle = initHeaderStyle(workbook);this.titleStyle = initTitleStyle(workbook);this.styles = initStyles(workbook);}/*** 大标题样式** @param color* @return*/@Overridepublic CellStyle getHeaderStyle(short color) {return headerStyle;}/*** 每列标题样式** @param color* @return*/@Overridepublic CellStyle getTitleStyle(short color) {return titleStyle;}/*** 数据行样式** @param parity 可以用来表示奇偶行* @param entity 数据内容* @return 样式*/@Overridepublic CellStyle getStyles(boolean parity, ExcelExportEntity entity) {return styles;}/*** 获取样式方法** @param dataRow 数据行* @param obj     对象* @param data    数据*/@Overridepublic CellStyle getStyles(Cell cell, int dataRow, ExcelExportEntity entity, Object obj, Object data) {return getStyles(true, entity);}/*** 模板使用的样式设置*/@Overridepublic CellStyle getTemplateStyles(boolean isSingle, ExcelForEachParams excelForEachParams) {return null;}/*** 初始化--大标题样式** @param workbook* @return*/private CellStyle initHeaderStyle(Workbook workbook) {CellStyle style = getBaseCellStyle(workbook);style.setFont(getFont(workbook, FONT_SIZE_TWELVE, true));return style;}/*** 初始化--每列标题样式** @param workbook* @return*/private CellStyle initTitleStyle(Workbook workbook) {CellStyle style = getBaseCellStyle(workbook);style.setFont(getFont(workbook, FONT_SIZE_ELEVEN, false));//背景色style.setFillForegroundColor(IndexedColors.GREY_25_PERCENT.getIndex());style.setFillPattern(FillPatternType.SOLID_FOREGROUND);return style;}/*** 初始化--数据行样式** @param workbook* @return*/private CellStyle initStyles(Workbook workbook) {CellStyle style = getBaseCellStyle(workbook);style.setFont(getFont(workbook, FONT_SIZE_TEN, false));style.setDataFormat(STRING_FORMAT);return style;}/*** 基础样式** @return*/private CellStyle getBaseCellStyle(Workbook workbook) {CellStyle style = workbook.createCellStyle();//下边框style.setBorderBottom(BorderStyle.THIN);//左边框style.setBorderLeft(BorderStyle.THIN);//上边框style.setBorderTop(BorderStyle.THIN);//右边框style.setBorderRight(BorderStyle.THIN);//水平居中style.setAlignment(HorizontalAlignment.CENTER);//上下居中style.setVerticalAlignment(VerticalAlignment.CENTER);//设置自动换行style.setWrapText(true);return style;}/*** 字体样式** @param size   字体大小* @param isBold 是否加粗* @return*/private Font getFont(Workbook workbook, short size, boolean isBold) {Font font = workbook.createFont();//字体样式font.setFontName("宋体");//是否加粗font.setBold(isBold);//字体大小font.setFontHeightInPoints(size);return font;}
}

此处模板导出使用地方:

/*** excel 导出** @param list         数据列表* @param pojoClass    pojo类型* @param fileName     导出时的excel名称* @param response* @param exportParams 导出参数(标题、sheet名称、是否创建表头,表格类型)*/private static void defaultExport(List<?> list, Class<?> pojoClass, String fileName, HttpServletResponse response, ExportParams exportParams) throws IOException {//改变原始样式ExportParams exportParamsSelf = new ExportParams(exportParams.getTitle(), exportParams.getSheetName(), ExcelType.XSSF);exportParamsSelf.setStyle(ExcelStyleUtil.class);//把数据添加到excel表格中Workbook workbook = ExcelExportUtil.exportExcel(exportParamsSelf, pojoClass, list);downLoadExcel(fileName, response, workbook);}

多sheet表普通导出使用地方:

public ResultDomain testExportMutiSheet(HttpServletResponse response) throws Exception{Workbook workBook = null;List<TestEntityVo> exportList = Lists.newArrayList(new TestEntityVo("中二班","张三",12,"广东深圳"),new TestEntityVo("中二班","李四",15,"湖北武汉"));// 创建参数对象(用来设定excel得sheet得内容等信息)ExportParams deptExportParams = new ExportParams();// 设置sheet得名称deptExportParams.setSheetName("员工表");deptExportParams.setStyle(ExcelStyleUtil.class);// 创建sheet1使用得mapMap<String, Object> deptExportMap = new HashMap<>();// title的参数为ExportParams类型,目前仅仅在ExportParams中设置了sheetNamedeptExportMap.put("title", deptExportParams);// 模版导出对应得实体类型deptExportMap.put("entity", TestEntityVo.class);// sheet中要填充得数据deptExportMap.put("data", exportList);List<TestGoodsVo> emExportList = Lists.newArrayList(new TestGoodsVo("001","辣条",1),new TestGoodsVo("002","方便面",2));ExportParams empExportParams = new ExportParams();empExportParams.setSheetName("货物表");empExportParams.setStyle(ExcelStyleUtil.class);// 创建sheet2使用得mapMap<String, Object> empExportMap = new HashMap<>();empExportMap.put("title", empExportParams);empExportMap.put("entity", TestGoodsVo.class);empExportMap.put("data", emExportList);// 将sheet1、sheet2、sheet3使用得map进行包装List<Map<String, Object>> sheetsList = new ArrayList<>();sheetsList.add(deptExportMap);sheetsList.add(empExportMap);ExcelUtils.exportMutiSheet(sheetsList,"测试",response);return ResultDomain.ok();}public static void exportMutiSheet(List<Map<String,Object>> list,String fileName,HttpServletResponse response) throws IOException{Workbook  workbook = ExcelExportUtil.exportExcel(list,ExcelType.XSSF);downLoadExcel(fileName, response, workbook);}

下载:

/*** excel下载** @param fileName 下载时的文件名称* @param response* @param workbook excel数据*/private static void downLoadExcel(String fileName, HttpServletResponse response, Workbook workbook) throws IOException {try {response.setCharacterEncoding("UTF-8");response.setHeader("content-Type", "application/vnd.ms-excel");response.setHeader("Content-Disposition", "attachment;filename=" + URLEncoder.encode(fileName + ".xlsx", "UTF-8"));workbook.write(response.getOutputStream());} catch (Exception e) {throw new IOException(e.getMessage());}}

easypoi 模板导出兼容合并单元格功能相关推荐

  1. EasyPoi导出复杂合并单元格

    前言: 上星期做了一个Excel的单元格合并,用的是EasyPoi,我之前合并单元格都是原生的,第一次使用EasyPoi合并也不太熟悉,看着网上自己套用,使用后发现比原生的方便些,贡献一下,也给其他用 ...

  2. EasyExcel导出自定义合并单元格文件

    目标 需要使用阿里的EasyExcel库来导出excel,并要自定义合并单元格. 思路 这里自定义的CellWriteHandler需要将数据进行如下处理: 1.Excel每一行数据必须对应一个对象: ...

  3. springboot项目导出excel 合并单元格表格

    springboot项目导出excel 合并单元格表格 导出效果 业务controller 业务数据 业务实体类 注解MyExcel.java 注解 MyExcels 导出工具类MyExcelUtil ...

  4. hutool导出excel大数据_Hutool excel导出并合并单元格

    一.Hutool介绍 Hutool是一个小而全的Java工具类库,通过静态方法封装,降低相关API的学习成本,提高工作效率,使Java拥有函数式语言般的优雅,让Java语言也可以"甜甜的&q ...

  5. java word导出表格_Java Word模板导出包含表格单元格合并

    java通过freemarker导出word循环合并表格单元格 本文主要讲解通过freemarker模板引擎来导出word,并且在word中包含表格的合并部分需要循环生成. 一.Java需要通过模板导 ...

  6. easypoi一对多,合并单元格,并且根据内容自适应行高

    记录一下 效果 一.引入依赖 <dependency><groupId>cn.afterturn</groupId><artifactId>easypo ...

  7. easyexcel 填写模板指定行合并单元格

    1.easyexcel(官网)添加版本依赖 <dependency><groupId>com.alibaba</groupId><artifactId> ...

  8. poi导出Excel合并单元格、设置打印参数页眉页脚等

    由于生成文件不能落地,使用SXSSFWorkBook来对excel的导出工作 生成excel步骤: 1.创建workbook SXSSFWorkbook workbook=new SXSSFWorkb ...

  9. java导出excel 边框不全_POI 导出Excel合并单元格后部分边框不显示

    用户需要导出自定义表格,其中合并单元格样式遇到的问题,合并后只显示第一行第一列的边框,其他边框不显示,于是遍查百度,寻到一点思路 ①了解Excel绘制原理 ②了解绘制Excel顺序 ③绘制Excel单 ...

最新文章

  1. Android的四大组件
  2. 内核kernel以及根文件系统rootfs是如何映射到对应的nand flash的
  3. tft lcd驱动参数详解_LED拼接屏和LCD拼接屏的区别
  4. 【工具推荐】ADB IDEA
  5. .NET中关于T4模板的使用
  6. hsweb提取页面查询参数_爬虫入门二-提取信息-正则表达式
  7. 蓝桥杯 ADV-182 算法提高 前10名
  8. load()是python文件操作的函数_python深入(函数,文件操作)
  9. 关于如何在Listener中注入service和ServletContextListener源码分析
  10. 时间变为.05PU sql长度写法
  11. 关闭计算机打印共享服务,win10系统电脑打印机服务被强行关闭的解决方案
  12. python面向对象程序设计实验_实验七 面向对象程序设计
  13. 影响世界的100条管理励志名言
  14. 调用方法有抛出异常的解决办法
  15. 全国计算机平面设计资格证,政策透明—平面设计师证全国统一报名入口报考条件...
  16. PDP-11 计算机
  17. 三星 android 刷机,三星安卓手机如何刷机 三星安卓手机刷机通用方法介绍【教程】...
  18. CDC CClientDC CPen CBrush使用
  19. Android中实现一键分享功能
  20. matlab 使用svm进行分类含实例代码(适用于二分类和多分类)

热门文章

  1. word如何只设置一张为横向_设置Word的某页为横向、单独设置某页的方法
  2. Netty+SpringBoot搭建游戏服务器(带控制台客户端)
  3. modbus通讯失败_STM32 MODBUS通讯失败
  4. 【算法】【动态规划篇】第5节:剪绳子问题
  5. Android系统编译优化:使用Ninja加快编译
  6. excel隐藏列显示列操作
  7. 程序员崩溃的四十多个个瞬间!!!
  8. 在 Excel 中如何对数字进行乘除
  9. Opensea创始人的豪赌之路:从五人团队到亿万富豪
  10. IntelliJ IDEA 字体大小设置(有三处地方设置)!!!