Following 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:

	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)
		{
			// do whatever with the target, e.g. refresh components
			target.add(...);

			// finally initiate the download
			download.initiate(target);
		}
	});

We have to add a custom behavior which enables us to initiate the download after the AJAX request has been completed. The overridden hook method provides an IResourceStream (e.g. a FileResourceStream) to serve the actual content.

import org.apache.wicket.ajax.AjaxRequestTarget;
import org.apache.wicket.behavior.AbstractAjaxBehavior;
import org.apache.wicket.request.handler.resource.ResourceStreamRequestHandler;
import org.apache.wicket.util.resource.IResourceStream;

/**
 * @author Sven Meier
 * @author Ernesto Reinaldo Barreiro (reiern70@gmail.com)
 * @author Jordi Deu-Pons (jordi@jordeu.net)
 */
public abstract class AJAXDownload extends AbstractAjaxBehavior
{
        private boolean addAntiCache;

        public AJAXDownload() {
    	    this(true);
    	}
    	
	public AJAXDownload(boolean addAntiCache) {
	    super();
	    this.addAntiCache = addAntiCache;
	}

	/**
	 * Call this method to initiate the download.
	 */
	public void initiate(AjaxRequestTarget target)
	{
		String url = getCallbackUrl().toString();

                if (addAntiCache) {
		    url = url + (url.contains("?") ? "&" : "?");
		    url = url + "antiCache=" + System.currentTimeMillis();
		}
 
                // the timeout is needed to let Wicket release the channel
                target.appendJavaScript("setTimeout(\"window.location.href='" + url + "'\", 100);");
	}

	public void onRequest()
	{
		ResourceStreamRequestHandler handler = new ResourceStreamRequestHandler(getResourceStream(),getFileName());
		handler.setContentDisposition(ContentDisposition.ATTACHMENT);
		getComponent().getRequestCycle().scheduleRequestHandlerAfterCurrent(handler);
	}

	/**
	 * Override this method for a file name which will let the browser prompt with a save/open dialog.
	 * @see ResourceStreamRequestTarget#getFileName()
	 */
	protected String getFileName()
	{
		return null;
	}

	/**
	 * Hook method providing the actual resource stream.
	 */
	protected abstract IResourceStream getResourceStream();
}
  • No labels

2 Comments

  1. @ Ernesto Reinaldo Barreiro

    What is the license that you would want to put this tool under?

    Best Regards,

    Wei

    1. I'm not the only contributor. Original idea/version was mine but Sven and Martin, and others, have improved on it. For me same licence as Wicket would be fine.

      Best Regards,

      Ernesto