I am trying to save a PDF using Angular and Spring Boot.
When I make an API call, my Java code is fetching the data from the database and transforming it to a byte-stream. This stream is sent as response.
if(format.equals(Constant.PDF_FORMAT)) {
ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos);
HttpHeaders headers = new HttpHeaders();
headers.add("Content-Disposition", "inline; filename=report.pdf");
return ResponseEntity.ok()
.headers(headers)
.contentType(MediaType.APPLICATION_PDF)
.body(new InputStreamResource(stream));
}
I have to use this response and save the data into a PDF.
Component.ts
public getReports(type?: string): void {
this.params['expected-format'] = type;
if (type === 'json') {
this.Service.getPilotReports(this.params).subscribe((res) => {
this.reportsData = res;
this.pilotBankSpinnerService.closeSpinner();
});
} else {
this.Service.customGetForDownload(this.params).subscribe(
(data: Blob) => {
var file = new Blob([data], { type: 'application/pdf' });
var fileURL = URL.createObjectURL(file);
window.open(fileURL);
var a = document.createElement('a');
a.href = fileURL;
a.target = '_blank';
a.download = 'reports.pdf';
document.body.appendChild(a);
a.click();
},
(error) => {
console.log('getPDF error: ', error);
}
);
}
}
Service.ts
public customGetForDownload<blob, T>(url: string, params: any): any {
const headers = new HttpHeaders({ 'Content-Type': 'application/json', responseType: 'blob' });
const httpParams = this.http.constructParams(params);
const absoluteUrl = this.getAbsoluteUrl(url);
return this.httpClient.get(absoluteUrl, {
headers: headers,
params: httpParams,
responseType: 'blob' as 'json',
observe: 'response',
});
}
Though the file is getting saved. When I try to open the file, it says "Failed to load pdf document".
CodePudding user response:
Syntax Issues
First I see a syntax error:
- missing argument in method-call:
ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos, );
(after the comma)
With this syntax error you most likely receive a compilation-error on console.
Assume this is a lapse and you can fix it to something like ByteArrayInputStream stream = reportPDF.generateReportDocument(dtos);
then it should compile.
Boots without errors? Then test the endpoint!
Assume further your server application boots and runs without errors, then you could test the HTTP-endpoint with a HTTP-call.
You can test using a HTTP-client like CURL, postman or maybe even a browser.
Then you should receive a response with HTTP status code 200 and the body containing the PDF-file as binary with MIME-type application/pdf
and specified header Content-Dispositon
.
The browser is expected to prompt you with a download-dialogue.
Responding with a binary in Spring
Your InputStreamResource
is a valid way, but you should be confident when using it.
In a Spring controller method, you can return the binary data in different types:
ResponseEntity<byte[]>
as byte-arrayResponseEntity<ByteArrayOutputStream>
as stream (not input-stream for reading input)ResponseEntity<Resource>
as abstract binary content, see Spring'sResource
ResponseEntity<File>
as entire file
See also
- Spring boot Angular2 file download not working
- PDF Blob is not showing content, Angular 2
- Return generated pdf using spring MVC
There are also some response-directed ways especially in Spring:
- return a
InputStreamResource
as you did - return a
StreamingResponseBody
is very convenient - write to a
HttpServletResponse
, probably the oldest way
See: How To Download A File Directly From URL In Spring Boot
From input to output
Remember: Input is for reading (e.g. from a request), output is for writing (e.g. to a response). So you need an output type, like byte[]
or ByteArrayOutputStream
etc for your response-body.
When reading input into ByteArrayInputStream stream
you could copy from that input to an output-stream with e.g. Apache-Commons IOUtils: IOUtils.copy(in, out);
.
Or simply return the byte-array: byte[] data = stream.readAllBytes();
See: Java InputStream to Byte Array and ByteBuffer | Baeldung