Arquivo

Posts Tagged ‘jsf 2.0’

JSF 2.0 – PRIMEFACES – P:TREE – CONTROLE DE PERMISSÕES A MENUS

zApós algum tempo sem postar, devido a grande carga de trabalho, consegui um tempo para escrever sobre este maravilhoso componete da biblioteca primefaces. Desde que o vi no showcase sempre tive a idéia de utiliza-lo conforme irei mostrar para vocês, como um controle de permissões com checkboxs. A capacidade de uso deste componente é muito grande e variada devido a flexibilidade e quantidade de recursos agredados a ele.

Antes de iniciar o post gostaria de avisar aos nossos leitores que estão abertas as inscrições para dois cursos na nossa plataforma de ensino a distância. São eles o de FUNDAMENTOS DA LINGUAGEM JAVA e DESENVOLVENDO UMA APLICAÇÃO BÁSICA COM JSF 2.0 E PRIMEFACES. Para mais detalhes, visite a área de cursos em http://www.quebrandoparadigmas.com/cursos/, os preços estão bastante acessiveis, por isso, espero a participação de vocês.

O componete TREE

É um componente usado para exibir dados em formato de árvore. Abaixo os atributos do componente com uma breve descrição:

Nome Valor Padrão Tipo Descrição
id null Tipo Identificador único do componente.
rendered TRUE Boolean Valor boleano que especifica a renderização ou não do componente, quando FALSE o componente não será renderizado.
binding null Object Uma expression language que mapeia o componente para um UIComponente no managed bean.
value null Object Representa uma instância de TreeNode no managed bean.
var null String Nome da variável que será usada para representar cada nó da árvore durante a renderização.
expandAnim null String Animação a ser exibida quando um nó for expandido. Os valores válidos são: FADE_IN ou FADE_OUT.
collapseAnim null String Animação a ser exibida quando um nó for retraido. Os valores válidos são: FADE_IN ou FADE_OUT.
nodeSelectListener null MethodExpr Método do managed bean a ser executado quando um nó for selecionado.
nodeExpandListener null MethodExpr Método do managed bean a ser executado quando um nó for expandido.
nodeCollapseListener null MethodExpr Método do managed bean a ser executado quando um nó for retraído.
cache TRUE Boolean Defini se haverá cache para os nós carregados dinâmicamente. Quando TRUE os nós expandidos serão mantidos na memória.
widgetVar null String Valor da variável para JavaScript.
onNodeClick null String Evendo JavaScript a ser processado quando um nó for clicado.
expanded FALSE Boolean Quando TRUE todos os nós iniciarão expandidos.
update null String Id(s) do(s) componente(s) a ser(em) expandido(s) quando um nó for selecionado.
onselectStart null String Evento JavaScript invocado antes da requisição ajax.
onselectComplete null String Evento JavaScript invocado antes da requisição ajax.
selection null Object Array que referencia todos os nós selecionados.
propagateSelectionUp FALSE Boolean Propaga as seleções para os nós superiores.
propagateSelectionDown FALSE Boolean Propaga as seleções para os nós inferiores.
selectionMode null String Define o modo de seleção.

Fonte: Primefaces User’s Guide 2.2

Para o nosso exemplo utilizaremos:

– Mojarra 2.1
– Primefaces 2.2.1
– Mysql 5.1.53

Neste exemplo irei demonstrar como criar um controle de permissões, com o componente Tree, para gerenciar o acesso de usuários aos menus de uma aplicação. Para quem conseguiu implementar o exemplo de menu dinâmico, pode agregar esta funcionalidade e criar as permissões para cada usuário.

Abaixo o DER com a disposição das tabelas:

Assim, teremos três tabelas, uma para cadastrar os usuários da aplicação, outra para cadastrar os menus e finalmente uma que irá definir os menus que os usuários podem ter acesso.

Desta forma, criaremos os beans e os DAOs, veja imagem abaixo com a organização do projeto.

Como você puderam observar criaremos os três beans, um para cada tabela, abaixo veja o código dos modelos:

Obs.: Suprimimos os getters e setters.

Menu.java

public class Menu {

    private int id;
    private String descricao;
    private String url;
    private String icone;
    private String indice;

    /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Menu other = (Menu) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 3;
        hash = 67 * hash + this.id;
        return hash;
    }

    @Override
    public String toString() {
        return descricao;
    }
}

Usuario.java

public class Usuario {

    private int id;
    private String login;
    private String senha;
    private Timestamp ultimoAcesso;
    private List<Permissao> listaPermissao = new ArrayList<Permissao>();

   /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Usuario other = (Usuario) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 31 * hash + this.id;
        return hash;
    }
}

Permissao.java

public class Permissao {

    private int id;
    private Menu menu = new Menu();
    private Usuario usuario = new Usuario();

   /* Getters e Setters */

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final Permissao other = (Permissao) obj;
        if (this.id != other.id) {
            return false;
        }
        return true;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 11 * hash + this.id;
        return hash;
    }
}

No beans é muito importate sobreescrever os métodos equals, hashcode e toString, principalmente na classe Menu, pois iremos fazer comparações entre os objetos criados a partir desta classe.

Com estas classes criadas, vamos criar os DAOs pra acessar os dados na base de dados. Abaixo o código:

MenuDAO.java

public class MenuDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_DESCRICAO = "descricao";
    private final String COL_URL = "url";
    private final String COL_ICONE = "icone";
    private final String COL_INDICE = "indice";

    public List<Menu> listaTodos() throws SQLException {
        List<Menu> listaMenu = new ArrayList();
        String query = "select * from menus";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Menu menu = new Menu();
            menu.setId(rs.getInt(COL_ID));
            menu.setDescricao(rs.getString(COL_DESCRICAO));
            menu.setUrl(rs.getString(COL_URL));
            menu.setIcone(rs.getString(COL_ICONE));
            menu.setIndice(rs.getString(COL_INDICE));
            listaMenu.add(menu);
        }
        con.close();
        return listaMenu;
    }
    public Menu buscaPorId(int id) throws SQLException {
        Menu menu = new Menu();
        String query = "select * from menus where id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, id);
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            menu.setId(rs.getInt(COL_ID));
            menu.setDescricao(rs.getString(COL_DESCRICAO));
            menu.setUrl(rs.getString(COL_URL));
            menu.setIcone(rs.getString(COL_ICONE));
            menu.setIndice(rs.getString(COL_INDICE));
        }
        con.close();
        return menu;
    }
}

Na classe acima, temos somente dois métodos básicos dos DAOs, listaTodos e buscaPorId.

UsuarioDAO.java

public class UsuarioDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_LOGIN = "login";
    private final String COL_SENHA = "senha";
    private final String COL_ULTIMOACESSO = "ultimo_acesso";

    public List<Usuario> listaTodos() throws SQLException {
        List<Usuario> listaUsuario = new ArrayList<Usuario>();
        String query = "select * from usuarios";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ResultSet rs = ps.executeQuery();
        while (rs.next()) {
            Usuario usuario = new Usuario();
            usuario.setId(rs.getInt(COL_ID));
            usuario.setLogin(rs.getString(COL_LOGIN));
            usuario.setSenha(rs.getString(COL_SENHA));
            usuario.setUltimoAcesso(rs.getTimestamp(COL_ULTIMOACESSO));
            listaUsuario.add(usuario);
        }
        con.close();
        return listaUsuario;
    }

    public Usuario buscaPorId(int id) throws SQLException {
        Usuario usuario = new Usuario();
        String query = "select * from usuarios where id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, id);
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            usuario.setId(rs.getInt(COL_ID));
            usuario.setLogin(rs.getString(COL_LOGIN));
            usuario.setSenha(rs.getString(COL_SENHA));
            usuario.setUltimoAcesso(rs.getTimestamp(COL_ULTIMOACESSO));
        }
        con.close();
        return usuario;
    }
}

Na classe acima, temos somente dois métodos básicos dos DAOs, listaTodos e buscaPorId.

PermissaoDAO.java

public class PermissaoDAO {

    private Connection con;
    private final String COL_ID = "id";
    private final String COL_USUARIO = "usuarios_id";
    private final String COL_MENU =  "menus_id";

    public List<Permissao> buscaPorUsuario(Usuario usuario) throws SQLException {
        List<Permissao> listaPermissao = new ArrayList<Permissao>();
        MenuDAO menuDAO = new MenuDAO();
        String query = "select * from permissoes where usuarios_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ResultSet rs = ps.executeQuery();
        while(rs.next()) {
            Permissao permissao = new Permissao();
            permissao.setId(rs.getInt(COL_ID));
            permissao.setUsuario(usuario);
            permissao.setMenu(menuDAO.buscaPorId(rs.getInt(COL_MENU)));
            listaPermissao.add(permissao);
        }
        con.close();
        return listaPermissao;
    }

    public Permissao buscaPorMenuUsuario(Menu menu, Usuario usuario) throws SQLException {
        Permissao permissao = new Permissao();
        String query = "select * from permissoes where usuarios_id=? and menus_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ps.setInt(2, menu.getId());
        ResultSet rs = ps.executeQuery();
        if (rs.next()) {
            permissao.setId(rs.getInt(COL_ID));
            permissao.setMenu(menu);
            permissao.setUsuario(usuario);
        }
        con.close();
        return permissao;
    }

