JSF – Tutorial combos aninhados Estados/Cidades

Neste post irei mostrar uma das implementações de combos aninhados estados/cidades. Percebi nas listas e fóruns que esse é um problema comum, onde desenvolvedores se deparam frequentemente.

Utilizarei Tomcat, Hibernate e MySQL para a persistência de dados e disponilizarei o projeto para download com o script sql contendo a lista completa de estados/cidades brasileiras.

Para gerenciar as sessões/transações do Hibernate criei um serlvet filter Open Session In View fazendo papel de um interceptador, que será executado a cada request e response.

Obs: o projeto vai com o script.sql com os Estados e Cidades brasileiras

Estrutura do projeto

estrutura_combos

Versões utilizadas

  • Eclipse 3.4.1
  • JDK 1.6
  • Tomcat 6.0.18
  • MyFaces 1.2.5
  • RichFaces 3.3.1
  • Hibernate Annotations 3.4.0
  • Hibernate 3.3.1
  • MySQL 5
  • MySQL Query Browser 1.2

Códigos

Estado.java:

package br.com.serjaum.modelo;

import java.io.Serializable;import java.util.ArrayList;import java.util.List;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.FetchType;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.OneToMany;import javax.persistence.Table;

import org.hibernate.annotations.Cascade;

@Entity@Table(name="estados")public class Estado implements Serializable {

 private static final long serialVersionUID = -5582648910303813488L;

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="ESTADO_ID") private Long id;

 @Column(name="sigla") private String sigla; 

 @Column(name="nome") private String nome; 

 @OneToMany(mappedBy="estado", fetch=FetchType.LAZY) @Cascade(org.hibernate.annotations.CascadeType.ALL) private List<Cidade> cidades = new ArrayList<Cidade>();

 public Long getId() { return id; }

 public void setId(Long id) { this.id = id; }

 public String getNome() { return nome; }

 public void setNome(String nome) { this.nome = nome; }

 public String getSigla() { return sigla; }

 public void setSigla(String sigla) { this.sigla = sigla; }

 public List<Cidade> getCidades() { return cidades; }

 public void setCidades(List<Cidade> cidades) { this.cidades = cidades; }

 public String toString() { return this.nome; }

 @Override public boolean equals(Object obj){ if( (obj instanceof Estado) && ( ((Estado)obj).getNome().equals(this.nome))){ return true; }else { return false; } }

 public int hashCode(){ return this.nome.length() * 23; }

}

Cidade.java:

package br.com.serjaum.modelo;

import java.io.Serializable;

import javax.persistence.Column;import javax.persistence.Entity;import javax.persistence.GeneratedValue;import javax.persistence.GenerationType;import javax.persistence.Id;import javax.persistence.JoinColumn;import javax.persistence.ManyToOne;import javax.persistence.Table;

@Entity@Table(name="cidades")public class Cidade implements Serializable{

 private static final long serialVersionUID = -2094704997130038211L;

 @Id @GeneratedValue(strategy=GenerationType.IDENTITY) @Column(name="CIDADE_ID") private Long id;

 @Column(name="nome") private String nome;

 @ManyToOne(cascade=javax.persistence.CascadeType.ALL) @JoinColumn(name="id_cid_est") private Estado estado;

 public Long getId() { return id; }

 public void setId(Long id) { this.id = id; }

 public String getNome() { return nome; }

 public void setNome(String nome) { this.nome = nome; }

 public Estado getEstado() { return estado; }

 public void setEstado(Estado estado) { this.estado = estado; }

 public String toString() { return this.nome; }

 @Override public boolean equals(Object obj){ if( (obj instanceof Cidade) && ( ((Cidade)obj).getNome().equals(this.nome))){ return true; }else { return false; } }

 public int hashCode(){ return this.nome.length() * 23; }}


HibernateSessionFilter.java:

package br.com.serjaum.filtro; 

import java.io.IOException; 

import javax.servlet.Filter;import javax.servlet.FilterChain;import javax.servlet.FilterConfig;import javax.servlet.ServletException;import javax.servlet.ServletRequest;import javax.servlet.ServletResponse; 

import br.com.serjaum.dao.HibernateUtil; 

public class HibernateSessionFilter implements Filter { 

 public void doFilter(ServletRequest req, ServletResponse res, FilterChain fc) throws IOException, ServletException { HibernateUtil.openSession(); try { HibernateUtil.currentSession().beginTransaction(); fc.doFilter(req, res); HibernateUtil.currentSession().getTransaction().commit(); } catch (Exception e) { HibernateUtil.currentSession().getTransaction().rollback(); throw new ServletException(e); } finally { HibernateUtil.closeCurrentSession(); } } 

