PrimeFaces 3.4.1: GMap
Autor: andii.brunetta | Publicado: 2012-11-13T02:38:00-03:00


Olá!

Depois de algum tempo, aqui estou eu com mais uma postagem sobre PrimeFaces, desta vez estou usando a versão 3.4.1. Peço desculpas se por acaso eu perdi a didática de escrever aqui, é que faz muito tempo que não escrevo mais.

Mas vamos lá...&nbsp;Hoje a postagem é sobre o GMap, pra quem ainda não sabe o PrimeFaces já tem um componente com a biblioteca GMap, pra usá-la é bem simples.

Primeiramente vamos baixar a biblioteca do Prime, basta clicar aqui.

Para este projeto estarei usando JPA, para quem ainda não sabe como usar: é só ver os primeiros links da página Nível: Intermediário.



Meu projeto ficou com essa estrutura:







Começando... adicione a biblioteca do PrimeFaces às bibliotecas do projeto. E na página index:


&lt;html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"&gt;
    &lt;h:head&gt;
        &lt;script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true" /&gt;
        &lt;title&gt;GMap&lt;/title&gt;
    &lt;/h:head&gt;
    &lt;h:body&gt;
        &lt;p:gmap center="-15.565986,-54.309782" zoom="15" type="HYBRID" style="width:600px;height:400px" /&gt;  
    &lt;/h:body&gt;
&lt;/html&gt;




Vamos aos pontos importantes do código acima:

Linha 3: lembre-se de adicionar a taglib do prime na página

Linha 5:&nbsp;Ponto importante para o funcionamento do p:gmap, que é a biblioteca do Google para o maps funcionar.

Linha 9:&nbsp;Este código é suficiente para aparecer o mapa, e você já poderá navegar pelo mundo! Mas vamos aos detalhes dessa linha: a propriedade center&nbsp;se refere à latitude e longitude, esta propriedade indica qual será o ponto onde o mapa deverá abrir inicialmente; a propriedade zoom se refere ao zoom do mapa, que pelos meus testes pode ir de 0 até 20 (talvez em alguns lugares possa ir a mais ou menos que isso); a propriedade type&nbsp;trata da forma de visualizar o mapa, que pode ser HYBRID (mapa e satélite), ROADMAP (apenas mapa), TERRAIN (terreno: uma opção que fica abaixo do mapa) ou&nbsp;SATELLITE (visão do satélite, mas vi que ele habilita a opção mapa também, mas se escolher ela, o mapa não aparece, uma solução para usar apenas o satélite seria usar a propriedade&nbsp;mapTypeControl="false").

Resultado:






Capturar Latitude e Longitude



Seguindo ainda a mesma base usado anteriormente, irei usar para este exemplo minha classe LocalBean (vide imagem da estrutura do meu projeto lá em cima), nela faça o seguinte:
@javax.faces.bean.ManagedBean
@javax.faces.bean.ViewScoped
public class LocalBean {
    
    public void pontoSelecionado(PointSelectEvent event) {  
        LatLng latituteLongitude = event.getLatLng();  
          
        FacesContext.getCurrentInstance().addMessage(
            null,
            new FacesMessage(
                FacesMessage.SEVERITY_INFO, 
                "Ponto selecionado", 
                "Lat:" + latituteLongitude.getLat() + ", Long:" + latituteLongitude.getLng()
            )
        );  
    }  
}


Detalhes do código
Linha 5 e 6: as classes&nbsp;PointSelectEvent e LatLng devem ser importadas da biblioteca do PrimeFaces.



E a index deve ser editada para:
&lt;h:form&gt;
    &lt;p:growl id="mensagem"  showDetail="true" /&gt;

    &lt;p:gmap center="-15.565986,-54.309782" zoom="15" type="HYBRID" style="width:600px;height:400px"&gt;
        &lt;p:ajax event="pointSelect" listener="#{localBean.pontoSelecionado}" update="mensagem" /&gt;
    &lt;/p:gmap&gt;
&lt;/h:form&gt;


Adicionamos tudo dentro de um h:form por conta do p:growl, então na linha 2 adicionamos o p:growl.
Linha 5:&nbsp;é adicionado a tag p:ajax, onde temos a propriedade event, listener que chama o método da nossa classe LocalBean, e por fim atualizamos o growl.
Resultando em:






Adicionando e carregando marcadores de um banco de dados

Para este exemplo estaremos gravando os marcadores em um banco de dados, e como disse anteriormente, estarei usando JPA para agilizar este desenvolvimento, então, para começo de conversa vamos fazer nossa classe model.Local:
@Entity
@Table(name="local")
public class Local implements Serializable{
    
    @Id
    @GeneratedValue(strategy= GenerationType.IDENTITY)
    @Column(name="codigo", nullable=false, unique=true)
    private Long codigo;
    @Column(name="descricao")
    private String descricao;
    @Column(name="latitude")
    private double latitude;
    @Column(name="longitude")
    private double longitude;

    /*
     * Getters e Setters
     */
}



