'Angular + Spring Boot + JasperSoft: Failed to load PDF document
I am currently working on a project with Angular, Spring Boot and Jaspersoft and i am having problems trying to preview the pdf document retrieved as an array of bytes from REST API. When the link is opened in a new tab, i am getting: Failed to load PDF document. The problem shouldn't be with the jrxml file, because i tried with other sample jrxml files and i am getting the same result. Failed to load pdf document screenshot
Here is the code:
@RequestMapping(value = "/daily-orders/{restaurantId}/export", method = RequestMethod.POST)
public ResponseEntity<?> exportDailyOrders(@PathVariable Long restaurantId) {
byte[] dailyOrdersBytes = exportService.exportDailyOrders(restaurantId);
HttpHeaders header = new HttpHeaders();
header.setContentDispositionFormData("inline", "dailyOrdersReport.pdf");
header.setContentType(MediaType.valueOf("application/pdf"));
header.setContentLength(dailyOrdersBytes.length);
return new ResponseEntity<Object>(dailyOrdersBytes, header, HttpStatus.OK);
}
And the code for generating the pdf report.
@Override
public byte[] exportDailyOrders(Long restaurantId) {
SimpleOutputStreamExporterOutput exporterOutput = null;
byte[] bytes = new byte[0];
try (ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
List<RestaurantDailyOrdersRowMapper> restaurantDailyOrders = orderDAO.getRestaurantDailyOrders(restaurantId);
File file = ResourceUtils.getFile("classpath:reports/daily-orders.jrxml");
JasperReport jasperReport = JasperCompileManager.compileReport(file.getAbsolutePath());
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(restaurantDailyOrders);
Map<String, Object> parameters = new HashMap<>();
parameters.put("createdBy", "author");
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
JRXlsxExporter exporter = new JRXlsxExporter();
exporter.setExporterInput(new SimpleExporterInput(jasperPrint));
exporterOutput = new SimpleOutputStreamExporterOutput(byteArrayOutputStream);
exporter.setExporterOutput(exporterOutput);
exporter.exportReport();
return byteArrayOutputStream.toByteArray();
} catch (JRException | IOException e) {
log.error("Unable to generate Report of type pdf.", e);
return bytes;
} finally {
if (exporterOutput != null) {
exporterOutput.close();
}
}
}
Here is the code from Angular:
exportDailyOrdersToPdf() {
this.exportService.generateDocumentReport(1).subscribe(response => {
let file = new Blob([response.data], { type: 'application/pdf' });
let fileURL = window.top.URL.createObjectURL(file);
window.top.open(fileURL, '_blank');
}, error => {
})
}
And the method in the service:
generateDocumentReport(restaurantId: number): Observable<any> {
return this.httpClient.post('https://localhost:8080/main/daily-orders/' + restaurantId + '/export', '',
{ responseType: 'arraybuffer'});
}
Solution 1:[1]
Okay, i managed to make it work. I used some of @hrdkisback code, with addition to changes to the method for generating the report. Here's the full code, if anyone encounters similar issue.
Controller:
@RequestMapping(value = "/daily-orders/{restaurantId}/export", method = RequestMethod.POST)
public void exportDailyOrders(@PathVariable Long restaurantId, HttpServletResponse httpServletResponse) throws IOException, JRException {
byte[] dailyOrdersBytes = exportService.exportDailyOrders(restaurantId);
ByteArrayOutputStream out = new ByteArrayOutputStream(dailyOrdersBytes.length);
out.write(dailyOrdersBytes, 0, dailyOrdersBytes.length);
httpServletResponse.setContentType("application/pdf");
httpServletResponse.addHeader("Content-Disposition", "inline; filename=dailyOrdersReport.pdf");
OutputStream os;
try {
os = httpServletResponse.getOutputStream();
out.writeTo(os);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
}
Service:
@Override
public byte[] exportDailyOrders(Long restaurantId) throws IOException, JRException {
List<RestaurantDailyOrdersRowMapper> restaurantDailyOrders = orderDAO.getRestaurantDailyOrders(restaurantId);
File file = ResourceUtils.getFile("classpath:reports/daily-orders.jrxml");
JasperReport jasperReport = JasperCompileManager.compileReport(file.getAbsolutePath());
JRBeanCollectionDataSource dataSource = new JRBeanCollectionDataSource(restaurantDailyOrders);
Map<String, Object> parameters = new HashMap<>();
parameters.put("createdBy", "Nikola");
JasperPrint jasperPrint = JasperFillManager.fillReport(jasperReport, parameters, dataSource);
ByteArrayOutputStream byteArrayOutputStream = getByteArrayOutputStream(jasperPrint);
return byteArrayOutputStream.toByteArray();
}
protected ByteArrayOutputStream getByteArrayOutputStream(JasperPrint jasperPrint) throws JRException {
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
JasperExportManager.exportReportToPdfStream(jasperPrint, byteArrayOutputStream);
return byteArrayOutputStream;
}
component.ts
exportDailyOrdersToPdf() {
this.exportService.generateDocumentReport(1).subscribe(response => {
console.log(response);
let url = window.URL.createObjectURL(response.data);
let a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display: none');
a.setAttribute('target', 'blank');
a.href = url;
a.download = response.filename;
a.click();
window.URL.revokeObjectURL(url);
a.remove();
}, error => {
console.log(error);
});}
service.ts
generateDocumentReport(restaurantId: number): Observable<any> {
let headers = new HttpHeaders();
headers.append('Accept', 'application/pdf');
let requestOptions: any = { headers: headers, responseType: 'blob' };
return this.httpClient.post('https://localhost:8080/main/daily-orders/' + restaurantId + '/export', '', requestOptions)
.pipe(map((response)=>{
return {
filename: 'dailyOrdersReport.pdf',
data: new Blob([response], {type: 'application/pdf'})
};
}));}
Solution 2:[2]
Try this one
Spring Controller
@RequestMapping(value = "/daily-orders/{restaurantId}/export", method = RequestMethod.POST)
public void exportDailyOrders(@PathVariable Long restaurantId, HttpServletResponse httpServletResponse) {
byte[] dailyOrdersBytes = exportService.exportDailyOrders(restaurantId);
ByteArrayOutputStream out = new ByteArrayOutputStream(dailyOrdersBytes.length);
out.write(dailyOrdersBytes, 0, dailyOrdersBytes.length);
httpServletResponse.setContentType("application/pdf");
httpServletResponse.addHeader("Content-Disposition", "inline; filename=dailyOrdersReport.pdf");
OutputStream os;
try {
os = httpServletResponse.getOutputStream();
byteArrayOutputStream.writeTo(os);
os.flush();
os.close();
} catch (IOException e) {
e.printStackTrace();
}
/*HttpHeaders header = new HttpHeaders();
header.setContentDispositionFormData("inline", "dailyOrdersReport.pdf");
header.setContentType(MediaType.valueOf("application/pdf"));
header.setContentLength(dailyOrdersBytes.length);
return new ResponseEntity<Object>(dailyOrdersBytes, header, HttpStatus.OK);*/
}
Angular Service
import { map } from "rxjs/operators";
generateDocumentReport(restaurantId: number): Observable<any> {
let headers = new HttpHeaders();
headers.append('Accept', 'application/pdf');
let requestOptions: any = { headers: headers, responseType: ResponseContentType.Blob };
return this.httpClient.post('https://localhost:8080/main/daily-orders/' + restaurantId + '/export', '',requestOptions).pipe(map((response)=>{
return {
filename: 'dailyOrdersReport.pdf',
data: response.blob()
};
}));
}
Angular Component
exportDailyOrdersToPdf() {
this.exportService.generateDocumentReport(1).subscribe(response => {
console.log(response);
var url = window.URL.createObjectURL(response.data);
var a = document.createElement('a');
document.body.appendChild(a);
a.setAttribute('style', 'display: none');
a.setAttribute('target', 'blank');
a.href = url;
a.download = response.filename;
a.click();
window.URL.revokeObjectURL(url);
a.remove();
}, error => {
console.log(error);
});
}
Solution 3:[3]
I have added onto the code form the answers above
exportDailyOrdersToPdf() {
this.exportService.generateDocumentReport(1).subscribe(response => {
console.log(response);
this.url = window.URL.createObjectURL(response.data);
}, error => {
console.log(error);
});
}
And then
<ngx-doc-viewer [url]="url" viewer="pdf" style="width:100%;height:100%;">
</ngx-doc-viewer>
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Nikola |
| Solution 2 | hrdkisback |
| Solution 3 | Tendai kastande |
