java - xhtml to pdf servlet with flyingsaucer

标签 java servlets pdf-generation flying-saucer

我正在尝试使用 flyingsaucer提供从 xhtml 生成的 pdf,但我无法运行 servlet 示例。

所有其他 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 block 中):

renderer.setDocument(doc, null);

我尝试了一些操作,例如更改输入流类型并验证 xhtml 是否正常运行,但没有解决任何问题。

我对 Java servlet 不是很熟悉,所以我不确定我是否在解决正确的问题,看来我需要想出一些方法来防止输入流在我运行之前关闭:

renderer.setDocument(doc, null);

这是可能的还是我应该解决其他问题?

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

最佳答案

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";

关于java - xhtml to pdf servlet with flyingsaucer,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14393142/

相关文章:

java - 从 PNG 图像或 Java 面板创建 PDF

java - 二叉树节点计数的递归方法

java连接类,从servlet传递字符串

java - 如何使用 Java 监视来自/到 servlet 的 HTTP 请求和响应

java - Log4j 在属性文件中找不到配置

java - 使用 Java 按顺序编写大型 PDF

java - 如何实现 doGenerate 方法?

java - 使用通过 apt 安装的 java 库

java - 避免在 java if 条件中使用多个 OR 语句的更好方法

matlab - 如何在 MATLAB 中打印小圆圈?