Solucionado (ver solução)
Solucionado
(ver solução)
5
respostas

Dúvida no Ex. 4 da Aula 8 - Enviando arquivos ao servidor

Olá pessoal!

Estou com o seguinte problema, o arquivo não é adicionado à pasta criada. Lembrando que o caminho do arquivo é persistido corretamente e a aplicação não acusa nenhum erro. Segue os fontes do meu projeto aqui:

Form

<%@ 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 lang="pt">

<head>
<meta charset="utf-8">
<title>Novo de livro - Casa do Código</title>
</head>

<body>

    <form:form action="${s:mvcUrl('PC#gravar').build() }" method="post"
        commandName="produto" enctype="multipart/form-data">
        <label for="titulo">Título</label>
        <br>
        <form:input path="titulo" id="titulo" />
        <form:errors path="titulo" />
        <br>
        <br>
        <label for="descricao">Descrição</label>
        <br>
        <form:textarea rows="5" cols="10" path="descricao" id="descricao"></form:textarea>
        <form:errors path="descricao" />
        <br>
        <br>
        <label for="numeroDePaginas">Número de páginas</label>
        <br>
        <form:input type="number" min="1" path="numeroDePaginas"
            id="numeroDePaginas" />
        <form:errors path="numeroDePaginas" />
        <br>
        <br>
        <label for="dataLancamento">Data de lançamento</label>
        <br>
        <form:input path="dataLancamento" id="dataLancamento" />
        <form:errors path="dataLancamento" />
        <br>
        <br>
        <c:forEach items="${tiposPreco}" var="tipoPreco" varStatus="status">
            <label>${tipoPreco}</label>
            <form:input path="precos[${status.index}].valor"/>
            <form:hidden path="precos[${status.index}].tipoPreco"
                value="${tipoPreco}"/>
        </c:forEach>
        <br>
        <br>
        <label for="sumario">Sumário</label>
        <br>
        <input type="file" name="sumario" id="sumario"/>
        <br>
        <br>
        <form:button type="submit">Cadastrar</form:button>
    </form:form>

</body>

</html>

ProdutosController

@Controller
@RequestMapping("/produtos")
public class ProdutosController {

    @Autowired
    private ProdutoDao dao;

    @Autowired
    private FileSaver fileSaver;

    @InitBinder
    public void InitBinder(WebDataBinder binder) {
        binder.addValidators(new ProdutoValidation());
    }

    @RequestMapping("/form")
    public ModelAndView formDeCadastroDe(Produto produto) {
        ModelAndView modelAndView = new ModelAndView("/produto/formularioDeCadastro");
        modelAndView.addObject("tiposPreco", TipoPreco.values());
        return modelAndView;
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView gravar(MultipartFile sumario, @Valid Produto produto, BindingResult result) {
        if (result.hasErrors())
            return formDeCadastroDe(produto);

        String sumarioPath = fileSaver.gravar("arquivos-sumario", sumario);
        produto.setSumarioPath(sumarioPath);
        dao.gravar(produto);
        return new ModelAndView("/produto/produtoCadastrado");
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView listar() {
        ModelAndView modelAndView = new ModelAndView("/produto/lista");
        modelAndView.addObject("produtos", dao.listar());
        return modelAndView;
    }
}

FileSaver

@Component
public class FileSaver {

    @Autowired
    HttpServletRequest request;

    public String gravar(String basePath, MultipartFile file) {
        try {
            String realPath = request.getServletContext().getRealPath("/" + basePath);
            String path = realPath + "/" + file.getOriginalFilename();
            file.transferTo(new File(path));

            return basePath + "/" + file.getOriginalFilename();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}

AppWebConfiguration

@EnableWebMvc
@ComponentScan(basePackageClasses = { HomeController.class, ProdutoDao.class, FileSaver.class })
public class AppWebConfiguration {

    @Bean
    public InternalResourceViewResolver internalResourceViewResolver() {
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();

        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");

        return resolver;
    }

    @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 registra = new DateFormatterRegistrar();
        registra.setFormatter(new DateFormatter("dd/MM/yyyy"));
        registra.registerFormatters(conversionService);

        return conversionService;

    }

    @Bean
    public MultipartResolver multipartResolver() {
        return new StandardServletMultipartResolver();
    }

}

ServletSpringMvc

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(""));
    }
}

5 respostas

Oi Jonas,

Algumas vezes as pastas que criamos no tomcat ficam em um local temporário, causando erros na aplicação.

