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.