2013-01-18 35 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";