 public void init(FilterConfig c) { 

 } 

 public void destroy() { 

 }}

combo.jsp:

<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%><%@ taglib prefix="f" uri="http://java.sun.com/jsf/core"%><%@ taglib prefix="h" uri="http://java.sun.com/jsf/html"%><%@ taglib prefix="rich" uri="http://richfaces.ajax4jsf.org/rich"%><%@ taglib prefix="a4j" uri="http://richfaces.org/a4j"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"><html><head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"></head>

<body><f:view> <h:form> <h:panelGrid columns="2"> <h:outputLabel for="estado" value="Estado " /> <h:selectOneMenu id="estado" value="#{regiaoMB.estado.id}"> <f:selectItem itemValue="" itemLabel="Selecione..." /> <f:selectItems value="#{regiaoMB.estados}" /> <a4j:support event="onchange" ajaxSingle="true" action="#{regiaoMB.actionCarregaCidades}" reRender="estado,cidade"/> </h:selectOneMenu>

 <h:outputLabel for="cidade" value="Cidade " /> <h:selectOneMenu id="cidade" value="#{regiaoMB.cidade.id}"> <f:selectItem itemValue="" itemLabel="Selecione..." /> <f:selectItems value="#{regiaoMB.cidades}" /> </h:selectOneMenu> </h:panelGrid> </h:form></f:view></body></html>

Importando o projeto

  1. Baixe o projeto atualizado >>aqui<<;
  2. Descompacte o projeto no seu workspace;
  3. No Eclipse vá em: File –> Import –> General – Existing Projects into Workspace –> Next –> Selecione o projeto descompactado no workspace –> Finish.

Executando o projeto

  1. Com o MySQL instalado e configurado com usuário: root e senha: root crie um novo schema com o nome de jsf.
  2. Para popular o banco de dados utilize seu cliente SQL favorito, eu gosto do MySQL Query Browser. Abra o script.sql que pode ser encontrado no pacote br.com.serjaum.sql e execute.
  3. Execute o arquivo combo.jsp;

Resultado

combos

Espero ter ajudado!


