Using a commandButton in a jsf Page to download a file

M.R. picture M.R. · Dec 2, 2010 · Viewed 24.5k times · Source

Using a commandButton in a jsf Page to download a file. Using: JSF & Richfaces.

I have a table (extends ExtendedDataModel implements Modifiable, Serializable) with some data and in each row a button "download".

<a4j:commandButton id="getDownload" value="download" 
    style="margin-left:10px;margin-right:10px;width:100px;"
    action="#{controller.download}" immediate="true" ajaxSingle="true">
    <f:setPropertyActionListener target="#{controller.idString}" value="#{item.id}" />                     
</a4j:commandButton>

I have to build the file in the controller:

public void download(){
 OutputStream out = null;
....

FacesContext fc = FacesContext.getCurrentInstance();
HttpServletResponse response = (HttpServletResponse) fc.getExternalContext().getResponse();
out = response.getOutputStream();

ZipOutputStream zipout = new ZipOutputStream(out);
.....

zipout.close();
response.setContentType("application/octet-stream");
response.addHeader("Content-Disposition", "attachment; filename=\""+filename+"\"");
out.flush();
....

} finally {
    try {
        if (out!=null){
            out.close();
        }
        FacesContext.getCurrentInstance().responseComplete();
    } catch (IOException e) {
        logger.error(e);
    }

}
...
}

The Problem started, when I implemented the ExtendedDataModel my self. At first i used h:commandLink, but the controller method was never called... i tried and tried... now the correct method is called, but the (zip) file content is displayed in the page. I want a button/link in the page, which the user can click to download the file. The page itself should not change. Any ideas?

I can create a servlet, but i do not understand why the ExtendedDataModel changed the behavior of the links inside.

Edit1

I used

<h:commandLink id="getDownload" value="download" action="#{controller.download}">                                                       
                            <f:setPropertyActionListener target="#{controller.idString}" value="#{item.id}" />                              
                        </h:commandLink>

before. It works with the "normal" richfaces table, but not when i used it inside my own table which extends ExtendedDataModel.

Edit 2 - Solution/Workaround

It is impossible to use the h:commandButton, .. Link... whatever inside of the self made table, to download a file. I am now using one button in the table to render a new PanelGroup and a second button inside of the new PanelGroupt to download the file. I googled a lot for this, seems like a rich faces bug.

Answer

BalusC picture BalusC · Dec 2, 2010

You can't download a file by ajax request. Replace a4j:commandButton by h:commandButton.


Update as per your question update: to get command links/buttons inside an UIData component such as <h:dataTable>, <rich:dataTable>, etc to work, you need to ensure that the bean which is holding the data model (whatever is behind the value attribute of the UIData component) is preserving exactly the same data model during the request of the form submit. If you want to keep your bean request scoped, then the easiest way is to reference the bean in an <a4j:keepAlive> tag.