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自体は空であり、コンテンツはありません。 6KBですが表示されます。
PDFを生成するJavaサーバーサイドモジュールをテストすると、すべてが正常に機能し、InputStream
からServletOutputStream
を送信します。したがって、問題はクライアント側のどこかにあり、おそらくMIME
、BLOB
、encoding
などの問題です。
生成されたPDFにデータが表示されない理由がわかりますか?
私は問題を解決しました。問題は、データがサーバーからクライアントに配信される方法にありました。サーバーがデータを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();
参照トピック:
これに感謝します。それは実際に動作します。
ところで、これが私がスプリングコントローラーとjasperによって生成されたpdfでajaxを使用してそれを行う方法です
コントローラー:
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が新しいウィンドウに読み込まれます。