diff options
Diffstat (limited to 'documentation/articles/LettingTheUserDownloadAFile.asciidoc')
-rw-r--r-- | documentation/articles/LettingTheUserDownloadAFile.asciidoc | 107 |
1 files changed, 107 insertions, 0 deletions
diff --git a/documentation/articles/LettingTheUserDownloadAFile.asciidoc b/documentation/articles/LettingTheUserDownloadAFile.asciidoc new file mode 100644 index 0000000000..fe54bdfd09 --- /dev/null +++ b/documentation/articles/LettingTheUserDownloadAFile.asciidoc @@ -0,0 +1,107 @@ +[[letting-the-user-download-a-file]] +Letting The User Download A File +-------------------------------- + +Providing a file for download to the user might be trickier that what it +seems - the file should be downloaded instead of just opened by the +browser, download blockers should be avoided, a unique URL should be +generated and server-side memory should be released when the file is no +longer available for download. All this is taken care of by the new +`FileDownloader` extension that can make almost any component start a +download when clicked. + +[source,java] +.... +public class LettingUserDownladFile extends UI { + + @Override + protected void init(VaadinRequest request) { + Button downloadButton = new Button("Download image"); + + StreamResource myResource = createResource(); + FileDownloader fileDownloader = new FileDownloader(myResource); + fileDownloader.extend(downloadButton); + + setContent(downloadButton); + } + + private StreamResource createResource() { + return new StreamResource(new StreamSource() { + @Override + public InputStream getStream() { + String text = "My image"; + + BufferedImage bi = new BufferedImage(100, 30, BufferedImage.TYPE_3BYTE_BGR); + bi.getGraphics().drawChars(text.toCharArray(), 0, text.length(), 10, 20); + + try { + ByteArrayOutputStream bos = new ByteArrayOutputStream(); + ImageIO.write(bi, "png", bos); + return new ByteArrayInputStream(bos.toByteArray()); + } catch (IOException e) { + e.printStackTrace(); + return null; + } + + } + }, "myImage.png"); + } +} +.... + +To use `FileDownloader`, you just create an instance of the extension +and use it to extend the component that should start the download. You +should also note that `FileDownloader` works best with resources that +are served by Vaadin as it relies on sending some special HTTP headers +along with the file to ensure the browser doesn't try to open the file +even if it's is a file type that the browser knows how to deal with. + +[[lazily-determine-the-content-and-the-name-of-the-file-being-server]] +Lazily determine the content and the name of the file being server +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +One can lazily determine the content of the file using a +`StreamResource`. Yet the name of the file that is going to be +downloaded has to be known at creation time of the `FileDownloader`. It +seems that a way around this, is in fact missing from Vaadin 7 as of +now. + +A possible solution is to subclass `FileDownloader` and set the name right +before the download happens: + +[source,java] +.... +/** + * This specializes {@link FileDownloader} in a way, such that both the file name and content can be determined + * on-demand, i.e. when the user has clicked the component. + */ +public class OnDemandFileDownloader extends FileDownloader { + + /** + * Provide both the {@link StreamSource} and the filename in an on-demand way. + */ + public interface OnDemandStreamResource extends StreamSource { + String getFilename (); + } + + private static final long serialVersionUID = 1L; + private final OnDemandStreamResource onDemandStreamResource; + + public OnDemandFileDownloader (OnDemandStreamResource onDemandStreamResource) { + super(new StreamResource(onDemandStreamResource, "")); + this.onDemandStreamResource = checkNotNull(onDemandStreamResource, + "The given on-demand stream resource may never be null!"); + } + + @Override + public boolean handleConnectorRequest (VaadinRequest request, VaadinResponse response, String path) + throws IOException { + getResource().setFilename(onDemandStreamResource.getFilename()); + return super.handleConnectorRequest(request, response, path); + } + + private StreamResource getResource () { + return (StreamResource) this.getResource("dl"); + } +} +.... |