Instead of writing to a file, I want the user is prompted to open or download the file. I tried with StreamResource, but I couldn’t find the way, because it seems to be built for InputStream and not for OutputStream.
Can anyone help me?
Thank you, Francesco
We do this in our application; I suspect there is an easier way to do it, but what we do is this.
We write the excel file to a temporary file.
We’ve create a DownloadResource that takes the data from a file, and a DeletingFileInputStream that deltes the file when it is closed.
Cut-n-pasted code below
File tempFile = File.createTempFile("tmp", ".xls");
// Create contents here, using POI, and write to tempFile
TemporaryFileDownloadResource resource = new TemporaryFileDownloadResource(getApplication(),
"default-name-of-file.xls", "application/vnd.ms-excel", file);
getWindow().open(resource, "_self");
Classes referred to :
public class TemporaryFileDownloadResource extends StreamResource {
private final String filename;
private String contentType;
public TemporaryFileDownloadResource(Application application, String fileName, String contentType, File tempFile) throws FileNotFoundException {
super(new FileStreamResource(tempFile), fileName, application);
this.filename = fileName;
this.contentType = contentType;
}
public DownloadStream getStream() {
DownloadStream stream = new DownloadStream(getStreamSource().getStream(), contentType, filename);
stream.setParameter("Content-Disposition", "attachment;filename=" + filename);
// This magic incantation should prevent anyone from caching the data
stream.setParameter("Cache-Control", "private,no-cache,no-store");
// In theory <=0 disables caching. In practice Chrome, Safari (and, apparently, IE) all ignore <=0. Set to 1s
stream.setCacheTime(1000);
return stream;
}
private static class FileStreamResource implements
StreamResource.StreamSource {
private final InputStream inputStream;
public FileStreamResource(File fileToDownload)
throws FileNotFoundException {
inputStream = new DeletingFileInputStream(fileToDownload);
}
public InputStream getStream() {
return inputStream;
}
}
/**
* This input stream deletes the given file when the InputStream is closed; intended to be used with temporary files.
*
*/
public class DeletingFileInputStream extends FileInputStream {
protected File file = null;
public DeletingFileInputStream(File file) throws FileNotFoundException {
super(file);
this.file = file;
}
@Override
public void close() throws IOException {
super.close();
file.delete();
}
}
Thanks so much to Charles Anthony for that example code. I got it to work for downloading PDF documents stored outside the web server’s purview.
Question:
How can I make this open in a new browser window?
Despite your code setting “Content-Disposition”, on some browsers the file is opened in a browser window rather than being saved. For example, I am seeing this behavior in iPad > Safari and Eclipse > built-in browser (WebKit?). That show-on-screen behavior would be OK, except that when the user hits the browser’s Back button the Vaadin app restarts. Restarting Vaadin app is a bad thing. Opening the loaded file in a new separate browser window would solve that problem. But I’m not savvy enough about web technology to know how to force a separate window.
Some googling led me to tips about using an attribute of target=‘_blank’ on an HTML ‘href’ tag as shown in the following snippet. But I have no idea how to translate that to this Vaadin programmatically controlled download.
<a
href="http://www.pageresource.com/linkus.htm"
target="_blank"
>
Link to us!</a>
Thank you for that information. I did not know about this feature of HTML. And I did not realize that the answer was outside the "
TemporaryFileDownloadResource " class, and was actually in the line:
getWindow().open(resource, "_self");
What I learned…
In a normal web page (outside Vaadin), you can have a ’
target ’ attribute on an ’
a ’ tag, to ask the web browser to open the link in a certain way. Example:
<a href="http://www.example.com/" [color=#00eb17]
target="[color=#e00101]
_blank
[/color]"
[/color]>Visit Example Company!</a>
Values for “target” include:
•
_blank
This asks the browser to open the link in a new browser window (or tab).
•
_self
This asks the browser to open the link in the same browser window.
Vaadin is setting these target values on your behalf when you pass the desired value as the window name argument in the call to
Window.open() .
Keep in mind that setting this
target value is only a request we are making of the web browser. Web browsers (or other ‘user agents’) are free to do what ever they want. Such is life as a web app programmer.
So here is my source code for calling my modified version of download resource class. I modified it to not delete the files after downloading. In this example I am letting the user download a PDF file.
Button downloadButton = new Button( "Bogus download…" );
downloadButton.addListener( new Button.ClickListener() {
@Override
public void buttonClick( ClickEvent event ) {
String filePath = "/Users/basilbourque/Desktop/my_important_document.pdf";
File file = new File( filePath );
FileDownloadResource resource = null;
try {
resource = new[color=#00d824]
FileDownloadResource( getApplication(), "My Important Document 2012.pdf", "application/pdf", file );
[/color]
} catch ( FileNotFoundException e ) {
// TODO Auto-generated catch block
e.printStackTrace();
}
getWindow().open( resource, [color=#d80000]
"_blank"
[/color] ); // "_self" = same browser window. "_blank" = new browser window/tab.
System.out.println( "DEBUG - Finished downloading PDF file. " + new DateTime().toString() );
}
} );
this.addComponent( downloadButton );