Olá, estava indo bem no curso Spring MVC I até chegar na parte de submissão de arquivo via formulário.
O caminho para o arquivo não é inserido na pasta existente, e ainda mesmo após o formulário ser submetido com todos os dados preenchidos e o arquivo selecionado, o mesmo não é redirecionado para a view "/produtos" como anteriormente.
Já bati cabeça com isso aqui algum tempo, logo vou pedir ajuda colocando aqui o meu código atual. O mesmo também está disponível no meu github https://github.com/DaviGadelhaLeitao/book-store
package br.com.bookstore.controller;
import java.util.List;
import javax.validation.Valid;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.WebDataBinder;
import org.springframework.web.bind.annotation.InitBinder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import br.com.bookstore.daos.ProductDAO;
import br.com.bookstore.infrastructure.FileSaver;
import br.com.bookstore.model.PriceType;
import br.com.bookstore.model.Product;
import br.com.bookstore.validation.ProductValidation;
@Controller
@RequestMapping("/products")
public class ProductsController {
    @Autowired
    private FileSaver fileSaver;
    @Autowired
    private ProductDAO productDAO;
    // responsible for binding the validator with the controller
    @InitBinder
    public void initBinder(WebDataBinder binder) {
        binder.addValidators(new ProductValidation());
    }    
    @RequestMapping(value="/form", method=RequestMethod.GET)
    public ModelAndView form(Product product) {
        ModelAndView modelAndView = new ModelAndView("/products/form");
        modelAndView.addObject("types", PriceType.values());
        return modelAndView;
    }
    @RequestMapping(method=RequestMethod.POST)
    public ModelAndView saveProduct(MultipartFile contentPath, @Valid Product product, BindingResult result, RedirectAttributes redirectAttributes) {
        System.out.println(contentPath.getOriginalFilename());
        if (result.hasErrors()) {
            return form(product);
        }
        String path = fileSaver.write("content-path-folder", contentPath);
        product.setContentPath(path);
        productDAO.save(product);
        redirectAttributes.addFlashAttribute("confirmationMessage", "Product " + product.getTitle() + " added with success.");
        return new ModelAndView("redirect:/products");
    }
    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView list() {
        List<Product> products = productDAO.list();
        ModelAndView modelAndView = new ModelAndView("/products/list");
        modelAndView.addObject("products", products);
        return modelAndView;
    }
}package br.com.bookstore.infrastructure;
import java.io.File;
import java.io.IOException;
import javax.servlet.http.HttpServletRequest;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
@Component
public class FileSaver {
    @Autowired
    private HttpServletRequest request;
    public String write(String baseFolder, MultipartFile file) {
        try {
            String realPath = request.getServletContext().getRealPath("/" + baseFolder);
            String path = realPath + "/" + file.getOriginalFilename();
            file.transferTo(new File(path));
            return baseFolder + "/" + file.getOriginalFilename();
        } catch (IllegalStateException | IOException e) {
            throw new RuntimeException(e);
        }
    }
}<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core"  prefix="c"%>
<%@ taglib uri="http://www.springframework.org/tags/form" prefix="form"%>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s"%>
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Products</title>
</head>
<body>
<form:form action="${s:mvcUrl('PC#saveProduct').build() }" method="POST" commandName="product" enctype="multipart/form-data">
    <div>
        <label>Title</label>
        <form:input path="title" />
    </div>
    <div>
        <form:errors path="title"></form:errors>
    </div>
    <div>
        <label>Description</label>
        <form:textarea path="description" rows="10" cols="20" />        
    </div>
    <div>
        <form:errors path="description"></form:errors>
    </div>
    <div>
        <label>Pages:</label>
        <form:input path="pages" />
    </div>
    <div>
        <form:errors path="pages"></form:errors>
    </div>
    <div>
        <label>Published:</label>
        <form:input path="published" />
    </div>
    <div>
        <form:errors path="published"></form:errors>
    </div>
    <c:forEach items="${types}" var="priceType" varStatus="status">
        <div>
            <label>${priceType}</label>
            <form:input path="prices[${status.index}].value" />
            <form:hidden path="prices[${status.index}].type" value="${priceType}" />
        </div>
    </c:forEach>
    <br>
    <div>
        <label>Book Content:</label>
        <input type="file" name="contentPath">
    </div>
    <button type="submit">Submit</button>
