JSF, Ajax and file download
Today I show you a example which combines Ajax (Richfaces) and a „normal“ download in a JSF application.
Here is the bean with the download-code:
import java.io.File; import java.io.IOException; import javax.faces.context.FacesContext; import javax.faces.event.ActionEvent; import javax.servlet.http.HttpServletResponse; public class DownloadBean { // actionListener="#{bean.execute}" public void execute (ActionEvent event) { download(); } // action="#{bean.download}" public String download() { final FacesContext facesContext = FacesContext.getCurrentInstance(); // XXX create temp. filecontent ... resultFile writeOutContent(getServletResponse(), new File(this.resultFile), "file.xml"); facesContext.responseComplete(); // dont use jsf-navigation-rules return null; } void writeOutContent(final HttpServletResponse res, final File content, final String theFilename) { if (content == null) return; try { res.setHeader("Pragma", "no-cache"); res.setDateHeader("Expires", 0); res.setContentType("text/xml"); res.setHeader("Content-disposition", "attachment; filename=" + theFilename); fastChannelCopy(Channels.newChannel(new FileInputStream(content)), Channels.newChannel(res.getOutputStream())); } catch (final IOException e) { // TODO produce a error message 🙂 } } void fastChannelCopy(final ReadableByteChannel src, final WritableByteChannel dest) throws IOException { final ByteBuffer buffer = ByteBuffer.allocateDirect(16 * 1024); while (src.read(buffer) != -1) { buffer.flip(); dest.write(buffer); buffer.compact(); } buffer.flip(); while (buffer.hasRemaining()){ dest.write(buffer); } } }
Now the facelets snipplets: Not Working – Javascript Error 😦
<h:form> <h:commandLink actionListener="#{command.execute}" value="Download"/> <h:commandLink action="#{command.download}" value="Download"/> </h:form>
Not Working – Download is shown in the current page – the ajax page will replaced with the download-content 😦
<a4j:form> <a4j:commandLink actionListener="#{command.execute}" value="Download"/> <a4j:commandLink action="#{command.download}" value="Download"/> </a4j:form>
Working 🙂
<a4j:form> <a4j:htmlCommandLink actionListener="#{command.execute}" value="Download"/> <a4j:htmlCommandLink action="#{command.download}" value="Download"/> </a4j:form>
<h:form> <a4j:htmlCommandLink actionListener="#{command.execute}" value="Download"/> <a4j:htmlCommandLink action="#{command.download}" value="Download"/> </h:form>
The a4j:htmlCommandLink was made for this szenario.
Notice: the fast channel copy routine was introduced by waffel.
walthersoft 13:51 am Freitag, 11. Juli 2008 Permalink | Zum Antworten anmelden
Nice, was looking for something like this. However, it doesn’t compile, where do you get ‚getServletResponse()‘ in your download() method from ?
Andreas Höhmann 7:48 am Donnerstag, 31. Juli 2008 Permalink | Zum Antworten anmelden
Its a private method wich return the current HttpServletResponse, i haven’t posted because the code is very easy
Dummal 15:38 am Mittwoch, 23. Dezember 2009 Permalink | Zum Antworten anmelden
You saved my day… man!
thanx a bunchh!
ajayjiit 13:42 am Donnerstag, 8. Juli 2010 Permalink | Zum Antworten anmelden
Hi can you list down the which packages classes ti be imported and zars required.
iam not able to run it
Andreas Höhmann 20:06 am Freitag, 9. Juli 2010 Permalink | Zum Antworten anmelden
I fixed the bean source code … without test … you have search the Cannel import by yourself 🙂 Have a look at waffel’s article.