AJAX update and file download in one blowPage edited by Sven Meieralternative solution with behaviorFollowing example shows how to use an AJAX request to refresh some components and at the same time make the browser ask back for a file to be downloaded. We start with a WebMarkupContainer that is at the same time an IResourceListener import org.apache.wicket.IResourceListener; import org.apache.wicket.markup.html.WebMarkupContainer; /** * @author Ernesto Reinaldo Barreiro ([email protected]) * */ public class DocumentResourceListener extends WebMarkupContainer implements IResourceListener { private static final long serialVersionUID = 1L; private IResourceListener resourceListener; /** * Constructor receiving an IResourceListener.. * * @param id * @param resourceListener */ public DocumentResourceListener(final String id, IResourceListener resourceListener) { super(id); this.resourceListener = resourceListener; } /** * Gets the url to use for this link. * * @return The URL that this link links to */ protected CharSequence getURL() { return urlFor(IResourceListener.INTERFACE); } @Override protected boolean getStatelessHint() { return false; } public void onResourceRequested() { this.resourceListener.onResourceRequested(); } } Next step is to define DynamicWebResource that will serves a PDF file as byteArray. import java.io.ByteArrayOutputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; import org.apache.wicket.markup.html.DynamicWebResource; import org.apache.wicket.protocol.http.WebResponse; /** * @author Ernesto Reinaldo Barreiro ([email protected]) * @author Christian Giambalvo ([email protected]) (extended this class) * */ public class MyPdfResource extends DynamicWebResource { private static final long serialVersionUID = 1L; private byte[] content = null; private String attachmentname = null; /** * */ public MyPdfResource() { } /* (non-Javadoc) * @see org.apache.wicket.markup.html.DynamicWebResource#getResourceState() */ @Override protected ResourceState getResourceState() { return new ResourceState() { @Override public String getContentType() { return "application/pdf"; } @Override public byte[] getData() { try { return MyPdfResource.this.content; } catch (Exception e) { return null; } } }; } public String getAttachmentname() { return this.attachmentname; } public void setAttachmentname(final String name) { this.attachmentname = name; } public void setContent(final byte[] content) { this.content = content; } @Override protected void setHeaders(final WebResponse response) { super.setHeaders(response); response.setAttachmentHeader(this.attachmentname); } } One important bit here is the line response.setAttachmentHeader(this.attachmentname);. Otherwise current page will be replaced instead of browser a "Do you want to download file" window. Then we have the page where the "trick" is performed: import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.ajax.markup.html.AjaxLink; import org.apache.wicket.markup.html.WebPage; import org.apache.wicket.markup.html.basic.Label; import org.apache.wicket.model.AbstractReadOnlyModel; /** * @author Ernesto Reinaldo Barreiro ([email protected]) * @author Christian Giambalvo ([email protected]) (simplified this class) */ public class TestPage extends WebPage{ private DocumentResourceListener documentResourceListener; private final MyPdfResource pdf; /** * */ public TestPage() { AjaxLink<Void> link = new AjaxLink<Void>("link") { private static final long serialVersionUID = 1L; @Override public void onClick(AjaxRequestTarget target) { if(target!= null) { target.addComponent(this); String fileName = "MyPdfFile.pdf"; pdf.setAttachmentname(fileName); // PdfHelper.generatePdf converts a file into a byte[]. pdf.setContent(PdfHelper.generatePdf(fileName)); String url = "" target.appendJavascript(";window.location.href='';"); } } }; this.add(link); this.documentResourceListener = new DocumentResourceListener("listener", this.pdf); this.add(documentResourceListener); } } The trick is just the lines:
@Override
public void onClick(AjaxRequestTarget target) {
if(target!= null) {
target.addComponent(this);
String fileName = "MyPdfFile.pdf";
pdf.setAttachmentname(fileName);
// PdfHelper.generatePdf converts a file into a byte[].
pdf.setContent(PdfHelper.generatePdf(fileName));
String url = ""
target.appendJavascript(";window.location.href='';");
}
}
This will make the browser send back a request to documentResourceListener component who will then stream And for sake of completeness the HTML of the TestPage page: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns:wicket="org.apache.wicket"> <head> </head> <body> <a wicket:id="link">Click Me</a> <div wicket:id="listener"></div> </body> </html> Note: I have tested this with FF-3.5, IE-7 and Chrome. I hope it works fine with other browsers, browser-versions, as well! Alternative with behaviorUtilizing a behavior might be a better alternative: import org.apache.wicket.ajax.AjaxRequestTarget; import org.apache.wicket.behavior.AbstractAjaxBehavior; import org.apache.wicket.request.target.resource.ResourceStreamRequestTarget; import org.apache.wicket.util.resource.IResourceStream; public abstract class AJAXDownload extends AbstractAjaxBehavior { public void initiate(AjaxRequestTarget target) { CharSequence url = "" target.appendJavascript("window.location.href=''"); } public void onRequest() { getComponent().getRequestCycle().setRequestTarget( new ResourceStreamRequestTarget(getResourceStream())); } protected abstract IResourceStream getResourceStream(); } You can add this behavior to any component, so you probably don't need to maintain additional state inside your components to identify the resource to download. final AJAXDownload download = new AJAXDownload() { @Override protected IResourceStream getResourceStream() { return createResourceStream(item.getModelObject()); } }; item.add(download); item.add(new AjaxLink<Void>("link") { @Override public void onClick(AjaxRequestTarget target) { download.initiate(target); } }); All you have to do is to create an IResourceStream (e.g. a FileResourceStream) to serve the actual content.
Change Notification Preferences
View Online
|
View Change
|
Add Comment
|
- [CONF] Apache Wicket > AJAX update and file download in one ... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
- [CONF] Apache Wicket > AJAX update and file download in... confluence
