提供PDF下载后自动打开打印机对话框



我目前在浏览器的新选项卡中打开pdf文件,但我需要知道如何在按下命令按钮后打开打印机对话框以打印pdf jasper报告

这是在新选项卡中打开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导出器:

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

这基本上指示Adobe Acrobat在打开PDF时执行脚本this.print()。参见adobeacrobat脚本指南第79-80页。以下是相关内容的摘录:

打印PDF文档

可以使用acrobatjavascript指定是否将PDF文档发送到打印机或PostScript文件。无论哪种情况,要打印PDF文档,都需要调用doc对象的print方法。[…]


没有JasperReports

如果您无法控制PDF的生成,因此无法操作它来添加上述脚本,那么另一种选择是相应地更改所有Java/JSF代码,以便PDF文件是幂等可用的(即PDF文件必须仅通过GET请求而不是POST请求可用)。这允许您将其嵌入到<iframe>中,从而可以在onload期间通过JavaScript打印其内容(请记住CORS)。

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

虽然可能会有一些令人讨厌的技巧,但JSF支持bean根本不适合为非JSF响应提供幂等服务的工作。为此,您最好使用"普通的"servlet。您将得到更简单的代码。下面是这样一个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可以使用它。

一旦你得到那部分工作,然后你只需要在<iframe>中引用它,它使用JavaScript在load事件期间打印自己的内容窗口。您可以在JSF页面中这样做,例如/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(...)获得它们)。

下面是一个启动示例:

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

有一个<p:printer> Primefaces的组件用于此目的。

这样的东西可能会工作,但没有测试。

<h:form>
    <h:commandButton value="Print" type="button" icon="ui-icon-print">
        <p:printer target="pdf" />
    </h:commandButton>
    <p:media style="display:none;" id="pdf" value="/aPDF.pdf" />
</h:form>

注意:

<p:media>确实有一个打印按钮来打印显示的pdf。

你必须将pdf文件嵌入到iframe中,并在其上使用JavaScript print()函数,或者你可以激活pdf本身的自动打印功能。但这绝对是可能的。

参见这个问题:PDF文件的打印对话框可以用Javascript打开吗?

如何使用JavaScript打印PDF

你不能直接从JavaScript打印URL,你只能打开现有页面 -文章的打印对话框和打印API。

PDF在服务器上生成并发送到网络浏览器(作为一个单独的"页面"),它必须决定如何处理它-用户通常被询问是否要显示或保存PDF。

要"自动打印"(即打开打印对话框)一个HTML页面,你只需要这样做:

window.onload = function() {
  window.print();
};

但是PDF不能这样做,因为它不是HTML页面。

要"自动打印"HTML页面以外的内容,您需要有一个web浏览器插件来处理来自服务器的pdf文件。

另一种可能性是编写一个GreaseMonkey用户脚本,它将对*.myserver.com/**.pdf作出反应并将其打印出来。注意:GreaseMonkey是Mozilla Firefox插件。

重载选项

您可以通过在服务器应用程序中添加打印支持来完成任务。应用程序需求:

  • 它必须是一个内部网应用程序(在用户的网络中自托管),
  • 管理员用户需要注册可通过JSP页面从服务器访问的网络打印机,
  • 一个"打印对话框"页面,您可以在其中选择一台已注册的打印机并单击"打印"按钮发送"打印"请求,例如:

    /打印?打印机= printer1&医生=/报告/report1

我已经看到一个Java web应用程序支持这个,但正如你所看到的,这不是一个容易的任务。

@Sujan Sivagurunathan

我尝试用p:media演示页中的PDF文件替换p:printer演示页上的图像来组合p:printer和p:media:
// Replace this line:
<img id="j_idt18:image" src="/showcase/images/nature1.jpg?pfdrid_c=true" alt="">
// With this one:
<object **id="j_idt18:image"** style="display:none;" type="application/pdf" data="/showcase/resources/other/guide.pdf?pfdrid_c=true">Undefined</object>

当你点击打印按钮时,你会得到一个空页面。如果你省略了style="display:none;",留下PDF的height="300px" width="100%",你会在页面打印预览上得到一个小矩形。

Eidt

谢谢你们,BalusC和Sujan。我同意,有一个在PDF中嵌入JavaScript的选项,但出于安全原因通常是禁用的。

我认为最浏览器兼容和用户友好的方式是有一个专用的打印预览弹出窗口与iframe显示给定的PDF通过GET请求和打印按钮调用IFRAME的contentWindow.print()

不让用户选择打印机和配置,直接打印文档通常不是一个好主意。

相关内容

  • 没有找到相关文章

最新更新