目录

  • EasyPOI 根据模板导出excel时,无法自适应行高得解决方案记录
    • 首先说一下问题得场景
      • 第一步
      • 第二步
      • 第三步
      • 第四步
      • 第五步
      • 第六步
      • 第七步 (就是这个方法!)

EasyPOI 根据模板导出excel时,无法自适应行高得解决方案记录

首先说一下问题得场景

  • 我这里时用来做PDF 得生成得 ,先使用Excel 模板生成excel,再将excel流转为pdf,但是问题也就产生了,就是如果行高不自适应得话会导致内容得丢失。这点我做了好多的处理也不好使,最先想到的是使用Excel的模板设置 ,但是不会生效,很遗憾。或者通过EasyPOI来设置Style,也没有设置行高的选项(我是使用模板进行转换的)。所以也是没有办法了,常规通用的方法已经不能实现需求了,只能是查看EasyPOI源码来哪个地方没有自适应,并对其做相应的更改。上一波模板。
  • 这里的这三个字段可能会过长需要换行并且调整行高,都是字符串String类型的数据。

第一步

第二步

第三步

  • 到这里就发现代码比较复杂了,但是不要慌,很容易我们就能找到对模板进行赋值操作的是这个方法parseTemplate(wb.getSheetAt(i),map,params.isColForEash()),所以我们继续点,嘿嘿!

第四步

  • 这一步很清晰的知道赋值代码是setValueForCellByMap(row.getCell(i),map);

第五步

  • 这里我们看到有好几处对单元格进行赋值,经过我测试debug发现上边的都不是对循环进行赋值的地方只有下边的代码是
        //判断foreach 这种方法if (oldString != null && oldString.contains(FOREACH)) {addListDataToExcel(cell, map, oldString.trim());}

所以继续点。

第六步

  • 我们能看到两处地方使用了这个 方法,我们点进去看看。

第七步 (就是这个方法!)

