我正在使用iText创建PDF文件并使用以下代码进行打印:
Document iText_xls_2_pdf = new Document(PageSize.A4.rotate());
PdfWriter writer = PdfWriter.getInstance(iText_xls_2_pdf, response.getOutputStream());
iText_xls_2_pdf.open();
PdfAction action = new PdfAction(PdfAction.PRINTDIALOG);
writer.setOpenAction(action);
iText_xls_2_pdf.close();
它第一次正常工作,即按预期打开打印对话框。一旦用户关闭打印对话框并再次调用相同的代码,它就不会执行任何操作。
我在这里做错了吗?
注意:我在servlet的doGet
方法中执行此操作。
首先:您用于添加打开操作的代码是正确的。打开正在创建的PDF文档的任何PDF查看器都应触发打印对话框。
您知道您的iText代码是正确的,因为它在第一次打开PDF时有效。在您的情况下,这发生在浏览器中。目前还不清楚使用哪种PDF查看器:Firefox中的pdf.js? Chrome的PDF查看器?在Apple上预览? Adobe Reader?
注意:您不应该假设每个PDF查看器都实现了完整的PDF规范。一些观众忽略了开放动作,其他观众甚至不知道PrintDialog动作是什么。
您编写:一旦用户关闭打印对话框并再次调用相同的代码,它就不会执行任何操作。
这是一种奇怪的放置方式。用户无需触发代码。该操作由打开操作触发,而不是通过单击某个按钮或选择某个菜单选项。如果你说“再次调用相同的代码”,你会解释你的意思,这会有所帮助。
现在,让我们假设“再次调用相同的代码”相当于刷新/重新加载页面。在这种情况下,PDF可能永远不会重新打开,因为它还没有过期。也许浏览器中的PDF查看器会说:“嘿,我现在显示的文档与我在缓存中的文档相同。我不需要重新打开它。”如果文档永远不会重新打开,则没有理由再次触发打开操作。
当您将PDF提供给浏览器时,您设置了哪些标题?
你可以尝试在doGet()
方法的适当位置添加这些行:
response.setHeader("Expires", "0");
response.setHeader("Cache-Control",
"must-revalidate, post-check=0, pre-check=0");
response.setHeader("Pragma", "public");
response.setContentType("application/pdf");
response.setContentLength(baos.size());
请注意,baos
是ByteArrayOutputStream
。这样做是错误的:
PdfWriter writer = PdfWriter.getInstance(iText_xls_2_pdf, response.getOutputStream());
你应该这样做:
ByteArrayOutputStream baos = new ByteArrayOutputStream();
PdfWriter writer = PdfWriter.getInstance(iText_xls_2_pdf, baos);
// do a lot of other stuff
在最后(特别是在设置标题之后),您将内容写入OutputStream
对象的response
:
OutputStream os = response.getOutputStream();
baos.writeTo(os);
os.flush();
os.close();
请参阅官方常见问题解答:How can I serve a PDF to a browser without storing a file on the server side?
如果所有这些都无济于事,则问题是由客户端的问题引起的。在这种情况下,你的问题没有答案。我们只能告诉你,你没有做错任何事。这是添加打开操作的正确方法:
PdfAction action = new PdfAction(PdfAction.PRINTDIALOG);
writer.setOpenAction(action);
如果这不起作用,您可以在Stack Overflow上获得的唯一答案是:“您的代码是正确的”(前提是您遵循有关ByteArrayOutputStream
和HTTP标头的建议)。