提供PDF下载后自动打开打印机对话框 [英] Automatically open the printer dialog after providing PDF download

查看:228
本文介绍了提供PDF下载后自动打开打印机对话框的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前正在浏览器的新标签页中打开pdf文件,但我需要知道如何在按下commandButton后打开打印机对话框以打印pdf jasper报告

I am currently opening a pdf file in a new tab in my browser but I need to know how to open a printer dialog to print the pdf jasper report after pressing a commandButton

这是在新标签页中打开pdf的方法:

public void printJasper() {

    JasperReport compiledTemplate = null;
    JRExporter exporter = null;
    ByteArrayOutputStream out = null;
    ByteArrayInputStream input = null;
    BufferedOutputStream output = null;

    FacesContext facesContext = FacesContext.getCurrentInstance();
    ExternalContext externalContext = facesContext.getExternalContext();
    HttpServletResponse response = (HttpServletResponse) externalContext.getResponse();

    try {

        List<String> sampleList = new ArrayList<String>();
        sampleList.add("Fist sample string");
        sampleList.add("Second sample string");

        JRBeanCollectionDataSource beanCollectionDataSource = new JRBeanCollectionDataSource(sampleList);
        Map<String, Object> reportValues = new HashMap<String, Object>();
        reportValues.put("anyTestValue", "test value");

        facesContext = FacesContext.getCurrentInstance();
        externalContext = facesContext.getExternalContext();
        response = (HttpServletResponse) externalContext.getResponse();

        FileInputStream file = new FileInputStream("/any_dir/sample.jasper");
        compiledTemplate = (JasperReport) JRLoader.loadObject(file);

        out = new ByteArrayOutputStream();
        JasperPrint jasperPrint = JasperFillManager.fillReport(compiledTemplate, reportValues, beanCollectionDataSource);

        exporter = new JRPdfExporter();
        exporter.setParameter(JRExporterParameter.JASPER_PRINT, jasperPrint);
        exporter.setParameter(JRExporterParameter.OUTPUT_STREAM, out);
        exporter.exportReport();

        input = new ByteArrayInputStream(out.toByteArray());

        response.reset();
        response.setHeader("Content-Type", "application/pdf");
        response.setHeader("Content-Length", String.valueOf(out.toByteArray().length));
        response.setHeader("Content-Disposition", "inline; filename=\"fileName.pdf\"");
        output = new BufferedOutputStream(response.getOutputStream(), Constants.DEFAULT_BUFFER_SIZE);

        byte[] buffer = new byte[Constants.DEFAULT_BUFFER_SIZE];
        int length;
        while ((length = input.read(buffer)) > 0) {
            output.write(buffer, 0, length);
        }
        output.flush();

    } catch (Exception exception) {
        /* ... */
    } finally {
        try {
            if (output != null) {
                output.close();
            }
            if (input != null) {
                input.close();
            }
        } catch (Exception exception) {
            /* ... */
        }
    }
    facesContext.responseComplete();
}

这是打开pdf文件的按钮:

<p:commandButton action="#{sampleBB.printJasper}"
    ajax="false" onclick="this.form.target='_blank'"
    value="#{msg['generate.report']}" />

我需要做什么?

推荐答案

使用JasperReports



使用JasperReports时,只需将此参数添加到JasperReports导出器中:

With JasperReports

When using JasperReports, simply add this parameter to JasperReports exporter:

exporter.setParameter(JRPdfExporterParameter.PDF_JAVASCRIPT, "this.print();");

这基本上指示Adobe Acrobat执行脚本 this.print()打开PDF时。另请参阅 Adob​​e Acrobat脚本编写指南<79页的第79-80页>。以下是相关摘录:

This basically instructs Adobe Acrobat to execute the script this.print() when opening the PDF. See also page 79-80 of Adobe Acrobat Scripting Guide. Below is an extract of relevance:


打印PDF文档



有可能使用Acrobat JavaScript指定是将PDF文档发送到
打印机还是发送到PostScript文件。在任何一种情况下,要打印PDF文档,请调用doc
对象的 print 方法。 [...]

Printing PDF Documents

It is possible to use Acrobat JavaScript to specify whether a PDF document is sent to a printer or to a PostScript file. In either case, to print a PDF document, invoke the doc object’s print method. [...]






没有JasperReports