Agora vamos fazer nossa classe dao.LocalDAO:
@Stateless
public class LocalDAO {
    
    @PersistenceContext(unitName="PrimeGmapPU")
    private EntityManager em;
    
    public void gravar(Local local){
        try {
            em.persist(local);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
    
    public List&lt;Local&gt; listar(){
        List&lt;Local&gt; locais = new ArrayList&lt;Local&gt;();
        try {
            Query query = em.createQuery("SELECT l FROM Local l");
            locais = query.getResultList();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return locais;
    }
    
}



Lembrando que na Linha 4, o unitName, é da minha unidade de persistência, o que pode mudar de acordo como você criou sua conexão.

Agora vamos para nossa classe controller.LocalBean, eu refiz ela, ou seja tirei do projeto aquela questão do growl,&nbsp;ela ficou dessa forma:


@javax.faces.bean.ManagedBean
@javax.faces.bean.ViewScoped
public class LocalBean implements Serializable{

    @EJB
    private LocalDAO localDAO;
    private Local local;
    private MapModel locais;

    public void novo(PointSelectEvent event) {
        local = new Local();
        LatLng coord = event.getLatLng();
        local.setLatitude(coord.getLat());
        local.setLongitude(coord.getLng());
    }

    public void gravar() {
        localDAO.gravar(local);
        carregarLocais();
    }

    private void carregarLocais() {
        locais = new DefaultMapModel();

        List&lt;Local&gt; locaisList = localDAO.listar();
        for (Local l1 : locaisList) {
            locais.addOverlay(
                    new Marker(
                    new LatLng(l1.getLatitude(), l1.getLongitude()),
                    l1.getDescricao()));
        }
    }

    /*
     * Getters e Setters
     */
    public MapModel getLocais() {
        if (locais == null) {
            carregarLocais();
        }
        return locais;
    }

}



Linha 8: a classe MapModel deve ser importada da biblioteca do Primefaces;

Linha 10: método novo, responsável por pegar as coordenadas geográficas e setar no meu objeto Local;

Linha 17: método gravar, responsável por chamar o DAO e gravar o método no banco de dados;

Linha 22: método carregarLocais, este método é responsável por converter uma lista de locais em um MapModel;

Linha 37: neste caso estou mostrando apenas esse get, por ter um diferencial que é carregar os locais caso o mesmo esteja null.



E por fim nossa página index.xhtml:
&lt;html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:h="http://java.sun.com/jsf/html"
      xmlns:p="http://primefaces.org/ui"&gt;
    &lt;h:head&gt;
        &lt;script type="text/javascript" src="http://maps.google.com/maps/api/js?sensor=true" /&gt;
        &lt;title&gt;GMap&lt;/title&gt;
    &lt;/h:head&gt;
    &lt;h:body style="font-size: 12px"&gt;
        &lt;p:gmap id="mapa" center="-15.565986,-54.309782" zoom="15" model="#{localBean.locais}" onPointClick="dlgLocal.show()" type="HYBRID" style="width:600px;height:400px"&gt;
            &lt;p:ajax event="pointSelect" listener="#{localBean.novo}" update="formLocal" /&gt;
        &lt;/p:gmap&gt;

        &lt;p:dialog widgetVar="dlgLocal" width="280" height="100"&gt;  
            &lt;h:form id="formLocal"&gt;  
                &lt;p:focus for="desc" /&gt;
                &lt;h:panelGrid columns="2" style="width: 100%"&gt;
                    &lt;h:outputLabel for="desc" value="Descrição:" /&gt;  
                    &lt;p:inputText id="desc" value="#{localBean.local.descricao}" /&gt; 
                &lt;/h:panelGrid&gt;
                &lt;p:toolbar&gt;
                    &lt;p:toolbarGroup align="right"&gt;
                        &lt;p:commandButton value="Gravar" actionListener="#{localBean.gravar()}" oncomplete="dlgLocal.hide()" update=":mapa" /&gt;
                    &lt;/p:toolbarGroup&gt;
                &lt;/p:toolbar&gt;
            &lt;/h:form&gt;  
        &lt;/p:dialog&gt;
    &lt;/h:body&gt;
&lt;/html&gt;



Agora vamos entender o que está acontecendo nesta página:

Linha 9:&nbsp; temos o gmap, com a propriedade model, que está relacionada ao MapModel do nosso controller, e a propriedade onPointClick, que abre o dialog de cadastro de um novo marcador;
Linha 10: chama o método novo quando é clicado no mapa;
Linha 13: temos o dialog que faz o cadastro de um novo marcador.
Ficando dessa forma:






Este projeto foi apenas para dar uma base de como carregar e adicionar marcadores no gmaps com o PrimeFaces. Também não tratei o dialog, ou seja, precisaria de um "trato especial" no caso dele não fechar quando o campo descrição estiver vazio. Bom eu tenho o código que faz isso, mas para não deixar essa postagem mais extensa, não coloquei aqui, provavelmente eu deva criar uma postagem sobre como controlar o dialog, até mesmo como abrir ou fechar ele pelo controller.

Até mais! :)