In addition to the below diagram (click to enlarge) note that Spring MVC controllers are singletons and should be kept stateless.
I had a form working in the Spring MVC way (Models, Validators and all) and was asked to add
a file upload field. I.e. an <input>
element with type='file'
For that it was necessary to change the form from the following:
<form:form id='the-form' modelAttribute="newAccountView" action="submit.do" method="POST">
… to the following:
<form:form id='the-form' modelAttribute="newAccountView" action="submit.do" method="POST" enctype="multipart/form-data">
This is very clearly stated in a number of guides.
However, this alone does not work as I was met by a number of weird NPE exceptions (on the validators of that model). This was due to the fact that Spring was unable to retrieve any of the parameters present in the form due to the change of the form encoding (from the default application/x-www-form-urlencoded to multipart/form-data)
To fix that I had to setup a multi-part resolver with my Spring application.
So I added the following to my mvc-dispatcher-servlet.xml
:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"> <!-- one of the properties available; the maximum file size in bytes --> <property name="maxUploadSize" value="30000000"/> </bean>
I also had to add the following dependency to my Ivy:
<dependency org="commons-fileupload" name="commons-fileupload" rev="1.3.3" conf="run-time->default"/>
After doing the above, I added a org.springframework.web.multipart.MultipartFile
field in my Spring MVC
model class for that view
Inside, the controller it wasn't necessary to change the signature of the method at all. I was simply able to access the blob doing a:
myViewModel.getCv().getSize()(where
cv
was the field I added to my view model)
For completeness purposes, here's a simplified view of my method inside the controller:
@RequestMapping(path="/submit", method=RequestMethod.POST) public String submit(HttpServletRequest request , @ModelAttribute("myModel") @Valid MyViewModel myViewModel , BindingResult result , Model model) { ... System.out.printf("%d bytes retrieved.\n", myViewModel.getCv().getSize()); ... }
NB: At the time of this writing I have not yet experimented using the alternative multi-part resolver
provided by Spring: the StandardServletMultipartResolver
one for Servlet 3.0 — see the source.
Checkout this project in my playground that shows how to deploy a simple Spring MVC application with a database back-end in JBoss (tested against JBoss EAP 6.4)