JAVA生成pdf

介紹一個PDF的生成方案

    博客分類:
  •  

  • Javahtml

CSSC#C++Cfreemarker java

在Java世界,要想生成PDF,方案很多。最近一直在和這個東西打交道,因此簡單作一個小結吧。 

在此以前,先來勾畫一下我心中比較理想的一個解決方案。在企業應用中,碰到的比較多的PDF的需求,多是針對某個比較典型的具有文檔特性的內容,導出成爲PDF進行存檔。因爲咱們如今每每使用一些開源框架,諸如ssh來構建咱們的應用,因此咱們相對熟悉的方案是針對具體的業務邏輯設計實體,使用開源框架來實現咱們的業務邏輯。而PDF的導出,最好不要破壞現有的程序框架,甚至能複用咱們業務邏輯層的代碼。由於若是把PDF做爲一種特殊的表現形式的話,實際上它有點相似模板。最佳的狀況,是咱們可以經過編寫某種模板,把PDF的大概樣子肯定下來,而後把數據和模板作一次整合,獲得最後的結果 

帶着這個目標,開始在網上搜索解決方案。也找到了一些方案,下面簡單小結一下: 

Jasper Report 

看到的市面上採用的最多的方案,是Jasper Report。相關的文檔也不少,不過很雜,須要徹底掌握,我認爲仍是有些坡度和時間的。這個時間和坡度我認爲主要來自於對iReport這個IDE的反覆嘗試,對裏面的每一個屬性的摸索。

Jasper Report的設計思路,自己是不違反我上面所說的初衷的。由於咱們的努力方向是先生成模板,而後獲得數據,最後將二者整合獲得結果。可是Jasper Report的問題在於,其生成模板的方式過於複雜,即便有IDE的幫助,咱們仍是須要對其中的衆多規則有所瞭解才行,不然就會給調試帶來極大的麻煩。 

因此,我認爲Jasper Report是一個半調子方案,這種強依賴於IDE進行可視化編輯的方式令我很不爽。同時,由此帶來的諸多的限制,相信也讓不少使用者頗爲頭疼。在經歷了一番痛苦的掙扎後,決定放棄使用這種方案。 

iText 

其實Jasper Report是基於iText的。因而有的人會說,那麼直接使用iText不是一種倒退麼?的確,直接使用iText彷佛就須要直接使用原生的API進行編程了。不過幸虧iText其實提供了一些方便的API,經過使用這些API,咱們能夠直接將HTML代碼轉化成iText可識別的Document對象,從而導出PDF文檔。 

程序員

 import java.io.FileOutputStream;  
import java.io.FileReader;  
import java.util.ArrayList;  
  
import com.lowagie.text.Document;  
import com.lowagie.text.Element;  
import com.lowagie.text.html.simpleparser.HTMLWorker;  
import com.lowagie.text.html.simpleparser.StyleSheet;  
import com.lowagie.text.pdf.PdfWriter;  
  
public class MainClass {  
  public static void main(String[] args) throws Exception {  
    Document document = new Document();  
    StyleSheet st = new StyleSheet();  
    st.loadTagStyle("body", "leading", "16,0");  
    PdfWriter.getInstance(document, new FileOutputStream("html2.pdf"));  
    document.open();  
    ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st);  
    for (int k = 0; k < p.size(); ++k)  
      document.add((Element) p.get(k));  
    document.close();  
  }  
}

收藏代碼

  1. import java.io.FileOutputStream;  web

  2. import java.io.FileReader;  編程

  3. import java.util.ArrayList;  app

  4.   

  5. import com.lowagie.text.Document;  框架

  6. import com.lowagie.text.Element;  ssh

  7. import com.lowagie.text.html.simpleparser.HTMLWorker;  字體

  8. import com.lowagie.text.html.simpleparser.StyleSheet;  google

  9. import com.lowagie.text.pdf.PdfWriter;  

  10.   

  11. public class MainClass {  

  12.   public static void main(String[] args) throws Exception {  

  13.     Document document = new Document();  

  14.     StyleSheet st = new StyleSheet();  

  15.     st.loadTagStyle("body""leading""16,0");  

  16.     PdfWriter.getInstance(document, new FileOutputStream("html2.pdf"));  

  17.     document.open();  

  18.     ArrayList p = HTMLWorker.parseToList(new FileReader("example.html"), st);  

  19.     for (int k = 0; k < p.size(); ++k)  

  20.       document.add((Element) p.get(k));  

  21.     document.close();  

  22.   }  

  23. }  



這是從網上找到的一個例子。從代碼中,咱們能夠看到,iText自己提供了一個簡單的HTML的解析器,它能夠把HTML轉化成咱們須要的PDF的document。 

有了這個東西,基本上個人目標就能達成一大半了。接下來個人任務就是根據實際狀況去編寫HTML代碼,而後扔進這個方法,就OK了。而真正的HTML代碼,咱們則能夠在這裏使用真正的模板技術,Freemarker或者Velocity去生成咱們所須要的內容。固然,這已是咱們熟門熟路的東西了。 

正當我以爲這個方案基本能符合個人要求的時候,我也一樣找到了它的不少弱項: 

1. 沒法識別不少HTML的tag和attribute(應該是iText的HTMLParser不夠強大) 
2. 沒法識別CSS 

若是說第一點我還能夠勉強接受的話,那麼第二點我就徹底不能接受了。沒法識別簡單的CSS,就意味着HTML失去了最基本的活力,也沒法根據實際要求調整樣式。 

