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

Erro ao carregar a página que lista os produtos.

Quando inseri a taglib

<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>

e em seguida o

<form:form action="${s:mvcUrl('PC#gravar').build()}" method="POST" commandName="produto">

o meu formulário carrega normalmente, quando testo as validações ela é feita normalmente, mas quando eu insiro um novo livro e gravo, o navegador me apresenta um erro 404 (que a página não foi encontrada) e o caminho que está no campo de url é http://localhost:8080/casadocodigo/produtos/produtos.

Não consegui identificar no meu controller onde ele gera esse outro /produtos.

Quando eu acesso diretamente http://localhost:8080/casadocodigo/produtos/ funciona normalmente, a minha lista é carregada e o produto recém adicionado é listado.

Abaixo está o código do meu 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://www.springframework.org/tags/form" prefix="form" %>
<%@ taglib uri="http://www.springframework.org/tags" prefix="s" %>
<!DOCTYPE html PUBLIC>
<html>
<head>
<meta charset="UTF-8">
<title>Livros de Java, Android, iPhone, PHP, Ruby e muito mais -
    Casa do Código</title>
</head>
<body>
    <form:form action="${s:mvcUrl('PC#gravar').build()}" method="POST" commandName="produto">
        <div>
            <label>Título</label>
            <input type="text" name="titulo">
            <form:errors path="titulo" />
        </div>
        <div>
            <label>Descrição</label>
            <textarea rows="10" cols="20" name="descricao"></textarea>
            <form:errors path="descricao" />
        </div>
        <div>
            <label>Número de páginas</label>
            <input type="text" name="paginas">
            <form:errors path="paginas" />
        </div>
        <c:forEach items="${tipos}" var="tipoPreco" varStatus="status">
            <div>
                <label>${tipoPreco}</label> <!-- Pega o enum e faz um toString() automaticamente. -->
                <input type="text" name="precos[${status.index}].valor">
                <input type="hidden" name="precos[${status.index}].tipo" value="${tipoPreco}">
            </div>

        </c:forEach>

        <button type="submit">Cadastrar</button>
    </form:form>
</body>
</html>

E o do meu controller:

package br.com.casadocodigo.loja.controllers;

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.servlet.ModelAndView;
import org.springframework.web.servlet.mvc.support.RedirectAttributes;
import br.com.casadocodigo.loja.daos.ProdutoDAO;
import br.com.casadocodigo.loja.models.Produto;
import br.com.casadocodigo.loja.models.TipoPreco;
import br.com.casadocodigo.loja.validations.ProdutoValidation;

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

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

    @Autowired
    private ProdutoDAO produtoDAO;

    @RequestMapping("/form") 
    public ModelAndView form() {
        ModelAndView modelAndView = new ModelAndView("produtos/form");
        modelAndView.addObject("tipos", TipoPreco.values());
        return modelAndView;
    }

    @RequestMapping(method=RequestMethod.POST)
    public ModelAndView gravar(@Valid Produto produto, BindingResult bindingResult, RedirectAttributes redirectAttribute) {

        if (bindingResult.hasErrors()) {
            return form();
        }
        produtoDAO.gravar(produto);
        redirectAttribute.addFlashAttribute("mensagem", "O produto foi cadastrado com sucesso!");
        return new ModelAndView("redirect:produtos");
    }

    @RequestMapping(method=RequestMethod.GET)
    public ModelAndView listar() {
        List<Produto> produtos = produtoDAO.listar();
        ModelAndView modelAndView = new ModelAndView("produtos/lista");
        modelAndView.addObject("produtos", produtos);
        return modelAndView;
    }
}

Desde já agradeço.

8 respostas

Oi Leandro, tudo bem?

Deixa ver se entendi. Você olhou o HTML gerado pelo Spring e no atributo action da tag <form:form> ele colocou o final da URL .../produtos/produtos

Foi isso? Quando você coloca na mão a action tudo funciona corretamente?

Boa noite,

Isso mesmo. XD

<form:form action="/casadocodigo/produtos" method="POST" commandName="produto" enctype="multipart/form-data">

Dessa forma funfa... Rs.

Leandro, consegue colocar o código no github pra que possamos ter uma visão completa? Fica mais fácil de ajudar.

Pois realmente parece tudo certo.

Abraço

Boa tarde Paulo,

