angular2 file download in java - java

How could download a file using Angular2 and Java?
There is a GET HTTP call which returns the file data:
If receive a byte[] array, the file (in this case ODT, but could be
other format) opens as a document with the literal byte content
written in it: "UEsDBBQAAAgAAPBZjklexjIMJwAAACcAAAA"
If receive a blob object , it shows
"{"binaryStream":{},"wrappedBlob":{"binaryStream":{}}}" in the
document
Angular2 code:
goFile() {
//This service calls #angular/http for a GET request and returs the response
//ends up doing:
// this.http.get(url, {responseType: ResponseContentType.Blob})
// .map(res => res.blob())
this.myService.subscribe(result=> { this.saveFile(result); });
return false;
}
downloadFile(file: any) {
var blob = new Blob([file], {type: 'application/vnd.oasis.opendocument.text'});
var url= window.URL.createObjectURL(blob);
window.open(url);
}
Java code just reads the file and returns a blob or byte array (in each case tried):
byte[] file = FileUtils.getFile("E:/file.odt");
return file;
byte[] file = FileUtils.getFile("E:/file.odt");
Blob blob = Hibernate.createBlob(fichero);
return blob;
UPDATE
I believe the problem comes that data is being received as a json object, something setup in the system i am working.
Have tried intead to return byte[] from java and try to convert to a blob in Angular2 (for a txt file):
//file is returned by a call to http.get which has a map:
// .map(res => res.text())
var blob = new Blob([file], {type: 'text/plain'});
var objectUrl = URL.createObjectURL(blob);
window.open(objectUrl);
but returns a page with the byte content ("YWJj"), obviously the content received is not converted to a proper blob object.
Also tried with same result:
var byteArray = new Uint8Array(file);
var blob = new Blob([byteArray], {type: 'text/plain'});
there is not solution for different mime types without using additional plugins?

Related

Save a PDF generated by SpringBoot in Angular

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".
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-array
ResponseEntity<ByteArrayOutputStream> as stream (not input-stream for reading input)
ResponseEntity<Resource> as abstract binary content, see Spring's Resource
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

How to dowload a file (blob) which is Int8Array in Angular

I am trying to download a file in Angular. The file is saved in db as varbinary. Java REST service fetched it as byte[]. I am having it as Int8Array in Angular. However when I download it I beleive it is base64 encoded
const link = document.createElement( 'a' );
link.style.display = 'none';
document.body.appendChild( link );
const blob = new Blob([myFileByteArray], {type: 'text/xlsx'}); //myFile is Int8Array
const objectURL = URL.createObjectURL(blob);
link.href = objectURL;
link.href = URL.createObjectURL(blob);
link.download = this.myfile.name;
link.click();
This is how it is in MSSQL: 0x323032312D30392D323720303 ...
And this is how it is when I download this xlsx and open it: MjAyMS0wOS0yNyAwNzozMDsxMi4wODI7bT
I beleive it is base64 encoded somewhere in that path from sql to browser...I saved it in a SQL like this 'CAST('this is my xslx' AS VARBINARY (MAX)) so I know it should be this text.
The solution was to change a type in Angular from Int8Array to string and then I could use atob() method to decode from base64. I just don't know why is it in base64. Could it be because I use Spring Boot ResponseEntity ...
this.myFile= this.myFileResultSet.result;
let myFileByteArray = this.myFile.myFileBytes //before Int8Array, now String
console.log(myFileByteArray);
let myFileDecoded = atob(myFileByteArray); // must be string not Int8Array to be able to
// convert it from base64
const link = document.createElement( 'a' );
link.style.display = 'none';
document.body.appendChild( link );
const blob = new Blob([myFileDecoded], {type: 'text/csv'});
const objectURL = URL.createObjectURL(blob);
link.href = objectURL;
link.href = URL.createObjectURL(blob);
link.download = this.myFile.name;
link.click();
});

Sending xls via API with Java apache poi and React

