PDA

View Full Version : Download a blob file using YUI?



Topper
26 Oct 2007, 3:25 PM
Hello. I have some files stored in the databse. I also have a java action that get's the file bytes, set's the headers accordingly and opens a 'download file'. Im trying to make it work with Ext. Until now I only managed to get the reponse headers to my Ext app, but not the file.

Here's the code until now:



function downloadSuccess(o){
if(o.responseText){
alert(o.getAllResponseHeaders);
}
}

var downloadButton = new Ext.Button({
handler: function(){
YAHOO.util.Connect.asyncRequest('GET', 'download.do?id='+fileId, {
success: downloadSuccess
});
},
scope: this,
iconCls:'save',
tooltip: '<b>Descargar Archivo</b><br/>Descarga el archivo a su PC.',
renderTo: Ext.get('dldTd'+fileId)
});


Any example arround?

Thx in advance.

Animal
26 Oct 2007, 10:42 PM
o.responseText is the response text. What do you want to do with it?

Topper
27 Oct 2007, 4:20 AM
The stuff inside the 'downloadSuccess' function is only temporal...I didnt know what to do so I started to write several alerts to see what was the response.

Here's the download action. As you can see, it configures the header to be an attachment and sends the file to the response. This action works if you run it directly (like http://localhost/topper/download.do?id=someId), and it opens the classic navigator's "download file". What I want to do is to handle the response inside Ext and, if success, open the 'download file' inside my Ext application. I could just put a normal link to this action inside my Ext app but my idea is to check several things in this action (like user logged in, etc) and handle some success/failures callbacks with Ext, and not with java.

Please be aware that "Archivo" is the spanish word to "File". So "ArchivoManager" is a "FileManager" that returns the file's content stored inside the database.



public class DownloadAction extends Action {

public ActionForward execute(ActionMapping mapping, ActionForm form,
HttpServletRequest request, HttpServletResponse response)
throws Exception {

String id = request.getParameter("id");

ArchivoManager aMan = new ArchivoManager();
Archivo a = aMan.getArchivo(Integer.valueOf(id).intValue());

String nombreArchivo = a.getNombre();
String contentType = a.getTipo();
InputStream stream = new ByteArrayInputStream(a.getData());

try {
response.setHeader("Content-Disposition","attachment; filename=\"" + nombreArchivo + "\"");
response.setContentType(contentType);
copy(stream, response.getOutputStream());
} catch (Exception e) {
e.printStackTrace();
} finally {
if (stream != null) {
stream.close();
}
}

return null;

}

public static int copy(InputStream input, OutputStream output)
throws IOException {
byte[] buffer = new byte[1024 * 4];
int count = 0;
int n = 0;
while (-1 != (n = input.read(buffer))) {
output.write(buffer, 0, n);
count += n;
}
return count;
}

}


Regars!
Topper

Animal
27 Oct 2007, 4:39 AM
Why are you posting server-side code?

You load some bytes using Ajax, what do you then want to do with them?

Topper
27 Oct 2007, 4:42 AM
Why are you posting server-side code?

You load some bytes using Ajax, what do you then want to do with them?

I just want to open the browser's 'download file' screen.

I know the bytes are loaded, what I dont know is how to handle them.

Animal
27 Oct 2007, 4:44 AM
The user has to click on a link for that to happen.

Topper
27 Oct 2007, 4:52 AM
I thought the 'downloadButton' button could act as the link.

Can't be done then? :/

Thx

Animal
27 Oct 2007, 5:22 AM
Just create a link!

Use a custom button template with an <A> element as the clickable.

Animal
27 Oct 2007, 5:28 AM
var linkButtonTpl = new Ext.Template(
'<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>' +
'<td class="x-btn-left"><i> </i></td><td class="x-btn-center">' +
'<a href="{1}">{0}</a>' +
'</td><td class="x-btn-right"><i> </i></td>' +
'</tr></tbody></table>');

var b = new Ext.Button({
template:imgButtonTpl,
buttonSelector: "a",
text: 'Click me',
type: '/download.do?id=' + theId
});