    public void excluiPorUsuario(Usuario usuario) throws SQLException {
        String query = "delete from permissoes where usuarios_id=?";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, usuario.getId());
        ps.execute();
        con.close();
    }

    public void salvar(Permissao permissao) throws SQLException {
        String query = "insert into permissoes(menus_id,usuarios_id) values(?,?)";
        con = ConnectionFactory.getMySQLConnection();
        PreparedStatement ps = con.prepareStatement(query);
        ps.setInt(1, permissao.getMenu().getId());
        ps.setInt(2, permissao.getUsuario().getId());
        ps.execute();
        con.close();
    }
}

Na classe acima temos os métodos buscaPorUsuario, que retorna uma coleção de Permissao, para todos os registros que o usuário for igual ao passado como parâmetro.  Temos tambem, buscaPorMenuUsuario, que retorna uma coleção de Permissao, para aquele registro onde o usuário e o menu são iguais aos passados como parâmetro. Além desses, temos excluirPorUsuario, que exclui todas as permissões do usuário passado como parâmetro e o método salvar, que persiste a permissão passada como parâmetro.

Com estas classes criadas, estamos prontos para partirmos para o desenvolvimento da página. Como toda aplicação JSF criaremos um managed bean para a página que iremos criar e neste colocaremos os atributos que serão acessados na página, além dos métodos que controlarão todas as ações.

A seguir confira como ficou nosso managed bean:

Obs.: Irei suprimir os getters e setters.

PermissaoManagedBean.java
@ManagedBean
@ViewScoped
public class PermissaoManagedBean {

    private TreeNode root;
    private TreeNode[] nosSelecionados;
    private Usuario usuarioSelecionado = new Usuario();
    private List<Usuario> listaUsuario = new ArrayList();
    private List<Permissao> listaPermissao = new ArrayList();
    private List<Menu> listaMenu = new ArrayList();
    private List<Menu> menusPermitidos = new ArrayList();
    private List<Menu> menusUsuario = new ArrayList();
    private UsuarioDAO usuarioDAO = new UsuarioDAO();
    private PermissaoDAO permissaoDAO = new PermissaoDAO();
    private MenuDAO menuDAO = new MenuDAO();

