Handling file upload with gwt-ext and spring mvc

Finally i managed to get file upload works using a gwt-ext client against spring mvc.
In GWT application file upload is something different,
you cannot do so through GWT-RPC due to the browser implementation.
File upload is only achievable through multipart form post.

On the client side you have to set up a form:


final FormPanel formPanel = new FormPanel();
// setFileUpload(true) is important because it sets the
// <form>'s content type to multipart
// so that your server knows what to do
formPanel.setFileUpload(true);

final TextField file = new TextField("File", "file");
file.setInputType("file");
formPanel.add(file);

formPanel.addButton(new Button("Upload", new ButtonListenerAdapter() {
    public void onClick(Button button, EventObject e) {
        formPanel.getForm().submit(url, null, Connection.POST, "loading...", false);
    }
}));

in the spring servlet config,
you will have to map the url you are POST-ing against to a controller that is responsible for handling file upload.


<!-- specify the java bean to bind the file upload as a byte array in the property 'commandClass" -->
<bean id="fileUploadController" class="example.server.FileUploadController">
	<property name="commandClass" value="example.web.bean.FileUploadBean"/>
</bean>
<bean class="org.springframework.web.servlet.handler.SimpleUrlHandlerMapping">
    <property name="mappings">
        <value>
            /**/fileupload.smvc=fileUploadController
        </value>
    </property>
</bean>
<!-- this bean is how spring mvc detects multipart form post -->
<!-- commons-fileupload jar is required for this bean to work -->
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
	<property name="maxUploadSize" value="100000"/>
</bean>

finally the controller code is easy,
at first I tried to subclass SimpleFormController,
but it involves specifying a formView and successView,
which, for a GWT client you are not going to need “view”.
so I simply extend the AbstractCommandController.
It binds the request parameters of a POST request to a commandClass,
this serves my purpose nicely.


public class FileUploadController extends AbstractCommandController {

    protected ModelAndView handle(HttpServletRequest request, HttpServletResponse response, Object command, BindException errors) throws Exception {
        // you will need to cast the command back to your commandClass
        FileUploadBean fileUploadBean = (FileUploadBean) command;
        byte[] file = fileUploadBean.getFile();

        // do whatever logic you needed
        // because we are not going to return a "view"
        // we simply have to give out some response to the GWT client and return a null view.
        response.getWriter().println("File upload succeeded!");

        return null;
    }

    // this method is overriding, and specify how spring convert multipart into a byte array that binds to our command class
    protected void initBinder(HttpServletRequest request, ServletRequestDataBinder binder) throws Exception {
	    binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
	    super.initBinder(request, binder);
    }
}

Integrating with spring mvc provides you free infrastructure of data binding, dependency injection on the controller,
and validation with spring’s Validator.

Hope this helps.

1 Comment so far

  1. bkabs on May 23, 2008

    Hi budy,

    Nice piece of work. I never thought it would look this nice. One question. Am having trouble binding a n object with nested collections to the FormPanel for a CRUD application using the free infrastructure of data binding in spring. Like we do with the nested tag in SpringMVC. Any suggestion on how you would work around that? Any example like above?

    Good day and thanks in anticipation.

Leave a reply