Fui upar meu projeto para o Git, não compreendi a logística da ferramenta e excluí meu projeto do repositório local. :(

Perdi meu trabalho e estou concluindo os dois últimos capítulos sem a prática e devido ao longo caminho percorrido até aqui (implementação do carrinho de compras e fechamento.), ficaria inviável implementar tudo novamente.

Primeiramente eu gostaria de saber se você tem um link para que eu possa fazer o download do projeto casadocodigo.

Pelo o que vi, no módulo Spring MVC II você usa esse projeto nas explicações.

E sobre esse problema com a listagem dos meus produtos utilizando a taglib do Spring, deixa quieto.

Sei que não é o lugar mais adequado, mas aproveitando a deixa, gostaria de lhe perguntar se é normal, depois de sermos metralhados com tanta informação a respeito do Spring MVC, seus recursos, etc, nos sentirmos inseguro, apesar de eu ter entendido a sua importância, ter feito as atividades (inclusive estava com comentários :( ) com exceção dos dois últimos capítulos porque perdi o projeto?

A sensação que tenho é que terei que abrir algum código e copiar determinado trecho de código para implementar alguma coisa análogo ao que aprendemos. Muito difícil guardar tanta informação, mas se eu ler o código eu sei o que cada annotation, método e classe faz... É normal tudo isso? Se eu persistir na prática (em projetos próprio, quem sabe, vai que vem uma ideia) eu conseguirei similar todo esse conhecimento com o tempo? Ou esquece projeto por agora porque sou muito noob para isso?

Passa um pouco da sua experiência... Como foi nos primórdios para você.

E, por fim, me ajuda a recuperar esse projeto para dar continuidade no Spring MVC II. Essa está praticamente encerrado.

Obrigado e desculpa a extensão do post, mas o desespero e a depressão bateu XD.

solução!

Oi Leandro,

Caramba, realmente muito ruim perder um projeto que fizemos pois sabemos onde colocamos a mão. Mas deixa te dar uma esperança, se você enviou para o git alguma coisa, seu repositório está salvo, vai ficar online, é só baixar novamente com git clone URLDOGIT.

Mas se não enviou, e não apagou a pasta do computador, pode ser que ele já esteja no git local.

Mas se matou a pasta do PC e não está online também, ai realmente perdeu.

O projeto pode ser baixado no meu github: https://github.com/paulojribp/casadocodigo/archive/master.zip

Mas ai tem tudo, ou seja, curso 1 e 2. Veja se pelo menos ajuda a entender e continuar.

Sobre seu medo em um framework novo, não se preocupe pois é normal sim. O grande ponto é praticar para que os conceitos que você já sabe na teoria ao olhar para uma annotation se torne natural para você. Então eu recomendo demais criar projetos, mesmo que próprios, ideias novas, e etc..

Sugiro inclusive procurar uma necessidade real sua e tentar suprir, pois assim você terá ânimo para ir até o fim. Você vai ver a necessidade do seu projeto, e com o conhecimento do curso você poderá aplicar.

Não é em todo projeto que usamos Cache por exemplo, só quando é necessário mesmo, nem requisições assincronas e alguns outros recursos são específicos. Mas mostramos no curso que, quando a necessidade surgir, você já saiba o que fazer.

Creio que é isso.. não desanime, mantenha a força nos estudos e você verá que logo logo será natural falar sobre esses recursos.

Abraço

Obrigado pela força. Vou persistir. :^)

Estou voltando aqui somente para divulgar a solução do problema que motivou a abertura desse post e que outros colegas evitem passar por isso.

Onde estava:

@RequestMapping(method=RequestMethod.POST)
    public ModelAndView gravar(@Valid Produto produto, BindingResult bindingResult, RedirectAttributes redirectAttribute) {

        if (bindingResult.hasErrors()) {
            return form();
        }
        produtoDAO.gravar(produto);
        redirectAttribute.addFlashAttribute("mensagem", "O produto foi cadastrado com sucesso!");
        return new ModelAndView("redirect:produtos");
    }

Faltou colocar a barra "/" entre o "redirect:" e "produtos".

Deve ficar assim:

@RequestMapping(method=RequestMethod.POST)
    public ModelAndView gravar(@Valid Produto produto, BindingResult bindingResult, RedirectAttributes redirectAttribute) {

        if (bindingResult.hasErrors()) {
            return form();
        }
        produtoDAO.gravar(produto);
        redirectAttribute.addFlashAttribute("mensagem", "O produto foi cadastrado com sucesso!");
        return new ModelAndView("redirect:/produtos");
    }

Agora sim.

Após cadastrar o livro, o usuário é redirecionado para a lista de livros cadastrados. Antes não acontecia isso.

Sem a barra, ao ser redirecionado, o usuário tinha um 404 informando que a página não foi encontrada.

Olhando a url estava "http://localhost:8080/casadocodigo/produtos/produtos".

Abraço pessoal.