I'm trying to send a xls file from my java spring server to react client.
Using default Apache POI constructors creates xlsx file, that's not good. In order to override it I have to create the file using FileOutputStream.
FileOutputStream outputStream = new FileOutputStream("file.xls");
But I cannot sent the file over the web. I've tried using the following answer: https://stackoverflow.com/a/54765335/10319765 I quote: "While downloading a file , your code needs to stream a file chunk by chunk - thats what Java streams are for."
return ResponseEntity.ok().contentLength(inputStreamWrapper.getByteCount())
.contentType(MediaType.parseMediaType("application/vnd.ms-excel"))
.cacheControl(CacheControl.noCache())
.header("Content-Disposition", "attachment; filename=" + "file.xls")
.body(new InputStreamResource(inputStreamWrapper.getByteArrayInputStream()));
so my controller is sending InputStreamResource.
How can I construct InputStreamResource using my FileOutputStream?
P.S this is my React client:
axios.get('/issues/export', { responseType: 'arraybuffer' }).then(response => {
if (response && !response.error) {
const blob = new Blob([response.payload.data], {type: 'application/vnd.ms-excel'});
saveAs(blob);
}
});
Source: https://stackoverflow.com/a/46331201/10319765
Edit:
I've managed to do that with a trick, right after I've written to the FileOutputStream I've opened a FileInputStream and returned the value.
FileOutputStream outputStream = new FileOutputStream("file.xls");
workbook.write(outputStream);
workbook.close();
final InputStream fileInputStream = new FileInputStream("file.xls");
return fileInputStream;
but now, the xls file returned as response to the client is corrupted and has weird characters inside:
The excel file should look the following (taken from my java server after sending it):
Issue solved. Eventually what I did in order to solve the corrupted xls file is to work with byte arrays. the controller looks exactly the same but now the return type is ResponseEntity<byte[]>. To convert the InputStream to byte array I've used IOUtils.toByteArray() method.
Client side code has also changed a bit because now the type is no longer responseType: 'arraybuffer' but 'blob'.
axios.get('/issues/export', { responseType: 'blob' }).then(response => {
if (response && !response.error) {
const blob = new Blob([response.payload.data]);
saveAs(blob);
}
});
That's all.

How to allow the user to download a byte[] or base64 to their chosen directory

I want to allow the user to download a pdf file created in iText.
The expected result is that the user can download the pdf to their selected directory. The actual result is the file will not download.
I am generating a pdf using iText and passing the result back to my ajax call to allow the user to download the file. I have the base64. I checked that it was valid by using https://base64.guru/converter/decode/pdf This showed the pdf correctly. However, I can not get the result to download in the ajax ".done".
I have tried using:
byte[] decoder = Base64.getDecoder().decode(b64);
Before passing it back; however, I get an error message on ".getDecoder()" of "The method getDecoder() is undefined for the type Base64".
The java code is:
resourceImage = MySQLConnection.recipePDF(accountID, crID, servings, servingSize);
String imageDataString = Base64Encode2.encode(resourceImage);
System.out.println("imageDataString: " + imageDataString);
if (resourceImage == null) {
response.sendError(HttpServletResponse.SC_BAD_REQUEST, "No recipe pdf.");
} else {
String json = new Gson().toJson(imageDataString);
response.setContentType("application/json");
response.setCharacterEncoding("UTF-8");
response.getWriter().write(json);
}
The javascript/ajax code on the is:
.done(function(responseJson1a){
dataType: "json";
alert(JSON.stringify(responseJson1a));
download(responseJson1a, "resourcefile.pdf", "application/pdf");
});
A very simple answer. I needed to add "data:application/pdf;base64," to the start of the string.
download("data:application/pdf;base64,"+responseJson1a, "resourcefile.pdf", "application/pdf");

How to convert ByteBuffer to pdf

In my application a pdf report only opens in print preview which allows user to directly print the pdf document. Now i want to automate this to verify the pdf content.
I have got the pdf content through an api which is in base64 [did split to get only data], i tried converting to byte array after decoding but it only prints junk characters.[byte array to string]
Now i have converted this data into ByteBuffer and want this to write in pdf.
ByteBuffer decodedBytes = new BASE64Decoder().decodeBufferToByteBuffer(
new String(base64split2[1].substring(0, base64split2[1].length() - 1))
);
Can someone tell me how do i convert this decodedBytes of ByteBuffer to pdf.
Thanks
byte[] decodedBytes = new BASE64Decoder().decodeBuffer(str);
InputStream targetStream = new ByteArrayInputStream(decodedBytes);
PDDocument document = PDDocument.load(targetStream);
document.save("C:/test.pdf");
FileUtils.writeByteArrayToFile(new File("C:/test.pdf"), decodedBytes);
Using above code to convert to pdf.
Getting blob data of pdf from API :
Future<dynamic> getBlobdata(int pdfId) async {
try {
var response = await Dio().get(
"https://www.google.com/pdf/$pdfId",
options: Options(
responseType: ResponseType.bytes,
contentType: 'application/octet-stream',
),
);
var data = {"data": response.data.buffer};
return data;
} on DioError catch (error) {
var data = error.response.data;
return data;
}
}
Define file name and directory to save file :
String fileName = "pdf$pdfId";
final dir = await getExternalStorageDirectory();
var pdfBlob = await getBlobdata(1); // have to be in a asyn func to use await
Save Pdf :
final file = File("${dir.path}/$fileName.pdf");
await file.writeAsBytes(pdfBlob.asUint8List());
View Pdf in app :
await OpenFile.open("${dir.path}/$fileName.pdf");

Categories