Veja se esse post que escrevi, falando exatamente sobre isso lhe ajuda: http://blog.alura.com.br/usando-a-pasta-do-tomcat-pelo-eclipse/

Se isso não resolver, só avisar que vemos outra solução.

Abraço

Olá Paulo!

Primeiro, muito obrigado pelo feedback cara! Segundo, curti o post. Só que a coisa ainda não está fluindo heheh... Ele salva as imagens agora em: C:\Tomcat_8\wtpwebapps\casadocodigo\arquivos-sumario Porém, as imagens não aparecem por dentro do eclipse, no projeto. Também não consigo exibir as imagens no navegador, e na barra de status (nas ferramentas do desenvolvedor) do arquivo ele me mostra a mensagem "(blocked:other)".

Segue os fontes:

detalhe.jsp

<%@ 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://java.sun.com/jsp/jstl/fmt" prefix="fmt"%>
<!DOCTYPE html>
<html>
<head>
<c:url value="/" var="contextPath" />
<meta charset="utf-8" />
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="viewport"
    content="width=device-width, initial-scale=1, maximum-scale=1" />
<link rel="icon"
    href="//cdn.shopify.com/s/files/1/0155/7645/t/177/assets/favicon.ico?11981592617154272979"
    type="image/ico" />
<link href="https://plus.googlecom/108540024862647200608"
    rel="publisher" />
<title>Livros de Java, SOA, Android, iPhone, Ruby on Rails e
    muito mais - Casa do Código</title>
<link href="${contextPath}resources/css/cssbase-min.css"
    rel="stylesheet" type="text/css" media="all" />
<link href='http://fonts.googleapis.com/css?family=Droid+Sans:400,700'
    rel='stylesheet' />
<link href="${contextPath}resources/css/fonts.css" rel="stylesheet"
    type="text/css" media="all" />
<link href="${contextPath}resources/css/fontello-ie7.css"
    rel="stylesheet" type="text/css" media="all" />
<link href="${contextPath}resources/css/fontello-embedded.css"
    rel="stylesheet" type="text/css" media="all" />
<link href="${contextPath}resources/css/fontello.css" rel="stylesheet"
    type="text/css" media="all" />
<link href="${contextPath}resources/css/style.css" rel="stylesheet"
    type="text/css" media="all" />
<link href="${contextPath}resources/css/layout-colors.css"
    rel="stylesheet" type="text/css" media="all" />
<link href="${contextPath}resources/css/responsive-style.css"
    rel="stylesheet" type="text/css" media="all" />
<link href="${contextPath}resources/css/guia-do-programador-style.css"
    rel="stylesheet" type="text/css" media="all" />
<link href="${contextPath}resources/css/produtos.css" rel="stylesheet"
    type="text/css" media="all" />
