Servlet-Response containing text (for display) as well as file download - javascript

I'm trying to download a file from my server through a Java Servlet.
The Problem I have is that when I enter the servlet url directly (https://localhost:8443/SSP/settings?type=db_backup) I get the servlet to execute its code and prompt me with a download dialog.
But I would like to call the servlets doGet method via Javascript to wrap it with a progress bar of some kind.
Problem here: Code in servlet is executed but I dont get the download prompt for the file.
My Code so far:
HTML:
<!-- Solution #1 -->
<button class="btn_do_db_backup" type="button">DB-Backup #1</button>
<!-- Solution #2 -->
<form action="/SSP/settings?type=db_backup" method="GET">
<button type="submit">DB-Backup #2</button></br>
</form>
JS:
// Solution #1
$(".btn_do_db_backup").click(function(e){
e.preventDefault();
$.get("settings?type=db_backup", function(data){
if(data != ""){
//further coding
}
});
// Having the code below works but doesnt
// give me the chance to wrap the call with a loading animation
//document.location = "/SSP/settings?type=db_backup";
});
Servlet:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
// PART 1
// execute srcipt to generate file to download later on
StringBuffer output = new StringBuffer();
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\\TEMP\\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
output.append(line + "\n");
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
tmp++;
}
// PART 2
// download the file generated above
OutputStream out = response.getOutputStream();
String filepath = "D:\\TEMP\\sql_dump\\";
response.setContentType("APPLICATION/OCTET-STREAM");
response.setHeader("Content-Disposition", "attachment;filename=\"" + filename + "\"");
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.close();
fileInputStream.close();
}
Solution #2 works great, I get a popup to download the file.
Solution #1 calls the servlets doGet-method (via the above JS-Code and the code from my servlet is executed correctly) but I dont get a download popup
I would like to go with solution #1 though as this gives me the opportunity to wrap the $.post call with a loading animation.
What am I missing within solution #1 to get that download popup to shop up?
EDIT 1:
I found that data in the $.get() function is filled with the content of the desired file. I can now display the content of a .txt file in a div for example but I would like to donwload said .txt file instead.
EDIT 2:
Solved it, see my answer below for details & comment/ansewer if you think it can be done in a better way

after quite some time trying to get it to work I found a solution that works. There may be better ones but thats the one I came up with.
Hope this may be helpfull for others as well.
Basic explanation of what I did here:
Have a form do a GET-Request (via JS) to a java servlet
The servlet executes a commandline script (in my case a sql-dump of my postgreSQL DB)
The servlets gathers the output from the commandline and the contents of the generated file (the sql_dump) and puts them in the response
The client gets the response and cuts it into 3 pieces (commandline output, filename & contents of sql_dump-file)
Then (via JS) the commandline output is shown in a textarea for a better overview of what the script actually did
The contents of the sql_dump-file is processed by JS-Code to generate a file to download (eihter manually via a button or automatically)
So without further ado, here we go with the flow ... code :)
SOLUTION:
HTML:
<form id="form_download_db_backup">
<input type="submit" value="Create & Download DB-Backup"></br>
<a download="" id="downloadlink" style="display: none">download</a>
</form>
<div class="db_backup_result" id="db_backup_result" style="display: none;">
</br>Commandline-Output</br>
<textarea id ="txta_db_backup_result" rows="4" cols="50"></textarea>
</div>
JS:
$("#form_download_db_backup").submit(function(e){
e.preventDefault();
var spinner = new Spinner().spin();
var target = document.getElementById('content');
target.appendChild(spinner.el);
$.ajax({
url:'settings?type=db_backup',
type:'get',
success:function(data){
spinner.stop();
if(data != ""){
var str_data = "" + data;
// Cut commanline output from data
var commandline_output = str_data.substring( 0, str_data.indexOf("--End") );
//show commanline output in textarea
$("#txta_db_backup_result").html(commandline_output);
// Cut content of db_backup file from data
var sql_dump_content = str_data.substring( str_data.indexOf("--sql_d_s--") + 13,str_data.indexOf("--sql_d_e--") );//|
// Cut filename from data
var filename = str_data.substring( str_data.indexOf("--sql_d_fns--") + 15,str_data.indexOf("--sql_d_fne--") - 2 );
//-------------------------------------------------------------
// Prepare download of backupfile
var link = document.getElementById('downloadlink');
var textFile = null;
var blob_data = new Blob([sql_dump_content], {type: 'text/plain'});
// FOR IE10+ Compatibility
if(window.navigator.msSaveOrOpenBlob) {
window.navigator.msSaveBlob(blob_data, filename);
}
// If we are replacing a previously generated file we need to
// manually revoke the object URL to avoid memory leaks.
if (textFile !== null) {
window.URL.revokeObjectURL(textFile);
}
textFile = window.URL.createObjectURL(blob_data);
link.href = textFile;
link.download = filename;
//link.style.display = 'block'; // Use this to make download link visible for manual download
link.click(); // Use this to start download automalically
//-------------------------------------------------------------
// show div containing commandline output & (optional) downloadlink
document.getElementById("db_backup_result").style.display = 'block';
}
}
});
});
Java-Servlet:
#Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException{
String type = request.getParameter("type");
if(null != type)switch (type) {
case "db_backup":
ServletOutputStream out = response.getOutputStream();
// Prepare multipart response
response.setContentType("multipart/x-mixed-replace;boundary=End");
// Start: First part of response ////////////////////////////////////////////////////////////////////////
// execute commandline script to backup the database
ProcessBuilder builder = new ProcessBuilder("cmd.exe", "/c", "D:\\TEMP\\sql_dump.cmd");
builder.redirectErrorStream(true);
Process p = builder.start();
BufferedReader r = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line = "";
String filename = "";
int tmp = 0;
while (true) {
line = r.readLine();
if (line == null) { break; }
// code for finding filename not optimal but works for now -> redo later on
if(tmp == 1){
filename = line.substring(line.indexOf("db_backup_"), line.indexOf('"', line.indexOf("db_backup_")) );
}
else{
line = line.replace("\u201E", "\'"); // replaces the lowercase " (DOUBLE LOW-9 QUOTATION MARK)
line = line.replace("\u201C", "\'"); // replaces the uppercase " (LEFT DOUBLE QUOTATION MARK)
}
out.println(line);
tmp++;
}
// End: First part of response ////////////////////////////////////////////////////////////////////////
// Separator of firt & second part
out.println("--End");
out.flush();
// Add filename in response (name of download file)
out.println("--sql_d_fns--"); // separator for filename (used to extract filename from response data)
out.println(filename);
out.println("--sql_d_fne--"); // separator for filename (used to extract filename from response data)
// Start: Second part of response ////////////////////////////////////////////////////////////////////////
out.println("--sql_d_s--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
String filepath = "D:\\TEMP\\sql_dump\\";
FileInputStream fileInputStream = new FileInputStream(filepath + filename);
int i;
while ((i = fileInputStream.read()) != -1) {
out.write(i);
}
out.println("--sql_d_e--"); // separator for content of db-dump (this is the text thats going to be downloaded later on)
// End: Second part of response ////////////////////////////////////////////////////////////////////////
// End the multipart response
out.println("--End--");
out.flush();
break;
default:
break;
}
}
postgreSQL dump contain "lowercase" & "uppercase" quotation marks which I had to replace. I put a link to each here in case someone struggles with them as well. They have multiple encodings for those characters listed there.
Unicode Character 'DOUBLE LOW-9 QUOTATION MARK' (U+201E)
Unicode Character 'LEFT DOUBLE QUOTATION MARK' (U+201C)

