« Open World 2007 Session: Building Secure Ajax Web Applications with ADF Faces RC and ADF Security | Main | ADF Faces: Detecting and handling user session expiry »
ADF Faces: Direct file download through managed bean
By frank.nimphius | August 18, 2007
A usecase that is requested quite often on OTN is how to directly download file content from a managed bean in JavaServer Faces. This requirement is not the same as displaying downloaded content in a JavaServer Faces page. In this usecase the developers want to show a download dialog to the user, ideally being able to propose a filename for the download.
Steve Muench blogged sample 85 about uploading/downloading files to the database and I am sure others provided similar examples. However, if this blogpost is a duplicate then this is in no way a waste of my time because it shows how important the usecase of file downloads in JavaServer Faces is.
The example I use in this blog is as shown in the image below
![]() |
A table contains a column showing a command link for each row to download a related document. In this case the assumption is that there exist a file on the server with the departmentId as the filename. This however would work with any filename you choose as long as it is stored in a table column.
![]() |
To create the download column, I added a ADF Faces table column to the table. Instead of an outputText component, I added an af:commandLink component into the column. A JavaServer Faces parameter element is added as a child of the commandLink. This is required to pass the document name to the server when the user clicks on a link.
-
:column sortProperty="LocationId" sortable="false" -
headerText="download">
-
:commandLink text="Document" -
action="#{DocumentDownload.onDownload}">
-
:param value="#{row.DepartmentId}.pdf" name="document"/> -
:commandLink>
-
:column>
Note that the parameter element has a name and value attribute. The name attribute is accessible from the parameter map of the web request. The value is what we want to access in the managed bean. The document name, as mentioned, is composed out of the departmentId and the "pdf" extension.
The commandLink action property points to an action method in a managed bean.
-
public onDownload() {
-
-
// hard coded in this example. In a production environment, you
-
// want to read the documentName location from a context parameter
-
// in web.xml
-
DOCUMENTS_LOCATION = "c:/temp/documents/";
-
-
FacesContext fctx = FacesContext.getCurrentInstance();
-
// read documentName name from the request
-
ValueBinding documentParameter = fctx.getApplication().createValueBinding("#{param.document}");
-
-
documentName = documentParameter.getValue(fctx);
-
-
if(documentName !=null){
-
srcdoc = new (DOCUMENTS_LOCATION+()documentName);
-
-
if (srcdoc.exists()) {
-
-
fis;
-
byte[] b;
-
-
HttpServletResponse response = (HttpServletResponse) fctx.getExternalContext().getResponse();
-
// file should be downloaded without display
-
response.setContentType("application/x-download");
-
response.setHeader("Content-Disposition", "attachement; filename=\"document"+documentName+".pdf\"");
-
response.setContentLength((new (srcdoc.length())).intValue());
-
out;
-
-
try {
-
out = response.getOutputStream();
-
} catch ( e) {
-
// TODO
-
e.printStackTrace();
-
// no error message shown to the user. Consider adding a Faces
-
// Message
-
return null;
-
}
-
try {
-
fis = new (srcdoc);
-
-
int n;
-
while ((n = fis.available())> 0) {
-
b = new byte[n];
-
int result = fis.read(b);
-
out.write(b, 0, b.length);
-
if (result == -1) break;
-
}
-
}
-
catch ( e)
-
{
-
e.printStackTrace();
-
return null;
-
}
-
try {
-
out.flush();
-
out.close();
-
} catch ( e) {
-
// TODO
-
}
-
fctx.responseComplete();
-
}
-
}
-
-
return null;
-
}
The action method always returns null because there is no navigation associated with the request. The following code snippet shows a JSF value binding that accesses the request parameter "document" that is sent with the request when a user clicked on the ADF Faces command link.
-
FacesContext fctx = FacesContext.getCurrentInstance();
-
// read documentName name from the request
-
ValueBinding documentParameter = fctx.getApplication().createValueBinding("#{param.document}");
-
documentName = documentParameter.getValue(fctx);
The code provides us with the document name in the managed bean. To this time we know which document we are looking for.
In the following code snippet, the response header of the HttpServletResponse is configured to download the file resource. The "application/x-download" type flags the download not to be associated with any application.
-
HttpServletResponse response = (HttpServletResponse) fctx.getExternalContext().getResponse();
-
// file should be downloaded without display
-
response.setContentType("application/x-download");
-
response.setHeader("Content-Disposition", "attachement; filename=\"document"+documentName);
-
response.setContentLength((new (srcdoc.length())).intValue());
The following code line allows developers to set the default name for the downloaded file
-
response.setHeader("Content-Disposition", "attachement; filename=\"document"+documentName);
So instead of downloading the file as .pdf, I prefixed it with the name "document".
The remaining code, not explicitly highlighted here, is to read and download the file content. The important line of code left to mention is
fctx.responseComplete();
to make sure the JSF request lifecyce understands that the response is completed and no further action needs to happen.
Frank
Topics: ADF Faces | No Comments »
Comments are closed.