I want to build a simple file upload functionality using Spring MVC.
I have the multipartResolver in place and working:
<bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="10240000"/>
</bean>
When uploading a file this is logged:
DEBUG:[org.springframework.web.multipart.commons.CommonsMultipartResolver]: Found multipart file [imageUpload] of size 29081 bytes with original filename [xyz.jpg], stored at [/home/myuser/workspace/myProject/target/tmp/upload_67f1107c_1b8f_402c_bebd_6cd8a6e4c830_00000032.tmp]
which tells me that it's basically working.
This is part of my JSP:
<form:form modelAttribute="placeForm" action="/platz/save" method="post" cssClass="placeForm" enctype="multipart/form-data">
...
<label for="imageUpload">Upload</label>
<form:input type="file" path="imageUpload" id="imageUpload" accept="image/*" />
...
</form:form>
This is my model attribute object's class:
public class PlaceEditForm
{
@Valid
private Place place = new Place();
private Map<Integer, PlaceFeature> features;
private MultipartFile imageUpload;
... getter/setter omitted...
}
And this is part of my Controller method:
@RequestMapping(value="/save", method=RequestMethod.POST)
public String savePlace (@Valid @ModelAttribute("placeForm") PlaceEditForm form, BindingResult result)
{
logger.debug("saveNewPlace");
logger.debug("Upload: "+form.getImageUpload()); // null
...
return "redirect:/platz/"+place.getPlaceId();
}
What happens is, that the imageUpload attribute of the form object is not populated (null), whereas all other form properties are.
I found that it does work when I use this in the controller:
@RequestMapping(value="/save", method=RequestMethod.POST)
public String savePlace (@Valid @ModelAttribute("placeForm") PlaceEditForm form, BindingResult result, @RequestParam("imageUpload") MultipartFile upload, BindingResult uploadResult)
{
logger.debug("saveNewPlace");
logger.debug("Upload: "+upload); // Works!!
...
return "redirect:/platz/"+place.getPlaceId();
}
So, having the MultipartFile as a @RequestParam
works, but binding it to the form's modelAttribute
object doesn't. I found hundreds of examples on the web that do about the same and I don't find the difference.
I'm still learning Spring, so I might miss a very obvious point. I could just use the second version of the controller, but I don't understand it, and as I said, I'm learning.
Shouldn't all the <form:input path="abc">
properties inside the <form:form modelAttribute="xyz">...</form:form>
be bound to xyz.abc
? It works like this for all properties except the file upload.
Any insights? Thanks
I found the problem:
I had a method like this in the controller, but forgot to add the imageUpload
property.
Very stupid and easy once found..!
@InitBinder
public void initBinder(WebDataBinder binder)
{
binder.setAllowedFields("place.placeId", "place.name", "place.description", "place.directions", "place.coordinates*", "features*", "tmpFiles*", "removeFiles*");
}
This prevents the binder to bind any other properties to the modelAttribute than the ones specified. Very important security measure to prevent evildoers from feeding in dangerous information into your system, when you only validate what you expect to be on the front-end.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With