Related

View the file from base64 string instead of varbinary

This is my simple program on downloading file from a varbinary string on click.
Controller:
public ActionResult Download(string StudentID, string SQNC)
{
string query = "exec spToGetVarbinaryString'" + StudentID + "','" + SQNC + "' ";
string dataStr = GlobalFunction.DataTableToJSON(GlobalFunction.TableFromMSSQL(dbname, query));
dynamic data = JsonConvert.DeserializeObject(dataStr);
byte[] file = data[0].ImgVarbinary;
return File(file, System.Net.Mime.MediaTypeNames.Application.Octet, (string)data[0].FileName);
}
how I download the File:
<a type="button" href="ControllerName/Download?StudentID=${row.StudentID}&SQNC=${row.SQNC}" class="btn btn-primary btn-sm active" role="button" aria-pressed="true">View File</a>
Now, I want the file instead of being downloaded on click, It will appear on tab or new. I tried the method of converting my Varbinary to Base64 string, but it doesnt read the PDF file for this example below.
From VarBinary to Base64 in SQL
update a set a.ImgStr=baze64
from #mytemptable
cross apply (select ImgVarbinary as '*' for xml path('')) T (baze64)
where a.ImgVarbinary is not null
Displaying Base64 PDF File (Display doesn't work)
<iframe width="500" height="500"
src="data:application/pdf;base64,<base64stringhere>"
I found a sample base64 data in this JSFiddle link, I tried it on local and it works.
Image example (left one: my base64 string. Right one: base64 from the js fiddle)
How can I do this and why my base64 string isn't working well? Thanks for answering.
add something like this on click event to read bytes....
public class LoadPdfFileHandler : IHttpHandler
{
public bool IsResuable => false;
public void ProcessRequest(HttpContext context)
{
string id = context.Request.QueryString["id"];
// TODO: Verify that the user is allowed to view the specified record.
using (var connection = new MySqlConnection("..."))
using (var command = new MySqlCommand("SELECT Data, ContentType FROM SomeTable WHERE ID = #ID", connection))
{
command.Parameters.AddWithValue("#ID", id);
connection.Open();
using (var reader = command.ExecuteReader(CommandBehavior.CloseConnection))
{
if (!reader.Read())
{
context.Response.StatusCode = 404;
return;
}
string contentType = (string)dr["ContentType"];
if (string.IsNullOrEmpty(contentType)) contentType = "application/octet-stream";
context.Response.ContentType = contentType;
byte[] bytes = (byte[])dr["Data"];
context.Response.BinaryWrite(bytes);
}
}
}
}
Then Write Frame Using this...
myiframe.Attributes["src"] = ResolveUrl("~/loadPdfFile.ashx?id=" + idOfTheRecordToLoad);
You can check Other Reference here image reference

Create and download TXT file in a Java servlet [duplicate]

I have a Struts2 action in the server side for file downloading.
<action name="download" class="com.xxx.DownAction">
<result name="success" type="stream">
<param name="contentType">text/plain</param>
<param name="inputName">imageStream</param>
<param name="contentDisposition">attachment;filename={fileName}</param>
<param name="bufferSize">1024</param>
</result>
</action>
However when I call the action using the jQuery:
$.post(
"/download.action",{
para1:value1,
para2:value2
....
},function(data){
console.info(data);
}
);
in Firebug I see the data is retrieved with the Binary stream. I wonder how to open the file downloading window with which the user can save the file locally?
2019 modern browsers update
This is the approach I'd now recommend with a few caveats:
A relatively modern browser is required
If the file is expected to be very large you should likely do something similar to the original approach (iframe and cookie) because some of the below operations could likely consume system memory at least as large as the file being downloaded and/or other interesting CPU side effects.
fetch('https://jsonplaceholder.typicode.com/todos/1')
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
// the filename you want
a.download = 'todo-1.json';
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
alert('your file has downloaded!'); // or you know, something with better UX...
})
.catch(() => alert('oh no!'));
2012 Original jQuery/iframe/Cookie based approach
Bluish is completely right about this, you can't do it through Ajax because JavaScript cannot save files directly to a user's computer (out of security concerns). Unfortunately pointing the main window's URL at your file download means you have little control over what the user experience is when a file download occurs.
I created jQuery File Download which allows for an "Ajax like" experience with file downloads complete with OnSuccess and OnFailure callbacks to provide for a better user experience. Take a look at my blog post on the common problem that the plugin solves and some ways to use it and also a demo of jQuery File Download in action. Here is the source
Here is a simple use case demo using the plugin source with promises. The demo page includes many other, 'better UX' examples as well.
$.fileDownload('some/file.pdf')
.done(function () { alert('File download a success!'); })
.fail(function () { alert('File download failed!'); });
Depending on what browsers you need to support you may be able to use https://github.com/eligrey/FileSaver.js/ which allows more explicit control than the IFRAME method jQuery File Download uses.
Noone posted this #Pekka's solution... so I'll post it. It can help someone.
You don't need to do this through Ajax. Just use
window.location="download.action?para1=value1...."
You can with HTML5
NB: The file data returned MUST be base64 encoded because you cannot JSON encode binary data
In my AJAX response I have a data structure that looks like this:
{
result: 'OK',
download: {
mimetype: string(mimetype in the form 'major/minor'),
filename: string(the name of the file to download),
data: base64(the binary data as base64 to download)
}
}
That means that I can do the following to save a file via AJAX
var a = document.createElement('a');
if (window.URL && window.Blob && ('download' in a) && window.atob) {
// Do it the HTML5 compliant way
var blob = base64ToBlob(result.download.data, result.download.mimetype);
var url = window.URL.createObjectURL(blob);
a.href = url;
a.download = result.download.filename;
a.click();
window.URL.revokeObjectURL(url);
}
The function base64ToBlob was taken from here and must be used in compliance with this function
function base64ToBlob(base64, mimetype, slicesize) {
if (!window.atob || !window.Uint8Array) {
// The current browser doesn't have the atob function. Cannot continue
return null;
}
mimetype = mimetype || '';
slicesize = slicesize || 512;
var bytechars = atob(base64);
var bytearrays = [];
for (var offset = 0; offset < bytechars.length; offset += slicesize) {
var slice = bytechars.slice(offset, offset + slicesize);
var bytenums = new Array(slice.length);
for (var i = 0; i < slice.length; i++) {
bytenums[i] = slice.charCodeAt(i);
}
var bytearray = new Uint8Array(bytenums);
bytearrays[bytearrays.length] = bytearray;
}
return new Blob(bytearrays, {type: mimetype});
};
This is good if your server is dumping filedata to be saved. However, I've not quite worked out how one would implement a HTML4 fallback
The simple way to make the browser downloads a file is to make the request like that:
function downloadFile(urlToSend) {
var req = new XMLHttpRequest();
req.open("GET", urlToSend, true);
req.responseType = "blob";
req.onload = function (event) {
var blob = req.response;
var fileName = req.getResponseHeader("fileName") //if you have the fileName header available
var link=document.createElement('a');
link.href=window.URL.createObjectURL(blob);
link.download=fileName;
link.click();
};
req.send();
}
This opens the browser download pop up.
1. Framework agnostic: Servlet downloading file as attachment
<!-- with JS -->
<a href="javascript:window.location='downloadServlet?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadServlet?param1=value1" >download</a>
2. Struts2 Framework: Action downloading file as attachment
<!-- with JS -->
<a href="javascript:window.location='downloadAction.action?param1=value1'">
download
</a>
<!-- without JS -->
<a href="downloadAction.action?param1=value1" >download</a>
It would be better to use <s:a> tag pointing with OGNL to an URL created with <s:url> tag:
<!-- without JS, with Struts tags: THE RIGHT WAY -->
<s:url action="downloadAction.action" var="url">
<s:param name="param1">value1</s:param>
</s:ulr>
<s:a href="%{url}" >download</s:a>
In the above cases, you need to write the Content-Disposition header to the response, specifying that the file needs to be downloaded (attachment) and not opened by the browser (inline). You need to specify the Content Type too, and you may want to add the file name and length (to help the browser drawing a realistic progressbar).
For example, when downloading a ZIP:
response.setContentType("application/zip");
response.addHeader("Content-Disposition",
"attachment; filename=\"name of my file.zip\"");
response.setHeader("Content-Length", myFile.length()); // or myByte[].length...
With Struts2 (unless you are using the Action as a Servlet, an hack for direct streaming, for example), you don't need to directly write anything to the response; simply using the Stream result type and configuring it in struts.xml will work: EXAMPLE
<result name="success" type="stream">
<param name="contentType">application/zip</param>
<param name="contentDisposition">attachment;filename="${fileName}"</param>
<param name="contentLength">${fileLength}</param>
</result>
3. Framework agnostic (/ Struts2 framework): Servlet(/Action) opening file inside the browser
If you want to open the file inside the browser, instead of downloading it, the Content-disposition must be set to inline, but the target can't be the current window location; you must target a new window created by javascript, an <iframe> in the page, or a new window created on-the-fly with the "discussed" target="_blank":
<!-- From a parent page into an IFrame without javascript -->
<a href="downloadServlet?param1=value1" target="iFrameName">
download
</a>
<!-- In a new window without javascript -->
<a href="downloadServlet?param1=value1" target="_blank">
download
</a>
<!-- In a new window with javascript -->
<a href="javascript:window.open('downloadServlet?param1=value1');" >
download
</a>
I have created little function as workaround solution (inspired by #JohnCulviner plugin):
// creates iframe and form in it with hidden field,
// then submit form with provided data
// url - form url
// data - data to form field
// input_name - form hidden input name
function ajax_download(url, data, input_name) {
var $iframe,
iframe_doc,
iframe_html;
if (($iframe = $('#download_iframe')).length === 0) {
$iframe = $("<iframe id='download_iframe'" +
" style='display: none' src='about:blank'></iframe>"
).appendTo("body");
}
iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
if (iframe_doc.document) {
iframe_doc = iframe_doc.document;
}
iframe_html = "<html><head></head><body><form method='POST' action='" +
url +"'>" +
"<input type=hidden name='" + input_name + "' value='" +
JSON.stringify(data) +"'/></form>" +
"</body></html>";
iframe_doc.open();
iframe_doc.write(iframe_html);
$(iframe_doc).find('form').submit();
}
Demo with click event:
$('#someid').on('click', function() {
ajax_download('/download.action', {'para1': 1, 'para2': 2}, 'dataname');
});
I faced the same issue and successfully solved it. My use-case is this.
"Post JSON data to the server and receive an excel file.
That excel file is created by the server and returned as a response to the client. Download that response as a file with custom name in browser"
$("#my-button").on("click", function(){
// Data to post
data = {
ids: [1, 2, 3, 4, 5]
};
// Use XMLHttpRequest instead of Jquery $ajax
xhttp = new XMLHttpRequest();
xhttp.onreadystatechange = function() {
var a;
if (xhttp.readyState === 4 && xhttp.status === 200) {
// Trick for making downloadable link
a = document.createElement('a');
a.href = window.URL.createObjectURL(xhttp.response);
// Give filename you wish to download
a.download = "test-file.xls";
a.style.display = 'none';
document.body.appendChild(a);
a.click();
}
};
// Post data to URL which handles post request
xhttp.open("POST", excelDownloadUrl);
xhttp.setRequestHeader("Content-Type", "application/json");
// You should set responseType as blob for binary responses
xhttp.responseType = 'blob';
xhttp.send(JSON.stringify(data));
});
The above snippet is just doing following
Posting an array as JSON to the server using XMLHttpRequest.
After fetching content as a blob(binary), we are creating a downloadable URL and attaching it to invisible "a" link then clicking it. I did a POST request here. Instead, you can go for a simple GET too. We cannot download the file through Ajax, must use XMLHttpRequest.
Here we need to carefully set few things on the server side. I set few headers in Python Django HttpResponse. You need to set them accordingly if you use other programming languages.
# In python django code
response = HttpResponse(file_content, content_type="application/vnd.openxmlformats-officedocument.spreadsheetml.sheet")
Since I download xls(excel) here, I adjusted contentType to above one. You need to set it according to your file type. You can use this technique to download any kind of files.
Ok, based on ndpu's code heres an improved (I think) version of ajax_download;-
function ajax_download(url, data) {
var $iframe,
iframe_doc,
iframe_html;
if (($iframe = $('#download_iframe')).length === 0) {
$iframe = $("<iframe id='download_iframe'" +
" style='display: none' src='about:blank'></iframe>"
).appendTo("body");
}
iframe_doc = $iframe[0].contentWindow || $iframe[0].contentDocument;
if (iframe_doc.document) {
iframe_doc = iframe_doc.document;
}
iframe_html = "<html><head></head><body><form method='POST' action='" +
url +"'>"
Object.keys(data).forEach(function(key){
iframe_html += "<input type='hidden' name='"+key+"' value='"+data[key]+"'>";
});
iframe_html +="</form></body></html>";
iframe_doc.open();
iframe_doc.write(iframe_html);
$(iframe_doc).find('form').submit();
}
Use this like this;-
$('#someid').on('click', function() {
ajax_download('/download.action', {'para1': 1, 'para2': 2});
});
The params are sent as proper post params as if coming from an input rather than as a json encoded string as per the previous example.
CAVEAT: Be wary about the potential for variable injection on those forms. There might be a safer way to encode those variables. Alternatively contemplate escaping them.
My approach is completly based on jQuery. The problem for me was that it has to be a POST-HTTP call. And I wanted it to be done by jQuery alone.
The solution:
$.ajax({
type: "POST",
url: "/some/webpage",
headers: {'X-CSRF-TOKEN': csrfToken},
data: additionalDataToSend,
dataType: "text",
success: function(result) {
let blob = new Blob([result], { type: "application/octetstream" });
let a = document.createElement('a');
a.href = window.URL.createObjectURL(blob);
a.download = "test.xml";;
document.body.appendChild(a);
a.click();
document.body.removeChild(a);
window.URL.revokeObjectURL(a.href);
...
},
error: errorDialog
});
Explanation:
What I and many others do is to create a link on the webpage, indicating that the target should be downloaded and putting the result of the http-request as the target. After that I append the link to the document than simply clicking the link and removing the link afterwards. You don't need an iframe anymore.
The magic lies in the lines
let blob = new Blob([result], { type: "application/octetstream" });
a.href = window.URL.createObjectURL(blob);
The interesting point is that this solution is only working with a "blob". As you can see in other answers, some are simply using a blob but not explaining why and how to create it.
As you can read e.g. in the Mozilla developer documentation you need a file, media ressource or blob for the function "createObjectURL()" to work. The problem is that your http-response might not be any of those.
Therefore the first thing you must do is to convert your response to a blob. This is what the first line does. Then you can use the "createObjectURL" with your newly created blob.
If you than click the link your browser will open a file-save dialog and you can save your data. Obviously it s possible that you cannot define a fixed filename for your file to download. Then you must make your response more complex like in the answer from Luke.
And don't forget to free up the memory especially when you are working with large files. For more examples and information you can look at the details of the JS blob object
Here is what I did, pure javascript and html. Did not test it but this should work in all browsers.
Javascript Function
var iframe = document.createElement('iframe');
iframe.id = "IFRAMEID";
iframe.style.display = 'none';
document.body.appendChild(iframe);
iframe.src = 'SERVERURL'+'?' + $.param($scope.filtro);
iframe.addEventListener("load", function () {
console.log("FILE LOAD DONE.. Download should start now");
});
Using just components that is supported in all browsers no additional
libraries.
Here is my server side JAVA Spring controller code.
#RequestMapping(value = "/rootto/my/xlsx", method = RequestMethod.GET)
public void downloadExcelFile(#RequestParam(value = "param1", required = false) String param1,
HttpServletRequest request, HttpServletResponse response)
throws ParseException {
Workbook wb = service.getWorkbook(param1);
if (wb != null) {
try {
String fileName = "myfile_" + sdf.format(new Date());
response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
response.setHeader("Content-disposition", "attachment; filename=\"" + fileName + ".xlsx\"");
wb.write(response.getOutputStream());
response.getOutputStream().close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
How to DOWNLOAD a file after receiving it by AJAX
It’s convenient when the file is created for a long time and you need to show PRELOADER
Example when submitting a web form:
<script>
$(function () {
$('form').submit(function () {
$('#loader').show();
$.ajax({
url: $(this).attr('action'),
data: $(this).serialize(),
dataType: 'binary',
xhrFields: {
'responseType': 'blob'
},
success: function(data, status, xhr) {
$('#loader').hide();
// if(data.type.indexOf('text/html') != -1){//If instead of a file you get an error page
// var reader = new FileReader();
// reader.readAsText(data);
// reader.onload = function() {alert(reader.result);};
// return;
// }
var link = document.createElement('a'),
filename = 'file.xlsx';
// if(xhr.getResponseHeader('Content-Disposition')){//filename
// filename = xhr.getResponseHeader('Content-Disposition');
// filename=filename.match(/filename="(.*?)"/)[1];
// filename=decodeURIComponent(escape(filename));
// }
link.href = URL.createObjectURL(data);
link.download = filename;
link.click();
}
});
return false;
});
});
</script>
Optional functional is commented out to simplify the example.
No need to create temporary files on the server.
On jQuery v2.2.4 OK. There will be an error on the old version:
Uncaught DOMException: Failed to read the 'responseText' property from 'XMLHttpRequest': The value is only accessible if the object's 'responseType' is '' or 'text' (was 'blob').
function downloadURI(uri, name)
{
var link = document.createElement("a");
link.download = name;
link.href = uri;
link.click();
}
I try to download a CSV file and then do something after download has finished. So I need to implement an appropriate callback function.
Using window.location="..." is not a good idea because I cannot operate the program after finishing download. Something like this, change header so it is not a good idea.
fetch is a good alternative however it cannot support IE 11. And window.URL.createObjectURL cannot support IE 11.You can refer this.
This is my code, it is similar to the code of Shahrukh Alam. But you should take care that window.URL.createObjectURL maybe create memory leaks. You can refer this. When response has arrived, data will be stored into memory of browser. So before you click a link, the file has been downloaded. It means that you can do anything after download.
$.ajax({
url: 'your download url',
type: 'GET',
}).done(function (data, textStatus, request) {
// csv => Blob
var blob = new Blob([data]);
// the file name from server.
var fileName = request.getResponseHeader('fileName');
if (window.navigator && window.navigator.msSaveOrOpenBlob) { // for IE
window.navigator.msSaveOrOpenBlob(blob, fileName);
} else { // for others
var url = window.URL.createObjectURL(blob);
const a = document.createElement('a');
a.style.display = 'none';
a.href = url;
a.download = fileName;
document.body.appendChild(a);
a.click();
window.URL.revokeObjectURL(url);
//Do something after download
...
}
}).then(after_download)
}
Adding some more things to above answer for downloading a file
Below is some java spring code which generates byte Array
#RequestMapping(value = "/downloadReport", method = { RequestMethod.POST })
public ResponseEntity<byte[]> downloadReport(
#RequestBody final SomeObejct obj, HttpServletResponse response) throws Exception {
OutputStream out = new ByteArrayOutputStream();
// write something to output stream
HttpHeaders respHeaders = new HttpHeaders();
respHeaders.setContentType(MediaType.APPLICATION_OCTET_STREAM);
respHeaders.add("X-File-Name", name);
ByteArrayOutputStream bos = (ByteArrayOutputStream) out;
return new ResponseEntity<byte[]>(bos.toByteArray(), respHeaders, HttpStatus.CREATED);
}
Now in javascript code using FileSaver.js ,can download a file with below code
var json=angular.toJson("somejsobject");
var url=apiEndPoint+'some url';
var xhr = new XMLHttpRequest();
//headers('X-File-Name')
xhr.onreadystatechange = function() {
if (this.readyState == 4 && this.status == 201) {
var res = this.response;
var fileName=this.getResponseHeader('X-File-Name');
var data = new Blob([res]);
saveAs(data, fileName); //this from FileSaver.js
}
}
xhr.open('POST', url);
xhr.setRequestHeader('Authorization','Bearer ' + token);
xhr.setRequestHeader('Content-Type', 'application/json');
xhr.responseType = 'arraybuffer';
xhr.send(json);
The above will download file
In Rails, I do it this way:
function download_file(file_id) {
let url = '/files/' + file_id + '/download_file';
$.ajax({
type: 'GET',
url: url,
processData: false,
success: function (data) {
window.location = url;
},
error: function (xhr) {
console.log(' Error: >>>> ' + JSON.stringify(xhr));
}
});
}
The trick is the window.location part. The controller's method looks like:
# GET /files/{:id}/download_file/
def download_file
send_file(#file.file,
:disposition => 'attachment',
:url_based_filename => false)
end
Use window.open https://developer.mozilla.org/en-US/docs/Web/API/Window/open
For example, you can put this line of code in a click handler:
window.open('/file.txt', '_blank');
It will open a new tab (because of the '_blank' window-name) and that tab will open the URL.
Your server-side code should also have something like this:
res.set('Content-Disposition', 'attachment; filename=file.txt');
And that way, the browser should prompt the user to save the file to disk, instead of just showing them the file. It will also automatically close the tab that it just opened.
The HTML Code :
<button type="button" id="GetFile">Get File!</button>
The jQuery Code :
$('#GetFile').on('click', function () {
$.ajax({
url: 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/172905/test.pdf',
method: 'GET',
xhrFields: {
responseType: 'blob'
},
success: function (data) {
var a = document.createElement('a');
var url = window.URL.createObjectURL(data);
a.href = url;
a.download = 'myfile.pdf';
document.body.append(a);
a.click();
a.remove();
window.URL.revokeObjectURL(url);
}
});
});
Ok so here is the working code when Using MVC and you are getting your file from a controller
lets say you have your byte array declare and populate, the only thing you need to do is to use the File function (using System.Web.Mvc)
byte[] bytes = .... insert your bytes in the array
return File(bytes, System.Net.Mime.MediaTypeNames.Application.Octet, "nameoffile.exe");
and then, in the same controller, add thoses 2 functions
protected override void OnResultExecuting(ResultExecutingContext context)
{
CheckAndHandleFileResult(context);
base.OnResultExecuting(context);
}
private const string FILE_DOWNLOAD_COOKIE_NAME = "fileDownload";
/// <summary>
/// If the current response is a FileResult (an MVC base class for files) then write a
/// cookie to inform jquery.fileDownload that a successful file download has occured
/// </summary>
/// <param name="context"></param>
private void CheckAndHandleFileResult(ResultExecutingContext context)
{
if (context.Result is FileResult)
//jquery.fileDownload uses this cookie to determine that a file download has completed successfully
Response.SetCookie(new HttpCookie(FILE_DOWNLOAD_COOKIE_NAME, "true") { Path = "/" });
else
//ensure that the cookie is removed in case someone did a file download without using jquery.fileDownload
if (Request.Cookies[FILE_DOWNLOAD_COOKIE_NAME] != null)
Response.Cookies[FILE_DOWNLOAD_COOKIE_NAME].Expires = DateTime.Now.AddYears(-1);
}
and then you will be able to call your controller to download and get the "success" or "failure" callback
$.fileDownload(mvcUrl('name of the controller'), {
httpMethod: 'POST',
successCallback: function (url) {
//insert success code
},
failCallback: function (html, url) {
//insert fail code
}
});
I found a fix that while it's not actually using ajax it does allow you to use a javascript call to request the download and then get a callback when the download actually starts. I found this helpful if the link runs a server side script that takes a little bit to compose the file before sending it. so you can alert them that it's processing, and then when it does finally send the file remove that processing notification. which is why I wanted to try to load the file via ajax to begin with so that I could have an event happen when the file is requested and another when it actually starts downloading.
the js on the front page
function expdone()
{
document.getElementById('exportdiv').style.display='none';
}
function expgo()
{
document.getElementById('exportdiv').style.display='block';
document.getElementById('exportif').src='test2.php?arguments=data';
}
the iframe
<div id="exportdiv" style="display:none;">
<img src="loader.gif"><br><h1>Generating Report</h1>
<iframe id="exportif" src="" style="width: 1px;height: 1px; border:0px;"></iframe>
</div>
then the other file:
<!DOCTYPE html>
<html>
<head>
<script>
function expdone()
{
window.parent.expdone();
}
</script>
</head>
<body>
<iframe id="exportif" src="<?php echo "http://10.192.37.211/npdtracker/exportthismonth.php?arguments=".$_GET["arguments"]; ?>"></iframe>
<script>document.getElementById('exportif').onload= expdone;</script>
</body></html>
I think there's a way to read get data using js so then no php would be needed. but I don't know it off hand and the server I'm using supports php so this works for me. thought I'd share it in case it helps anyone.
If the server is writing the file back in the response (including cookies if
you use them to determine whether the file download started), Simply create a form with the values and submit it:
function ajaxPostDownload(url, data) {
var $form;
if (($form = $('#download_form')).length === 0) {
$form = $("<form id='download_form'" + " style='display: none; width: 1px; height: 1px; position: absolute; top: -10000px' method='POST' action='" + url + "'></form>");
$form.appendTo("body");
}
//Clear the form fields
$form.html("");
//Create new form fields
Object.keys(data).forEach(function (key) {
$form.append("<input type='hidden' name='" + key + "' value='" + data[key] + "'>");
});
//Submit the form post
$form.submit();
}
Usage:
ajaxPostDownload('/fileController/ExportFile', {
DownloadToken: 'newDownloadToken',
Name: $txtName.val(),
Type: $txtType.val()
});
Controller Method:
[HttpPost]
public FileResult ExportFile(string DownloadToken, string Name, string Type)
{
//Set DownloadToken Cookie.
Response.SetCookie(new HttpCookie("downloadToken", DownloadToken)
{
Expires = DateTime.UtcNow.AddDays(1),
Secure = false
});
using (var output = new MemoryStream())
{
//get File
return File(output.ToArray(), "application/vnd.ms-excel", "NewFile.xls");
}
}
I have tried Ajax and HttpRequest ways to get my result download file but I've failed, finally I've solved my problem using these steps:
implemented a simple hidden form in my html code:
<form method="post" id="post_form" style="display:none" action="amin.php" >
<input type="hidden" name="action" value="export_xlsx" />
<input type="hidden" name="post_form_data" value="" />
</form>
input with 'action' name is for calling function in my php code,
input with 'post_form_data' name for sending long data of a table which were not possible to send with GET. this data was encoded to json, and put json in input:
var list = new Array();
$('#table_name tr').each(function() {
var row = new Array();
$(this).find('td').each(function() {
row.push($(this).text());
});
list.push(row);
});
list = JSON.stringify(list);
$("input[name=post_form_data]").val(list);
now, the form is ready with my desire values in inputs, just need to trigger the submit.
document.getElementById('post_form').submit();
and done!
while my result is a file (xlsx file for me) the page wouldn't be redirected and instantly the file starts to download in last page, so no need to useiframe or window.open etc.
if you are trying to do something like this, this should be an easy trick 😉.
If you want to use jQuery File Download , please note this for IE.
You need to reset the response or it will not download
//The IE will only work if you reset response
getServletResponse().reset();
//The jquery.fileDownload needs a cookie be set
getServletResponse().setHeader("Set-Cookie", "fileDownload=true; path=/");
//Do the reset of your action create InputStream and return
Your action can implement ServletResponseAware to access getServletResponse()
It is certain that you can not do it through Ajax call.
However, there is a workaround.
Steps :
If you are using form.submit() for downloading the file, what you can do is :
Create an ajax call from client to server and store the file stream inside the session.
Upon "success" being returned from server, call your form.submit() to just stream the file stream stored in the session.
This is helpful in case when you want to decide whether or not file needs to be downloaded after making form.submit(), eg: there can be a case where on form.submit(), an exception occurs on the server side and instead of crashing, you might need to show a custom message on the client side, in such case this implementation might help.
there is another solution to download a web page in ajax. But I am referring to a page that must first be processed and then downloaded.
First you need to separate the page processing from the results download.
1) Only the page calculations are made in the ajax call.
$.post("CalculusPage.php", { calculusFunction: true, ID: 29, data1: "a", data2: "b" },
function(data, status)
{
if (status == "success")
{
/* 2) In the answer the page that uses the previous calculations is downloaded. For example, this can be a page that prints the results of a table calculated in the ajax call. */
window.location.href = DownloadPage.php+"?ID="+29;
}
}
);
// For example: in the CalculusPage.php
if ( !empty($_POST["calculusFunction"]) )
{
$ID = $_POST["ID"];
$query = "INSERT INTO ExamplePage (data1, data2) VALUES ('".$_POST["data1"]."', '".$_POST["data2"]."') WHERE id = ".$ID;
...
}
// For example: in the DownloadPage.php
$ID = $_GET["ID"];
$sede = "SELECT * FROM ExamplePage WHERE id = ".$ID;
...
$filename="Export_Data.xls";
header("Content-Type: application/vnd.ms-excel");
header("Content-Disposition: inline; filename=$filename");
...
I hope this solution can be useful for many, as it was for me.
That's it works so fine in any browser (I'm using asp.net core)
function onDownload() {
const api = '#Url.Action("myaction", "mycontroller")';
var form = new FormData(document.getElementById('form1'));
fetch(api, { body: form, method: "POST"})
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
$('#linkdownload').attr('download', 'Attachement.zip');
$('#linkdownload').attr("href", url);
$('#linkdownload')
.fadeIn(3000,
function() { });
})
.catch(() => alert('An error occurred'));
}
<button type="button" onclick="onDownload()" class="btn btn-primary btn-sm">Click to Process Files</button>
<a role="button" href="#" style="display: none" class="btn btn-sm btn-secondary" id="linkdownload">Click to download Attachments</a>
<form asp-controller="mycontroller" asp-action="myaction" id="form1"></form>
function onDownload() {
const api = '#Url.Action("myaction", "mycontroller")';
//form1 is your id form, and to get data content of form
var form = new FormData(document.getElementById('form1'));
fetch(api, { body: form, method: "POST"})
.then(resp => resp.blob())
.then(blob => {
const url = window.URL.createObjectURL(blob);
$('#linkdownload').attr('download', 'Attachments.zip');
$('#linkdownload').attr("href", url);
$('#linkdownload')
.fadeIn(3000,
function() {
});
})
.catch(() => alert('An error occurred'));
}
I struggled with this issue for a long time. Finally an elegant external library suggested here helped me out.