Topper
29 Oct 2007, 6:33 AM
var linkButtonTpl = new Ext.Template(
'<table border="0" cellpadding="0" cellspacing="0" class="x-btn-wrap"><tbody><tr>' +
'<td class="x-btn-left"><i> </i></td><td class="x-btn-center">' +
'<a href="{1}">{0}</a>' +
'</td><td class="x-btn-right"><i> </i></td>' +
'</tr></tbody></table>');

var b = new Ext.Button({
template:imgButtonTpl,
buttonSelector: "a",
text: 'Click me',
type: '/download.do?id=' + theId
});


I tried that...the problem is that I that the download action has to make several checks before opening the browsers's 'download file' window. For example, if the user isn't logged in, it should return a {failure} callback that opens a login window or shows an error. And only if the callback is {success} it should open the 'download file' window. And I want all that checks in the same action that opens the browser 'download file' to avoid people calling that url directly and downloading files they should't download without being logged in for example.

Thanks anyway.

Animal
29 Oct 2007, 7:11 AM
You cannot do it like that. Thje only way to download is have the user click a link, an <A> element. You will have to use a custom button.

Only create the button if they are logged in.

devnull
29 Oct 2007, 8:57 AM
If you want it to be secure, you have to duplicate the security on the server side; javascript is easy to read and manipulate, and as such the link to the download will be easy enough to find. security by obscurity is seldom an acceptable policy ;)
also because of security concerns, the javascript engine in the browser has absolutely no access to the local file system, which means it cannot nor will it likely ever be able to save or read files. this includes showing a "save as" dialog.
the only way is to create a direct link to the file or do a redirect to it. I use the redirect method, which is accomplished hidden iframe on the page to prevent a real redirect.

parveenbeniwal
25 Jan 2008, 3:14 AM
devnull,

can u post some example code. How to achieve virtual redirect with the iframe.
Thanks in advance.

devnull
25 Jan 2008, 8:47 AM
sure thing! this is from my current Ext 1 app, but i think it will work in Ext 2 as well. I use it to return excel spreadsheets.
In an init function somewhere:


var xlsLoad = Ext.DomHelper.append(document.body, {
tag: 'iframe',
frameBorder: 0,
width: 0,
height: 0,
css: 'display:none;visibility:hidden;height:1px;'
});

Then when you want to use it:


xlsLoad.src='handler.php?getSpreadsheet';

I found i also had to make the url unique by appending a timestamp or IE would just return cached results.

parveenbeniwal
28 Jan 2008, 11:11 PM
sorry for late reply. I am posting my code in which I am getting URL of a file and using that as src of iframe. I am creating a file on server on ajax request and returning URL in response. I have checked that file is being created and is accessible.

response is like : {'success':'true','url':'files/test.html'}

One more question here url should be absolute or can use relative URL ?

One doubt also I am sending url of a html file. Will it make some difference ?


var downloadLink = Ext.DomHelper.append(document.body, {
tag: 'iframe',
frameBorder: 0,
width: 0,
height: 0,
css: 'display:none;visibility:hidden;height:1px;'
});

var shwButton = new Ext.Button({
text: 'Hello',
minWidth: 100,
renderTo: 'btns',
handler: function(){
Ext.Ajax.request({
url: 'DataSource.do',
params: {
OBJECTTYPE: 'Sample web page',
OBJECTID: 1,
ACTION: 'DOWNLOAD'
},
success: function(response, options){
var evaluatedObject = Ext.util.JSON.decode(response.responseText);
var record = new Ext.data.Record(evaluatedObject);
downloadLink.src = record.get('url');
},
failure: function(response, options){
alert(" FAILURE " + response.responseText);
}
});
},
tooltip: 'Download File'
});Thanks

parveenbeniwal
28 Jan 2008, 11:18 PM
My mistake :">. Now I can answer my questions myself, please make me correct if i m getting something wrong.

One more question here url should be absolute or can use relative URL ?
Yes we can use relative URL.

One doubt also I am sending url of a html file. Will it make some difference ?
Yes it makes difference,as if we are sending other than .html or .txt download popup appears. May be for some other extensions too ;) as I have checked for above two only.


How can I have the download popup for html/text files ?

Thanks