    public PermissaoManagedBean() {
        try {
            listaUsuario = usuarioDAO.listaTodos();
        } catch (SQLException ex) {
            Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

/* Getters e Setters */
    private boolean isFilho(String[] indicesPai, String[] indicesFilho) {
        boolean isFilho = false;
        int i = 0;
        if (indicesPai.length == indicesFilho.length - 1) {
            for (String string : indicesPai) {
                isFilho = string.equals(indicesFilho[i]);
                if (!isFilho) {
                    break;
                }
                i++;
            }
        }
        return isFilho;
    }

    private void carregarFilhos(List<Menu> menus, Menu menu, TreeNode treeNode) {
        for (Menu m : menus) {
            String[] indicesPai = menu.getIndice().split("\\.");
            String[] indicesFilho = m.getIndice().split("\\.");
            TreeNode tr;
            if ((indicesFilho.length > indicesPai.length)) {
                if (isFilho(indicesPai, indicesFilho)) {
                    if (m.getUrl().equals("")) {
                        tr = new DefaultTreeNode(m, treeNode);
                        carregarFilhos(menus, m, tr);
                    } else {
                        tr = new DefaultTreeNode(m, treeNode);
                        if (isPermitido(m)) {
                            tr.setSelected(true);
                        }
                    }
                }
            }
        }
    }

    private boolean isPermitido(Menu menu) {
        boolean retorno = false;
        for (Menu m : menusPermitidos) {
            if (m.equals(menu)) {
                retorno = true;
                break;
            }
        }
        return retorno;
    }

    public void carregaPermissoesUsuario() {
        permissaoDAO = new PermissaoDAO();
        menuDAO = new MenuDAO();
        root = new DefaultTreeNode("Qp", null);
        menusPermitidos = new ArrayList<Menu>();
        try {
            listaPermissao = permissaoDAO.buscaPorUsuario(usuarioSelecionado);
            listaMenu = menuDAO.listaTodos();

            for (Permissao permissao : listaPermissao) {
                menusPermitidos.add(permissao.getMenu());
            }
            if (usuarioSelecionado.getId() != 0) {
                for (Menu menu : listaMenu) {
                    if ((menu.getUrl().trim().equals("")) && (menu.getIndice().length() == 1)) {
                        TreeNode treeNode = new DefaultTreeNode(menu, root);
                        carregarFilhos(listaMenu, menu, treeNode);
                    }
                }
            }
        } catch (SQLException ex) {
            Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    public void salvaPermissoes() {
        if (usuarioSelecionado.getId() == 0) {
            FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_ERROR, "Nenhum usuário SELECIONADO", "Erro"));
        } else {
            try {
                permissaoDAO.excluiPorUsuario(usuarioSelecionado);
                for (TreeNode no : nosSelecionados) {
                    if (no.isLeaf()) {
                        Menu folha = (Menu) no.getData();
                        Permissao permissao = new Permissao();
                        permissao.setMenu(folha);
                        permissao.setUsuario(usuarioSelecionado);

                        permissaoDAO.salvar(permissao);
                        salvaPai(no);
                    }
                }
                carregaPermissoesUsuario();
                FacesContext.getCurrentInstance().addMessage(null, new FacesMessage(FacesMessage.SEVERITY_INFO, "Permissões Salvas", "Permissões Salvas"));
            } catch (SQLException ex) {
                Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }

    public void salvaPai(TreeNode no) {
        TreeNode tr = no.getParent();
        if (!tr.equals(root)) {
            Permissao p;
            try {
                p = permissaoDAO.buscaPorMenuUsuario((Menu) tr.getData(), usuarioSelecionado);
                if (p == null) {
                    Permissao permissao = new Permissao();
                    permissao.setUsuario(usuarioSelecionado);
                    permissao.setMenu((Menu) tr.getData());
                    permissaoDAO.salvar(permissao);
                }
                salvaPai(tr);
            } catch (SQLException ex) {
                Logger.getLogger(PermissaoManagedBean.class.getName()).log(Level.SEVERE, null, ex);
            }
        }
    }
}

E abaixo o código da página, que é controlada pelo backing bean acima:

<?xml version='1.0' encoding='UTF-8' ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml"
      xmlns:p="http://primefaces.prime.com.tr/ui"
      xmlns:f="http://java.sun.com/jsf/core"
      xmlns:h="http://java.sun.com/jsf/html">
    <h:head>
        <title>QuebrandoParadigmas.com</title>
    </h:head>
    <h:body>
        <h:form>
            <p:panel header="Controle de Permissões" style="margin-top: 10px; width: 500px;">
                <h:panelGrid columns="2">
                    <h:selectOneMenu value="#{permissaoManagedBean.usuarioSelecionado.id}">
                        <f:selectItem itemValue="0" itemLabel=""/>
                        <f:selectItems value="#{permissaoManagedBean.listaUsuario}" var="usuario"
                                       itemValue="#{usuario.id}" itemLabel="#{usuario.login}"/>
                        <p:ajax event="change" listener="#{permissaoManagedBean.carregaPermissoesUsuario()}"
                                update="panelPermissoes"/>
                    </h:selectOneMenu>
                    <p:ajaxStatus>
                        <f:facet name="start">
                            <h:graphicImage value="./imagens/ajax-loader.gif" />
                        </f:facet>
                        <f:facet name="complete">
                            <h:outputText value="" />
                        </f:facet>
                    </p:ajaxStatus>
                </h:panelGrid>
            </p:panel>
            <p:panel id="panelPermissoes" style="margin-top: 10px; margin-bottom: 10px; width: 500px;">
                <p:messages/>
                <p:tree value="#{permissaoManagedBean.root}" selectionMode="checkbox" var="no"
                        expanded="true" expandAnim="FADE_IN" collapseAnim="FADE_OUT"
                        selection="#{permissaoManagedBean.nosSelecionados}" propagateSelectionUp="true" propagateSelectionDown="true">
                    <p:treeNode>
                        <h:outputText value="#{no}" style="margin-left: 10px;"/>
                    </p:treeNode>
                </p:tree>
            </p:panel>
            <p:commandButton value="Salvar" action="#{permissaoManagedBean.salvaPermissoes()}" update="panelPermissoes"/>
        </h:form>
    </h:body>
</html>

Temos um selectOneMenu que lista todos os usuários, representados no managed bean por List<Usuario>, que é preenchido no controller.

Como o escopo do backing bean é de visão(@ViewScoped) sempre que dermos um refresh na página os comandos contidos no construtor serão novamente executados e a página retorna ao seu estado padrão.

Dentro do selectOneMenu inserimos um componente do AjaxEngine do primefaces, o p:ajax com o parametro event = change, ou seja, sempre que "mudarmos" o valor do "combo" será executado o método que esta em parametro listener. Ou seja, sempre que o valor for alterado o métodos carregaPermissoesUsuario() será executado e o painel panelPermissoes será atualizado ao final.

O método carregaPermissoesUsuario() preenche o objeto raiz da árvore, root, com todos os menus que existem na tabela Menu e posteriormente verifica quais dos menus são permitidos ao usuário selecionado e, através do método setSelected(true), define na visão quais "folhas" deverão ser marcadas no componente tree. Bom pessoal, espero que consigam integrar com o menu dinâmico, é simples.

Boa sorte e espero ter ajudado.

Abaixo vídeo da aplicação exemplo rodando:

Gostou do Post? Então faça-nos uma doação:

JSF 2.0 – Primefaces 2.2 – FileUpload com ImageCropper

 

FileUpload

O componente FileUpload, como o prórprio nome diz, é responsável pelo envio de imagens da máquina cliente para o lado servidor. Este componente vai além da navegação da tag html <input type=”file”>, trazendo funcionalidades flashjavascript. Podemos filtrar arquivos, fazer múltiplos uploads, processamento parcial da página e uma barra para acompanhamento do progresso do upload. Caso o navegador cliente não suporte flash ou javascrip o fileupload retorna a funcionalidade padrão de <input type=”file”>.

Em um post anterior, já descrevi como utilizar FileUpload, porém, da versão utilizada no post até a atual tivemos algumas modificações na forma de configuração, o que me leva a descrever alguns procedimentos novamente.

Bibliotecas necessárias:

Configuração do web.xml:

<filter>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <filter-class>org.primefaces.webapp.filter.FileUploadFilter</filter-class>
</filter>

<filter-mapping>
   <filter-name>PrimeFaces FileUpload Filter</filter-name>
   <servlet-name>Faces Servlet</servlet-name>
</filter-mapping>

Abaixo descrição dos principais atributos do componente:

  • id:  Identificador único do componente
  • rendered: Valor boleano para especificar se o componente deve ou não ser exibido
  • fileUploadListener:  Método a ser executado quando sempre que um arquivo for ser enviado
  • multiple:  Habilita o envio de múltiplos arquivos
  • update: id de um componente a ser atualizado após o término do envio do arquivo
  • auto: Quando habilitado(true) o upload do arquivo começa logo após a seleção
  • label: Rótulo do botão, o padrão é ‘Browse’
  • image: Imagem de fundo do botão
  • cancelImage: Imagem do botão cancelar
  • width: Largura do botão de procura
  • height: Altura do botão de procura
  • allowTypes: Lista de extensões de arquivos aceitas
  • description: Rótulo que descreve quais tipos de arquivo podem ser enviados
  • sizeLimit: Número máximo de bytes aceitos
  • wmode: Propriedade wmode do objeto flash
  • customUI: Quando habilitado(true) os links upload e cancel  não são exibidos
  • widgetVar: Nome do widget para referências em javascript

ImageCropper

O componente ImageCropper  tem como funcionalidade recortar determinadas regiões de uma imagem. Esta funcionalidade criauma nova imagem contendo a região recordada e associando-a a um objeto do tipo CroppedImage instanciado no lado servidor.

Abaixo descrição dos principais atributos do componente:

  • id:  Identificador único do componente
  • rendered: Valor boleano para especificar se o componente deve ou não ser exibido
  • required: Indica se o campo é obrigatório
  • value:  EL para um Objeto do tipo CroppedImage instanciado no managed bean.
  • image:  Caminho para a imagem(context path)
  • initialCoords:  Coordenadas da posição inicial da região de corte

Criação de Aplicação integrando FileUpload e ImageCropper

Para criação desta aplicação iremos criar uma view(index.xhtml), uma pasta imagens onde armazenaremos as imagens utilizadas no sistema e uma pasta upload para colocar as imagens enviadas através do file upload. A estrutura do projeto ficará conforme imagem abaixo:

Para este projeto simples devemos criar um bean gerenciado de escopo de sessão para controlar a nossa view, abaixo confira o código.
Obs.: Desconsideramos os getters e setters.

IndexManagedBean.java

@ManagedBean
@SessionScoped
public class IndexManagedBean {

private StreamedContent imagemEnviada = new DefaultStreamedContent();
private String imagemTemporaria;
private CroppedImage croppedImage;
private boolean exibeBotao = false;

/* getters e setters */

   public void criaArquivo(byte[] bytes, String arquivo) {
      FileOutputStream fos;
      try {
         fos = new FileOutputStream(arquivo);
         fos.write(bytes);
         fos.close();
      } catch (FileNotFoundException ex) {
         Logger.getLogger(IndexManagedBean.class.getName()).log(Level.SEVERE, null, ex);
      } catch (IOException ex) {
         Logger.getLogger(IndexManagedBean.class.getName()).log(Level.SEVERE, null, ex);
      }
   }

   public void enviarImagem(FileUploadEvent event) {
      byte[] img = event.getFile().getContents();
      imagemTemporaria = event.getFile().getFileName();
      FacesContext facesContext = FacesContext.getCurrentInstance();
      ServletContext scontext = (ServletContext) facesContext.getExternalContext().getContext();
      String arquivo = scontext.getRealPath("/upload/" + imagemTemporaria);
      criaArquivo(img, arquivo);
      setExibeBotao(true);
   }

   public void crop() {
      setImagemEnviada(new DefaultStreamedContent(new ByteArrayInputStream(croppedImage.getBytes())));
   }
}

O método enviarImagem(FileUploadEvent event) é utilizado no atributo fileUploadListener para ser executado sempre que uma imagem estiver sendo enviada. É neste método onde poderemos fazer conversões, criação de arquivos, etc.

Observem que no método é passado um parâmetro event com o qual eu consigo retirar todos os dados que preciso, como nome de arquivo, caminho, array de bytes referentes ao arquivo, etc. Iremos criar um arquivo temporário que será utilizado na view com o imageCropper, este arquivo é criado na pasta upload através do método criaArquivo, e também salvar o nome do arquivo criado em uma String, a imagemTemporaria.

Em seguida criamos o método crop() para coletar a imagem recortada e jogar dentro da imagemEnviada que é do tipo StreamedContent, que pode ser trabalhado dinamicamente com o um p:graphicImage. Abaixo confira a utilização de todos os métodos e atributos na view:

<h:form>
   <p:panel header="ImageCropper com FileUpload - QuebrandoParadigmas.com" style="width: 900px; margin: 0 auto; margin-top: 0px">
      <p:fileUpload fileUploadListener="#{indexManagedBean.enviarImagem}" sizeLimit="204800" auto="true"
                            image="/imagens/imgBuscar.png" customUI="true" update="outputPanelUpload"/>
      <p:outputPanel id="outputPanelUpload">
         <h:panelGrid columns="2">
            <h:outputText value="Imagem" rendered="#{indexManagedBean.exibeBotao}"/>
             <h:outputText value="Pre-visualização" rendered="#{indexManagedBean.exibeBotao}"/>
             <p:imageCropper id="imageCropperImagemTemporaria" value="#{indexManagedBean.croppedImage}"
              image="#{pageContext.servletContext.contextPath}/upload/#{indexManagedBean.imagemTemporaria}"/>
              <p:graphicImage value="#{indexManagedBean.imagemEnviada}" cache="false"/>
         </h:panelGrid>
         <p:commandLink action="#{indexManagedBean.crop}" update="outputPanelUpload"
                                   rendered="#{indexManagedBean.exibeBotao}">
            <p:graphicImage style="margin-top: 5px; border: none;" value="/imagens/imgCortar.png"/>
         </p:commandLink>
      </p:outputPanel>
   </p:panel>
</h:form>

Criamos um outputPanel de nome outputPanelUpload que é  atualizado sempre que algum dado no managed bean é alterado, como quando a imagem de upload é enviada e damos um update para exibi-la ou quando cortamos a imagem e atualizamos para exibir a região cortada em uma outra imagem. Gostaria de salientar o código abaixo, pois é nele onde carregamos  a imagem que foi criada no na pasta upload do servidor:
image=”#{pageContext.servletContext.contextPath}/upload/#{indexManagedBean.imagemTemporaria}”

Perceba que pego o caminho do contexto(pasta web) e dentro dele a pasta upload e, em seguida, acrescento com uma EL que representa o nome do arquivo que foi definido no fileUploadListener(enviaImagem).

O resultado você pode conferir no vídeo abaixo:





Twitter: @benignoms

Converters – JSF 2.0

Atendendo a pedidos vou comentar um pouco sobre o uso de converters no JSF 2.0. Para aqueles que não sabem Converters são classes que implementam a interface Converter e servem para converter dados da view(String) para um Objeto e vice-versa.  Todos os tipos básicos JSF converterá automaticamente. Mas, se você quiser converter um objeto do tipo Date, JSF provê o converter <f:convertDateTime>. Para utilizar esta tag, basta inseri-la dentro do componente que quer fazer a conversão, como no exemplo abaixo:

<h:outputText value="#{meuBean.data}">
<f:convertDateTime type="date" dateStyle="medium"/>
</h:outputText>

O convertDateTime suporta alguns atributos para uma melhor configuração, como type e dateStyle, dentre outros. Abaixo dou uma breve explicação sobre estes atributos.

dateStyle – Somente é válido se o atributo type estiver definido. Especifica o estilo da formatação da data. Os valores válidos são: short, medium  (default), long and full.

timeStyle – Somente é válido se o atributo type estiver definido. Especifica o estilo da formatação da hora. Os valores válidos são: short, medium  (default), long and full.

timeZone – Especifica uma zona de tempo. Caso não seja setado GMT será utilizado.

locale – Informa o local de exibição da data.

pattern – Especificação da formatação da data. Use esse atributo ou o type.

type – Informa o tipo de data. Os tipos validos são: date, time ou both

Caso você deseje fazer conversões de números, JSF te oferece o convertNumber. Abaixo veja um exemplo do uso deste converter:

</pre>
<h:outputText value="#{meuBean.data}">
<f:convertNumber type="number" maxIntegerDigits="3"/>
</h:outputText>

Attributos da tag:

currencyCode – Especifica o caractere que aparecerá a cada três digitos. Expressor de milhares, milhões, etc.

currencySymbol – O simbolo a ser exibido antes do valor monetário. Ex.: Para R$ você usa ?R$?.

integerOnly – Alguém tem dúvida? Somente inteiros 😀

minFractionDigits – Mínimo número de dígitos fracionados a serem exibidos.

maxFractionDigits – Máximo de dígitos fracionados a serem exibidos.

minIntegerDigits e maxIntegerDigits – Mínimo e máximo de dígitos inteiros.

pattern – É a máscara

type – Tipo do campo. Padrão é numeric, mas existem tambem currency e percent.

Caso nenhum destes dois converters resolva seu problema, veremos agora como criar o nosso converter customizado.

O problema é o seguinte:

No meu formulário vou precisar de um campo para armazernar o peso de uma pessoa. Até ai tudo bem, mas eu gostaria que no inputText o campo aparecesse com o sufixo kg(quilograma) Ex.: 82kg(uma String) e que quando fosse salvo no banco de dados, fosse salvo somente o 82 que é um numero inteiro. Então como fazer isso?

Primeiramente iremos criar a nossa classe que servirá como converter:


//Aqui eu digo que esse cara é um FACES CONVERTER, Antes eu tinha de mapear no facesc-config.xml
@FacesConverter(value="pesoConverter")
public class PesoConverter implements Converter {
//Aqui faremos a conversão de String(82kg) para Inteiro(82)
public Object getAsObject(FacesContext context, UIComponent component, String value) {
int retorno = 0;
 if (!(value.equals(""))) {
 String peso = value;
 String somenteNumero = peso.replace("kg", "");
 retorno = Integer.parseInt(somenteNumero);
 }
 return retorno;
}
//Aqui faremos o inverso. Conversão de Inteiro(82) para String(82kg)
 public String getAsString(FacesContext context, UIComponent component, Object value) {
String peso = value.toString();
peso = peso + "kg";
return peso;
 }
}

Para usa o converter agora é muito simples. basta inserir dentro do campo que você desejar, no nosso caso um inputText.

<h:inputText value="#{meuBean.peso}" converter="pesoConverter" />

E é isso, espero que tenham gostado de mais essa dica, aguardo sugestões para novos posts.

abraços

Menu dinâmico – JSF 2.0 + Primefaces

Bom dia,

Depois de algum tempo sem postar, volto com tudo pra falar sobre outro tema que muitas pessoas tem dificuldade de encontrar material completo na internet. Para completar, vamos começar a utilizar JSF 2.0 com Primefaces.

Nosso projeto consistirá em uma tabela que representará menus e submenus e através dela montaremos o menu da nossa aplicação dinâmicamente conforme o exemplo abaixo:

Menu dinâmico

Menu dinâmico

Segue abaixo a estrutura da tabela e os campos:

tab_menu

Tabela que contem todos os menus e sub-menus

tabela menu povoada

tabela menu povoada

Crie um esquema de banco de dados no banco de dados que preferir e apartir dele crie uma tabela chamada tab_menu. No nosso exemplo a tabela contem cinco campos: id, descrição, viewId, icone e tab_menus_id. O campo id representa o id do menu, o campo descrição é como se fosse o label, é o nome que será exibido no menu, o viewId representa a view que será exibida quando clicarmos no menu, a página ou a expression language, ou uma navigation rule depende de como você irá chamar a próxima view. O campo ícone, é a imagem que aparecerá junto ao menu e deverá estar na pasta imagens dentro da pasta web. Já o campo tab_menu_id condiz a um auto-relacionamento da tabela, que indicará a profundidade do menu.

Após a criação da tabela, veja como ficará a estrutura de pacotes do nosso projeto:

pacotes

pacotes e páginas

Daremos ênfase as classes que construirão o menu. Primeiro iremos criar a classe Menu.java dentro do pacote beans que será o modelo do nosso menu. Segue abaixo o código da classe:


package info.esolucao.sac.beans;

import java.util.List;

/**
 *
 * @author BENIGNO
 */
public class Menu {

 private int id;
 private String descricao;
 private String viewId;
 private String icone;
 private Menu menu;
 private List<Menu> listaMenu;

 public int getId() {
return id;
 }

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

 public List<Menu> getListaMenu() {
return listaMenu;
 }

 public void setListaMenu(List<Menu> listaMenu) {
this.listaMenu = listaMenu;
 }

 public String getDescricao() {
return descricao;
 }

 public void setDescricao(String descricao) {
this.descricao = descricao;
}

 public String getIcone() {
 return icone;
 }

 public void setIcone(String icone) {
 this.icone = icone;
 }

 public Menu getMenu() {
 return menu;
 }

 public void setMenu(Menu menu) {
 this.menu = menu;
 }

 public String getViewId() {
 return viewId;
 }

 public void setViewId(String viewId) {
 this.viewId = viewId;
 }
}

Todos os campos da tab_menu representados no bean. Agora veremos a classe MenuDAO.java que representa outro padrão de projetos, o padrão DAO(Data Access Object) onde separamos a regra de negócio do acesso ao banco de dados.


package info.esolucao.sac.dao;

import info.esolucao.sac.beans.Menu;
import info.esolucao.sac.factory.ConnectionFactory;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

/**
 *
 * @author BENIGNO
 */
public class MenuDAO {

 Connection con;
 String sql;

 public boolean verificaSubMenu(Menu menu) {
 sql = "select count(*) as total from tab_menus where tab_menus_id=?";
 con = ConnectionFactory.getConnection();
 int t = 0;
 try {
 PreparedStatement pstm;
 pstm = con.prepareStatement(sql);
 pstm.setInt(1, menu.getId());
 ResultSet rs = pstm.executeQuery();
 if (rs.next()) {
 t = rs.getInt("total");
 }
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return (t > 0);
 }

 public List<Menu> buscaPorMenu(Menu menu) {
 List<Menu> listaMenu = new ArrayList<Menu>();
 sql = "select * from tab_menus where tab_menus_id=?";
 con = ConnectionFactory.getConnection();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 pstm.setInt(1, menu.getId());
 ResultSet rs = pstm.executeQuery();
 while (rs.next()) {
 Menu m = new Menu();
 m.setId(rs.getInt("id"));
 m.setDescricao(rs.getString("descricao"));
 m.setIcone(rs.getString("icone"));
 m.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 m.setMenu(subMenu);
 listaMenu.add(m);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return listaMenu;
 }

 public Menu buscaPorId(int id) {
 sql = "select * from tab_menus where id=?";
 con = ConnectionFactory.getConnection();
 Menu menu = new Menu();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 pstm.setInt(1, id);
 ResultSet rs = pstm.executeQuery();
 if (rs.next()) {
 menu.setId(rs.getInt("id"));
 menu.setDescricao(rs.getString("descricao"));
 menu.setIcone(rs.getString("icone"));
 menu.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 menu.setMenu(subMenu);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return menu;
 }

 public List<Menu> listaTodos() {
 List<Menu> listaMenu = new ArrayList<Menu>();
 sql = "select * from tab_menus";
 con = ConnectionFactory.getConnection();
 try {
 PreparedStatement pstm = con.prepareStatement(sql);
 ResultSet rs = pstm.executeQuery();
 while (rs.next()) {
 Menu menu = new Menu();
 menu.setId(rs.getInt("id"));
 menu.setDescricao(rs.getString("descricao"));
 menu.setIcone(rs.getString("icone"));
 menu.setViewId(rs.getString("viewId"));
 Menu subMenu = new Menu();
 subMenu = buscaPorId(rs.getInt("tab_menus_id"));
 menu.setMenu(subMenu);
 listaMenu.add(menu);
 }
 con.close();
 } catch (SQLException ex) {
 Logger.getLogger(MenuDAO.class.getName()).log(Level.SEVERE, null, ex);
 }
 return listaMenu;
 }
}

Criei quatro métodos de acesso a dados do banco de dados, o primeiro public boolean verificaSubMenu(Menu menu), verifica se o menu tem filhos(submenus ou itens do menu) retornando verdadeiro ou falso. O segundo List<Menu> buscaPorMenu(Menu menu) busca todos os filhos do menu passado como parâmetro e retorna uma coleção do tipo Menu. O terceiro Menu buscaPorId(int id) retorna o Menu correspondente ao id passado como parâmetro. Por fim, o quarto método List<Menu> listaTodos() retorna todos os Menus cadastrados no banco de dados. Todos estes métodos nós utilizaremos na nossa classe de controle, no nosso bean gerenciado, que chamaremos de indexController.java.

Abaixo o código da classe indexController.java


package info.esolucao.sac.controllers;

import info.esolucao.sac.beans.Menu;
import info.esolucao.sac.dao.MenuDAO;
import java.util.List;
import javax.enterprise.context.RequestScoped;
import javax.faces.bean.ManagedBean;
import org.primefaces.component.menuitem.MenuItem;
import org.primefaces.component.submenu.Submenu;
import org.primefaces.model.DefaultMenuModel;
import org.primefaces.model.MenuModel;

/**
 *
 * @author BENIGNO
 */
@ManagedBean
@RequestScoped
public class indexController {

 private MenuModel menuModel;
 private MenuDAO menuDAO = new MenuDAO();

 public void geraMenu() {
 menuModel = new DefaultMenuModel();
 List<Menu> listaMenu = menuDAO.listaTodos(); // Substituir o listaTodos() pelos menus permitidos
 for (Menu menu : listaMenu) {
 if (menu.getMenu().getId() == 0) {
 Submenu submenu = new Submenu();
 submenu.setLabel(menu.getDescricao());
 for (Menu m : menuDAO.buscaPorMenu(menu)) {
 if (!menuDAO.verificaSubMenu(m)) {
 MenuItem mi = new MenuItem();
 mi.setValue(m.getDescricao());
 mi.setIcon("imagens/" + m.getIcone());
 submenu.getChildren().add(mi);
 } else {
 Submenu sm = new Submenu();
 sm.setLabel(m.getDescricao());
 sm = geraSubmenu(m);
 submenu.getChildren().add(sm);
 }
 }
 menuModel.addSubmenu(submenu);
 }
 }
 }

 public Submenu geraSubmenu(Menu menu) {
 Submenu submenu = new Submenu();
 submenu.setLabel(menu.getDescricao());
 for (Menu m : menuDAO.buscaPorMenu(menu)) {
 if (!menuDAO.verificaSubMenu(m)) {
 MenuItem mi = new MenuItem();
 mi.setValue(m.getDescricao());
 mi.setStyle("width:100px");
 submenu.getChildren().add(mi);
 } else {
 submenu.getChildren().add(geraSubmenu(m));
 }
 }
 return submenu;
 }

 public MenuModel getMenuModel() {
 return menuModel;

 }

 public indexController() {
 geraMenu();

 }
}

Como estamos trabalhando com JSF 2.0, definimos que uma classe é um bean gerenciado através da anotação @ManagedBean e  dizemos o escopo do bean é de request através da anotação @RequestScoped. O que antes nós faziamos em um arquivo xml separado, agora é feito através de anotações, de forma elegante e sem precisar criar linhas e mais linhas de xml.

No nosso bean gerenciado possuímos dois atributos e quatro métodos. O atributo menuModel, do tipo org.primefaces.model.MenuModel que fará binding com o menu na view, representando o menu que será exibido. O segundo atributo é o menuDAO do tipo MenuDAO, que será usados empre que precisarmos verificar alguma informação no banco de dados. Além dos dois atributos, temos os quatro métodos, dos quais, um é o construtor do indexController.java onde iremos chamar o método principal geraMenu(), para gerar o menu assim que a view for chamada e o outro é um get do menuModel que envia o atributo para a view quando referenciado na mesma.

Os outros dois métodos, são onde está o “pulo do gato”, são os principais métodos da criação dos menus dinâmicos. São eles o método  geraMenu que vai gerar a base do menu, pegando os menus que não possuem PAI e colocando eles na base do menu e o geraSubmenu, um método recursivo que gera toda a árvode de submenus para um menu passado como parâmetro.

Agora, vamos ver como ficará  a nossa view, a nossa página xhtml:


<html xmlns="http://www.w3.org/1999/xhtml"
 xmlns:p="http://primefaces.prime.com.tr/ui"
 xmlns:h="http://java.sun.com/jsf/html">
 <h:head>
<link href="./css/skin.css" rel="stylesheet" type="text/css" />
<link href="./css/default.css" rel="stylesheet" type="text/css" />
<title>SAC</title>
</h:head>
<h:body>
<center>
<p:panel header="Sistema de Avaliação de Competências" style="text-align: left;width: 850px; vertical-align: middle;">
<h:panelGrid columns="2">
<h:column>
<h:form>
<p:menu model="#{indexController.menuModel}"/>
</h:form>
</h:column>
<h:column>
<h:form>
<p:panel style="width: 600px; vertical-align: top;">
</p:panel>
 </h:form>
 </h:column>
 </h:panelGrid>
 </p:panel>
 </center>
 </h:body>
</html>

Ficou muito simples, não? Todo o trabalho ficou no indexController.java através do método geraMenu() e na nossa camada de visão apenas exibimos o que foi gerado. Atentem para o detalhe que estou usando um skin(skin.css)  para que a página fique com uma aparência melhor. Para aprender como usar skins e outras funcionalidades do primefaces, visitem o blog do meu amigo Wagner Borges: [url]http://quebrandoparadigmas.wordpress.com/2010/06/28/utilizando-skin-no-primefaces/[/url]

Bom, essa é a forma que gosto de trabalhar, se é a melhor ou não… fica a critério de vocês julgar.  Espero ter ajudado, qualquer dúvida é só mandar um comentário. Valeu!

Introdução ao JSF 2.0 com PrimeFaces parte II

Hoje eu vou mostrar mais um componente do primefaces e vou também falar um pouco sobre a nova forma de declarar Managed Beans no JSF 2.0. O componente que vou mostrar é o <p:collector />, esse componente é um facilitador para formulario do tipo  mestre-detalhe visto que ele inseri e remove objetos de uma lista a ele associado. O componente comumente está associado á um componente <h:commandButton> e um <h:dataTable />.

Criando nossas classes de Modelo e Managed Bean.

Seguindo o exemplo que foi dado no último post, a nossa estrutura de projeto deve está conforme a imagem exibida abaixo:

Estrutura do projeto

Por questão de organização e padronização nós vamos adicionar dois novos pacotes em nosso pacotes de código-fonte chamados de org.seed.exemploprime.managedbeans e org.seed.exemploprime.modelo. Para criar os pacotes basta clicar com o botão direito sobre a pasta Pacotes de código-fonte –> Novo –> Pacote Java. Dentro do pacote org.seed.exemploprime.modelo vamos adicionar uma classe java chamada de Aluno, a classe Aluno representa uma entidade de nosso sistema e é comumente chamada pela comunidade como um DTO (Data Transfer Object) e segue um padrão chamado de JavaBeans. A nossa classe é exibida abaixo:

package org.seed.exemploprime.modelo;

/**
 *criado em 27/04/2010
 * @author wagnerborges
 */
public class Aluno {
 private String matricula;
 private String nomeCompleto;
 private String login;
 private String senha;

 public String getLogin() {
 return login;
 }

 public void setLogin(String login) {
 this.login = login;
 }

 public String getMatricula() {
 return matricula;
 }

 public void setMatricula(String matricula) {
 this.matricula = matricula;
 }

 public String getNomeCompleto() {
 return nomeCompleto;
 }

 public void setNomeCompleto(String nomeCompleto) {
 this.nomeCompleto = nomeCompleto;
 }

 public String getSenha() {
 return senha;
 }

 public void setSenha(String senha) {
 this.senha = senha;
 }
}

Agora vamos adicionar no pacote org.seed.exemploprime.managedbeans uma classe chamada de AlunoManagedBean, essa classe vai interagir com nossa página capturando os eventos e dados fornecidos pelos usuários. Essa classe também é chamada de Backing Bean. A classe vai ficar como o código abaixo:


package org.seed.exemploprime.managedbeans;

import java.util.ArrayList;
import java.util.List;
import javax.faces.bean.ManagedBean;
import org.seed.exemploprime.modelo.Aluno;

/**
 *criado em 27/04/2010
 * @author wagnerborges
 */

@ManagedBean
@SessionScoped

public class AlunoManagedBean {
 private Aluno aluno = new Aluno();
 private List<Aluno> listaAlunos = new ArrayList();

 public Aluno getAluno() {
 return aluno;
 }

 public void setAluno(Aluno aluno) {
 this.aluno = aluno;
 }

 public List<Aluno> getListaAlunos() {
 return listaAlunos;
 }

 public void setListaAlunos(List<Aluno> listaAlunos) {
 this.listaAlunos = listaAlunos;
 }

public void create(){
 aluno = new Aluno();
 }


}

A classe acima merece alguns comentários. Como foi dito acima ela representa um managed bean, isso significa dizer que eu posso vincular (binding) seus atributos ou métodos com componentes de minhas páginas JSF. É essa caracteristica que torna o JSF uma framework orientado a componentes e a eventos. O que caractetiza nossa classe como sendo um bean gerenciado é a anotação @ManagedBean sobre a definição da classe. Essa é nova forma de se declarar  Managed Bean na nova especificação JSF, antes isso era feito em pelo menos 5 linhas em um arquivo xml chamdo de faces-config.xml que é o arquivo de configuração do Java Server Faces. Uma outra anotação que podemos perceber logo abaixo é a anotação @SessionScoped, essa anotação informa que o escopo de nosso bean gerenciado é de sessão, ou seja, enquanto durar minha sessão eu vou ter um objeto da classe AlunoManagedBean na sessão da minha aplicação. Análogo ao escopo de sessão existe o escopo de request referenciado pela anotação @RequestScoped onde um novo objeto é criado a cada requisição realizada pelo usuario. Ainda existem outros tipos de escopos: @ConversationScoped que cria um escopo de conversação entre duas páginas onde os objetos permanecem “vivos”  entre a pagina que originou o request até a página alvo. @ApplicationScoped que cria um escopo cujos os objetos são vistos por toda aplicação enquanto a aplicação estiver em execução.

Nossa classe AlunoManagedBean possui dois atributos: aluno da classe Aluno cujos atributos vamos vincular com os campos do nosso formulario e um atributo listaAlunos que é do tipo ArrayList que é onde vamos armazenar nossos objetos criado. A lista também será usada para exibir uma tabela com os objetos já cadastrados. Além dos dois atributos a classe possui um método chamado de create que será chamdo sempre que um novo objeto for inserido na lista, isso para que todos objetos sejam diferentes e não apontem para o mesmo endereço de memória.

Feito isso, a nova estrutura de nosso projeto deve está conforme imagem abaixo:

Nova Estrutura

O que vamos fazer agora é vincular nossa página index.xhtml com os atributos do nosso Bean Managed, mas qual é o nome do nosso Bean Managed? é o mesmo nome da classe? Antes do JSF2 deveriamos informa qual o nome do objeto que seria criado e referenciado nas páginas, mas agora quando colocamos a anotação @ManagedBean temos a opção de informa um nome ou não. Se desejarmos informar um nome fazemos assim: @ManagedBean(name=”alunoBean”), mas se não desejamos explicitar um nome para o nosso bean gerenciado um nome é criado tomando como base o nome da classe com a primeira letra em minusculo, então no nosso caso o objeto que será criado e que vamos referenciar em nossas páginas vai ser alunoManagedBean. Abaixo o código da nossa página index.html depois de alterado. Os comentários sobre os componentes vem logo em seguida.


<?xml version='1.0' encoding='UTF-8' ?>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml"

xmlns:h="http://java.sun.com/jsf/html"

xmlns:p="http://primefaces.prime.com.tr/ui"

xmlns:f="http://java.sun.com/jsf/core">

<h:head>

<title>Facelet Title</title>

</h:head>

<h:body>

<h:panelGrid>

<p:messages />

<h:form>

<p:panel closable="true" footer="Cadastro" header="Cadastro de Alunos" style="width: 350PX">

<h:panelGrid columns="2">

<h:outputLabel value="Matricula:"/>

<h:inputText id="matricula" required="true" value="#{alunoManagedBean.aluno.matricula}"

requiredMessage="Campo [Matricula] obrigatório"/>

<h:outputLabel value="Nome Completo:"/>

<h:inputText id="nome" required="true" value="#{alunoManagedBean.aluno.nomeCompleto}"

requiredMessage="Campo [Nome Completo] obrigatório"/>

<h:outputLabel value="Nome p/ Login:"/>

<h:inputText id="login" required="true" value="#{alunoManagedBean.aluno.login}"

requiredMessage="Campo [Nome p/ login] obrigatório"/>

<h:outputLabel value="Senha:"/>

<p:password minLength="6" value="#{alunoManagedBean.aluno.senha}"

promptLabel="Digite uma senha segura"

goodLabel="Boa"

weakLabel="Razoável"

strongLabel="Excelente" />

<h:commandButton value="Cadastrar" action="#{alunoManagedBean.create}">

<p:collector value="#{alunoManagedBean.aluno}" addTo="#{alunoManagedBean.listaAlunos}"/>

</h:commandButton>

</h:panelGrid>

</p:panel>

</h:form>

<br/><br/>

<h:form>

<p:dataTable value="#{alunoManagedBean.listaAlunos}" var="aluno">

<p:column>

<f:facet name="header">

<h:outputText value="Matricula" />

</f:facet>

<h:outputText value="#{aluno.matricula}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Nome" />

</f:facet>

<h:outputText value="#{aluno.nomeCompleto}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Login" />

</f:facet>

<h:outputText value="#{aluno.login}" />

</p:column>

<p:column>

<f:facet name="header">

<h:outputText value="Remover" />

</f:facet>

<h:commandLink value="remover">

<p:collector value="#{aluno}" removeFrom="#{alunoManagedBean.listaAlunos}"/>

</h:commandLink>

</p:column>

</p:dataTable>

</h:form>

</h:panelGrid>

</h:body>

</html>

Vamos aos comentários

Primeiramente, fazemos a vinculação dos campos com os atributos:

<pre><h:inputText id="matricula" required="true" value="#{alunoManagedBean.aluno.matricula}" requiredMessage="Campo [Matricula] obrigatório"/></pre>

alunoManagedBean é o nome do objeto que foi criado da nossa classe AlunoManagedBean, aluno é um atributo da classe Aluno e nomeCompleto um atributo do objeto aluno.

O trecho abaixo mostra onde fazemos uso do componente <p:collector /> associado com um componente <h:commandButton />, o componente <h:commanButton/> possui um atributo chamado de action onde informamos qual o método que deverá ser executado quando o mesmo for pressionado. Nesse caso, a action associada a esse botão é o método create do nosso ManagedBean. Em seguida nosso componente <p:collector/> é adicionado com dois atributos, no atributo value é informado qual o objeto do ManagedBean se deseja armazenar na lista e no atributo addTo é informado em qual lista o objeto será amazeado.

<pre><h:commandButton value="Cadastrar" action="#{alunoManagedBean.create}">

<p:collector value="#{alunoManagedBean.aluno}" addTo="#{alunoManagedBean.listaAlunos}"/>

</h:commandButton></pre>

Em seguida criamos uma tabela informando no atributo value qual a lista que será exibida e um atributo var para informa o nome do objeto que está sendo interado pela lista.

<pre><p:dataTable value="#{alunoManagedBean.listaAlunos}" var="aluno"></pre>

Na tabela também adicionamos um link para remover objetos da lista utilizando o componente <p:collector> informando qual o objeto se deseja remover através do atributo value e de qual lista esse objeto será removido através do atributo removeFrom.

<pre><h:commandLink value="remover">

<p:collector value="#{aluno}" removeFrom="#{alunoManagedBean.listaAlunos}"/>

</h:commandLink></pre>

A imagem abaixo exibe nossa página index.xhtml em execução:

Resultado Final do Exemplo

Bom pessoal é isso aí. Espero que gostem e que seja útil.

abraços e até a próxima.

Introdução à JPA com Hibernate

Pessoal, desculpa pelo longo tempo sem fazer nenhum post aqui no blog. Esses dias eu andava ocupadíssimo escrevendo um pré-projeto para participar de uma seleção de mestrado da UFPE, graças a Deus que deu certo :).

Voltando aos posts, hoje eu vou escrever um post que prometi para alguns alunos que me indagaram esses dias sobre JPA e Hibernate.

Introdução ao Hibernate

Para quem ainda não sabe o hibernate é uma ferramenta de ORM, Object Relational Mapping (Mapeamento objeto relacional) que foi desenvolvido por Gave King e hoje faz parte da corporação Red Hat, juntamente com o JBoss. Uma ferramenta de mapeamento Objeto relacional como o Hibernate, TopLink, JDO  tem como objetivo facilitar o trabalho do desenvolvedor no que diz respeito ao relacionamento entre uma aplicação java orientada a objeto e um banco de dados relacional. A idéia principal é criar uma camada entre a aplicação e o banco de dados de modo que o desenvolvedor não tenha que se preocupar com instruções SQL ou com o banco de dados na qual a aplicação irá persistir seus dados, algo que não é feito utilizando só JDBC.

Anotações e JPA

Fazer mapeamento no hibernate era um tanto trabalho até a chegada do Java 5 que trouxe as fabulosas anotações. Antes tudo era configurado em arquivos XML, mas agora tudo ficou bem mais simples com o uso das anotações.

O hibernate se tornou de fato a ferramenta ORM  mais utilizada no mundo e uma prova disso foi o convite da Sun Microsystems para o Gavin King escrever a especificação JPA (Java Persistence API). Agora o java possui uma especificação para ORM.

Estudo de Caso

Para demonstrar o básico do hibernate vamos criar um pequeno sistema de gerencia de projetos contendo as seguintes entidades: Projeto, Atividade e Responsavel. Para esse projeto vamos utilizar o Netbeans IDE 6.8, banco de dados MySQL e o Hibernate 3.x . Em um outro post vamos utilizar JSF 2.0 para colocar nosso projeto na web e aproveitar para conhecer as novidades desse magnifico framework na JEE6.

Criando novo Projeto e Configurando o hibernate.

Com o Netbeans aberto cri um novo projeto aplicativo java( Arquivo -> Novo Projeto -> Java -> Aplicativo Java) e chame-o de exemplo_hibernate.

Vamo agora preparar nosso projeto para utilizar o hibernate. A primeria coisa a ser feita é adicinar as bibliotecas do hibernate no nosso projeto, para fazer isso clique com o botão direito sobre a pasta bibliotecas e escolha a opção Adicionar Biblioteca. Na tela que se abrir procure por Hibernate JPA e depois clique em adicionar, a partir desse momento nosso projetojá possui todas as bibliotecas que precisamos para trabalhar com o hibernate.

Uma outra biblioteca deve ser adicionada, essa corresponde ao driver JDBC do banco que vamos utilizar para o nosso exemplo, nesse caso o driver do MySQL. O procedimento é semelhante ao descrito acima, o nome da biblioteca a ser adicionada é MySQL JDBC Driver.

Depois de ter adicionado nossas bibliotecas, vamos adicionar três pacotes no nossso pacote de código fonte:

conf -> pacote onde vamos colocar o arquivo de configuração do hibernate

modelos – > pacote onde vamos coloca nossas classes de domínio (Projeto, Atividade e Responsavel)

testes -> pacote onde vamos colocar as classes que vamos utilizar para fazer nossos testes.

utils -> pacote onde vamos colocaralgumas classes utilitarias.

Para adicionar um pacote siaga: botão direito em cima da pasta pacotes de código fonte -> Novo -> Pacote Java

Vamos adicionar no pacote conf o arquivo de configuração do hibernate, o hibernate.cfg.xml, clique com o botão direito do mouse sobre o pacote conf e escolha a opção novo. Na tela que abrir escolha, no lado categorias a opção Hibernate e do lado direito escolha a opção Assistente Para configuração do Hibernate, conforme imagem abaixo:

Criando arquivo de configuração do Hibernate

Clicando no botão próximo o assistente solicita o nome arquivo, vamos deixar com estar. Observe o campo pasta, provavelmente ele deve está com o src, vamos subistituir por src/conf, porque nós queremos que nosso arquivo fique no pacote conf.

Na próxima tela ele pede que seja informado uma conexão com alguma fonte de dados, essa conexão pode ter sido criada anteriomente, mas nós vamos criar uma nova conexão. Então escolhano combobox a opção Nova Conexão com Banco de Dados, uma tela semelhante a exibida abaixo deverá aparecer:

Nova Conexão

Configuração da Nova conexão com o bando de dados

Algumas informações importantes dessa última tela:

Nome do Driver: Informação do Driver JDBC do banco que gostariamos de nos conectar. No nosso caso, vamos escolher MySQL

Host: Máquina onde nosso banco de dados está instalado e esperando por conexão, vamos informar localhost para dizer que o banco está instalado na nossa própria máquina.

Porta: Informação sobre qual porta o mysql está escutando, aguardando por conexão, se nenhuma porta é informada é utilizada a porta padrão a 3306.

Banco de Dados: Nome da nossa fonte de dados, onde nossas tabelas serão criadas. Caso ainda não tenha criado seu banco faço isso agora usando o seu mysql. Vamos chamar nosso banco de dados de projectdb

Nome Usuário: Nome do usuário usado para acessar seu banco de dados, vamos usar o usuário administrador que no mysql é o usuario root.

Senha: Informe a senha usada para acessar o banco de dados.

Pronto,  feito isso pode-se clicar em OK.  Se tudo estiver certo o assistente vai retornar para a tela anterior e nossa conexão vai está criada. Já podemos finalizar o assistente. Nossa arquivo irá aparecer dentro do nosso pacote conf e será automaticamente aberto pela nossa IDE, na visualização existem duas opções de exibição: XML e Projeto, a primeira exibe o xml corresponde e a outra dá a possibilidade de fazermos tudo visualmente.

Vamos fazer uma alteração na configuração atual do hibernate, vamos fazer com que seja exibido no console toda e qualquer instrução enviada para o banco de dados. Na janela de configuração do arquivo vamos selecionar a opção Propriedades Opcionais -> Propriedades de Configurar -> Adicionar, conforme imagem abaixo:

Adicionando a propriedade adicional

Na janela que se abrir escolha a opção hibernate.show_sql e campo digite true. Pronto está configurado.

Vamos adicionar nossa primeira entidade no nosso pacote modelos. Vamos escrever a entidade Responsavel. Clicando com o botão direito do mouse escolha a opção Novo -> Classe Java. Nossa classe ficará igual ao trecho abaixo:

package modelos;

import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;

/**
 * criando em 21/03/2010
 * @author wagner
 */
@Entity
public class Responsavel implements Serializable {

 @Id
 @GeneratedValue
 private long id;
 private String matricula;
 private String nome;

 public long getId() {
 return id;
 }

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

 public String getMatricula() {
 return matricula;
 }

 public void setMatricula(String matricula) {
 this.matricula = matricula;
 }

 public String getNome() {
 return nome;
 }

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

A classe acima merece alguns destaques. Nossa classe já se encontra devidamente anotada com as anotações da JPA. É importante observar que os imports feitos, foram todos do pacote javax.persitence e não do pacote do hibernate, isso porque nós queremos seguir a especificação e não apenas usar o hibernate de forma pura. Detalhando as anotações:

@Entity -> Informa que nossa classe é uma entidade e que seus objetos serão persistido em banco de dados.

@Id -> Informa o atributo que será nossa chave primaria.

@GeneratedValue -> Informa que o valor desse atributo será gerado automaticamente.

Observe que em nenhum momento fizemos referencia à nenhum nome de tabela ou coluna do banco de dados, isso porque estamos convencionando que o nome da tabela será o mesmo nome da classe e que o nome das colunas será o mesmo nome dos atributos. Caso quisessemos fazer isso deuma forma diferente poderiamos utilizar a anotação @Table(name=”nome_tabela”) para informa o nome da tabela com a qual nossa entidade seria mapeada. E também poderíamos utilziar @Column(“nome_coluna”) para informa nomes diferente para nossas colunas da tabela.

Vamos agora informar para o hibernate a localização da classe Responsavel para que ele possa reconhecer como uma entidade mapeada. Para isso vamos abrir nosso arquivo hibernate.cfg.xml e na opção mapeamentos vamos adicionar nossa classe. Veja Imagens abaixo:

Adicionando a entidade Responsavel no mapeamento

Adicionando a entidade Responsavel

Próximo passo é criar uma classe que leia nossa configuração e gere nosso banco de dados. Vamos criar uma classe chamada de GerarBancoDeDados no pacote utils, a classe em questão é exibida logo abaixo com os devidos comentários.

package utils;

import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.tool.hbm2ddl.SchemaExport;

/**
 * criando em 21/03/2010
 * @author wagner
 **/
public class GerarBancoDeDados {
 public static void main(String...args) {
 /**
 * A classe AnnotarionConfiguration é classe responsavel por ler nosso arquivo
 * hibernate.cfg.xml e reconhecer nossas entidades mapeadas.
 **/
 AnnotationConfiguration configuration = new AnnotationConfiguration();
 /**
 * o método configure é um método sobrecarregado, e em uma de suas sobrecargas
 * ele solicita o caminho do arquivo hibernate.cfg.xml. Caso o arquivo
 * não esteja em um pacote diferente do pacote desta classe, não seria necessario
 * informa o arquivo. Simplesmente chamariamos configuration.configure().
 **/
 configuration.configure("conf/hibernate.cfg.xml");
 SchemaExport export = new SchemaExport(configuration);
 /**
 * 0o método create espera dois argumento booleanos. O primeira informa
 * se queremos que ele exiba o script sql gerado. O segundo se queremos
 * que ele execute diretamente as instruções no banco de dados.
 * Vamos colocar ambos o paramentros true, para exibir o sql e executar
 * o mesmono banco de dados.
 **/
 export.create(true, true);
 }

}

Bom, se tudo estiver bem configurado e você não tiver esquecido nenhum detalhe, o hibernate gerou para você a tabela responsavel em seu banco de dados. Você pode contastar isso abrindo seu banco de dados ou simplesmente olhando o log gerado pelo hibernate na saída padrão (console), vocë deve ver algo parecido com isso:

...
INFO: connection properties: {user=root, password=****}
drop table if exists Responsavel
create table Responsavel (id bigint not null auto_increment, matricula varchar(255), nome varchar(255), primary key (id))
21/03/2010 14:35:07 org.hibernate.tool.hbm2ddl.SchemaExport execute
INFO: schema export complete
21/03/2010 14:35:07 org.hibernate.connection.DriverManagerConnectionProvider close
INFO: cleaning up connection pool: jdbc:mysql://localhost/projectdb
...

Com a tebela criada agora podemos fazer alguns testes. Mas antes disso vamos criar uma classe chamada de HibernateUtils, essa classe tem como finalidade funcionar como uma fábrica de sessões do hibernate para nós. Vamos adicionar essa classe no nosso pacote utils e ela tem a aparência da classe abaixo:

package utils;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.cfg.AnnotationConfiguration;

/**
 * criando em 21/03/2010
 * @author wagner
 **/
public class HibernateUtil {
 private static SessionFactory factory;

 /**
 * escopo estático. É a primeira coisa executa em uma classe e só executada
 * apenas uma vez. O bjetivo é carregar nossas configurações do hibernate
 * para que sessões possam ser criadas.
 *
 * O hibernate possui uma classe responsavel por funciona como uma fábrica
 * de sessões é a classe SessionFactory.
 *
 **/
 static {
 AnnotationConfiguration configuration = new AnnotationConfiguration();
 configuration.configure("conf/hibernate.cfg.xml");

 factory = configuration.buildSessionFactory();

 }

 /**
 * sempre que quisermos uma session do hibernate apenas chamamos
 * HibernateUtils.getSession();
 * @return
 **/
 public static Session getSession(){
 return factory.openSession();
 }

}

Esse procedimento para se obter uma sessão do hibernate, agora imagina ter que fazer isso sempre precisassemos de uma sessão! Por isso que escrevemos a classe HibernateUtils e adicionamos o método getSeesion(). Agora é bem simples obter uma sessão do hibernate, basta chama o método estático getSession assim: HibernateUtil.getSession().

Vamos agora fazer alguns testes com nossa entidade Responsavel. Para isso vamos criar uma nova classe no pacote testes chamada de TestaEntidadeResponsavel. O primeiro teste que vamos fazer é verificar se nossos objetos realmente estão sendo persistindo (armaezados) no nosso banco de dados. Nossa classe vai ter aparencia da classe abaixo:

package testes;

import modelos.Responsavel;
import org.hibernate.Session;
import utils.HibernateUtil;

/**
 * criando em 21/03/2010
 * @author wagner
 **/
public class TestaEntidadeResponsavel {
 public static void main(String...args) {
 /**
 * Solicitando uma sessão para nossa fábrica de sessões.
 **/
 Session session = HibernateUtil.getSession();
 /**
 * Criando um objeto da nossa entidade que será salvo no banco
 **/

 Responsavel responsavel = new Responsavel();
 responsavel.setMatricula("AM-123");
 responsavel.setNome("Wagner Borges");

 /**
 * Iniciando uma transação com o banco de dados
 **/
 session.getTransaction().begin();
 /**
 * chamando o método save do hibernate para persistir nosso objeto
 **/
 session.save(responsavel);
 /**
 * encerrando e comitando nossa transação
 **/
 session.getTransaction().commit();
 }
}

É simples assim mesmo. Dessa forma acabamos de fazer um insert na nossa tabela responsavel. Para constatar isso veja seu banco de dados e dê select em sua tabela. Ou simplesmente veja o log gerado na saída padrão, você deve ver algo mais ou menos assim:

...
INFO: building session factory
21/03/2010 15:08:36 org.hibernate.impl.SessionFactoryObjectFactory addInstance
INFO: Not binding factory to JNDI, no JNDI name configured
Hibernate: insert into Responsavel (matricula, nome) values (?, ?)
...

Utilizando a mesma classe poderíamos recuperar o objetos Responsavel cojo ID seja igual 1 de nosso banco de dados, assim:

...
Responsavel resp = (Responsavel) session.load(Responsavel.class, 1L);
System.out.println("Nome: " + resp.getNome());
...

Bom pessoal, pra começar já esta bom. Isso foi bem pouco do que realmente o hibernate pode fazer. No próximo post vamos falar um pouco de DAO, Generic DAO, Criteria API. Um abraço a todos e espero que ajude alguém com esse post. 🙂

JEE6 e Plugabilidade

Chega de fériado!!!

Continuando nossa série de posts sobre JEE6, vou falar um pouco sobre plugabilidade. Essa idéia é bastante interessante e com certeza ela veio para ficar. Essa nova feature faz parte das especificação de servlet 3.0 e consiste em tornar as aplicações web  mais modularizada e plugaveis, onde você pode plugar à sua aplicação web novas bibliotecas ou framework sem necessariamente fazer qualquer tipo de configuração extra em sua aplicação. Os modulos plugaveis são simples arquivos .jar que são adicionado ao seu projeto.

Para exemplificar vamos criar  um exemplo bem trivial no netbeans IDE.

  • Primeiramente vamos criar um novo projeto web no netbeans chamando de jee6webfragments.
  • Depois vamos criar um outro fragmento contento um Servlet.

Vamos adicionar esse fragmento à nossa aplicação e entender como ele funciona.

Criando um novo projeto web no netbeans.

Com o netbeans aberto vamos no menu Arquivo –> Novo Projeto,  janela que se abrir escolha a categoria Java Web do lado esquerdo e do lado direito escolha Aplicação Web. Na próxima janela chame a aplicação de jee6webfragments. na próxima janela É IMPORTANTE ATENTAR PARA A VERSÃO JEE, nós queremos trabalhar com a JEE6 E GLASSFISH V3 como servidor. Feito esses passos nós já temos uma aplicação web criada e pronta para nós trabalharmos. Vamos adicionar á nossa aplicação um servlet que vai ter como nome da classe o nome FachadaServlet, como nome do servlet o nome fachada e que responda pela URL /fachada. Depois de crido nosso servlet vai ter a seguinte aparencia:

Servlet fachada depois de criado

Nosso servlet está criado. Em caso de dúvida de como criar um servlet veja os posts anteriores. Para testar seu novo servlet execute sua aplicação pressionando a tecla F6. Quando seu navegador padrão abrir coloque na URL esse endereço: http://localhost:33292/jee6webfragments/fachada, a primeira parte da URL representa o contexto da nossa aplicação e parte em vermelhor representa a parte da URL que nosso servlet é responsavel por atender.

Criando nosso primero Fragmento WEB

vamos criar nosso primeiro fragmento web e plugar à nossa aplicação. Inicialmente devemos criar um novo projeto através do menu Arquivo–>Novo Projeto, na janela que se abrir vamos escolher a opção Java do lado esquerdo e do lado direito a opção Biblioteca de Classe Java. Conforme imagem abaixo:

Criando um novo fragmento web

A próxima tela pede pra você informar um nome para essa nova biblioteca de classes java, vamos chamá-la de servlet_fragmento. Feito isso um novo projeto é configurado na nossa IDE. Vamos adicionar ao nosso novo projeto um pacote chamado ser servlets, clique com o botão direito em cima da pasta pacotes de código fontes e escolha a opção novo depois pacote. Conforme imagem abaixo:

Criando um novo pacote java

Em nosso novo pacote vamos adionar um servlet cujo nome da classe vai ser ServletFragmento, o nome do servlet é fragmento1 e o padrão de URL que nosso servlet vai atender vai ser /fragmento1, nosso servlet vai ficar como a imagem abaixo:

Novo servlet do fragmento web

Você pode observar que os servlets criado apartir do netbeans contém um método chamado de processRequest. Esse método é executado quando o servlet é chamado para atender alguma requisição independentemente de ser uma requisição via GET ou via POST, pois ele (processRequest) é chamado tanto no método doGet como no método doPost. Vamos alterar o corpo do processRequest apagando o código comentado e acrescentando apenas a linha abaixo:

Método processRequest depois de alterado

Duas informações importante:

  • Devemos adicionar nas bibliotecas do nosso fragmento web todas as bibliotecas que fazem parte da JEE6 para que nosso fragmento compile com sucesso. Você pode notar que a classe do nosso servlet que acabamos de criar contem vários erros de imports, para resolver clique com o botão direito na pasta bibliotecas do fragmento web e escolha a opção adicionar biblioteca, na janela que se abrir escolha a bilbioteca Java-EE-Glassfish-v3. Todos os erros devem ter desaparecido agora. Veja Imagem abaixo:

Adicionando a biblioteca que contém os jar da JEE6

  • Opcionalmente podemos adicionar ao nosso fragmento web um arquivo xml chamado de web-fragment.xml. Esse arquivo é um aquivalente ao web.xml, é nele que colocamos configurações de fragmework, mapeamos servlets e filtros. Para o nosso exemplo não vamos adicioanar um web-fragment.xml, já que estamos mapeando nosso servlet via anotações. Entenderam a ideia? veja bem, eu adiciono no arquivo web-fragment.xml as confgurações de um determinado framework e depois plugo esse fragmento à minha aplicação. Isso é vantajoso porque na próxima aplicação já não preciso fazer as configurações novamente.

Agora só falta plugar nosso fragmento web na nossa aplicação. Antes de fazermos isso precisamos fazer o clear-build do nosso fragmento web para que o .jar seja criado, para fazer isso basta clicar com o botão direito em cima do projeto e escolher a opção Limpar e construir.

Para plugar nosso fragmento em nossa aplicação clique com o botão direito sobre a pasta bibliotecas da nossa aplicação e escolha a opção Adicionar projeto, na janela que se abrir vá até aonde está seu fragmento e selecione-o, observe que o Netbeans automaticamente identifica o seu .jar. Veja imagem abaixo:

Adicionando o Fragmento web na aplicação

Feito isso é só clicar em Adicionar arquivos JAR de Projeto, e o seu fragmento está plugado à sua aplicação. Para testar o que acabamos de fazer execute sua aplicação e acesse a seguinte URL: http://localhost:33292/jee6webfragments/fragmento1. Observe que fragmento1 é o padrão de URL do servlet que está em nosso fragmento web. Você deve ver em seu browser algo como a imagem abaixo:

Aplicação chamando o servlet do fragmento web

É isso aí pessoal!! depois a gente fala um pouco mais sobre os web fragments.

espero que que gostem..

um abraço.

Java Enterprise Edition 6

Recentemente, em 10 dezembro de 2009, a Sun Microsystems levou a público a tão esperada especificação JEE6. Essa nova especificação realmente se tornou um divisor de águas entre as anteriores devido as grande melhorias feitas em seus principais frameworks. Além das mudanças no que já existia, muitas outras tecnologias foram agregadas à plataforma.

Adotando as tendências modernas da convertion over configuration, depois um post sobre o assunto, coisas que eram bastante trabalhosas em versões anteriores agora estão bem mais simples.

Vou iniciar uma série de posts relacionados à essas mudanças de uma maneira bem prática e teórica, de modo que essas principais mudanças possam ser vista e compreendidas.

Dentre as princiapais mudanças e as novas teconologias que vieram agregadas à essa nova versão nós temos:

  • EJB 3.1
  • JPA 2.0
  • Servlet 3.0
  • JSF 2.0
  • Connectors 1.6
  • Interceptors 1.1
  • JAX-WS 2.2
  • JSR-109 1.3
  • JSP 2.2
  • EL 2.2
  • JSR-250 1.1
  • JACC 1.4
  • JASPIC 1.0
  • JAX-RS 1.1
  • Bean Validation 1.0
  • DI 1.0
  • CDI 1.0
  • Managed Bean 1.0

A figura abaixo mostra um pouco dessa evolução.

Evolução JEE

No próximo post vamos ver o que veio de novo na tecnologia de servlets e o quanto isso vai deixar nosso desenvolvimento mais produtivo.

abraços.