Using CKEditor custom filebrowser and upload with ASP.Net MVC

I have a MVC app that Im trying to use CKEditor with. One example I was looking at is here but there are many others. So far so good, but one section im still curious about, is the js that sends the selected file name back to the file upload dialog textbox.
<script type="text/javascript">
$(document).ready(function () {
$(".returnImage").click("click", function (e) {
var urlImage = $(this).attr("data-url");
window.opener.updateValue("cke_72_textInput", urlImage);
window.close();
});
});
</script>
In particular, the cke_72_textInput element. My example wasnt working initially, until I opened chrome dev tools and found the actual id of the textinput, which was in my case cke_76_textInput. Why the id change I wonder? Seems a little "fragile" to refer to a specific id like this? The above js code just takes the selected image file and returns it into the textbox of the fileupload dialog.
Is there something exposed that references this textbox element indirectly without specifying it by id (via the config for example)?
On view:
$(document).ready(function () {
CKEDITOR.replace('Text-area-name', {
filebrowserImageUploadUrl: '/Controller-name/UploadImage'
});
CKEDITOR.editorConfig = function (config) {
// Define changes to default configuration here. For example:
config.language = 'de';
// config.extraPlugins = 'my_own_plugin'; // if you have any plugin
// config.uiColor = '#AADC6E';
// config.image_previewText = CKEDITOR.tools.repeat(' Hier steht dann dein guter Text. ', 8 );
// config.contentsLanguage = 'de';
config.height = 350; // 350px, specify if you want a larger height of the editor
config.linkShowAdvancedTab = false;
config.linkShowTargetTab = false;
};
CKEDITOR.on('dialogDefinition', function (ev) {
var dialogName = ev.data.name;
var dialogDefinition = ev.data.definition;
ev.data.definition.resizable = CKEDITOR.DIALOG_RESIZE_NONE;
if (dialogName == 'link') {
var infoTab = dialogDefinition.getContents('info');
infoTab.remove('protocol');
dialogDefinition.removeContents('target');
dialogDefinition.removeContents('advanced');
}
if (dialogName == 'image') {
dialogDefinition.removeContents('Link');
dialogDefinition.removeContents('advanced');
var infoTab = dialogDefinition.getContents('info');
infoTab.remove('txtBorder');
infoTab.remove('txtHSpace');
infoTab.remove('txtVSpace');
infoTab.remove('cmbAlign');
}
});
}
On Contoller:
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase file, string CKEditorFuncNum, string CKEditor, string langCode)
{
if (file.ContentLength <= 0)
return null;
// here logic to upload image
// and get file path of the image
const string uploadFolder = "Assets/img/";
var fileName = Path.GetFileName(file.FileName);
var path = Path.Combine(Server.MapPath(string.Format("~/{0}", uploadFolder)), fileName);
file.SaveAs(path);
var url = string.Format("{0}{1}/{2}/{3}", Request.Url.GetLeftPart(UriPartial.Authority),
Request.ApplicationPath == "/" ? string.Empty : Request.ApplicationPath,
uploadFolder, fileName);
// passing message success/failure
const string message = "Image was saved correctly";
// since it is an ajax request it requires this string
var output = string.Format(
"<html><body><script>window.parent.CKEDITOR.tools.callFunction({0}, \"{1}\", \"{2}\");</script></body></html>",
CKEditorFuncNum, url, message);
return Content(output);
}
I had the same problem...a little frustrating that I couldn't find any official documentation, considering this seems like a common use case.
Anyways, take a look at the quick tutorial here: http://r2d2.cc/2010/11/03/file-and-image-upload-with-asp-net-mvc2-with-ckeditor-wysiwyg-rich-text-editor/. In case the link ever breaks, here's what I did.
[HttpPost]
public ActionResult UploadImage(HttpPostedFileBase upload, string ckEditorFuncNum)
{
/*
add logic to upload and save image here
*/
var path = "~/Path/To/image.jpg"; // Logical relative path to uploaded image
var url = string.Format("{0}://{1}{2}",
Request.Url.Scheme,
Request.Url.Authority,
Url.Content(path)); // URL path to uploaded image
var message = "Saved!"; // Optional
var output = string.Format("<script>window.parent.CKEDITOR.tools.callFunction({0}, '{1}', '{2}');</script>",
CKEditorFuncNum,
url,
message);
return Content(output);
}

