Execute after sending http response Java - java

I want to know if this can be done.
I got a RESTful service sending a javax.ws.rs.core.Response response like this
File filer = new File("C:\tempfile.txt");
return Response.ok(filer, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition", "attachment; filename=\"" + newName + "\"").build();
I want to delete file after http response has been sent to the client (making filer a temporary file on server).
I thank your help in advance.

You probably shouldn't be using a temporary file to begin with. If you want to send generated binary data and don't want to keep it all in memory, pass a StreamingOutput as the entity when calling ok().

make it in finally block
try {
File filer = new File("C:\tempfile.txt");
return Response.ok(filer, MediaType.APPLICATION_OCTET_STREAM).header("content-disposition", "attachment; filename=\"" + newName + "\"").build();
} finally {
// delete file
}

Related

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 write webservice response to a json file?

I am getting the response from webservice request which I am able to print on the console. I want to write this response to a json file. I tried with buffereWriter but it did not write.
String cwd = System.getProperty("user.dir");
buffereWriter writer = new buffereWriter (new File writer(cwd + "filepath"));
Writer.write(response);
// This response is being currently displayed in the console correctly.
There are no error or exception but the content is not getting written in the file.
You can use FileWriter for that. Also a try block with resources which will guarantee your file will be closed.
try(FileWriter fw = new FileWriter(cwd + "filepath")){
fw.write(response); //I guess the response is a String.
}catch(Exception ignored){}

download a file from rest api is giving me some garbage value

