flying-saucer/iText PDF in servlet not finding css

2019-04-13 10:51发布

问题:

A code snippet is at the bottom of the question

I am successfully able to render a PDF in the client's browser using a servlet and flying-saucer/iText. However, I can't figure out how to get the style sheet included in the PDF rendering.

I've tried the following and none have worked thus far:

  • getServletContext().getRealPath("/PDFservlet.css") and putting "PDFservlet.css" at the web root directory
  • buf.append("<head><link rel='stylesheet' type='text/css' href='PDFservlet.css' /></head>") and putting "PDFservlet.css" at the web root directory, the directory where the servlet class file is and right under the "classes" directory
  • Same as above except for href='\PDFservlet.css' and putting "PDFservlet.css" in various places under my web root directory

Not sure what else to try here and how to get this CSS sheet recognized when the PDF is rendered in the client's browser.

Can any of you tell me what I'm doing wrong here?

Also, I'm getting a java.io.IOException: Stream closed after the PDF is rendered and not sure where that's coming from.

I'm testing this locally and running WebLogic Server 10.3.3.

public void doGet(HttpServletRequest req, HttpServletResponse resp)
    throws javax.servlet.ServletException, java.io.IOException
{
    resp.setContentType("application/pdf");

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

    // put in some style
    buf.append("<head><link rel='stylesheet' type='text/css' href='PDFservlet.css' /></head>");

    // generate the rest of the HTML...
    buf.append("<body>");
    buf.append("    <div id='container'>");
    buf.append("        <div id='check_num'>1000</div>");
    buf.append("        <div id='address'><b>Estate Of JAMES SMITH</b><br />35 Addison Avenue<br />New York, NY 00000<br />(123)456-7890</div>");
    buf.append("        <div id='date'><i>Date</i>&#160;<u>02/08/2012</u></div>");
    buf.append("        <div id='void_message'><b>VOID 180 DAYS FROM CHECK DATE</b></div>");
    buf.append("        <div id='pay_line_container'>");
    buf.append("            <div id='pay_line_message'><i>Pay To The Order Of:</i></div>");
    buf.append("            <div id='pay_line'></div>");
    buf.append("            <div id='pay_line_pay_to'>Richard Richards XXIII</div>");
    buf.append("            <div id='pay_line_amount'>$&#160;5.00</div>");
    buf.append("        </div>");
    buf.append("        <div id='pay_line2_container'>");
    buf.append("            <div id='pay_line2'></div>");
    buf.append("            <div id='pay_line2_amount_description'>Five and 00/100</div>");
    buf.append("            <div id='pay_line2_dollars'>DOLLARS</div>");
    buf.append("        </div>");
    buf.append("        <div id='void_stamp'><b>VOID</b></div>");
    buf.append("        <div id='for_line'><i>For:</i>&#160;<u>test</u></div>");
    buf.append("        <div id='bank_info'><b>TD BANKNORTH</b><br />MAINE</div>");
    buf.append("        <div id='signature_line'></div>");
    buf.append("        <div id='bank_numbers'><b>c1000c a123456789a 987654321c</b></div>");
    buf.append("    </div>");
    buf.append("</body>");
    buf.append("</html>");

    System.out.println(buf.toString());

    // parse our markup into an xml Document
    try {
        DocumentBuilder builder = DocumentBuilderFactory.newInstance().newDocumentBuilder();
        Document doc = builder.parse(new StringBufferInputStream(buf.toString()));
        ITextRenderer renderer = new ITextRenderer();
        renderer.setDocument(doc, null);
        renderer.layout();
        OutputStream os = resp.getOutputStream();
        renderer.createPDF(os);
        os.close();
    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

Edit I

Reading the contents of the CSS file on the server side code into a String is working for me as an alternative (the readFile method is based off of Jon Skeet's post at How do I create a Java string from the contents of a file?):

buf.append("<head><style>");
buf.append(readFile(getServletContext().getRealPath("/PDFservlet.css"), "UTF-8"));
buf.append("</style></head>");

Does this seem like an OK approach as an alternative?

Edit II

I've created a chat room for iText that I'm hoping some of you may take a look in every once in awhile. I've had several issues with iText/flying-saucer that I think may be easy to resolve with help from some of you experts. Please take a look if you get a chance and post whatever helpful material you might be able to for iText issues: http://chat.stackoverflow.com/rooms/8945/itext

回答1:

There are multiple ways to solve this, one is yours, others are:

1: Set the url for your document. You call renderer.setDocument(doc, null); the second parameter is the base url, resources will be located relateive to that.

An example:

  • Your document has <link href="my.css" ..
  • The css is located at http://example.com/something/my.css
  • You should call renderer.setDocument(doc, "http://example.com/something/page.html");

2: Implement the UserAgentCallback interface and set it with renderer.getSharedContext().setUserAgentCallback(myUserAgentCallback);



回答2:

I decided with just reading my CSS file on the server side into a String.

The readFile method is based off of Jon Skeet's post at How do I create a Java string from the contents of a file?):

buf.append("<head><style>");
buf.append(readFile(getServletContext().getRealPath("/PDFservlet.css"), "UTF-8"));
buf.append("</style></head>");