get response from servel on ajax call when uploading file with multidata form

I'm with a little problem on my project.
Hi have several jsp's and Java class. In one jsp i create a form with only a input type="file" and type="submit", then I have an ajax call and send all the formdata to a doPost class on my servel. Then I send that file to the DataBase and it all's go fine, my problem is I want to return the id from the database to the .jsp. I can access and have prints on the doPost to check my key, but cant send it to success function inside the ajax call..
Here's my code, i really apreciate any kind of help, thanks!
<form id="uploadDocuments" target="invisible" method="POST" action="UploadDocumentsAjaxService" enctype="multipart/form-data">
<iframe name="invisible" style="display:none;"></iframe>
<h3 style="width: 71%;margin-left: 8%;">ANEXAR FICHEIROS:</h3>
<h4 style="margin-left: 8%; color: #F7A707" >Escolher ficheiro para anexar: </h4>
<input type="file" id="file_input" name="file" size="50" style="width: 60%; margin-left: 8%;"/>
<input type="submit" value="Upload" />
</form>
the I have my Ajax Call:
$("#uploadDocuments").submit(function (e) {
alert(10);
alert($("#uploadDocuments").attr('action'));
$.ajax({
type: $("#uploadDocuments").attr('method'),
url: $("#uploadDocuments").attr('action'),
contentType: $("#uploadDocuments").attr( "enctype"),
data: new FormData($("#uploadDocuments")[0]),
processData: true,
success: function (data) {
alert("submitDocument");
alert();
/* key = data;
addFilesToTable(key); */
return true;
}
});
e.preventDefault();
$(form).off('submit');
return false;
});
And then my servlet class:
protected void doPost(HttpServletRequest request, HttpServletResponse response)throws ServletException, IOException{
response.setContentType("text/html;charset=ISO-8859-1");
PrintWriter out = response.getWriter();
boolean isMultipart = ServletFileUpload.isMultipartContent(request);
ChangeEntityRequestActionBean actionBean = new ChangeEntityRequestActionBean();
if(!isMultipart)
return;
// Create a factory for disk-based file items
DiskFileItemFactory factory = new DiskFileItemFactory();
// Sets the size threshold beyond which files are written directly to
// disk.
factory.setSizeThreshold(MAX_MEMORY_SIZE);
// constructs the folder where uploaded file will be stored
String uploadFolder = getServletContext().getRealPath("") + DATA_DIRECTORY;
// Create a new file upload handler
ServletFileUpload upload = new ServletFileUpload(factory);
// Set overall request size constraint
upload.setSizeMax(MAX_REQUEST_SIZE);
String fileName = "";
Long documentKey = null;
String key = "";
try {
// Parse the request
List items = upload.parseRequest(request);
Iterator iter = items.iterator();
while (iter.hasNext()) {
FileItem item = (FileItem) iter.next();
if (!item.isFormField()) {
fileName = new File(item.getName()).getName();
String filePath = uploadFolder + File.separator + fileName;
File uploadedFile = new File(filePath);
System.out.println(filePath);
// saves the file to upload directory
item.write(uploadedFile);
}
documentKey = actionBean.insertDocument(item, fileName);
System.out.println("Key from DAO ------->>>>>"+documentKey);
key = String.valueOf(documentKey);
}
System.out.println("Key in String from DAO ----->"+key);
System.out.println();
out.println("success");
response.flushBuffer();
}catch (FileUploadException ex) {
throw new ServletException(ex);
} catch (Exception ex) {
throw new ServletException(ex);
} finally {
out.close();
}
}
All I want is to send the key value to out.println so I can use that value on a jquery function
In the first line of doPost() in your servlet, change the content-type of the response to "application/json". Then write a JSON string to the output stream. There are libraries available to do this for you, but for something so simple, you can compose the JSON yourself. This might actually have an advantage because your key is a java long; treat it as a string and you don't have to worry about how the integer is represented.
// replace out.println("success"); with this:
out.print("{\"key\": \"" + key + "\"}");
Then in the success callback function, you can access the key as a field of the data object. You'll need to specify the data type in the ajax method (dataType: 'json').
success: function (data) {
var key = data['key'];
addFilesToTable(key);
return true;
}