因此這種方案也必然沒法成爲個人方案。 

flying sauser 

在這種狀況下,我幾乎已經燃起了本身編寫一個支持CSS解析的HTML Parser的想法。幸虧,在一個很是偶然的狀況下,我在google中搜到了這樣一個開源項目,它可以知足個人一切需求。這就是flying sauser,項目主頁是:https://xhtmlrenderer.dev.java.net/ 

項目的首頁很是吸引人:An XML/XHTML/CSS 2.1 Renderer。這不正是我要的東西麼? 

仔細再看裏面的文檔: 

引用

Flying Saucer is an XML/CSS renderer, which means it takes XML files as input, applies formatting and styling using CSS, and generates a rendered representation of that XML as output. The output may go to the screen (in a GUI), to an image, or to a PDF file. Because we believe most people will be interested in re-using their knowledge of web layout, our main target for content is XHTML 1.0 (strict), an XML document format that standardizes HTML. 



完美了。這東西能解析HTML和CSS,並且能輸出成image,PDF等格式。哇!咱們來看看sample代碼(代碼醜陋,不過已經能說明問題了): 

 /*  
* ITextRendererTest.java *  
* Copyright 2009 Shanghai TuDou.   
* All rights reserved.  
*/  
  
package itext;  
  
import java.io.File;  
import java.io.FileOutputStream;  
import java.io.OutputStream;  
  
import org.xhtmlrenderer.pdf.ITextFontResolver;  
import org.xhtmlrenderer.pdf.ITextRenderer;  
  
import com.lowagie.text.pdf.BaseFont;  
  
/**  
 * TODO class description *  
 * 
 * @author pcwang 
 * 
 * @version 1.0, 上午11:03:26  create $Id$ 
 */  
public class ITextRendererTest {  
    public static void main(String[] args) throws Exception {  
        String inputFile = "conf/template/test.html";  
        String url = new File(inputFile).toURI().toURL().toString();  
        String outputFile = "firstdoc.pdf";  
        OutputStream os = new FileOutputStream(outputFile);  
        ITextRenderer renderer = new ITextRenderer();  
        renderer.setDocument(url);  
  
        // 解決中文支持問題  
        ITextFontResolver fontResolver = renderer.getFontResolver();  
        fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);  
  
        // 解決圖片的相對路徑問題  
        renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");  
          
        renderer.layout();  
        renderer.createPDF(os);  
          
        os.close();  
    }  
}
  1. /*  

  2. * ITextRendererTest.java *  

  3. * Copyright 2009 Shanghai TuDou.   

  4. * All rights reserved.  

  5. */  

  6.   

  7. package itext;  

  8.   

  9. import java.io.File;  

  10. import java.io.FileOutputStream;  

  11. import java.io.OutputStream;  

  12.   

  13. import org.xhtmlrenderer.pdf.ITextFontResolver;  

  14. import org.xhtmlrenderer.pdf.ITextRenderer;  

  15.   

  16. import com.lowagie.text.pdf.BaseFont;  

  17.   

  18. /**  

  19.  * TODO class description *  

  20.  * 

  21.  * @author pcwang 

  22.  * 

  23.  * @version 1.0, 上午11:03:26  create $Id$ 

  24.  */  

  25. public class ITextRendererTest {  

  26.     public static void main(String[] args) throws Exception {  

  27.         String inputFile = "conf/template/test.html";  

  28.         String url = new File(inputFile).toURI().toURL().toString();  

  29.         String outputFile = "firstdoc.pdf";  

  30.         OutputStream os = new FileOutputStream(outputFile);  

  31.         ITextRenderer renderer = new ITextRenderer();  

  32.         renderer.setDocument(url);  

  33.   

  34.         // 解決中文支持問題  

  35.         ITextFontResolver fontResolver = renderer.getFontResolver();  

  36.         fontResolver.addFont("C:/Windows/Fonts/arialuni.ttf", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);  

  37.   

  38.         // 解決圖片的相對路徑問題  

  39.         renderer.getSharedContext().setBaseURL("file:/D:/Work/Demo2do/Yoda/branch/Yoda%20-%20All/conf/template/");  

  40.           

  41.         renderer.layout();  

  42.         renderer.createPDF(os);  

  43.           

  44.         os.close();  

  45.     }  

  46. }  



運行,成功!實在太簡單了!API幫你完成了一切! 

有了這個東西,咱們就能夠將PDF的生成流程變成這樣: 

1) 編寫Freemarker或者Velocity模板,打造HTML,勾畫PDF的樣式(請任意使用CSS) 

2) 在你的業務邏輯層引入Freemarker的引擎或者Velocity的引擎,並將業務邏輯層中能夠獲取的數據和模板,使用引擎生成最終的內容 

3) 將我上面的sample代碼作簡單封裝後,調用,生成PDF 

這樣,我想做爲一個web程序員來講,上面的3點,都不會成爲你的絆腳石。你能夠輕鬆駕馭PDF了。 

在Flying Saucer的官方文檔中,有一些Q&A,能夠解決讀者們大部分的問題。包括PDF的字體、PDF的格式、Image如何處理等等。你們能夠嘗試着去閱讀。 

還有一篇文章,好像是做者寫的,很是不錯:http://today.java.net/pub/a/today/2007/06/26/generating-pdfs-with-flying-saucer-and-itext.html

相關文章
相關標籤/搜索