JasperReports PdfServlet to save report in PDF - h

2019-03-04 06:06发布

问题:

Stack: JSF + PrimeFaces on JBoss AS with JasperReports

I have been using a pattern of exporting in PDF format using JasperReports with a three steps process:

[1] obtain the compiled Jasper report from a path in the war

[2] place the JasperPrint object on the session

[3] redirect to the URL of the PdfServlet

So when the user from the GUI clicks on a p:commandButton a backing-bean's method is called that goes through [1], [2] and [3] as in the following example code:

xhtml file:

<p:commandButton ajax="false" action="#{indexController.exportPDF}" value="Export PDF"/>

backing bean code:

private void putPrintObjectInSession() throws JRException {
    ExternalContext externalContext = FacesContext.getCurrentInstance().getExternalContext();
    ServletContext context = (ServletContext) externalContext.getContext();
    String reportFileName = context.getRealPath("/reports/PrimeNumbersReport.jasper");
    File reportFile = new File(reportFileName);
    if (!reportFile.exists())
        throw new JRRuntimeException(".jasper file not found in the war.");
    Map parameters = new HashMap();
    parameters.put("ReportTitle", "2nd Prime Numbers Report");
    parameters.put("BaseDir", reportFile.getParentFile());
    JasperPrint jasperPrint = 
            JasperFillManager.fillReport(
                      reportFileName, 
                      parameters, 
                      getSQLConnection()
                    );
    ((HttpSession) externalContext.getSession(false)).setAttribute(BaseHttpServlet.DEFAULT_JASPER_PRINT_SESSION_ATTRIBUTE, jasperPrint);
}

public String exportPDF() throws IOException, JRException {
    putPrintObjectInSession();
    FacesContext facesContext = FacesContext.getCurrentInstance();  
    ExternalContext externalContext = facesContext.getExternalContext();  
    externalContext.redirect("servlets/pdf");
    return null;
}

I have two questions:

[i] do you see any obvious code smells or limitations with this approach?

[ii] with the example code above both Chrome and Conkeror can save the report but the default filename they present to the user for saving the file is simply "pdf". How can I configure that to a meaningful name (e.g. "report-2012-08-23c.pdf") ?

回答1:

As to your concrete problem with the "Save as" filename, it defaults to the last path in the request URL (which is in case of /servlets/pdf indeed just pdf), unless otherwise specified in Content-Disposition header.

The problem is not directly caused by your JSF code (although it is at its own kind of odd, but that's a different problem/question), but more in the servlet which is been mapped on /servlets/pdf. To set the desired "Save as" filename, you need to add the following line before writing any byte to the response:

response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");

You can if necessary replace attachment by inline if you want to display it by default inline.

The Internet Explorer browser, however, ignores this value and sticks to using the last path in the request URL. So to cover that browser as well, you'd need to include the desired filename in the request URL yourself and change the servlet mapping.

E.g.

String filename = "report-2012-08-23c.pdf";
externalContext.redirect("servlets/pdf/" + filename);

with

@WebServlet("/servlets/pdf/*") // instead of @WebServlet("/servlets/pdf")

With this URL pattern, the filename is inside the servlet available by

String filename = request.getPathInfo().substring(1);