Sunday, 29 March 2015

Advanced File download with PrimeFaces

Introduction


When your Web application needs to send a file to the browser, the classic approach is using a web servlet to serve the contents.
PrimeFaces has a specific tag for downloading a file, so that you don't need a servlet. And with a small trick, you can even update the screen in the same action.

FileDownload component

The example with the servlet can be skipped, I guess. Everyone created already a servlet which is able to send content to the browser.
When you are working with JSF, and PrimeFaces, there is an alternative for the servlet approach.
PrimeFaces has the FileDownload component. It is an ActionListener, so you can use it on a commandButton to perform the download.

Let's have an example.
<p:commandButton value="Download" ajax="false">
    <p:fileDownload value="#{fileBean.file}"/>
</p:commandButton>

@ManagedBean(name = "fileBean")
@RequestScoped
public class FileDownloadController {

    public StreamedContent getFile() {
        InputStream stream = this.getClass().getResourceAsStream("/yourfile.txt");        return new DefaultStreamedContent(stream, "text/plain", "downloaded_file.txt");    }
    
}

The StreamedContent, already used by the graphicImage component, contains the data which is send to the browser. You can supply the constructor with an InputStream which has the actual contents.

This can be static file or a dynamically generated one. The PrimeFaces code is then responsible for reading from the InputStream and send it to the browser. Together with the required housekeeping like setting the mime type, http status and setting the JSF response as completed.

Advanced use case

Together with file download, there are use cases where you also need to update the screen which initiated the download.
Recently we had the use case where the end user can specify some options of the file he wants to download.  The options are presented in a dialog which should be preferably closed when the download is performed. Also the screen should be indicate the file download occurred.

Here the RemoteCommand is the solution to these cases.  The RemoteCommand allows to call some JSF bean methods and JSF lifecycle methods from JavaScript.

<p:commandButton value="Download2" ajax="false" onclick="pageRefresh();">
    <p:fileDownload value="#{fileBean.file}"/>
</p:commandButton>
<p:remoteCommand update="@all" name="pageRefresh"/>

When we click on the button, the onClick activates the javaScript version of the RemoteCommand and initiates a AJAX partial page refresh of the screen. On the other hand, the click on the button also initiates the ActionListener of the FileDownload component to perform the file download.

Since we where able to initiate 2 calls, we can perform 2 actions, the download and the screen update.

Conclusion

With the help of the FileDownload component it becomes easier to program the download of a static or dynamic file in JSF. You no longer need a servlet to perform these kind of actions.
With the help of the very broad useable RemoteCommand component, we can even initiate 2 actions.  The file download and some screen updates.