Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Using a commandButton in a jsf Page to download a file

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.

like image 583
M.R. Avatar asked Dec 02 '10 14:12

M.R.


2 Answers

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.

like image 148
BalusC Avatar answered Oct 22 '22 21:10

BalusC


<h:commandButton id="getDownload" value="download"  action="#{controller.download()}"   >

</h:commandButton>
public class Controller {

OutputStream out = null;
String filename = "ali.pdf";
public void download() throws IOException {



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

    ZipOutputStream zipout = new ZipOutputStream(out);




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







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

    }

}
like image 5
mahmut Avatar answered Oct 22 '22 20:10

mahmut