PDA

View Full Version : WebDataBinder.setBindEmptyMultipartFiles not working


kramer
Mar 4th, 2008, 09:03 PM
Hi all,

I'm trying to switch off binding empty multipart files in order to facilitate editing a form containing 2 images. See the initBinder() near the end. According to the javadoc, that should do what I want, but when I processSubmit(), if either of the 2 file uploads are empty, but there is already an image stored in the DB for them, then it incorrectly binds the empty multipart to my command object. This is my controller, big thanks to anyone who can help:


package org.z.controller;

import java.io.IOException;
import java.io.OutputStream;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpSession;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.springframework.beans.factory.annotation.Autow ired;
import org.springframework.beans.factory.annotation.Quali fier;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.util.FileCopyUtils;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder ;
import org.springframework.web.bind.annotation.ModelAttri bute;
import org.springframework.web.bind.annotation.RequestMap ping;
import org.springframework.web.bind.annotation.RequestMet hod;
import org.springframework.web.bind.annotation.RequestPar am;
import org.springframework.web.bind.support.SessionStatus ;
import org.springframework.web.multipart.support.ByteArra yMultipartFileEditor;
import org.z.model.Article;
import org.z.model.ArticleDAO;
import org.z.model.User;
import org.z.validator.ArticleValidator;

@Controller
public class ArticleController {

protected final Log logger = LogFactory.getLog(getClass());

@Autowired
ArticleDAO articleDao;

@Autowired
@Qualifier("articleView")
String articleView;

@Autowired
@Qualifier("editArticleView")
String editArticleView;

@Autowired
@Qualifier("articleListView")
String articleListView;

@Autowired
@Qualifier("submittedView")
String submittedView;

@RequestMapping(value="/view.do", method=RequestMethod.GET)
public String viewArticle(ModelMap model, @RequestParam("id") Integer id)
{
logger.info("loading article id:" + id);
Article article = articleDao.findById(id);
model.addAttribute("article", article);
return articleView;
}

// TODO this below is a bit crap...

@RequestMapping("/graphic1.do")
public void streamImage1(@RequestParam("id") Integer id,
OutputStream outputStream) throws IOException {
byte[] bytes = articleDao.findById(id).getGraphic1();
if (bytes.length > 0)
FileCopyUtils.copy(bytes, outputStream);
}

@RequestMapping("/graphic2.do")
public void streamImage2(@RequestParam("id") Integer id,
OutputStream outputStream) throws IOException {
byte[] bytes = articleDao.findById(id).getGraphic2();
if (bytes.length > 0)
FileCopyUtils.copy(bytes, outputStream);
}
// --

@RequestMapping(value="/list.do", method=RequestMethod.POST)
public String articleList(Model model)
{
logger.info("displaying article list");
model.addAttribute("articles", articleDao.findAll());
return articleListView;
}

@RequestMapping(value="/list.do", method=RequestMethod.GET)
public String articleList(@RequestParam(value="code", required=false) String code, Model model)
{
logger.info("displaying article list, code=" + code);
List<Article> articles;
if (code != null) {
code = code.toUpperCase();
articles = articleDao.findByStockCode(code);
} else {
articles = articleDao.findAll();
}
model.addAttribute("articles", articles);
return articleListView;
}

@RequestMapping(value="/new.do", method=RequestMethod.GET)
public String setupForm(Model model)
{
Article article = new Article();
model.addAttribute(article);
return editArticleView;
}

@RequestMapping(value="/edit.do", method=RequestMethod.GET)
public String setupForm(@RequestParam("id") Integer id, Model model)
{
Article article = articleDao.findById(id);
model.addAttribute(article);
return editArticleView;
}

@RequestMapping(value={"/new.do", "/edit.do"}, method=RequestMethod.POST)
public String processSubmit(@ModelAttribute("article") Article article,
BindingResult result, SessionStatus status, HttpSession session)
{
new ArticleValidator().validate(article, result);
if (result.hasErrors()) {
return editArticleView;
}
else {
logger.info("Saving article on " + article.getStockCode());
article.setStockCode(article.getStockCode().toUppe rCase());
String username = ((User)session.getAttribute("user")).getUsername();
article.setAuthor(username);
article.setWritten(new Date());
articleDao.save(article);
status.setComplete();
return submittedView;
}
}

@RequestMapping(value="/delete.do", method=RequestMethod.GET)
public String delete(@RequestParam("id") Integer id, Model model)
{
logger.info("deleting article id:" + id);
articleDao.delete(id);
model.addAttribute("articles", articleDao.findAll());
return articleListView;
}

@InitBinder
public void initBinder(WebDataBinder binder)
{
binder.setBindEmptyMultipartFiles(false);
binder.registerCustomEditor(byte[].class, new ByteArrayMultipartFileEditor());
}

}

kramer
Mar 5th, 2008, 09:47 PM
After doing some debugging, I've found that binder.setBindEmptyMultipartFiles(false) is working exactly as it should; ie: if i select a file for image1, but nothing for image2, it will skip attempting to bind image2.

So what I think is happening is that, as my Article object is being prepared for the edit form, it's somehow losing it's byte[] multipart fields... or perhaps, it's happening straight after submit... I'm not sure.

Is there something here I'm missing? It works fine to create a new article with images, save it, then display again... just editing is the problem...