如果您无法控制PDF的生成,因此无法操纵它来添加所提到的脚本,另一种方法是相应地更改所有Java / JSF代码,以便PDF文件可以有效地使用(即PDF文件必须仅由GET请求而不是POST请求提供)。这允许您将其嵌入到< iframe> 中,然后在onload期间可以通过JavaScript打印其内容(尽管请记住CORS)。


Without JasperReports

If you don't have control over generation of PDFs and thus can't manipulate it to add the mentioned script, an alternative is to change all the Java/JSF code accordingly so that the PDF file is idempotently available (i.e. the PDF file must be available by just a GET request rather than a POST request). This allows you to embed it in an <iframe> for which it's in turn possible to print its content by JavaScript during onload (keep CORS in mind though).

简单地说,最终用户必须能够通过在浏览器的地址栏中输入其URL来下载所需的PDF文件。您当然可以使用GET请求查询字符串来指定参数,从而允许更多动态性。如果它是非常大的数据,那么你总是可以让JSF把它放在HTTP会话或数据库中,然后传递一个唯一的标识符作为请求参数,这样servlet就可以从同一个HTTP会话或数据库中获取它。

Simply put, the enduser must be able to download the desired PDF file by just entering its URL in browser's address bar. You can of course make use of GET request query string to specify parameters, allowing a bit more dynamicness. If it's "very large" data, then you can always let JSF put it in the HTTP session or DB and then pass an unique identifier around as request parameter so that the servlet can in turn obtain it from the very same HTTP session or DB.

虽然可能会有一些讨厌的 hacks ,一个JSF支持bean根本不可能用于提供非JSF响应的功能。为此,您最好使用普通香草 servlet 。你最终会得到更简单的代码。以下是这种servlet的启动示例:

Whilst possible with some nasty hacks, a JSF backing bean is simply insuitable for the job of idempotently serving a non-JSF response. You'd better use a "plain vanilla" servlet for this. You'll end up with much simpler code. Here's a kickoff example of such a servlet:

@WebServlet("/pdf")
public class PdfServlet extends HttpServlet {

    @Override    
    protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        String foo = request.getParameter("foo");
        String bar = request.getParameter("bar");
        // ...

        // Now just use the same code as in your original bean *without* FacesContext.
        // Note that the HttpServletResponse is readily available as method argument!
        response.setContentType("application/pdf");
        // ...
    }

}

使用此设置,可以通过 http:// localhost:8080 / context / pdf?foo = abc& bar = xyz

With this setup, it's available by http://localhost:8080/context/pdf?foo=abc&bar=xyz.

一旦你开始使用该部分,你只需要在< iframe> 中引用它,它使用JavaScript打印自己的内容窗口在加载事件期间。您可以在JSF页面中执行此操作,例如 /pdf.xhtml

Once you get that part to work, then you just have to reference it in an <iframe> which uses JavaScript to print its own content window during its load event. You can do this in a JSF page, e.g. /pdf.xhtml:

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml"
    xmlns:f="http://java.sun.com/jsf/core"
    xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets"
>
    <h:head> 
         <style>html, body { height: 100%; margin: 0; overflow: hidden; }</style>
    </h:head>
    <h:body>
        <iframe src="#{request.contextPath}/pdf?#{request.queryString}"
            width="100%" height="100%" onload="this.contentWindow.print()" />
    </h:body>
</html>

您需要在JSF支持bean中执行的操作是在必要时向该页面发送重定向请求查询字符串中的参数(最终将在#{request.queryString} 中,以便servlet可以通过 request.getParameter(。 ..))。

All you need to do in your JSF backing bean is to send a redirect to that page, if necessary with parameters in request query string (which will end up in #{request.queryString} so that the servlet can obtain them via request.getParameter(...)).

这是一个启动示例:

<h:form target="_blank">
    <h:commandButton value="Generate report" action="#{bean.printPdf}" />
</h:form>



public String printPdf() {
    // Prepare params here if necessary.
    String foo = "abc";
    String bar = "xyz";
    // ...

    return "/pdf?faces-redirect=true" 
        + "&foo=" + URLEncoder.encode(foo, "UTF-8")
        + "&bar=" + URLEncoder.encode(bar, "UTF-8");
}

这篇关于提供PDF下载后自动打开打印机对话框的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