我正在尝试使用JavaScript实现PDF文件下载功能。
作为对POST
请求的响应,我得到了一个PDF文件,在Chrome DevTools控制台中,它看起来像(oResult
数据容器,片段):
“%PDF-1.4↵%����↵40obj↵<>stream↵x��
现在我正在尝试初始化下载过程:
let blob = new Blob([oResult], {type: "application/pdf"});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = "tstPDF";
link.click();
结果是,单击按钮后,我得到 tstPDF.pdf ,它包含正确的页面数,但是PDF本身为空,没有内容显示,尽管它是6 KB。
当我测试生成PDF的Java服务器端模块时,一切正常,它通过InputStream
发送ServletOutputStream
。因此,我认为问题出在客户端的某个地方,也许是MIME
,BLOB
,encoding
或类似的东西。
您知道为什么生成的PDF不显示任何数据吗?
答案 0 :(得分:5)
我解决了这个问题。
问题出在某种程度上,数据是从服务器传递到客户端的。
确保服务器以Base64
编码发送数据非常重要,否则客户端无法将PDF字符串反序列化为二进制格式。在下面,您可以找到完整的解决方案。
服务器端:
OutputStream pdfStream = PDFGenerator.pdfGenerate(data);
String pdfFileName = "test_pdf";
// represent PDF as byteArray for further serialization
byte[] byteArray = ((java.io.ByteArrayOutputStream) pdfStream).toByteArray();
// serialize PDF to Base64
byte[] encodedBytes = java.util.Base64.getEncoder().encode(byteArray);
response.reset();
response.addHeader("Pragma", "public");
response.addHeader("Cache-Control", "max-age=0");
response.setHeader("Content-disposition", "attachment;filename=" + pdfFileName);
response.setContentType("application/pdf");
// avoid "byte shaving" by specifying precise length of transferred data
response.setContentLength(encodedBytes.length);
// send to output stream
ServletOutputStream servletOutputStream = response.getOutputStream();
servletOutputStream.write(encodedBytes);
servletOutputStream.flush();
servletOutputStream.close();
客户端
:let binaryString = window.atob(data);
let binaryLen = binaryString.length;
let bytes = new Uint8Array(binaryLen);
for (let i = 0; i < binaryLen; i++) {
let ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
let blob = new Blob([bytes], {type: "application/pdf"});
let link = document.createElement('a');
link.href = window.URL.createObjectURL(blob);
link.download = pdfFileName;
link.click();
参考主题:
答案 1 :(得分:0)
谢谢。确实有效。
顺便说一句,这是我如何使用spring控制器和ajax以及jasper生成的pdf来实现
控制器:
public ResponseEntity<?> printPreview(@ModelAttribute("claim") Claim claim)
{
try
{
//Code to get the byte[] from jasper report.
ReportSource source = new ReportSource(claim);
byte[] report = reportingService.exportToByteArrayOutputStream(source);
//Conversion of bytes to Base64
byte[] encodedBytes = java.util.Base64.getEncoder().encode(report);
//Setting Headers
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.parseMediaType("application/pdf"));
headers.setContentDispositionFormData("pdfFileName.pdf", "pdfFileName.pdf");
headers.setCacheControl("must-revalidate, post-check=0, pre-check=0");
headers.setContentLength(encodedBytes.length);
return new ResponseEntity<>(encodedBytes, headers, HttpStatus.OK);
}
catch (Exception e)
{
LOG.error("Error on generating report", e);
return new ResponseEntity<>(null, HttpStatus.INTERNAL_SERVER_ERROR);
}
}
ajax:
$.ajax({
type: "POST",
url: "",
data: form.serialize(), //Data from my form
success: function(response)
{
let binaryString = window.atob(response);
let binaryLen = binaryString.length;
let bytes = new Uint8Array(binaryLen);
for (let i = 0; i < binaryLen; i++) {
let ascii = binaryString.charCodeAt(i);
bytes[i] = ascii;
}
let blob = new Blob([bytes], {type: "application/pdf"});
let link = URL.createObjectURL(blob);
window.open(link, '_blank');
},
error: function()
{
}
});
这将在新窗口中加载pdf。