</form:form>
</body>
</html>package br.com.bookstore.conf;
import org.springframework.context.MessageSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.format.datetime.DateFormatter;
import org.springframework.format.datetime.DateFormatterRegistrar;
import org.springframework.format.support.DefaultFormattingConversionService;
import org.springframework.format.support.FormattingConversionService;
import org.springframework.web.multipart.MultipartResolver;
import org.springframework.web.multipart.support.StandardServletMultipartResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import br.com.bookstore.controller.HomeController;
import br.com.bookstore.daos.ProductDAO;
import br.com.bookstore.infrastructure.FileSaver;
@EnableWebMvc
@ComponentScan(basePackageClasses= {HomeController.class, ProductDAO.class, FileSaver.class})
public class AppWebConfiguration {
    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolve = new InternalResourceViewResolver("/WEB-INF/views/", ".jsp");
        return resolve;
    }
    @Bean
    public MessageSource messageSource() {
        ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
        messageSource.setBasename("/WEB-INF/messages");
        messageSource.setDefaultEncoding("UTF-8");
        messageSource.setCacheSeconds(1);
        return messageSource;
    }
    @Bean
    public FormattingConversionService mvcConversionService() {
        DefaultFormattingConversionService conversionService = new DefaultFormattingConversionService();
        DateFormatterRegistrar formatterRegistrar = new DateFormatterRegistrar();
        formatterRegistrar.setFormatter(new DateFormatter("dd/MM/yyyy"));
        formatterRegistrar.registerFormatters(conversionService);
        return conversionService;
    }
    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }
}package br.com.bookstore.model;
import java.util.Calendar;
import java.util.List;
import javax.persistence.ElementCollection;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import org.springframework.format.annotation.DateTimeFormat;
@Entity
public class Product {
    // let the database manage the id
    @Id @GeneratedValue(strategy=GenerationType.IDENTITY)
    private Integer id;
    private String title;
    private String description;
    private Integer pages;
    private String contentPath;
    @DateTimeFormat
    private Calendar published;
    @ElementCollection
    private List<Price> types;
    @Override
    public String toString() {
        return "Product [title=" + title + ", description=" + description + ", pages=" + pages + "]";
    }
    public String getTitle() {
        return title;
    }
    public void setTitle(String title) {
        this.title = title;
    }
    public String getDescription() {
        return description;
    }
    public void setDescription(String description) {
        this.description = description;
    }
    public Integer getPages() {
        return pages;
    }
    public void setPages(Integer pages) {
        this.pages = pages;
    }
    public Integer getId() {
        return id;
    }
    public void setId(Integer id) {
        this.id = id;
    }
    public List<Price> getPrices() {
        return types;
    }
    public void setPrices(List<Price> prices) {
        this.types = prices;
    }
    public Calendar getPublished() {
        return published;
    }
    public void setPublished(Calendar published) {
        this.published = published;
    }
    public String getContentPath() {
        return contentPath;
    }
    public void setContentPath(String contentPath) {
        this.contentPath = contentPath;
    }
}package br.com.bookstore.conf;
import javax.servlet.Filter;
import javax.servlet.MultipartConfigElement;
import javax.servlet.ServletRegistration.Dynamic;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class ServletSpringMVC extends AbstractAnnotationConfigDispatcherServletInitializer {
    @Override
    protected Class<?>[] getRootConfigClasses() {
        return null;
    }
    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] {AppWebConfiguration.class, JPAConfiguration.class};
    }
    @Override
    protected String[] getServletMappings() {
        return new String[] {"/"};
    }
    @Override
    protected Filter[] getServletFilters() {
        CharacterEncodingFilter encodingFilter = new CharacterEncodingFilter();
        encodingFilter.setEncoding("UTF-8");
        return new Filter[] {encodingFilter};
    }
    @Override
    protected void customizeRegistration(Dynamic registration) {
        registration.setMultipartConfig(new MultipartConfigElement(""));
    }
}Eu já verifiquei as anotações para injeção de dependência através do Spring, a configuração, estou rodando tanto o eclipse quanto o mysql como root num Ubuntu.
Agradeço qualquer feedback. Grato.
 
            