问题描述
我正在尝试将iText生成的PDF从服务器端返回到客户端,以使用户能够存储它。我正在关注( AceFunk)
I am trying to return an iText generated PDF from the server side to the client side to enable the user to store it. I am following How to convert iTextPDF Document to Byte Array (AceFunk)
private static ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
public static byte[] main(java.util.List<Transcript> listymAwards, String scoutName, String groupName) {
Document document = new Document(PageSize.A4, 0f, 0f, 0f, 0f);
try {
//PdfWriter.getInstance(document, new FileOutputStream(FILE));
PdfWriter.getInstance(document, byteArrayOutputStream); // Do this BEFORE document.open()
document.open();
addMetaData(document);
addImages(document);
addTitlePage(document, scoutName);
//Add the table of achievements
if (listymAwards == null || listymAwards.isEmpty()) {
//Nothing to do.
//System.out.println("Scout not found.");
}else{
Paragraph preface = new Paragraph();
PdfPTable table = new PdfPTable(3);
table.setWidths(new int[]{1, 3, 1});
table.setHeaderRows(1);
PdfPCell c1 = new PdfPCell(new Phrase("Section"));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
c1 = new PdfPCell(new Phrase("Award"));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
c1 = new PdfPCell(new Phrase("Date"));
c1.setHorizontalAlignment(Element.ALIGN_CENTER);
table.addCell(c1);
table.setHeaderRows(1);
String storedName = null;
int noRows = 0;
String firstTable = "Yes";
DateFormat df1 = new SimpleDateFormat("yyyy-MM-dd");
DateFormat df2 = new SimpleDateFormat("dd-MM-yyyy");
// We add three empty lines
addEmptyLine(preface, 1);
addEmptyLine(preface, 1);
addEmptyLine(preface, 1);
for (final Transcript scoutNamesDescription : listymAwards) {
if (firstTable.equals("Yes") && noRows > 30){ // Change this to number of rows required
noRows = 0;
firstTable = "No";
document.add(table);
document.newPage();
table.flushContent();
}else{
if (firstTable.equals("No") && noRows > 50){ // Change this to number of rows required
// We add three empty lines if not the first table
document.add(preface);
}
}
noRows++;
if (scoutNamesDescription.getSection().equals(storedName)){
table.addCell(" ");
}else{
storedName = scoutNamesDescription.getSection();
table.addCell(scoutNamesDescription.getSection());
}
table.addCell(scoutNamesDescription.getAwardName());
Date awardedDate = df1.parse(scoutNamesDescription.getAwardedDate());
String awardedString = df2.format(awardedDate);
table.addCell(awardedString);
}
//Print the remaining rows.
// We add three empty lines if not the first table
if (firstTable.equals("No")){
document.add(preface);
}else{
firstTable = "No";
}
document.add(table);
}
//Add signature
addSignaturePage(document, groupName);
document.close();
} catch (Exception e) {
e.printStackTrace();
}
byte[] pdfBytes = byteArrayOutputStream.toByteArray();
return pdfBytes;
}
这是返回给服务器端:
byte[] pdfBytes = ScoutTranscript.main(listymAwards, scoutName, groupName);
System.out.println("Point 3");
return pdfBytes;
然后返回到客户端:
Window.open("data:application/pdf;base64,"+result,"_parent", "location=no");
我收到错误消息:
This site can’t be reached
The webpage at data:application/pdf;base64,[B@154 might be temporarily down or it may have moved permanently to a new web address.
推荐答案
错误#1:
让我们从一个不涉及iText的小测试开始。试试这个:
Let's start with a small test that doesn't involve iText in any way. Try this:
byte[] test = "Test".getBytes();
System.out.println("Test " + test);
什么写入输出?就我而言,它是:
What is written to the output? In my case, it's:
Test [B@3da3da69
[
表示我正在尝试将数组转换为 String
; B
表示数组包含字节; @
将类型与ID分开;后面的字符是十六进制格式的ID(哈希码)。请参阅
The [
indicates that I am trying to convert an array to a String
; the B
indicates that the array contains bytes; the @
separates the type from the ID; the characters that follow are the ID in hexadecimal format (a hashcode). See Java: Syntax and meaning behind "[B@1ef9157"? Binary/Address?
如果结果
的类型为 byte []
你有这一行:
If result
is of type byte[]
and you have this line:
Window.open("data:application/pdf;base64,"+result,"_parent", "location=no");
然后data:application / pdf; base64,+ result
结果类似于data:application / pdf; base64,[B @ 154
。这没有任何意义,是吗?
Then results in something like . That doesn't make any sense, does it?
现在试试这个:
byte[] test = "Test".getBytes();
System.out.println("Test " + new String(test));
输出为:
Test Test
您使用的是字节[ ]
好像是 String
。这是你的第一个错误。
You were using a byte[]
as if it was a String
. This is your first error.
我会说一些令人讨厌的东西,因为这不是Java开发人员会犯的错误。但是,我刚看了你的生物,我看到你是Java的新手,你(可能)教你自己如何使用Java编写代码(就像我20年前那样),所以我自己进行了审查;-)
I was going to say something nasty because this is not an error that a Java developer would make. However, I've just read your bio, and I see that you're new at Java and you are (probably) teaching yourself how to code in Java (just like I did 20 years ago), so I censored myself ;-)
错误#2:
您无法通过更换您的问题来解决问题代码:
You can not solve your problem by replacing your code by:
Window.open("data:application/pdf;base64,"+ new String(result),"_parent", "location=no");
你不能这样做,因为你发出了第二个错误:<$ c $中的字节c> result 表示二进制文件,浏览器中的JavaScript需要Base64编码文件。 Base64编码用于将二进制转换为文本,反之亦然。请参阅
You can't do that because you are making a second error: the bytes in result
represent a binary file, and the JavaScript in your browser expects a Base64 encoded file. Base64 encoding is used to convert binary to text, and vice-versa. See What is base 64 encoding used for?
如果要将二进制PDF文件作为Base64编码的字符串发送到浏览器,则必须对字节进行Base64编码。这可以通过以下类来完成:
If you want to send the binary PDF file to the browser as a Base64-encoded string, you have to Base64 encode your bytes. This can be done with this class: http://itextsupport.com/apidocs/itext5/latest/com/itextpdf/text/pdf/codec/Base64.html
例如:
Window.open("data:application/pdf;base64,"+ Base64.encodeBytes(result),"_parent", "location=no");
这应该适用于某些浏览器,但不适用于所有浏览器。我不知道你在哪里使用 Window.open()
,也不知道为什么要使用Base64。您可能想详细说明。在我看来,这是一个坏主意。
This should already work for some browsers, but not for all. I have no idea where you are using Window.open()
, nor why you want to involve Base64. You may want to elaborate on that. In my opinion, it's a bad idea.
应如何做:
通常,您将编写在应用程序服务器中运行的 Servlet
。可以使用URL从浏览器访问该servlet。 你不需要像在另一个答案中所建议的那样在服务器上保存生成的文件(我对这个答案进行了低估,因为它没有用,而且完全错误)。您创建 ByteArrayOutputStream
然后获取 byte []
的方法是正确的,但您必须将这些字节提供给a HttpServletResponse
对象。
Typically, you will write a Servlet
that runs in an application server. That servlet can be reached from a browser using a URL. You do not need to save the generated file on the server as suggested in the other answer (I down-voted that answer because it is not helpful and totally wrong). Your approach that creates a ByteArrayOutputStream
and then gets a byte[]
is correct, but you have to serve those bytes to a HttpServletResponse
object.
参见获取完整示例。
关于Window.open()
您可以在客户端使用 Window.open()
,在新窗口中打开网页。例如:
You can use Window.open()
on the client side, to open a web page in a new window. For instance:
window.open("http://www.itextpdf.com");
您可以投放包含此代码段的网页,但在您的情况下,您必须替换 http://www.itextpdf.com
,其中包含为您的servlet定义的URL。
You can serve a page that has contains this snippet, but in your case, you have to replace http://www.itextpdf.com
with the URL that was defined for your servlet.
您可能已找到你的解决方案在这里:
You may have found your "solution" here: Opening PDF String in new window with javascript
但如果您阅读了这些评论,您会发现这种方法与某些浏览器结合使用会产生问题。
But if you read the comments, you'll notice that this approach is problematic in combination with some browsers.
这篇关于如何将iText PDF文档返回给客户端的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!