2013-01-18 44 views
3

我想用flyingsaucer來提供從xhtml生成的pdf,但我無法獲得運行的servlet示例。xhtml到pdf servlet與flyingsaucer

所有其他的flyingsaucer的例子對我很好,但我需要這個作爲一個servlet來合併到一個webapp。

該Servlet完整的代碼如下:

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) 
    ... 

它不運行超出這條線(在try-catch塊):

renderer.setDocument(doc, null); 

我嘗試了一些東西,如改變輸入流類型,並驗證xhtml運行正常,但沒有n不解決任何事情。

我不是那麼熟悉Java servlet的,所以我不知道,如果我解決真正的問題,看來我需要找出一些方法來從關保持輸入流運行此之前:

renderer.setDocument(doc, null); 

這是可能的,還是我應該解決其他問題?

我正在使用Tomcat 7和Java 6.我注意到其他人有一個similar problem但我只在運行servlet示例時纔得到它 - 所有其他示例運行良好。

+0

之後再進行嘗試,我發現它與讀出CSS創建的XML文檔中的CSS鏈接的問題。如果我自己將鏈接解析出鏈接,並在創建XML文檔之前將其包含在StringBuffer中,則一切正常。無論如何,我需要爲我的用例做這件事,但直接解決問題不會有什麼傷害,所以我會在這裏留下問題。 – Geronimo

回答

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

這是不對的。它必須是一個URL,而不是本地磁盤文件系統路徑。 IText試圖通過URL「通常的方式」下載它,就像網頁瀏覽器會做的那樣。

一個構建正確的URL會是這樣的方式:

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