I am trying to download a file from rest API, I am writing code in Java and react. but when i call that rest api it is not downloading that file instead gives me some garbage
#POST
#Path("/{loginId}")
#Produces(MULTIPART_FORM_DATA)
#Consumes(APPLICATION_JSON)
public Response downloadExportedFile(#PathParam("loginId") String loginId, ExportFileDTO fileDetails) {
File exportFolder = new File("C://directory");
File[] listOfFiles = exportFolder.listFiles();
for (File listOfFile : listOfFiles) {
if (listOfFile.getName().equals(fileDetails.getFileName())) {
InputStream is = new FileInputStream(listOfFile.getAbsolutePath());
byte[] buffer = IOUtils.toByteArray(is);
return Response.ok(listOfFile)
.header("content-disposition", "attachment; filename=" + new File(listOfFile.getName()).getName())
.type(MediaType.APPLICATION_OCTET_STREAM_TYPE).build();
}
}
It should download the file instead it is giving me output as
PK!b�h^�[Content_Types].xml �(����N�0E�H�C�-Jܲ#5��Q>�ēƪc[�ii����B�j7���{2��h�nm���ƻR����U^7/���%��rZY�#1__�f��q��R4D�AJ�h>����V�ƹ�Z�9����NV�8ʩ����ji){^��-I�"{�v^�P!XS)bR�r��K�s(�3�`c�0��������7M4�����ZƐk+�|\|z�(���P��6h_-[�#�!���Pk���2n�}�?�L��� ��%���d����dN"m,�ǞDO97�~��ɸ8�O�c|n���E������B��!$}�����;{���[����2���PK!�U0#�L_rels/.rels �(���MO�0��H�����ݐBKwAH�!T~�I����$ݿ'T�G�~����<���!��4��;#�w����qu*&r�Fq���v�����GJy(v��*����K��#F��D��.W ��=��Z�MY�b���BS�����7��ϛז��
?�9L�ҙ�sbgٮ|�l!��USh9i�b�r:"y_dl��D���|-N��R"4�2�G�%��Z�4�˝y�7 ë��ɂ�����PK!
You have to change the associated mimetype by changing the the parameter of the #Produces annotation which basically describes what type of data you transmit in your response.
It should become:
#Produces("application/vnd.ms-excel")
According to this other stackoverflow question you should change the #Produces annotation to #Produces(MediaType.APPLICATION_OCTET_STREAM).
According to this second stackoverflow question you are asking an impossible question.
Out of curiosity I reproduced your problem here : see the full gist
If you change #POST to #GET it starts working
If you keep #POST, it has to be posted from a real form and can't post application/json
Finally, posting application/json means React is doing a programmatic XmlHTTPRequest. The above gist shall convince you there is no user prompt in that case
When you say it 'is giving me output', you're not telling where and how the post was requested . You will have to adapt that part.
actually It is APPLICATION_OCTET_STREAM response for a file. we have to handle download functionality at client side AS per Nate's answer here, the response of Ajax request is not recognized by a browser as a file. It will behave in the same way for all Ajax responses. You need to trigger the download popup manually.
downloadFile(fileDetails) {
let username = getUserName();
return fetch(`/files/${username}`, {
method: 'POST',
body: JSON.stringify(fileDetails)
}).then(response => {
return response.blob();
}).then(response => {
let blob = new Blob([response], {type: 'application/octet-stream'});
let fileUrl = window.URL.createObjectURL(blob);
Files.triggerDownload(fileUrl, fileDetails.fileName);
}).catch((error) => {
//myerror
});
}
static triggerDownload(url, fileName) {
let a = document.createElement('a');
a.setAttribute('href', url);
a.setAttribute('download', fileName);
a.click();
}
This will download the file at client machine

Downloaded file from server is different than original one saved previously

I cannot find out why the mp3 file is different after download from my server than original one saved previously there.
This is my controller method. The content of file (byte[] content) is identical with original file on this stage - the original file is the same as file retrieved from database (checked in debugger).
#ResponseBody
#RequestMapping(method = RequestMethod.GET, value = "/{sampleId}/file")
public HttpEntity<byte[]> getFile(#PathVariable Long sampleId) {
ResourceEntity resourceEntity = testSampleRepository.getFile(sampleId);
byte[] content = resourceEntity.getContent();
String fileName = resourceEntity.getFileName();
HttpHeaders header = new HttpHeaders();
header.setContentType(new MediaType("audio", "mpeg"));
header.set(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename=" + fileName.replace(" ", "_"));
header.setContentLength(content.length);
return new HttpEntity<byte[]>(content, header);
}
This is how files differ (the left is original one):
Why passing using HTTP distors my file? Should mediaTypes enforce certain encoding? (there was no difference with "audio/mpeg" mediaType and without it).
It should work, if you set the produces = "application/octet-stream" attribute (MediaType.APPLICATION_OCTET_STREAM). Otherwise, you are trapped by Spring's converter framework.
You may want to have a look here, seems your problem is very similar: Spring MVC: How to return image in #ResponseBody? .

Sending in-memory generated .docx files from server to client with Spark

I am creating a web application using the Spark Java framework. The front-end is developed using AngularJS.
I want to generate a .docx file on the server (in-memory) and send this to the client for download.
To achieve this I created an angular service with the following function being called after the user clicks on a download button:
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey).success(function (response) {
var element = angular.element('<a/>');
element.attr({
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response,
target: '_blank',
download: 'test.docx'
})[0].click();
});
};
On the server, this api call gets forwarded to the following method:
public Response exportToWord(Response response) {
try {
File file = new File("src/main/resources/template.docx");
FileInputStream inputStream = new FileInputStream(file);
byte byteStream[] = new byte[(int)file.length()];
inputStream.read(byteStream);
response.raw().setContentType("data:attachment;chatset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document");
response.raw().setContentLength((int) file.length());
response.raw().getOutputStream().write(byteStream);
response.raw().getOutputStream().flush();
response.raw().getOutputStream().close();
return response;
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
I have tried to solve this in MANY different ways and I always end up with a corrupted 'test.docx' that looks like this:
Solved it by using blobs and specifying the response type as 'arraybuffer' in the $http.post api call. The only bad thing with this solution (as far as I know) is that it doesn't play well with IE, but that's a problem for another day.
functions.generateWord = function () {
$http.post('/api/v1/surveys/genword', data.currentSurvey, {responseType: 'arraybuffer'})
.success(function (response) {
var blob = new Blob([response], {type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'});
var url = (window.URL || window.webkitURL).createObjectURL(blob);
var element = angular.element('<a/>');
element.attr({
href: url,
target: '_blank',
download: 'survey.docx'
})[0].click();
});
};
I think what went wrong was that the byte stream got encoded as plain text when I tried to create a URL with:
href: 'data:attachment;charset=utf-8;application/vnd.openxmlformats-officedocument.wordprocessingml.document' + response
thus corrupting it.
When using blobs instead, I get a "direct" link to the generated byte stream and no encoding is done on it since the response type is set to 'arraybuffer'.
Note that this is just my own reasoning of why things went wrong with the original code. I might be terribly wrong, so feel free to correct me if that's the case.

Categories