利用Java動態生成 PDF 文檔,則須要開源的API。首先咱們先想象需求,在企業應用中,客戶會提出一些複雜的需求,好比會針對具體的業務,構建比較典型的具有文檔性質的內容,通常會導出PDF進行存檔。那麼目前最佳的解決方案,你可能會想到 iText ,對沒錯。。。 iText+(Velocity / Freemarker)能夠實現。不過據我熟悉,iText自己提供的HTML解析器仍是不夠強大,許多HTML標籤和屬性沒法識別,更悲催的是簡單的CSS它不認識,排版調整樣式會讓你頭大的。不要失望,接下來我就來介紹一個比較理想的解決方案 flying-saucer + iText + (Velocity / Freemarker)。 你們都知道 iText 是一個生成PDF文檔的開源Java庫,可以動態的從XML或者數據庫生成PDF,同時還能夠對文檔進行加密,權限控制,甭且還支持Java/C#等。。。 flying-saucer也是導出PDF的一種解決方案而且是基於iText的開源API,而且實現了CSS解析器,可以很好的支持CSS2.1,以及少許的CSS3 生成PDF解決方案: Flying-Saucer + iText + Velocity 1. 第一步 將jar包放到你的工程裏,須要的jar以下: bcprov-jdk15-140.jar core-renderer.jar iText-2.0.8.jar iTextAsian.jar velocity-1.4.jar Jar包下載地址:http://code.google.com/p/flying-saucer/downloads/list 2. 第二步 設計模版,進行排版調整樣式,css樣式也能夠導入@import 等,經過Velocity模版引擎動態替換 頁面內容,如下是模版內容: <?xml version="1.0" encoding="UTF-8" ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>PDF模版</title> <style type="text/css"> <!-- body { font: 100% Verdana, Arial, Helvetica, sans-serif; margin: 0; padding: 0; text-align: center; color: #000000; } .oneColLiqCtrHdr #container { width: 100%; margin: 0 auto; text-align: left; } div.header-left {display: none} div.header-right {display: none} div.footer-left {display: none} div.footer-right {display: none} @media print { div.header-left { display: block; position: running(header-left); } div.header-right { display: block; position: running(header-right); } div.footer-left { display: block; position: running(footer-left); } div.footer-right { display: block; position: running(footer-right); } } @page { margin: 0.65in; padding: 1em; @top-left{ content:element(header-left); }; @top-right { content: element(header-right) }; @bottom-left { content: element(footer-left) }; @bottom-right { content: element(footer-right) }; } #pagenumber:before { content: counter(page); } #pagecount:before { content: counter(pages); } .tbClass { width:100%;height:100%; border-left:1px #000000 solid; border-bottom:1px #000000 solid } .tbClass td { border-top:1px #000000 solid; border-right:1px #000000 solid } @page landscape{ size:841.9pt 595.3pt; mso-page-orientation:landscape; margin:89.85pt 72.0pt 89.85pt 72.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:15.6pt; } div.landscape{ page:landscape; } @page portrait{ size:595.3pt 841.9pt; margin:36.0pt 36.0pt 36.0pt 36.0pt; mso-header-margin:42.55pt; mso-footer-margin:49.6pt; mso-paper-source:0; layout-grid:16.3pt 0pt; mso-layout-grid-char-alt:0; } div.portrait{ page:portrait; } --> </style> </head> <body class="oneColLiqCtrHdr"> <div id="container"> <div id="header"> <!--***************頁眉_start*****************--> <div id="header-left" class="header-left" align="left"> 頁眉左側 </div> <div id="header-right" class="header-right"> 頁眉右側 </div> <!--***************頁眉_end*****************--> </div> <div id="footer"> <!--***************頁腳_start*****************--> <div id="footer-left" class="footer-left" align="left"> 頁腳左側 </div> <div id="footer-right" class="footer-right" align="right"> 頁腳右側 </div> <!--***************頁腳_endt*****************--> </div> <div id="mainContent"> <!-- start #mainContent --> <div>內容1</div> <div class="portrait" style="page-break-after:always"><!--分頁--> <div>內容2</div> <div class="portrait" style="page-break-after:always"><!--分頁--> <div class="landscape">內容3 橫向顯示</div> <!-- end #mainContent --> </div> </div> </body> </html> 3. 模版與業務數據整合 @SuppressWarnings("unchecked") //打印業務數據對象baseInfo public void getPdf(BASEINFO baseInfo) throws Exception{ String sysurl = PdfBO.class.getProtectionDomain().getCodeSource().getLocation().getPath(); sysurl = sysurl.substring(0,sysurl.indexOf("WEB-INF/",0)); sysurl = java.net.URLDecoder.decode(sysurl, "UTF-8"); //首先建立一個模板引擎的實例 VelocityEngine engine = new VelocityEngine(); //模版路徑 String tempath = sysurl+"\\pdf\\template"; //設置參數 engine.setProperty(Velocity.FILE_RESOURCE_LOADER_PATH, tempath); engine.setProperty(Velocity.INPUT_ENCODING, "UTF-8"); engine.setProperty(Velocity.OUTPUT_ENCODING, "UTF-8"); //初始化 engine.init(); //得到模板 Template template = engine.getTemplate("template.html"); //建立上下文,填充數據 VelocityContext context = new VelocityContext(); context.put("baseInfo",baseInfo); PrintUtils pdfUtil = new PrintUtils(); context.put("PrintUtils", pdfUtil); //如今,把模板和數據合併,輸出到Writer String vmpath = sysurl + "\\pdf\\template\\a.html"; Writer writer = new PrintWriter(new FileOutputStream(new File(vmpath))); template.merge(context,writer); writer.flush(); //生成PDF電子文檔 String sysurl = PdfBO.class.getProtectionDomain().getCodeSource().getLocation().getPath(); sysurl = sysurl.substring(0,sysurl.indexOf("WEB-INF/",0)); sysurl = java.net.URLDecoder.decode(sysurl, "UTF-8"); //轉換的文檔路徑 String inFileUrl = sysurl + "\\pdf\\template\\a.html"; String url = new File(inFileUrl).toURI().toURL().toString(); //轉換後PDF文件的輸出路徑 String outFile_url_ = sysurl + "\\pdf\\doc\\a.pdf"; OutputStream output = new FileOutputStream(outFile_url_); //實例ITextRenderer,加載html文檔 ITextRenderer renderer = new ITextRenderer(); renderer.setDocument(url); //支持中文 ITextFontResolver fontResolver = renderer.getFontResolver(); fontResolver.addFont("C:/Windows/Fonts/ARIALUNI.TTF",BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); //PDF頁眉圖片路徑 renderer.getSharedContext().setBaseURL("file:"+sysurl+"\\images\\a.gif"); renderer.layout(); renderer.createPDF(output); output.close(); PdfReader reader = new PdfReader(outFile_url_); // 加水印後PDF文件輸出路徑 String filePath_stamper = sysurl + "\\pdf\\doc\\my.pdf"; PdfStamper stamper = new PdfStamper(reader, new FileOutputStream(filePath_stamper)); BaseFont base = BaseFont.createFont("STSong-Light", "UniGB- UCS2-H",BaseFont.NOT_EMBEDDED); int total = reader.getNumberOfPages() + 1; //水印圖片的路徑 String imageFilePath = sysurl + "\\images\\b.gif"; Image image = Image.getInstance(imageFilePath); image.setAbsolutePosition(20, 50); image.scalePercent(50); PdfContentByte under; for (int i = 1; i < total; i++) { under = stamper.getUnderContent(i); under.addImage(image); under.beginText(); under.setColorFill(Color.CYAN); under.setFontAndSize(base, 30); under.endText(); } stamper.close();} } 五、生成PDF完成