需求:將網頁內容導出為pdf文件,其中包含文字,圖片,echarts圖
原理:利用freemarker模板與數據渲染所得到的html內容,通過
ITextRenderer對象解析html內容生成pdf
參考地址:
導出pdf
帶有圖片
使用itext將html生成pdf中文換行問題解決方案
本文內容是參考以上地址內容對需求的實現
1.添加依賴
<!-- freemarker --> <dependency> <groupId>org.freemarker</groupId> <artifactId>freemarker</artifactId> <version>2.3.19</version> </dependency> <!-- itextpdf,導出pdf核心架包 --> <dependency> <groupId>com.itextpdf</groupId> <artifactId>itextpdf</artifactId> <version>5.5.11</version> </dependency> <!-- itextpdf工具包,用來解析html生成pdf --> <dependency> <groupId>com.itextpdf.tool</groupId> <artifactId>xmlworker</artifactId> <version>5.5.11</version> </dependency> <!-- flying saucer,支持對CSS高級特性的解析 --> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf</artifactId> <version>9.1.5</version> </dependency> <dependency> <groupId>org.xhtmlrenderer</groupId> <artifactId>flying-saucer-pdf-itext5</artifactId> <version>9.1.5</version> </dependency>
2.freemarker模板數據渲染html內容
// 獲設置模板路徑,供參考 static { freemarkerCfg =new Configuration(); //freemarker的模板目錄 freemarkerCfg.setClassForTemplateLoading(JavaToPdfHtmlFreeMarker.class,"/"); } public static String freeMarkerRender(Map<String, Object> data, String htmlTmp) { Writer out = new StringWriter(); try { // 獲取模板,並設置編碼方式 Template template = freemarkerCfg.getTemplate(htmlTmp); template.setEncoding("UTF-8"); // 合並數據模型與模板 template.process(data, out); //將合並后的數據和模板寫入到流中,這里使用的字符流 out.flush(); return out.toString(); } catch (Exception e) { e.printStackTrace(); } finally { try { out.close(); } catch (IOException ex) { ex.printStackTrace(); } } return null; }
3.解析html內容生成pdf
public static void createPdf(String content,OutputStream out) throws IOException, com.lowagie.text.DocumentException { ITextRenderer render = new ITextRenderer(); ITextFontResolver fontResolver = render.getFontResolver(); fontResolver.addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); // 解析html生成pdf render.setDocumentFromString(content); //解決圖片相對路徑的問題 //render.getSharedContext().setBaseURL(""); render.layout(); render.createPDF(out); render.finishPDF(); }
OutputStream out可以換作其他輸出流對象,比如new FileOutputStream("D:/a.pdf")
注意:設置字體后,需在CSS文件中也設置該字體,才可以顯示中文
圖片可以使用CSS設置背景圖片為base64碼格式展示
body{ font-family:SimSun; }
上面內容為網頁下載pdf所調用,調用方法如下(供參考):
try{ OutputStream out = null; out = response.getOutputStream(); //設置響應對象上下文類型 response.setContentType( "application/pdf,charset=utf-8"); //文件名處理,防止亂碼問題 fileName += DateTimeUtils.currentDate("yyMMddHHmmss") + ".pdf"; String filename = ""; filename = request==null? java.net.URLEncoder.encode(fileName, "UTF-8"): AppUtils.encodingFileName(fileName,request); //設置響應頭 response.setHeader("Content-Disposition","attachment;filename=" + filename); JavaToPdfHtmlFreeMarker.createPdf(content,out); //獲取響應對象輸出流並返回 if (out != null) { out.close(); out = null; } } catch (UnsupportedEncodingException e) { e.printStackTrace(); return super.outJsonStringFail(); } catch (IOException e) { e.printStackTrace(); return super.outJsonStringFail(); } catch (com.lowagie.text.DocumentException e) { e.printStackTrace(); return super.outJsonStringFail(); }
4.如有echarts圖,可添加一下js,將圖轉為base64碼放於css或者html中的style屬性中
/** * 將多個canvas畫布組成的圖表合成為一個完整的canvas,並獲取完整的dataURl * @param divId divId 包含整個畫布的divId * @returns {String} widthXheight@dataURL 例: * 400X300@data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAA */ function getFullCanvasDataURL(divId){ //將第一個畫布作為基准。 var baseCanvas = $("#"+divId).find("canvas").first()[0]; if(!baseCanvas){ return false; }; var width = baseCanvas.width; var height = baseCanvas.height; var ctx = baseCanvas.getContext("2d"); //遍歷,將后續的畫布添加到在第一個上 $("#"+divId).find("canvas").each(function(i,canvasObj){ if(i>0){ var canvasTmp = $(canvasObj)[0]; ctx.drawImage(canvasTmp,0,0,width,height); } }); //獲取base64位的url return baseCanvas.toDataURL(); }