<link rel="canonical" href="http://www.casadocodigo.com.br/" />
</head>
<body>

    <header id="layout-header">
        <div class="clearfix container">
            <a href="/" id="logo"> </a>
            <div id="header-content">
                <nav id="main-nav">

                    <ul class="clearfix">
                        <li><a href="#">Meu carrinho (${carrinhoCompras.quantidade})</a></li>

                        <li><a href="/pages/sobre-a-casa-do-codigo" rel="nofollow">Sobre
                                Nós</a></li>

                        <li><a href="/pages/perguntas-frequentes" rel="nofollow">Perguntas
                                Frequentes</a></li>
                    </ul>
                </nav>
            </div>
        </div>
    </header>
    <nav class="categories-nav">
        <ul class="container">
            <li class="category"><a href="http://www.casadocodigo.com.br">Home</a></li>
            <li class="category"><a href="/collections/livros-de-agile">
                    Agile </a></li>
            <li class="category"><a href="/collections/livros-de-front-end">
                    Front End </a></li>
            <li class="category"><a href="/collections/livros-de-games">
                    Games </a></li>
            <li class="category"><a href="/collections/livros-de-java">
                    Java </a></li>
            <li class="category"><a href="/collections/livros-de-mobile">
                    Mobile </a></li>
            <li class="category"><a
                href="/collections/livros-desenvolvimento-web"> Web </a></li>
            <li class="category"><a href="/collections/outros"> Outros </a></li>
        </ul>
    </nav>

    <article id="livro-css-eficiente">
        <header id="product-highlight" class="clearfix">
            <div id="product-overview" class="container">
                <img width="280px" height="395px" src="${produto.sumarioPath }"
                    class="product-featured-image" />
                <h1 class="product-title">${produto.titulo }</h1>
                <p class="product-author">
                    <span class="product-author-link"> </span>
                </p>

                <p class="book-description">${produto.descricao }</p>
            </div>
        </header>


        <section class="buy-options clearfix">
            <form action='<c:url value="/carrinho/add"/>' method="post" class="container">
                <input type="hidden" name="produtoId" value="${produto.id }"/>
                <ul id="variants" class="clearfix">

                    <c:forEach items="${produto.precos }" var="preco">

                        <li class="buy-option">
                            <input type="radio" name="tipoPreco" class="variant-radio" id="product-variant-9720393823"    value="${preco.tipoPreco }" checked="checked" /> 
                            <label class="variant-label" for="product-variant-9720393823">${preco.tipoPreco }</label> 
                            <small class="compare-at-price">R$ 39,90</small>
                            <p class="variant-price">R$ ${preco.valor }</p>
                        </li>

                    </c:forEach>

                </ul>
                <button type="submit" class="submit-image icon-basket-alt" alt="Compre Agora" title="Compre Agora"></button>

            </form>

        </section>

        <div class="container">
            <section class="summary">
                <ul>
                    <li><h3>
                            E muito mais... <a href='/pages/sumario-java8'>veja o sumário</a>.
                        </h3></li>
                </ul>
            </section>

            <section class="data product-detail">
                <h2 class="section-title">Dados do livro:</h2>
                <p>
                    Número de páginas: <span>${produto.numeroDePaginas }</span>
                </p>
                <p></p>
                <p>
                    Data de publicação:
                    <fmt:formatDate value="${produto.dataLancamento.time }"
                        pattern="dd/MM/yyyy" />
                </p>
                <p>
                    Encontrou um erro? <a href='/submissao-errata' target='_blank'>Submeta
                        uma errata</a>
                </p>
            </section>
        </div>

    </article>

    <footer id="layout-footer">
        <div class="clearfix container">




            <div id="collections-footer">
                <!-- cdc-footer -->
                <p class="footer-title">Coleções de Programação</p>
                <ul class="footer-text-links">
                    <li><a href="/collections/livros-de-java">Java</a></li>
                    <li><a href="/collections/livros-desenvolvimento-web">Desenvolvimento
                            Web</a></li>
                    <li><a href="/collections/livros-de-mobile">Mobile</a></li>
                    <li><a href="/collections/games">Games</a></li>
                    <li><a href="/collections/livros-de-front-end">Front End</a></li>
                </ul>
                <p class="footer-title">Outros Assuntos</p>
                <ul class="footer-text-links">
                    <li><a href="/collections/livros-de-agile">Agile</a></li>
                    <li><a href="/collections/outros">e outros...</a></li>
                </ul>
            </div>
            <div id="social-footer">
                <!-- books-footer -->
                <p class="footer-title">Links da Casa do Código</p>
                <ul class="footer-text-links">
                    <li><a href="http://livros.casadocodigo.com.br" rel="nofollow">Meus
                            E-books</a></li>
                    <li><a href="/pages/sobre-a-casa-do-codigo">Sobre a Casa
                            do Código</a></li>
                    <li><a href="/pages/perguntas-frequentes">Perguntas
                            Frequentes</a></li>
                    <li><a href="https://www.caelum.com.br">Caelum - Ensino e
                            Inovação</a></li>
                    <li><a href="http://www.codecrushing.com/" rel="nofollow">Code
                            Crushing</a></li>
                    <li><a
                        href="http://www.casadocodigo.com.br/pages/politica-de-privacidade"
                        rel="nofollow">Política de Privacidade</a></li>
                </ul>
                <p class="footer-title">Redes Sociais</p>
                <ul>
                    <li class="social-links"><a
                        href="http://www.twitter.com/casadocodigo" target="_blank"
                        id="twitter" rel="nofollow">Facebook</a> <a
                        href="http://www.facebook.com/casadocodigo" target="_blank"
                        id="facebook" rel="nofollow">Twitter</a></li>
                </ul>
            </div>
            <div id="newsletter-footer">
                <!-- social-footer -->
                <p class="footer-title">Receba as Novidades e Lançamentos</p>
                <div id="form-newsletter">
                    <form action="" method="POST" id="ss-form" class="form-newsletter">
                        <ul>
                            <li><input type="hidden" name="pageNumber" value="0" /><input
                                type="hidden" name="backupCache" value="" /><input type="email"
                                name="entry.0.single" value="" class="ss-q-short" id="entry_0"
                                placeholder="seu@email.com" /></li>
                            <li><input type="submit" name="submit"
                                value="Quero Receber!" id="submit-newsletter" /></li>
                        </ul>
                    </form>
                    <ul>
                        <li class="ie8"><a href="" rel="nofollow">Receba as
                                Novidades e Lançamentos</a></li>
                    </ul>
                </div>
                <ul class="footer-payments">
                    <li></li>
                    <li></li>
                </ul>
            </div>
        </div>
    </footer>
