經歷過多少踩坑,翻看過多少相似博客,下載過多少版本的Jar,才能摸索出正確的代碼書寫方式,才能實現項目經理需求分析書中的功能點。前端
本文借一次 JavaEE 生成PDF的顛簸的實現過程,描述中小公司程序員的坎坷成長之路。程序員
俺上面只因此將成熟大公司排除在外的緣由是,大公司通常都有成熟的產品線和技術積澱。後端
至少會有完善的建構師團隊,有像掃地神僧那樣的牛人隱士......ui
公司中初級程序員遇到問題,能找到之前實現過的相似功能的代碼做爲參照,也能諮詢技術經理。搜索引擎
小公司是沒有這種福分的,就像昨天早晨"生成PDF"需求到,工期一天,明日要給客戶看。編碼
第一反應是找谷歌,關鍵字 "Java生成PDF",博客不是通常的多,下面簡述幾種實現方式和實現過程當中遇到的問題。加密
(目錄已列在上面,經過搜索引擎進來的小夥伴,看看上面列表中是否有能解決你問題的,有點到相應的小節,沒有就關閉看下一條搜索記錄吧....)spa
谷歌中佔比例最大的Java 生成PDF實現類庫,也是許多技術博客中涉及到技術,官網:http://itextpdf.com/.net
開源中國中的介紹:http://www.oschina.net/p/itext,好嘞,既然都推薦那就採用這類庫看看。
code
下載 Jar 也是琳琅滿目,讓你挑花眼,從 2.1--5.5 應有盡有,有些論壇下載東西還須要註冊o(︶︿︶)o 唉。
這裏採用的是最新的版本 5.5,仔細閱讀下別人的技術博客或者是官方文檔,編碼起來確實不是很費勁。筆者將業務抽象實現的類以下:
public class createSimplePDF { private Font FontChinese; public void simplePDF() { try { BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); FontChinese = new Font(bfChinese, 12, Font.NORMAL); Document document = new Document(); PdfWriter.getInstance(document, new FileOutputStream("F:\\Garbage\\Hello simplePDF.pdf")); document.open(); PdfPTable table = new PdfPTable(4); table.addCell(getCell("姓名", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("編號", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("部門", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("崗位名稱", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("到職日期", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("預約離職日期", 1, 1)); table.addCell(getCell("", 1, 1)); table.addCell(getCell("事由", 1, 3)); table.addCell(getCell("", 3, 3)); table.addCell(getCell("部門意見", 1, 3)); table.addCell(getCell("", 3, 3)); document.add(table); document.close(); } catch (Exception e) { e.printStackTrace(); } } private PdfPCell getCell(String cellValue, int colspan, int rowSpan) { PdfPCell cell = new PdfPCell(); try { cell = new PdfPCell(new Phrase(cellValue, FontChinese)); cell.setRowspan(rowSpan); cell.setColspan(colspan); cell.setHorizontalAlignment(Element.ALIGN_CENTER); } catch (Exception e) { e.printStackTrace(); } return cell; } }
愉快的將代碼編寫完成,生成後中文不見了,注意是不見了,不是亂碼。
仔細觀察報錯,發現IText須要添加另外itext-asian.jar去支持中文,那就添加吧。
由於本身IText使用的是最新的5.5版本,致使其餘低版本的 itext-asian.jar 沒法支持(具體緣由是5.0以上的itext包名發生了變化),拋出的錯誤以下:
Font 'STSong-Light' with 'UniGB-UCS2-H' is not recognized
最終在一篇博客中尋獲解決方法,嘗試後奏效,就是上述代碼中:
BaseFont bfChinese = BaseFont.createFont("STSong-Light", "UniGB-UCS2-H", BaseFont.NOT_EMBEDDED); FontChinese = new Font(bfChinese, 12, Font.NORMAL);
筆者這裏將最新的IText.jar 和 配套的中文支持 itext-asian.jar,放置百度雲盤,節省其餘同窗找 Jar 時間。
雲盤地址:http://pan.baidu.com/s/1bqs4km 提取密碼: 99eg
最終實現的截圖以下:
其實項目中最終要實現的表格的樣子比這個複雜的多,80%花費時間主要是在調整樣式,編譯輸出--->看樣式,到這裏其實需求已經可以實現了。
筆者也是用這種方式實現的,畢竟是給客戶演示的。
這裏要感謝的是這位博主的博客,裏面有詳細的IText 設置段落,標題,表格,加密..........只要你能在生成PDF想到的,這裏面基本上都有。
博客地址:http://rensanning.iteye.com/blog/1538689
Flying saucer 作爲HTML渲染PDF的開源項目(老外起名字我也是醉了,想起一出是一出,HTML 渲染 PDF起個"飛行器")。
其中的核心類 iTextRenderer 支持將HTML生成PDF。
iTextRenderer 在依賴 iText 的基礎上,單獨實現了HTML渲染PDF,基本上能實現 CSS 2.1的總體性,而且徹底符合 W3C 規範。
若是採用這種方式,編譯輸出調整樣式什麼的,就讓它見鬼去吧。
具體的流程以下圖:
這纔是高大上的解決方案有木有,模版引擎如今也是玲琅滿目(freemark,velocity.......),具體看大家項目吧。
這樣就不用爲繁瑣的樣式發愁了,定義模版前端查看,注入數據,生成PDF,核心代碼:
ITextRenderer iTextRenderer = new ITextRenderer(); iTextRenderer.getFontResolver().addFont("C:/Windows/Fonts/simsun.ttc", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); iTextRenderer.setDocument(new File(currWebcontentPath + reviewHtmlPath).toURI().toString()); iTextRenderer.layout(); String pdfName = getPdfName(testVO); OutputStream fileOutputStream = new FileOutputStream(currWebcontentPath + pdfPath + pdfName); iTextRenderer.createPDF(fileOutputStream); iTextRenderer.finishPDF();
這裏面須要解決的問題還有生成的HTML存放的位置,而後就是跳轉到下載頁面了,若是你是JavaEE後端開發,這些問題應該都難不到你。
使用的iTextRenderer的jar一樣也放到: http://pan.baidu.com/s/1kTOpM0R 提取密碼: y9y2
具體參考的博客有:
http://www.tuicool.com/articles/qAFNFja