# Excel模板转PDF合并单元格边框全乱了?逐个格子读取边线信息再还原
Excel模板转PDF合并单元格边框全乱了逐个格子读取边线信息再还原非科班野生程序员深耕政务信息化20年。从VC到PB再到Java自研框架browise也打磨了十几年。最近整理框架代码发现不少有趣的决策写出来和大家聊聊。最后感谢豆包、智谱、OpenCode决策是我做的代码是我搓的文字是他们总结的。问题政务报表的流程是业务人员用 Excel 画模板表头、合并单元格、边框样式系统读取 Excel 填数据转 PDF 给用户预览或打印。但 Excel 转 PDF 时合并单元格的边框处理是个大坑。jxl 读取 Excel 时合并区域只有左上角那个格子里有值其他格子是空的。转成 PDF 的 PdfPTable 时合并单元格的上下左右边线信息需要从正确的位置取取错了边框就乱了。实现思路第一步从 Excel 读出每个格子的完整信息publicvoidxlsToPDF(Workbookworkbook,Stringpage,Stringfile)throwsException{Sheetsheetworkbook.getSheet(0);Range[]msheet.getMergedCells();// 拿到所有合并区域for(inti0;isheet.getRows();i){StringhString.valueOf(sheet.getRowView(i).getSize()/18);ArrayListHashMapString,StringcontentnewArrayListHashMapString,String();for(intj0;jsheet.getColumns();j){HashMapString,StringmapnewHashMapString,String();Cellcellsheet.getCell(j,i);Stringstrcell.getContents();// 数字格式化保留两位小数if(cell.getType()CellType.NUMBER||cell.getType()CellType.NUMBER_FORMULA){strString.format(%.2f,Double.valueOf(str));}// 读取格式信息jxl.format.CellFormatftcell.getCellFormat();Stringalign,valign,bold0;intfontsize0;Stringst0,tl0,bl0,ll0,rl0;if(ft!null){// 对齐方式if(ft.getAlignment()jxl.format.Alignment.CENTRE)alignc;elseif(ft.getAlignment()jxl.format.Alignment.LEFT)alignl;elsealignr;// 垂直对齐if(ft.getVerticalAlignment()jxl.format.VerticalAlignment.CENTRE)valignm;elseif(ft.getVerticalAlignment()jxl.format.VerticalAlignment.BOTTOM)valignb;elsevalignt;// 字号和加粗jxl.format.Fonttfft.getFont();if(tf!null){fontsizetf.getPointSize();if(tf.getBoldWeight()700)bold1;}// 四个方向的边线tlString.valueOf(ft.getBorder(Border.TOP).getValue());blString.valueOf(ft.getBorder(Border.BOTTOM).getValue());llString.valueOf(ft.getBorder(Border.LEFT).getValue());rlString.valueOf(ft.getBorder(Border.RIGHT).getValue());// 只要有一个方向有线就算有边框if(1.equals(tl)||1.equals(bl)||1.equals(ll)||1.equals(rl))st1;}// 存到 HashMapmap.put(val,str);map.put(fs,String.valueOf(fontsize));map.put(line,st);map.put(lb,ll);// left bordermap.put(tb,tl);// top bordermap.put(rb,rl);// right bordermap.put(bb,bl);// bottom bordermap.put(h,h);map.put(a,align);map.put(v,valign);map.put(bold,bold);content.add(map);}tableContent.add(content);}}每个格子读出12个属性值、字号、四个方向的边线、行高、水平对齐、垂直对齐、是否加粗、是否超长文本。第二步合并单元格的边线要从正确的位置取这是关键部分。Excel 合并区域里只有左上角格子有完整格式。但合并后的底边线实际在区域最底行右边线实际在最右列for(Rangeobj:m){intrsobj.getTopLeft().getRow();intreobj.getBottomRight().getRow();intcsobj.getTopLeft().getColumn();intceobj.getBottomRight().getColumn();if((irsire)(jcsjce)){if(irsjcs){// 只处理左上角if(rsre){// 底边线要从最底行取Cellcell2sheet.getCell(j,ire-rs);jxl.format.CellFormatft2cell2.getCellFormat();blString.valueOf(ft2.getBorder(Border.RIGHT).getValue());}if(csce){// 右边线要从最右列取Cellcell2sheet.getCell(jce-cs,i);jxl.format.CellFormatft2cell2.getCellFormat();rlString.valueOf(ft2.getBorder(Border.BOTTOM).getValue());}break;}else{break;}}}这段代码虽然短但解决了核心问题合并区域的边界线要从实际边界位置的格子读取而不是从左上角格子读取。第三步写 PDF 时还原合并和边框for(ArrayListHashMapString,Strings:tableContent){for(HashMapString,Stringt:s){booleancfalse;// 处理合并for(Rangeobj:m){intrsobj.getTopLeft().getRow();intreobj.getBottomRight().getRow();intcsobj.getTopLeft().getColumn();intceobj.getBottomRight().getColumn();if((irsire)(jcsjce)){if(irsjcs){if(rsre)cell.setRowspan(re-rs1);if(csce)cell.setColspan(ce-cs1);break;}else{ctrue;// 被合并的格子跳过break;}}}if(c){j;continue;}// 还原边框if(0.equals(t.get(line))){cell.disableBorderSide(15);// 全部无边框}// ... 以下根据四个方向的边线状态组合处理}}第四步边框组合的排列处理这部分代码最多——根据上、下、左、右四条边线的有无组合出各种情况调用 iText 的disableBorderSideelseif(0.equals(t.get(lb))0.equals(t.get(rb))0.equals(t.get(bb)))cell.disableBorderSide(14);// 隐藏下、左、右elseif(0.equals(t.get(lb))0.equals(t.get(rb))0.equals(t.get(tb)))cell.disableBorderSide(13);// 隐藏上、左、右elseif(0.equals(t.get(lb))0.equals(t.get(rb)))cell.disableBorderSide(12);// 隐藏左、右// ... 十几种组合 ...elseif(0.equals(t.get(tb)))cell.disableBorderSide(1);// 只隐藏上每个组合对应一个数字是 iText 的Rectangle.LEFT、Rectangle.RIGHT等常量的位运算组合值。这段代码看着啰嗦但每一种组合都是实测踩出来的。第五步加水印PDF 生成后还能叠加图片水印publicvoidaddWaterMarkIncludeWords(StringinputFile,StringoutputFile,StringimageFilePath,intwidth,intheight){PdfReaderreadernewPdfReader(inputFile);PdfStamperstampernewPdfStamper(reader,newFileOutputStream(outputFile));inttotalreader.getNumberOfPages()1;ImageimageImage.getInstance(imageFilePath);image.setAbsolutePosition(width,height);image.scalePercent(35f);for(inti1;itotal;i){stamper.getUnderContent(i).addImage(image);}stamper.close();newFile(inputFile).delete();// 删除无水印版本}政务报表经常要加内部文件之类的印章水印。小结ToPDF 这个类445行大部分代码在处理合并单元格的边框还原。核心思路就是从 Excel 逐格子读取格式信息包括四条边的线写到 PDF 时逐格子还原。合并区域的边界线从实际边界位置取不是从左上角取。做报表的同学有没有更好的 Excel 转 PDF 方案评论区聊聊。标签#Java #Excel转PDF #iText #jxl #合并单元格 #政务报表 #自研框架
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2501097.html
如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!