I'm trying to implement a Service that automatically starts a download with the requested file.
This is my AJAX call:
function downloadFile(fileName) {
$.ajax({
url : SERVICE_URI + "files/" + fileName,
contentType : 'application/json',
type : 'GET',
success : function (data)
{
alert("done!");
},
error: function (error) {
console.log(error);
}
});
}
and this is my Spring Service method GET:
#RequestMapping(value = "/files/{file_name}", method = RequestMethod.GET)
public void getFile(#PathVariable("file_name") String fileName,
HttpServletResponse response) {
try {
// get your file as InputStream
FileInputStream fis = new FileInputStream( fileName + ".csv" );
InputStream is = fis;
// copy it to response's OutputStream
ByteStreams.copy(is, response.getOutputStream());
response.setContentType("text/csv");
response.flushBuffer();
} catch (IOException ex) {
throw new RuntimeException("IOError writing file to output stream");
}
}
When my client requests the existing file from the server, the AJAX success() method is executed but the file is not even downloading. Am I doing anything wrong?
Don't use ajax, just set window.location.href to the url of the file and set the http content disposition header in your server script to force the browser to save the file.
function downloadFile(fileName) {
window.location.href = SERVICE_URI + "files/" + fileName;
}
Related
I'm trying to make a download of a ODS file (Open Office's Calc file).
I'm using Java for back end and AngularJS for front end.
This is my code of the front end where I receive and download the file:
vm.downloadModel = () => {
DataFactory.GET(`${URL.CTM_ODS()}/rotas/modelo`, { headers: { 'Content-Type': 'application/octet-stream' } }).then(response => {
let file = new Blob([response], { type: 'application/vnd.oasis.opendocument.spreadsheet' });
let url = window.URL || window.webkitURL;
let downloadLink = angular.element('<a></a>');
downloadLink.attr('href', url.createObjectURL(file));
downloadLink.attr('target', '_self');
downloadLink.attr('download', 'Model_Routes_OD.ods');
downloadLink[0].click();
});
}
This is my endpoint on my back end:
#GetMapping(value = "/modelo")
#ResponseBody
public ResponseEntity<ByteArrayResource> getModelo() throws IOException {
String path = "C:\\Model_Routes_OD.ods";
File file = new File(path);
Path pathObj = Paths.get(file.getAbsolutePath());
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(pathObj));
HttpHeaders headers = new HttpHeaders();
headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + file.getName());
headers.add(HttpHeaders.CONTENT_TYPE, MediaType.APPLICATION_OCTET_STREAM_VALUE);
headers.add(HttpHeaders.CONTENT_LENGTH, String.valueOf(Files.readAllBytes(pathObj).length));
headers.add(HttpHeaders.TRANSFER_ENCODING, "binary");
return new ResponseEntity<>(resource, headers, HttpStatus.OK);
}
The file that is downloaded came corrupted! My file has 13Kb and when it downloads shows 21Kb, when I try to open he says that the file is "broken" and he can try to fix it but, without success.
I tried your code and api is working fine.
You don't need to explicitly handle file at frontend, instead you can just download it.
Example code for above scenario:
var app = angular.module('demo', []);
app.controller('Download', function($scope, $http) {
$scope.download = function(){
var url = "http://localhost:8080/modelo"
window.open(url, "_self");
}
});
I am able to download file perfectly and here is complete code for this example
I have a website with an ongoing webcam stream which should send snapshots of the video stream to my own Java webserver. The snapshot generating and displaying functionality works perfectly on the website. I want to send the snapshot with a jQuery AJAX POST request to my webserver which looks like that:
$.ajax({
type: 'POST',
url: servicePath + "upload",
contentType: 'multipart/form-data',
xhrFields: {withCredentials: false},
headers: {},
data: hidden_canvas.toDataURL('image/png'),
success: function(data, status, xhttp) {
alert(data);
},
error: function() {
alert("Error uploading snapshot file to server!");
}
});
As I mentioned, displaying the hidden_canvas.toDataURL('image/png') inserted in a src attribute of an <img> works perfectly, so it is definitely valid.
My service on the webserver looks as follows:
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadPicture(byte[] imageBytes) {
String uploadedFileLocation = UPLOAD_FOLDER + "test.png";
try {
OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
out.write(imageBytes);
out.flush();
out.close();
} catch (IOException e) {
return Response.status(500).entity("Can not save file<br>" + e.toString()).build();
}
return Response.status(200).entity("success").build();
}
Test.png is created successfully but not a valid png, when I open it, it does not display at all. And the file on the server looks as follows:
What did I miss? Would there be an alternative way to process the image?
Here's my takeSnapshot method. How could I send the file without the toDataURL()? And what for param would I have to expect then on the server side?
function generateSnapshot() {
var video = document.querySelector('#camera-stream');
var hidden_canvas = document.querySelector('#canvas');
var context = hidden_canvas.getContext('2d');
var width = video.videoWidth;
var height = video.videoHeight;
if (width && height) {
hidden_canvas.width = width;
hidden_canvas.height = height;
// Make a copy of the current frame in the video on the canvas.
context.drawImage(video, 0, 0, width, height);
// Turn the canvas image into a dataURL that can be used as a src for our photo.
return hidden_canvas.toDataURL('image/png');
}
}
I finally could make it work. The toBlob suggestion from Kayaman put me on the right track. But I was not able to send the blob as expected, I had to put it into a FormData and thus had to adjust my webservice. The solution looks as follows:
Website Javascript code:
hidden_canvas.toBlob(function(blob) {
var fd = new FormData();
fd.append('fileName', 'testBlob.png');
fd.append('data', blob);
sendAJAXFileUploadRequest(fd);
},'image/png');
function sendAJAXFileUploadRequest(formData) {
$.ajax({
type: 'POST',
url: servicePath + "upload",
xhrFields: {withCredentials: false},
headers: {},
data: formData,
processData: false,
contentType: false,
success: function(data, status, xhttp) {
alert(data);
},
error: function() {
alert("Error uploading snapshot file to server!");
}
});
}
And the Java Webservice:
#POST
#Path("/upload")
#Consumes(MediaType.MULTIPART_FORM_DATA)
public Response uploadPicture(#FormDataParam("data") byte[] imageBytes, #FormDataParam("fileName") String fileName) {
String uploadedFileLocation = UPLOAD_FOLDER + fileName;
try {
OutputStream out = new FileOutputStream(new File(uploadedFileLocation));
out.write(imageBytes);
out.flush();
out.close();
} catch (IOException e) {
logger.severe("Can not save file (file location: " + uploadedFileLocation + ")");
return Response.status(500).entity("Can not save file<br>" + e.toString()).build();
}
return Response.status(200).entity("success").build();
}
I have created a webpage (JSP & AngularJS) that contains a form allowing the user to attach a file and send it to the server (Java Servlet). The server will then take that file and forward it to an API by attaching it to a HTTP POST request.
The code I have at the moment within the JSP File and the AngularJS Controller appears to be working correctly. Once the file is sent from the webpage to the server, I can then access some of the file details (field name and size but not content type or file name) in the Java Servlet and print them out via System.out.println().
The problem I am facing at the moment is trying to find a way how to attach the FileItem (attachment) to the HttpPost (postRequest).
I have read a number of examples online on how files are uploaded, however these examples always assume the file will be stored on a disk on the server instead of being forwarded elsewhere.
This is my current code (the problem seems to be in the Java Servlet section):
JSP File:
<form name="issueForm">
<input id="attachment" class="form-control" type="file" data-ng-model="attachment"/>
<button type="submit" data-ng-click="setAttachment()">Create Issue</button>
</form>
AngularJS Controller:
app.directive('fileModel', ['$parse', function ($parse) {
return {
restrict: 'A',
link: function(scope, element, attrs) {
var model = $parse(attrs.fileModel);
var modelSetter = model.assign;
element.bind('change', function() {
scope.$apply(function() {
modelSetter(scope, element[0].files[0]);
});
});
}
};
}]);
$scope.setAttachment = function()
{
var attachment = $scope.attachment;
var fd = new FormData();
fd.append('attachment', attachment);
$http({
url: 'IssueAttachment',
method: 'POST',
transformRequest: function(data, headersGetterFunction) { return data; },
headers: { 'Content-Type': undefined },
data: fd
})
.success(function(data, status) { alert("Success: " + status); })
.error(function(data, status) { alert("Error: " + status); });
}
Java Servlet:
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
FileItem attachment = null;
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
if (!isMultipart) { System.out.println("Not Multipart Content!"); }
else {
FileItemFactory factory = new DiskFileItemFactory();
ServletFileUpload upload = new ServletFileUpload(factory);
List items = null;
try {
items = upload.parseRequest(new ServletRequestContext(request));
} catch (FileUploadException e) { e.printStackTrace(); }
try {
//Get attachment and print details
//This section prints "attachment", 9, null, null in that order).
attachment = (FileItem) items.get(0);
System.out.println("Field Name: " + attachment.getFieldName());
System.out.println("Size: " + attachment.getSize());
System.out.println("Content Type: " + attachment.getContentType());
System.out.println("File Name: " + attachment.getName());
} catch (Exception e) { e.printStackTrace(); }
//Create a HTTP POST and send the attachment.
HttpClient httpClient = HttpClientBuilder.create().build();
HttpPost postRequest = new HttpPost(API_URL);
MultipartEntityBuilder entity = MultipartEntityBuilder.create();
entity.addPart("attachment", new FileBody(attachment)); //THE ERROR OCCURS HERE.
postRequest.setEntity(entity.build());
try {
HttpResponse response = httpClient.execute(postRequest);
} catch (IOException e) { e.printStackTrace(); }
}
}
Ended up using the following:
FileItem file = (FileItem)items.get(0);
//Create a temporary file.
File myFile = File.createTempFile(base, extension);
//Write contents to temporary file.
file.write(myFile);
/**
* Do whatever you want with the temporary file here...
*/
//Delete the temporary file.
myFile.delete(); //-OR- myFile.deleteOnExit();
I need help with sending xlsx-file from the server back to the client
This is how it worked BEFORE:
JavaScript (click #export_xls button):
export_xls: function(event) {
window.location = ... + this.workspace.query.id + "/export/xls";
}
Java (create xls-file using Apache POI API):
#GET
#Produces({"application/vnd.ms-excel" })
#Path("/{queryname}/export/xls/{format}")
public Response getQueryExcelExport(
#PathParam("queryname") String queryName,
#PathParam("format") #DefaultValue("flattened") String format){
// ...
try {
byte[] doc = olapQueryService.getExport(queryName,"xls","flat"); // file
String name = "file.xls";
return Response.ok(doc, MediaType.APPLICATION_OCTET_STREAM).header(
"content-disposition",
"attachment; filename = " + name).header(
"content-length",doc.length).build();
}
catch (Exception e) {
log.error("Cannot get excel for query (" + queryName + ")",e);
return Response.serverError().build();
}
}
And it worked fine, but now i need to send some data from javascript to the java, then java process it and create xlsx
So, i use ajax to send that data (in json format)...
export_xls: function(event) {
var data = this.workspace.query.result.lastresult();
var url = ... + this.workspace.query.id + "/testexportxls";
$.ajax({
url: url,
type: "POST",
data: JSON.stringify(data),
async: false,
contentType: "application/json"
});
},
...and create my file in java (almost like it was before):
#POST
#Produces({"application/vnd.ms-excel" })
#Consumes(MediaType.APPLICATION_JSON)
#Path("/{queryname}/testexportxls")
public Response setQueryExcelExport(final Object jsonData)
{
Workbook wb = MyFileBuilder.getFile(jsonData);
try {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
wb.write(bout);
byte[] doc = bout.toByteArray();
String name = "file.xlsx";
return Response.ok(doc, MediaType.APPLICATION_OCTET_STREAM).header(
"content-disposition",
"attachment; filename = " + name).header(
"content-length",doc.length).build();
}
catch (Exception e){
log.error("Error while xlsx-file creating. Exception message: ",e);
return Response.serverError().build();
}
}
But i can't get that file now, because of the ajax, i think.
Do you know some quick solution, with minimum code edits?
Unfortunately, I almost know nothing about Response, or some HttpServletResponse and stuff like that =/
Thank you for your time.
If you were to define a callback function on success, wouldn't that function be able to handle the file?
Seems not, so I'll have a second try: put the JSON in a hidden form input, and POST the form?
This question already has an answer here:
How to download file from httpServlet with Jquery?
(1 answer)
Closed 5 years ago.
I'm pretty new to jQuery and ajax and i have a question.
In a jsp I call
function downloadDocument(documentId){
var action = "attachment.do";
var method = "downloadDocument";
var url = action + "?actionType="+method+"&documentId=" + documentId;
$.ajax({
url: url,
dataType: "json",
type: 'POST',
success: function(data){
alert("downloaded!");
},
error: function (request, status, error) {
alert(request.responseText);
}
});
then in the servlet I do
public void downloadDocument(ActionMapping mapping, ActionForm actionForm, HttpServletRequest request, HttpServletResponse response) throws IOException{
AttachmentActionForm form = (AttachmentActionForm)actionForm;
ServletOutputStream out = response.getOutputStream();
try{
// Get the downloadFileName, the name of the file when it will be downloaded by user
String downloadFileName = "hello.txt";
String mimetype = "application/x-download"
// Get the byte stream of the file
FileInputStream in = new FileInputStream(Global.ATTACHMENTS_SHARED_FOLDER_PATH + downloadFileName);
// Print out the byte stream
byte[] buffer = new byte[4096];
int length;
while ((length = in.read(buffer)) > 0){
out.write(buffer, 0, length);
}
response.addHeader("Content-Disposition", "attachment; filename="+downloadFileName);
response.setHeader("Content-Length", Integer.toString(length));
response.setContentType(mimetype);
in.close();
}
catch(Exception e){
response.setContentType("text/text;charset=utf-8");
response.setHeader("cache-control", "no-cache");
System.out.println(e.getMessage());
out.println(e.getMessage());
}finally{
out.flush();
}
}
But in the ajax function, I never get a success, all the time I get the error message, even if the message is composed by the string inside of the file. What can I do?
Remove your dataType: "json", options and you will see some debug informations.
By the way, there is a jQuery option that meet you need:
$.fileDownload('some/file.pdf')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); })
Taken from this answer: https://stackoverflow.com/a/9970672/1420186
EDIT:
Your JSP
function downloadDocument(documentId){
var action = "attachment.do";
var method = "downloadDocument";
var url = action + "?actionType="+method+"&documentId=" + documentId;
$.ajax({
url: url,
dataType: "text", // Change dataType to "text"
type: 'POST',
success: function(data){
if (data == "FAIL") {
alert("File not found!");
} else {
window.location.href = data; // Download the file
}
},
error: function (request, status, error) {
alert("The request failed: " + request.responseText);
}
});
}
In your Servlet, if the file is not exists, just return a "FAIL" string, else return the file URL.
Hope that helps.
dont use Ajax call use //use hidden form approach
<form action='../servletname' method='POST' id='formid'>
<input type='hidden' value='' name='name' id='id'/>
<input type='hidden' value=' ' name='name' id='id' />
</form>
on click of button submit form
$('#formid').submit();
in servlet
response.setContentType("application/vnd.ms-excel");
response.setHeader("Content-Disposition", "attachment; filename=filnemae.fileformat");
ServletOutputStream out = res.getOutputStream();
write on ouput stream then close or flush
if you are sending large data through post update postsize in server.xml