</body>
</html>

ProdutosController

@Controller
@RequestMapping("/produtos")
public class ProdutosController {

    @Autowired
    private ProdutoDao dao;

    @Autowired
    private FileSaver fileSaver;

    @InitBinder
    public void InitBinder(WebDataBinder binder) {
        binder.addValidators(new ProdutoValidation());
    }

    @RequestMapping("/form")
    public ModelAndView formDeCadastroDe(Produto produto) {
        ModelAndView modelAndView = new ModelAndView("/produto/formularioDeCadastro");
        modelAndView.addObject("tiposPreco", TipoPreco.values());
        return modelAndView;
    }

    @RequestMapping(method = RequestMethod.POST)
    public ModelAndView gravar(MultipartFile sumario, @Valid Produto produto, BindingResult result) {
        if (result.hasErrors())
            return formDeCadastroDe(produto);

        String sumarioPath = fileSaver.gravar("arquivos-sumario", sumario);
        produto.setSumarioPath(sumarioPath);
        dao.gravar(produto);
        return new ModelAndView("/produto/produtoCadastrado");
    }

    @RequestMapping(method = RequestMethod.GET)
    public ModelAndView listar() {
        ModelAndView modelAndView = new ModelAndView("/produto/lista");
        modelAndView.addObject("produtos", dao.listar());
        return modelAndView;
    }

    @RequestMapping("/detalhe/{id}")
    public ModelAndView detalhe(@PathVariable("id") Integer id) {
        ModelAndView modelAndView = new ModelAndView("/produto/detalhe");
        Produto produtoPesquisado = dao.buscarPor(id);
        modelAndView.addObject("produto", produtoPesquisado);

        return modelAndView;
    }
}

FileSaver

@Component
public class FileSaver {

    @Autowired
    HttpServletRequest request;

    public String gravar(String basePath, MultipartFile arquivo) {
        try {
            String realPath = request.getServletContext().getRealPath("/" + basePath);
            String nomeArquivo = nomeDo(arquivo);
            File file = new File(realPath + "/" + nomeArquivo);
            file.getParentFile().mkdirs();
            System.out.println(file.getParent());
            if (!file.exists()) {
                arquivo.transferTo(file);
            }
            return realPath + nomeArquivo;
            // return basePath + "/" + arquivo.getOriginalFilename();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    private String nomeDo(MultipartFile arquivo) {
        return arquivo.getOriginalFilename();
    }
}

solução!

Oi Jonas, na verdade você não vai conseguir ver os arquivos pelo navegador ainda, pois falta uma configuração que libera os arquivos comuns do SpringMVC. Só fazemos essa configuração no segundo curso, mas se quiser testar, segue abaixo, na class AppWebConfiguration:

public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
    configurer.enable();
}

Por fora do Eclipse, indo na pasta do tomcat direto, em .../wptwebapps/casadocodigo/arquivos-sumario, você deve achar os arquivos. Mas lembre de uma coisa, sempre que você alterar o projeto e enviar novamente ao servidor, ele vai limpar os arquivos e enviar tudo de novo, e muitas vezes ele limpa essa pasta, por isso, assim que fizer o UPLOAD, você deve olhar na pasta.

Olá novamente Paulo!

Deixamos para o próximo curso então heheh.. Logo iniciarei! Outra coisa, indo por fora do eclipse realmente consigo achar os arquivos sim. O problema é que não consigo encontrar na pasta, dentro do ide. Mas tranquilo, se o efeito desejado era esse então (subir os arquivos para o Tomcat, foi que foi heheh..). Quanto aos outros detalhes, até o próximo curso.

Grande abraço e obrigado pelas respostas!

Como falei antes Jonas, está no próximo curso a explicação completa, mas não lhe impede de usar agora para já funcionar. :)

Sobre a IDE, o eclipse não atualiza automaticamente com o seu sistema operacional, e por isso não mostra os arquivos.

Após o upload, basta apertar F5 em cima do projeto no eclipse ou clicar com o botão direito do mouse em cima do projeto, e escolher a opção Atualizar (Refresh) que os arquivos da pasta devem aparecer.

Veja se isso lhe ajuda.

Abraço