當前位置:首頁 > 資訊 > info6 > 正文

Java實現HTML頁面轉PDF解決方案

發表于: 2016-07-26   作者:chenaini119   來源:轉載   瀏覽:
摘要: 首先,當然是找到能夠解析PDF的完美組件,百度和谷歌不約而同的告訴我們。IText是王道。而目前開源的組件中,Itext的確是一個FirstChoice,如果各位單純是做把圖片轉成PDF或者自己寫了Velocity或者FreeMarker模板生成了HTML是非常推薦直接用Itext來進行的。而如果,大家像我這樣已經有前人寫好了HTML頁面或者懶得寫FreeMarker模板的話。可以直接看下一段。由

首先,當然是找到能夠解析PDF的完美組件,百度和谷歌不約而同的告訴我們。IText是王道。而目前開源的組件中,Itext的確是一個First Choice,如果各位單純是做把圖片轉成PDF或者自己寫了Velocity或者FreeMarker模板生成了HTML是非常推薦直接用Itext來進行的。而如果,大家像我這樣已經有前人寫好了HTML頁面或者懶得寫FreeMarker模板的話。可以直接看下一段。
由于他們已經寫好了HTML頁面,而且顯示已經很完美了。那我要做的就是能完美解析HTML+CSS的PDF生成工具。這時候flying-saucer進入了我的選擇范圍中。
http://code.google.com/p/flying-saucer/
上面是網址,這個工具托管在GoogleCode上面,作者做他們能夠做下面的工作:
Flying Saucer takes XML or XHTML and applies CSS 2.1-compliant stylesheets to it, in order to render to PDF (via iText), images, and on-screen using Swing or SWT。
不難看出工作原理,就是解析XML或者XHTML并且包括css樣式表,并且用Swing或者SWT的組件生成PDF的功能。這解決了頁面的顯示問題。IText自身的一個很嚴重的問題就是解析CSS有很大的問題。而這個解決了。下面就是用Flying Saucer來實現的代碼:

public boolean convertHtmlToPdf(String inputFile, String outputFile)
    throws Exception {

        OutputStream os = new FileOutputStream(outputFile); 
        ITextRenderer renderer = new ITextRenderer(); 
        String url = new File(inputFile).toURI().toURL().toString(); 

        renderer.setDocument(url); 

        // 解決中文支持問題     
        ITextFontResolver fontResolver = renderer.getFontResolver(); 
        fontResolver.addFont("C:/Windows/Fonts/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED); 
        //解決圖片的相對路徑問題
        renderer.getSharedContext().setBaseURL("file:/D:/");
        renderer.layout(); 
        renderer.createPDF(os); 

        os.flush();
        os.close();
        return true;
    }

上面這段代碼是這樣的,輸入一個HTML地址URL = inputFile,輸入一個要輸出的地址,就可以在輸出的PDF地址中生成這個PDF。

注意事項:

1.輸入的HTML頁面必須是標準的XHTML頁面。頁面的頂上必須是這樣的
TML頁面的語法必須是非常嚴謹的,所有標簽都必須閉合等等(由于flying-Saucer做了XML解析的工作,不嚴謹會報錯的。),這是對頁面的第一個要求。

2.要用到圖片的地方寫相對路徑的形式,323圖片位置則必須在Java代碼中指定。

renderer.getSharedContext().setBaseURL(“file:/D:/”);

也有另一種方法就是直接在標簽中寫絕對路徑。

3.Flying-Saucer在解析tiff格式的圖片的時候會報錯。具體原因我還沒找到。希望大家能夠指點我。

4.如果在頁面中有中文字體的話。必須在HTML代碼中的樣式中寫上某種字體的css,并且必須是用英文的,然后在Java代碼中寫上對應的文件位置。

ITextFontResolver fontResolver = renderer.getFontResolver();

           fontResolver.addFont("C:/Windows/Fonts/SIMSUN.TTC", BaseFont.IDENTITY_H, BaseFont.NOT_EMBEDDED);

上面的方法是添加了宋體。也可以添加其他字體。

以上就是解決方案。

下面給出這幾個包的下載地址。大家可以直接下載。

http://download.csdn.net/detail/jasonchris/4403777

網上遇到一個問題
I am trying to use flyingsaucer to serve pdf generated from xhtml but I am having trouble getting the servlet example to run.

All the other flyingsaucer examples work fine for me but I need this to work as a servlet to incorporate into a webapp.

The full code for the servlet is as follows

import java.io.*;
import java.net.*;

import javax.servlet.*;
import javax.servlet.http.*;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import org.w3c.dom.Document;
import org.xhtmlrenderer.pdf.ITextRenderer;

public class PDFServlet extends HttpServlet {

    protected void processRequest(HttpServletRequest request, 
        HttpServletResponse response) throws ServletException, IOException {
        response.setContentType("application/pdf");

        StringBuffer buf = new StringBuffer();
        buf.append("<html>");

        String css = getServletContext().getRealPath("/PDFservlet.css");
        System.out.println("css url 2= " + css);
        // put in some style
        buf.append("<head><link rel='stylesheet' type='text/css' "+
                "href='"+css+"' media='print'/></head>");

        buf.append("<body>");
        buf.append("<h1>Quarterly Reports for " +
            request.getParameter("username")+"</h1>");

        buf.append("<table cellspacing='0'>");
        buf.append("<tr><th>Sales</th><th>Profit</th><th>Bonus</th></tr>");

        // generate sales data
        int totalSales = 0;
        int totalProfit = 0;
        int totalBonus = 0;
        for(int i=0; i<10; i++) {
            int currentSales = (int)(Math.random()*10000);
            int currentProfit = (int)(currentSales*0.2);
            int currentBonus = (int)(currentProfit*0.33);
            buf.append("<tr><td>"+currentSales+"$</td><td>"+
                currentProfit+"$</td><td>"+currentBonus+"$</td></tr>");
            totalSales  += currentSales;
            totalProfit += currentProfit;
            totalBonus  += currentBonus;
        }

        buf.append("<tr class='total-header'><td colspan='3'>totals</td></tr>");
        buf.append("<tr class='total'><td>"+totalSales+"$</td><td>"+
            totalProfit+"$</td><td>"+totalBonus+"$</td></tr>");
        buf.append("</table>");

        buf.append("</body>");
        buf.append("</html>");

        byte[] byteArray = buf.toString().getBytes("ISO-8859-1"); 

        // parse our markup into an xml Document
        DocumentBuilder builder;
        try {
            builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
            ByteArrayInputStream baos = new ByteArrayInputStream(byteArray); 
            Document doc = builder.parse(baos);

            ITextRenderer renderer = new ITextRenderer();
            renderer.setDocument(doc, null);

            OutputStream os = response.getOutputStream();
            renderer.layout();
            renderer.createPDF(os);
            os.flush();
            os.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    protected void doGet(HttpServletRequest request, 
        HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    protected void doPost(HttpServletRequest request, 
        HttpServletResponse response) throws ServletException, IOException {
        processRequest(request, response);
    }

    public String getServletInfo() {
        return "Short description";
    }
}
Jan 17, 2013 7:55:23 PM org.xhtmlrenderer.util.XRLog log
WARNING: Unhandled exception. IOException on parsing style seet from a Reader; don't know the URI.
java.io.IOException: Stream closed
    at java.io.BufferedInputStream.getInIfOpen(Unknown Source)
    at java.io.BufferedInputStream.read1(Unknown Source)
    at java.io.BufferedInputStream.read(Unknown Source)
    at sun.nio.cs.StreamDecoder.readBytes(Unknown Source)
    at sun.nio.cs.StreamDecoder.implRead(Unknown Source)
    at sun.nio.cs.StreamDecoder.read(Unknown Source)
    at java.io.InputStreamReader.read(Unknown Source)
    at org.xhtmlrenderer.css.parser.Lexer.zzRefill(Lexer.java:1527)
    ...
    at org.xhtmlrenderer.context.StyleReference.readAndParseAll(StyleReference.java:122)
    at org.xhtmlrenderer.context.StyleReference.setDocumentContext(StyleReference.java:106)
    at org.xhtmlrenderer.pdf.ITextRenderer.setDocument(ITextRenderer.java:130)
    at org.xhtmlrenderer.pdf.ITextRenderer.setDocument(ITextRenderer.java:106)
    at PDFServlet.processRequest(PDFServlet.java:73)
    at PDFServlet.doGet(PDFServlet.java:75)
    ...

解決方法

String css = getServletContext().getRealPath("/PDFservlet.css");

This is not right. It has to be an URL, not a local disk file system path. IText is attempting to download it by an URL “the usual way”, like as a webbrowser would do.

One of the ways to construct the proper URL would be this:

ringBuffer url = req.getRequestURL();
String base = url.substring(0, url.length() - req.getRequestURI().length() + req.getContextPath().length());
String css = base + "/PDFservlet.css";

Java實現HTML頁面轉PDF解決方案

版權所有 IT知識庫 CopyRight ? 2009-2015 IT知識庫 IT610.com , All Rights Reserved. 京ICP備09083238號
广东25选5开奖结果