我正在使用 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
方法中执行此操作。
答案 0 :(得分:0)
首先:您用于添加打开操作的代码是正确的。打开正在创建的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标头上的建议)。