15 Comentários on “JSF – Tutorial combos aninhados Estados/Cidades”

  1. André Lima disse:

    Sergio,
    estou pegando a seguinte excecao…estou pensando se não é relacionado às versões dos jars…não entendo também quando se diz que o projeto usa o MyFaces…onde está a configuracao??

    SEVERE: Servlet.service() for servlet jsp threw exception
    java.lang.NoSuchFieldError: TRACE
    at org.slf4j.impl.Log4jLoggerAdapter.trace(Log4jLoggerAdapter.java:90)
    at org.hibernate.cfg.annotations.PropertyBinder.make(PropertyBinder.java:184)
    at org.hibernate.cfg.AnnotationBinder.bindId(AnnotationBinder.java:1911)
    at org.hibernate.cfg.AnnotationBinder.processElementAnnotations(AnnotationBinder.java:1279)
    at org.hibernate.cfg.AnnotationBinder.bindClass(AnnotationBinder.java:754)
    at org.hibernate.cfg.AnnotationConfiguration.processArtifactsOfType(AnnotationConfiguration.java:546)
    at org.hibernate.cfg.AnnotationConfiguration.secondPassCompile(AnnotationConfiguration.java:291)
    at org.hibernate.cfg.Configuration.buildSessionFactory(Configuration.java:1319)
    at org.hibernate.cfg.AnnotationConfiguration.buildSessionFactory(AnnotationConfiguration.java:867)
    at br.com.serjaum.dao.HibernateUtil.(HibernateUtil.java:17)
    at br.com.serjaum.filtro.HibernateSessionFilter.doFilter(HibernateSessionFilter.java:17)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    at java.lang.Thread.run(Thread.java:619)
    31/08/2009 21:29:09 org.apache.catalina.core.StandardWrapperValve invoke
    SEVERE: Servlet.service() for servlet jsp threw exception
    java.lang.NoClassDefFoundError: Could not initialize class br.com.serjaum.dao.HibernateUtil
    at br.com.serjaum.filtro.HibernateSessionFilter.doFilter(HibernateSessionFilter.java:17)
    at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:235)
    at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
    at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:233)
    at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:191)
    at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:128)
    at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:102)
    at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:109)
    at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:293)
    at org.apache.coyote.http11.Http11Processor.process(Http11Processor.java:849)
    at org.apache.coyote.http11.Http11Protocol$Http11ConnectionHandler.process(Http11Protocol.java:583)
    at org.apache.tomcat.util.net.JIoEndpoint$Worker.run(JIoEndpoint.java:454)
    at java.lang.Thread.run(Thread.java:619)

    • serjaumfantin disse:

      André,

      o MyFaces é somente UMA de várias implementações JSF existentes no mercado. Este código que está no web.xml faz uso de qualquer implementação JSF que estiver no projeto. No caso deste projeto, as libs do MyFaces estão contidos no mesmo, e é essa implementação que será usada.

      |servlet|
      |servlet-name|>Faces Servlet|/servlet-name|
      |servlet-class|javax.faces.webapp.FacesServlet|/servlet-class|
      |load-on-startup|1|/load-on-startup|
      |/servlet|

      Abraços…

  2. luiz disse:

    estou pegando a seguinte exceção:
    HTTP Status 500 –

    ——————————————————————————–

    type Exception report

    message

    description The server encountered an internal error () that prevented it from fulfilling this request.

    exception

    org.apache.jasper.JasperException
    org.apache.jasper.servlet.JspServletWrapper.handleJspException(JspServletWrapper.java:460)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:355)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    root cause

    javax.servlet.ServletException
    org.apache.jasper.runtime.PageContextImpl.doHandlePageException(PageContextImpl.java:841)
    org.apache.jasper.runtime.PageContextImpl.handlePageException(PageContextImpl.java:774)
    org.apache.jsp.consulta_jsp._jspService(consulta_jsp.java:90)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    root cause

    java.lang.ExceptionInInitializerError
    pacote.ConnectLivrariaFactory.(ConnectLivrariaFactory.java:14)
    pacote.Consulta.procurarCurso(Consulta.java:24)
    org.apache.jsp.consulta_jsp._jspService(consulta_jsp.java:72)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    root cause

    java.lang.NoClassDefFoundError: org/hibernate/cfg/AnnotationConfiguration
    pacote.ConnectLivrariaFactory.(ConnectLivrariaFactory.java:10)
    pacote.Consulta.procurarCurso(Consulta.java:24)
    org.apache.jsp.consulta_jsp._jspService(consulta_jsp.java:72)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    root cause

    java.lang.ClassNotFoundException: org.hibernate.cfg.AnnotationConfiguration
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1363)
    org.apache.catalina.loader.WebappClassLoader.loadClass(WebappClassLoader.java:1209)
    java.lang.ClassLoader.loadClassInternal(Unknown Source)
    pacote.ConnectLivrariaFactory.(ConnectLivrariaFactory.java:10)
    pacote.Consulta.procurarCurso(Consulta.java:24)
    org.apache.jsp.consulta_jsp._jspService(consulta_jsp.java:72)
    org.apache.jasper.runtime.HttpJspBase.service(HttpJspBase.java:98)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)
    org.apache.jasper.servlet.JspServletWrapper.service(JspServletWrapper.java:331)
    org.apache.jasper.servlet.JspServlet.serviceJspFile(JspServlet.java:329)
    org.apache.jasper.servlet.JspServlet.service(JspServlet.java:265)
    javax.servlet.http.HttpServlet.service(HttpServlet.java:803)

    note The full stack trace of the root cause is available in the Apache Tomcat/5.5.26 logs.

    ——————————————————————————–

    Apache Tomcat/5.5.26

  3. Kleber Cardoso disse:

    eae serjaum, blz??

    Primeiro quero te parabenizar pelos tutoriais!!! São realmente a “luz no fim do túnel” pra muito desenvolvedor!!
    Agora, quero tirar a minha dúvida contigo… usei tua implementação como modelo, e estou tendo problemas com o ServletException…

    Se não for pedir d+, gostaria que vc me ajudasse…

    vou postar meu codigo no bean, no dao e no jsp pra ver se fica mais claro….

    no Bean===============

    public List getServicoParaComboBox() {
    // NOVA IMPLEMENTAÇAO DE TESTE
    Session session = HibernateUtil.currentSession();

    ServicoDao dao = new ServicoDao(session, Servico.class);

    List servicos = dao.pesquisaServicos(this.programa
    .getCod_programa());

    List lista = new ArrayList(servicos.size());
    for (Servico s : servicos) {
    lista.add(new SelectItem(s.getCod_servico(), s.getNome()));
    }

    return lista;
    }

    public void actionCarregaServicos() {
    System.out.println("id do programa selecionado >>> "
    + this.programa.getCod_programa());

    this.servico = (Servico) this.getServicoParaComboBox(); //TIVE DE COLOCAR O CAST PARA SERVICO, PQ FICAVA DANDO ERRO E PEDINDO PRA MUDAR O servico para List;
    }

    o DAo========
    public class ServicoDao extends Dao {

    public ServicoDao(Session session, Class classe) { //no tutorial do serjaum, ele recomendou usar Class classe, aqui não deu certo
    super(session, classe);
    }

    @SuppressWarnings("unchecked")
    public List getServicoByPrograma(Long id) { // esse foi o método do serjaum... deu a ServletException
    Query q = session.createQuery("select c from "
    + Servico.class.getName()
    + " as c where c.programa.id like :id");
    q.setParameter("id", id);

    return q.list();
    }

    @SuppressWarnings("unchecked")
    public List pesquisaServicos(Long id) { //esse eu adaptei para teste, usando criteria, mas deu a mesma ServletException
    Criteria c = session.createCriteria(Servico.class);
    c.add(Restrictions.ilike("id", "%" + id + "%"));

    return c.list();
    }

    }

    jsp==========

    //ELE APRESENTA O ERRO NESSA LINHA!!!!

    Eae serjaum, me ajuda ae man!!!! Agradeço!!!

    Feliz Natal e um Próspero ano novo!!!!!

  4. juniorsatanas disse:

    Esse tópico serve para várias coisas !

  5. juniorsatanas disse:

    TO PEGANDO ESTE ERRO:

    HTTP Status 500 –

    type Exception report

    message

    descriptionThe server encountered an internal error () that prevented it from fulfilling this request.

    exception

    javax.servlet.ServletException: javax.servlet.ServletException: org.hibernate.exception.SQLGrammarException: could not execute query

    root cause

    javax.servlet.ServletException: org.hibernate.exception.SQLGrammarException: could not execute query

    root cause

    javax.faces.el.EvaluationException: org.hibernate.exception.SQLGrammarException: could not execute query

    root cause

    org.hibernate.exception.SQLGrammarException: could not execute query

    root cause

    org.postgresql.util.PSQLException: ERRO: operador n�o existe: bigint ~~ bigint

    note The full stack traces of the exception and its root causes are available in the GlassFish v3 logs.
    GlassFish v3

  6. Murilo Moreira disse:

    olá Serjaumfantin,

    primeiro agradeçer pelo tutorial, muito bom!

    utilizando a mesma ideia, acrescentei mais um combo, o de bairros,
    o qual é carregado a partir da cidade selecionada.
    bom até ai beleza! o problema é quando mudo novamente o estado,
    a lista de cidade é carregada, porém a lista de bairros não é renderizada.
    Assim o valor do bairro fica com o valor do selected do bairro que eu selecionei
    antes de mudar o estado.
    por mais que eu coloque o id do combo no código reRender, ele não muda.
    reRender="cmbUnidadeFederativa,cmbCidade,cmbBairro"

  7. andré disse:

    Serjaumfantin, gostei do projeto porém tentei fazer o download e o link está inativo.
    Peço que restabeleça o link.

  8. jeferson disse:

    Opa serjaum não sei se você ainda ta respondendo aqui nesse toturial em todo caso…
    Muito bom mesmo o material aqui segunda vez que você me salva, no entanto
    estou com um problema:
    meu projeto possui um sistema de login e quando tento usar esse seu exemplo
    não consigo pegar a sessão que foi aberta. Alguma dica de como posso resolver?

    abraços
    Jeff

  9. jeferson disse:

    Serjaum tenho uma pagina onde tem essas duas combobox.
    apos escolher as duas e preencher alguns campos devo clicar no botao de salvar.
    no entanto como o event ta onchange é feita uma nova requisisição e eu perco os valores de cidade e estado selecionados antes. Pode me ajudar a resolver isso? Fazer com que ele não recarregue a pagina ao clicar no botão salvar?

    abraços
    Jeff Costa

  10. Tiago disse:

    Olá Sergio parabéns pelo tutorial, achei mto bom, entao implementei em um exemplo.
    porem ao colocar o Estado como um atributo de uma classe Cliente, precisei criar um conversor. Agora estou com um erro de validação, se puder me ajudar eu agradeço.

    http://www.guj.com.br/java/278322-jsf—validation-error-value-is-not-valid-#1465969

    obrigado.


Deixe uma resposta

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s