Upload the image with preview

Hi I wanted to upload images(along with other form details) and preview them, using jsp and servlets. I am able to do the uploading part but could not get, how to preview the images in the frontend.
I am using YUI to implement it. Actually I am trying to reuse an example which is implemented in PHP. I am attaching my Servlet code here. In this 'completeFileName' will be populated when a upload has been done.
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
if(completeFileName == null) {
PrintWriter pout = response.getWriter();
JSONObject obj = new JSONObject();
obj.put("hasError", new Boolean(true));
pout.println(obj.toString());
}
try {
OutputStream out = response.getOutputStream();
Image image = Toolkit.getDefaultToolkit().getImage(completeFileName);
ImageIcon icon = new ImageIcon(image);
int height = icon.getIconHeight();
int width = icon.getIconWidth();
BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
ImageIO.write(bi, "jpg", out);
out.flush();
} catch (Exception ex) {
}
My Jsp code looks like this:
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.0/build/connection/connection.js"></script>
<script type="text/javascript" src="http://yui.yahooapis.com/2.3.0/build/utilities/utilities.js"></script>
<script type="text/javascript">
var $E = YAHOO.util.Event;
var $ = YAHOO.util.Dom.get;
var $D = YAHOO.util.Dom;
function init(){
var listImageHandler = {
success:function(o) {
var r = eval('(' + o.responseText + ')');
if(!r.hasError) {
var imageListCon = $('imageListCon');
var img = document.createElement('img');
//img.src = 'image.php?i=' + r.imageList[i];
img.src = r.fileName;
imageListCon.appendChild(img);
}
}
};
var onUploadButtonClick = function(e){
var uploadHandler = {
upload: function(o) {
//console.log(o.responseText);
$D.setStyle('indicator', 'visibility', 'hidden');
var r = eval('(' + o.responseText + ')');
if(r.hasError){
var errorString = '';
for(var i=0; i < r.errors.length; i++){
errorString += r.errors[i];
}
alert(errorString);
}else{
YAHOO.util.Connect.asyncRequest('GET', 'UploadFileServlet', listImageHandler);
}
}
};
$D.setStyle('indicator', 'visibility', 'visible');
//the second argument of setForm is crucial,
//which tells Connection Manager this is an file upload form
YAHOO.util.Connect.setForm('testForm', true);
YAHOO.util.Connect.asyncRequest('POST', 'UploadFileServlet', uploadHandler);
};
$E.on('uploadButton', 'click', onUploadButtonClick);
YAHOO.util.Connect.asyncRequest('GET', 'UploadFileServlet', listImageHandler);
}
$E.on(window, 'load', init);
</script>
</head>
<body>
<form action="UploadFileServlet" method="POST" enctype="multipart/form-data" id="testForm">
<input type="file" name="testFile"><br>
<input type="button" id="uploadButton" value="Upload"/>
</form>
<div class="restart">Redo It</div>
<div style="visibility:hidden; margin-bottom:1.5em;" id="indicator">Uploading... <img src="indicator.gif"/></div>
<div id="imageListCon">
</div>
</body>
I am unable to get the response, can anyone help in this please ?
Thanks,
Amit
try this:
http://pixeline.be/experiments/jqUploader/
Due to security limitations, you cannot preview the image on the front-end prior to uploading
If you are already able to upload the image in a folder at your server, you can easily display the image with a image control in your page. Let that folder be a temp folder which you may wish to empty after upload is completed. Then you first upload the file in the temp folder and display it to the user. If the user cancels the operation, you can delete the file from the folder.
But remember this will not be the real image preview as we generally visualize. But since this mimics the image preview, it may be a choice.
I don't know YUI, so I can't go in detail about this, but I can at least tell that there are several flaws in your logic: you're attempting to write the entire binary contents of the image back to the ajax response. This isn't going to work. In HTML you can only display images using an <img> element whose src attribute should point to a valid URL. Something like:
<img src="/images/uploadedimage.jpg">
To achieve this, just store the image at the local disk file system or a database at the server side and give in the ajax response the URL back with which the client can access the image. Let the ajax success handler create a DOM element <img> and fill its src value with the obtained URL.
You'll need to create a Servlet which listens on this URL and get the image as an InputStream from the local disk file system by FileInputStream or from the database by ResultSet#getBinaryStream() and writes it to the OutputStream of the response, along with a correct set of response headers with at least content-type. You can find here an example of such a servlet.
That said, you really don't need the Java 2D API for that. The Image and ImageIcon only unnecessarily adds much overhead. Just get it as an InputStream and write it the usual Java IO way to the OutputStream of the response.

Categories

Resources