JFreeChart not showing in generated Spring MVC and

2019-08-19 03:28发布

问题:

I asked before the question "Append PDF at the available space of another PDF file" and I have successfully made a PDF with both native iText and JFreeChart combined in one page.

I merged this setup to my Spring MVC application using the tutorial "Spring Web MVC with PDF View Example (using iText 5.x)".

I understand that using Spring's AbstractView and in turn implemented as

@Override
protected void buildPdfDocument(Map<String, Object> map, Document document,
        PdfWriter pdfWriter, HttpServletRequest request,
        HttpServletResponse response) throws Exception {

    // do iText and JFreeCharts

}

and that a JFreeChart instance needs an existing PDF file to be inserted into it as demonstrated in "Creating an iText pdf with embedded JFreeChart":

// get the direct pdf content
PdfContentByte dc = docWriter.getDirectContent();

// get a pdf template from the direct content
PdfTemplate tp = dc.createTemplate(width, height);

// create an AWT renderer from the pdf template
Graphics2D g2 = tp.createGraphics(width, height, new DefaultFontMapper() );
Rectangle2D r2D = new Rectangle2D.Double(0,0, width,height);
chart.draw(g2,r2D,null);
g2.dispose();

// add the rendered pdf template to the direct content
// you will have to play around with this because the chart is absolutely positioned.
// 38 is just a typical left margin
// docWriter.getVerticalPosition(true) will approximate the position that the content above the chart ended
dc.addTemplate(tp, 38, docWriter.getVerticalPosition(true)-height);

My problem now is that whenever I call the method that extends AbstractView (refer to the second link), it shows the PDF before inserting the JFreeChart and not the one with the generated chart. I haven't encountered any errors for this one but I would like to know if there is a solution for this behavior.

I just want the user to see the PDF with JFreeChart, just like a normal PDF implementation in Spring MVC.

As you can see I just followed the tutorials above and combined them. They worked perfectly in a separate project but when I merged with Spring, the JFreeChart is not showing, specifically the wrong PDF file is shown.


I know that I can just call the generated PDF with JFreeChart and somewhat intercept the viewing by putting a link to the correct file but I am keeping my hopes up with this setup because it would be a convenient way to use the three technologies altogether without the hassle of file I/O in server (which I have trouble in).


Below is a snippet of the class AbstractITextPdfView from "Spring Web MVC with PDF View Example (using iText 5.x)" that I use.

Can someone tell me how to direct the PDF file being opened to the one with the chart ie inside the buildPdfDocument()?

@Override
protected void renderMergedOutputModel(Map<String, Object> model,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    // IE workaround: write into byte array first.
    ByteArrayOutputStream baos = createTemporaryOutputStream();

    // Apply preferences and build metadata.
    Document document = newDocument();
    PdfWriter writer = newWriter(document, baos);
    prepareWriter(model, writer, request);
    buildPdfMetadata(model, document, request);

    // Build PDF document.
    document.open();
    buildPdfDocument(model, document, writer, request, response);
    document.close();

    // Flush to HTTP response.
    writeToResponse(response, baos);
}

Update

I intercepted the ByteArrayOutputStream by saving in into a file after JFreeChart "attaches" itself to the iText PDF.

@Override
protected void renderMergedOutputModel(Map<String, Object> model,
        HttpServletRequest request, HttpServletResponse response)
        throws Exception {
    // IE workaround: write into byte array first.
    ByteArrayOutputStream baos = createTemporaryOutputStream();

    // Apply preferences and build metadata.
    Document document = newDocument();
    PdfWriter pdfWriter = newWriter(document, baos);
    prepareWriter(model, pdfWriter, request);
    buildPdfMetadata(model, document, request);

    // Build PDF document.
    document.open();
    buildPdfDocument(model, document, pdfWriter, request, response);
    document.close();

    FileOutputStream fos = null;
    try {
        fos = new FileOutputStream(new File("D:/MUST-HAVE-CHART.pdf"));
        baos.writeTo(fos);
    } catch (IOException ioe) {
        // Handle exception here
        ioe.printStackTrace();
    } finally {
        fos.close();
    }
    System.out.println(baos.toString());

    // Flush to HTTP response.
    writeToResponse(response, baos);
}

What happened is that MUST-HAVE-CHART.PDF does not have the chart, same as the one provided by Spring MVC after creation. The one with the chart however is saved somewhere else, as seen in the code:

@Override
protected void buildPdfDocument(Map<String, Object> map, Document document,
        PdfWriter pdfWriter, HttpServletRequest request,
        HttpServletResponse response) throws Exception {

    logger.info("Start of PDF creation");

    Domain domain = (Domain) map.get("domain");

    ServletContext servletContext = request.getSession()
            .getServletContext();
    File servletTempDir = (File) servletContext
            .getAttribute("javax.servlet.context.tempdir");

    if (servletTempDir == null)
        throw new IllegalStateException(
                "Container does not provide a temp dir");

    File targetFile = new File(servletTempDir, NAME_FILE);

    pdfWriter = PdfWriter.getInstance(document, new FileOutputStream(
            targetFile));

    logger.info("PDF file path: " + targetFile.getAbsolutePath().toString());

    document.open();

    PdfBuilder.assemble(document, pdfWriter, domain);

    document.close();
    pdfWriter.close();

    logger.info("End of PDF creation");

    map.put("file", targetFile.getAbsolutePath().toString());
}

The correct one is saved in javax.servlet.context.tempdir or in C:/tomcat/work/Catalina/localhost/my_spring_app/pdf_file.pdf.

How do I make the latter the one showed in the screen???

回答1:

I had the same problem. I resolved it using the following code, and the file is now downloading instead of rendering a new pfd-view page (I prefer this).

protected final void renderMergedOutputModel(Map<String, Object> model, 
           HttpServletRequest request, HttpServletResponse response) throws Exception {

    // IE workaround: write into byte array first.
    ByteArrayOutputStream baos = createTemporaryOutputStream();

    // Apply preferences and build metadata.
    Document document = newDocument();
    PdfWriter writer = newWriter(document, baos);
    prepareWriter(model, writer, request);
    buildPdfMetadata(model, document, request);

    // Build PDF document.
    document.open();
    buildPdfDocument(model, document, writer, request, response);
    document.close();

    //Custom code start 
    String filestorePath = "/var/www/xxx/xxxxx/";
    String downloadfileNm = "DeliveryNote.pdf";
    String filePath = filestorePath+downloadfileNm;
    URL url = new URL("file:"+filePath);
    File file = new File(url.toURI());
    if (file.exists()) {
        response.setContentLength(new Long(file.length()).intValue());
        response.setHeader("Content-Disposition", "attachment; filename="+downloadfileNm);
        FileCopyUtils.copy(new FileInputStream(file), response.getOutputStream());      
    }
    //Custom code end

    // Flush to HTTP response.
    //writeToResponse(response, baos);

}