setForEeachRowCellValue(isCreate, cell.getRow(), cell.getColumnIndex(), t, columns, map,rowspan, colspan, mergedRegionHelper)
 private void setForEeachRowCellValue(boolean isCreate, Row row, int columnIndex, Object t,List<ExcelForEachParams> columns, Map<String, Object> map,int rowspan, int colspan,MergedRegionHelper mergedRegionHelper) throws Exception {//所有的cell创建一遍for (int i = 0; i < rowspan; i++) {int size = columns.size();//判断是不是超出设置了for (int j = columnIndex, max = columnIndex + colspan; j < max; j++) {if (row.getCell(j) == null) {row.createCell(j);CellStyle style = row.getRowNum() % 2 == 0? getStyles(false,size >= j - columnIndex ? null : columns.get(j - columnIndex)): getStyles(true,size >= j - columnIndex ? null : columns.get(j - columnIndex));//返回的styler不为空时才使用,否则使用Excel设置的,更加推荐Excel设置的样式if (style != null) {row.getCell(j).setCellStyle(style);}}}if (i < rowspan - 1) {row = row.getSheet().getRow(row.getRowNum() + 1);}}//填写数据ExcelForEachParams params;row = row.getSheet().getRow(row.getRowNum() - rowspan + 1);for (int k = 0; k < rowspan; k++) {int ci = columnIndex;//cell的序号short high=columns.get(0).getHeight();int n=k;while (n>0) {if ( columns.get(n * colspan).getHeight()==0) {n--;} else {high= columns.get(n * colspan).getHeight();break;}}row.setHeight(high);for (int i = 0; i < colspan && i < columns.size(); i++) {boolean isNumber = false;params = columns.get(colspan * k + i);tempCreateCellSet.add(row.getRowNum() + "_" + (ci));if (params == null) {continue;}if (StringUtils.isEmpty(params.getName())&& StringUtils.isEmpty(params.getConstValue())) {row.getCell(ci).setCellStyle(params.getCellStyle());ci = ci + params.getColspan();continue;}String val = null;Object obj = null;//是不是常量if (StringUtils.isEmpty(params.getName())) {val = params.getConstValue();} else {String tempStr = new String(params.getName());if (isNumber(tempStr)) {isNumber = true;tempStr = tempStr.replaceFirst(NUMBER_SYMBOL, "");}map.put(teplateParams.getTempParams(), t);obj = eval(tempStr, map);val = obj.toString();}if (obj != null  && obj instanceof ImageEntity) {ImageEntity img = (ImageEntity)obj;row.getCell(ci).setCellValue("");createImageCell(row.getCell(ci),img.getHeight(),img.getUrl(),img.getData());}else if (isNumber && StringUtils.isNotEmpty(val)) {row.getCell(ci).setCellValue(Double.parseDouble(val));row.getCell(ci).setCellType(Cell.CELL_TYPE_NUMERIC);} else {try {row.getCell(ci).setCellValue(val);} catch (Exception e) {LOGGER.error(e.getMessage(), e);}}row.getCell(ci).setCellStyle(params.getCellStyle());    // plq modify at 2017-11-13//判断这个属性是不是需要统计if (params.isNeedSum()) {templateSumHandler.addValueOfKey(params.getName(), val);}//如果合并单元格,就把这个单元格的样式和之前的保持一致setMergedRegionStyle(row, ci, params);//合并对应单元格if ((params.getRowspan() != 1 || params.getColspan() != 1)&& !mergedRegionHelper.isMergedRegion(row.getRowNum() + 1, ci)) {PoiMergeCellUtil.addMergedRegion(row.getSheet(), row.getRowNum(),row.getRowNum() + params.getRowspan() - 1, ci,ci + params.getColspan() - 1);}ci = ci + params.getColspan();}row = row.getSheet().getRow(row.getRowNum() + 1);}}
  • 通过查看前面代码的模式可以看出,或者可以debug得出这里是对字符串赋值的地方。
    上边那两个是图片和数字赋值的地方。所以我们需要在这里进行更改就好了。进入细节。大家要注意奥!上一波我得代码。方便大家复制参考我上代码,不是图片
 private void setForEeachRowCellValue(boolean isCreate, Row row, int columnIndex, Object t,List<ExcelForEachParams> columns, Map<String, Object> map,int rowspan, int colspan,MergedRegionHelper mergedRegionHelper) throws Exception {//所有的cell创建一遍for (int i = 0; i < rowspan; i++) {int size = columns.size();//判断是不是超出设置了for (int j = columnIndex, max = columnIndex + colspan; j < max; j++) {if (row.getCell(j) == null) {row.createCell(j);CellStyle style = row.getRowNum() % 2 == 0? getStyles(false,size >= j - columnIndex ? null : columns.get(j - columnIndex)): getStyles(true,size >= j - columnIndex ? null : columns.get(j - columnIndex));//返回的styler不为空时才使用,否则使用Excel设置的,更加推荐Excel设置的样式if (style != null) {row.getCell(j).setCellStyle(style);}}}if (i < rowspan - 1) {row = row.getSheet().getRow(row.getRowNum() + 1);}}//填写数据ExcelForEachParams params;row = row.getSheet().getRow(row.getRowNum() - rowspan + 1);List<CellRangeAddress> cellRangeAddressList = getCombineCellList(row.getSheet());for (int k = 0; k < rowspan; k++) {int ci = columnIndex;//cell的序号short high=columns.get(0).getHeight();int n=k;while (n>0) {if ( columns.get(n * colspan).getHeight()==0) {n--;} else {high= columns.get(n * colspan).getHeight();break;}}row.setHeight(high);for (int i = 0; i < colspan && i < columns.size(); i++) {boolean isNumber = false;params = columns.get(colspan * k + i);tempCreateCellSet.add(row.getRowNum() + "_" + (ci));if (params == null) {continue;}if (StringUtils.isEmpty(params.getName())&& StringUtils.isEmpty(params.getConstValue())) {row.getCell(ci).setCellStyle(params.getCellStyle());ci = ci + params.getColspan();continue;}String val = null;Object obj = null;//是不是常量if (StringUtils.isEmpty(params.getName())) {val = params.getConstValue();} else {String tempStr = new String(params.getName());if (isNumber(tempStr)) {isNumber = true;tempStr = tempStr.replaceFirst(NUMBER_SYMBOL, "");}map.put(teplateParams.getTempParams(), t);obj = eval(tempStr, map);val = obj.toString();}if (obj != null  && obj instanceof ImageEntity) {ImageEntity img = (ImageEntity)obj;row.getCell(ci).setCellValue("");createImageCell(row.getCell(ci),img.getHeight(),img.getUrl(),img.getData());}else if (isNumber && StringUtils.isNotEmpty(val)) {row.getCell(ci).setCellValue(Double.parseDouble(val));row.getCell(ci).setCellType(Cell.CELL_TYPE_NUMERIC);} else {try {int valLength = 0;Map<String,Object> cellMap = isCombineCell(cellRangeAddressList,row.getCell(ci),row.getSheet());// 合并的单元格列数int mergeCellCount = ObjectUtils.isEmpty(cellMap.get("mergedCol"))? 0 : (Integer) cellMap.get("mergedCol");char [] strs = val.toCharArray();// 如果是汉字则为 两个字符for (char e : strs) {if(String.valueOf(e).matches("[\u4e00-\u9fa5]")){valLength = valLength +2;}else {valLength = valLength + 1;}}// 获取单元格宽int width = (row.getSheet().getColumnWidth(row.getCell(ci).getColumnIndex()) / 256) +1 ;// 获取单元格高度BigDecimal height = new BigDecimal(row.getHeight()).divide(new BigDecimal(256));// 如果该单元格被合并了if(mergeCellCount > 0){// 获取合并单元格宽度for(int j = 1 ;j < mergeCellCount ; j++){width = width + (row.getSheet().getColumnWidth(row.getCell(ci+j).getColumnIndex()) / 256) +1;}}//向下取整if (width * height.setScale(0,BigDecimal.ROUND_DOWN).intValue() < valLength) {row.setHeight(new BigDecimal(256).multiply(height) .multiply(new BigDecimal((valLength / width) + 1)).shortValue());}row.getCell(ci).setCellValue(val);} catch (Exception e) {LOGGER.error(e.getMessage(), e);}}row.getCell(ci).setCellStyle(params.getCellStyle());    // plq modify at 2017-11-13//判断这个属性是不是需要统计if (params.isNeedSum()) {templateSumHandler.addValueOfKey(params.getName(), val);}//如果合并单元格,就把这个单元格的样式和之前的保持一致setMergedRegionStyle(row, ci, params);//合并对应单元格if ((params.getRowspan() != 1 || params.getColspan() != 1)&& !mergedRegionHelper.isMergedRegion(row.getRowNum() + 1, ci)) {PoiMergeCellUtil.addMergedRegion(row.getSheet(), row.getRowNum(),row.getRowNum() + params.getRowspan() - 1, ci,ci + params.getColspan() - 1);}ci = ci + params.getColspan();}row = row.getSheet().getRow(row.getRowNum() + 1);}}

这里解释一下代码。先说几个问题。

  • 首先是第一个问题就是根据什么来调整行高?当然是根据文字的长度,但是这里有一个问题就是中文字符的宽度和数字和英文字符的长度不是一样的长度,我们这里假设一个中文字符宽度等于两个其他字符的宽度。
  • 第二我们通过POI方法row.getSheet().getColumnWidth(row.getCell(ci).getColumnIndex()来获取单元格宽度是一个什么样数字这里我debug到这里的时候发现是一个很大数值,这个数值除以256 等与一个字符的长度!!!!! 这是重点哦,这样我们才能完成后边的计算。
  • 第三如果我们合并了单元格,但是POI获取宽度的方法只会获取第一个单元格的宽度,并不是实际单元格的长度。因此我们需要考虑合并单元格的问题。先上两个方法再解释。
 /*** 判断cell是否为合并单元格,是的话返回合并行数和列数(只要在合并区域中的cell就会返回合同行列数,但只有左上角第一个有数据)* @param listCombineCell  上面获取的合并区域列表* @param cell* @param sheet* @return* @throws Exception*/public  static Map<String,Object> isCombineCell(List<CellRangeAddress> listCombineCell,Cell cell,Sheet sheet)throws Exception{int firstC = 0;int lastC = 0;int firstR = 0;int lastR = 0;String cellValue = null;Boolean flag=false;int mergedRow=0;int mergedCol=0;Map<String,Object> result=new HashMap<>();result.put("flag",flag);for(CellRangeAddress ca:listCombineCell){//获得合并单元格的起始行, 结束行, 起始列, 结束列firstC = ca.getFirstColumn();lastC = ca.getLastColumn();firstR = ca.getFirstRow();lastR = ca.getLastRow();//判断cell是否在合并区域之内,在的话返回true和合并行列数if(cell.getRowIndex() >= firstR && cell.getRowIndex() <= lastR){if(cell.getColumnIndex() >= firstC && cell.getColumnIndex() <= lastC){flag=true;mergedRow=lastR-firstR+1;mergedCol=lastC-firstC+1;result.put("flag",true);result.put("mergedRow",mergedRow);result.put("mergedCol",mergedCol);break;}}}return result;}//获取合并单元格集合public static List<CellRangeAddress> getCombineCellList(Sheet sheet) {List<CellRangeAddress> list = new ArrayList<>();//获得一个 sheet 中合并单元格的数量int sheetmergerCount = sheet.getNumMergedRegions();//遍历所有的合并单元格for(int i = 0; i<sheetmergerCount;i++){//获得合并单元格保存进list中CellRangeAddress ca = sheet.getMergedRegion(i);list.add(ca);}return list;}

这两个方法 下边的是获取该sheet页所有合并单元格的对象。上边的方法是获取返回该位置被合并单元格的地址,长几个格高几个格!!!! 重点啊.。在我们的主方法上我们可以看到我在上边的地方我调用方法获取了一个该sheet所有合并单元格集合的方法

然后在核心改动的地方调用了获取单元格合并大小的方法

该方法返回一个Map,有两个主要字段就是mergeColmergedRow的字段,是合并的单元格数量。
然后后边就是计算该行行高应该扩展到多大。然后最后set我们的值就结束了。

最后说一下怎么更改源码。首先我们把这个类复制出来,然后建一个与这个类同样目录的地方。名字也要一样。上一波图片。

到这里EasyPOI改源码的过程就结束了,有问题的可以讨论哦,然后还有就是这是公司项目我不能发到git上 抱歉啦!

EasyPOI 根据模板导出excel时,无法自适应行高得解决方案记录相关推荐

  1. 使用EasyPoi根据模板导出Excel或word文档

    接着上篇文章 Java根据模板导出Excel并生成多个Sheet 简单介绍下EasyPoi的使用,直接上代码吧 首先当然是先引入jar包了,看下图 其次,还是贴代码吧看实例,下面是根据模板导出的工具类 ...

  2. java easypoi使用模板导出Excel,合并单元格

    工作几年,每年都有java数据导出Excel的需求,从最初的POI到公司封装的工具再到阿里的EasyExcel.总是有这个那个的小痛点,最近发现easypoi比较满足工作需求,可以很好的导出数据并处理 ...

  3. Java 根据模板导出Excel时,如何根据后台数据设置复选框的勾选

    我之前遇到这个问题,上网查找解决方案.都说要在Excel中设置复选框的链接单元格,然后通过赋值给单元格控制复选框的勾选. 在我设置好链接单元格之后,点击复选框,单元格中的值会改变 TRUE 或 FAL ...

  4. 【合并单元格如何自适应行高】

    合并单元格如何自适应行高 autofit You've most likely heard this warning -- "Avoid merged cells in your Excel ...

  5. 使用easypoi和原生poi接口实现导出excel时选中指定单选框

    使用easypoi和原生poi接口实现导出excel时选中指定单选框 工程需求:导出excel时,选中指定的单选框 步骤一:在excel模板中插入三个单选框 步骤二:设置单选框的单元格连接 我们发现 ...

  6. 使用EasyPoi利用excel模板导出excel表格下载

    前言:使用excel模板导出excel的好处在于可以事先在模板上定义颜色.格式等,适用于模板设计得比较灵活复杂的场景 一.添加jar包 <dependency><groupId> ...

  7. Easypoi使用模板导出文档或excel表格详解

    Easypoi使用模板导出docx文档或excel表格详解 **doc或docx文档的模板导出** **Excel的模板导出** 话不多说先上依赖 <dependency><grou ...

  8. 使用EasyPoi轻松导入导出Excel文档

    提到Excel的导入导出,大家肯定都知道alibaba开源的EasyExcel,该项目的github地址为:https://github.com/alibaba/easyexcel. 这个项目非常活跃 ...

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

    easypoi导出一对多,合并单元格,且根据内容自适应行高 EasyPoi一对多导出 一.pom引入依赖 二.导出实体类 excelPoi常用注解说明 @Excel注解 @ExcelCollectio ...

最新文章

  1. 博科300交换机不中断(non-disruptive)固件升级
  2. C#访问Access和Win7 64位下可能遇到的 未在本地计算机上注册“Microsoft.Jet.OLEDB.4.0” 提供程序 问题
  3. CkEditor批量上传图片(java)
  4. linux中高并发socket最大连接数的优化详解
  5. Zookeeper--ZAB与Paxos算法联系与区别
  6. Python基础----集合
  7. 小米5如何支持ATT网络运营商
  8. [VB]BMP转JPG
  9. 【spring boot】启动类启动 错误: 找不到或无法加载主类 com.codingapi.tm.TxManagerApplication 的解决方案...
  10. [Python] itertools.islice(iterable, start, stop[, step]) 创建迭代器并返回所选元素
  11. oracle读取blob字段的方法,如何读取Oracle的BLOB字段里的文件?
  12. 超级硬盘恢复软件真的超好用哦!
  13. Bioventus在马来西亚上市DUROLANE(R),并选中Athrotech作为独家经销伙伴
  14. 微信公众号消息text换行问题
  15. 汇编语言里 eax ebx ecx edx esi edi ebp esp这些都是什么意思啊
  16. python使用gdal读取tif经纬度
  17. 问卷设计:NPS/CSAT要先问还是后问?
  18. pytdx 安装 初步使用
  19. orecol与mysql_MDPI News | Entropy期刊被PubMed数据库收录
  20. 《Adobe Photoshop CS5中文版经典教程(全彩版)》—第2课2.6节替换图像中的颜色...

热门文章

  1. utools 效率桌面工具
  2. 100层楼2个鸡蛋求最低破碎楼层与信息论
  3. 浅谈Node.js模块系统
  4. Infoworld发布2009年度开源软件大奖
  5. 桂林师范高等专科学校计算机专业,桂林师范高等专科学校什么专业最好 附王牌特色重点专业名单...
  6. W7共享打印显示服务器脱机,手把手教你解决win7系统连接网络共享打印机时出现脱机提示的恢复方案...
  7. Hello Kafka(五)——Kafka管理
  8. 怎么把html背景换白色,美图秀秀怎么将图片背景替换成白色?
  9. 快印客人工智能名片,7个销售新玩法
  10. pixhawk飞控调试_Pixhawk之调试方法