Introdução ao VRaptor – Crud

Este é o primeiro post de uma série que vai contemplar algumas tecnologias que estão ganhando cada vez mais espaço na área de programação WEB com Java. No primeiro momento, serão abordadas tecnologias como Hibernate 3, JPA 2.0, EJB 3, VRaptor 3, Ext JS e jQuery.

Inicialmente, vou preparar um projeto web simples, contendo apenas a camada de persistência gerenciada pelo JPA com Hibernate e VRaptor 3 para a camada de controle.

De forma simplificada, o fluxograma de um projeto VRaptor3 com persistência de dados é semelhante à imagem a seguir:

Os passos básicos para criar essa estrutura de projeto são:

  • Criação do projeto web
  • Adição das bibliotecas do VRaptor e JPA/Hibernate
  • Criação da base de dados
  • Configuração do JPA/Hibernate
  • Criação da Factory
  • Criação da entidade
  • Criação do DAO
  • Criação das classes entidades
  • Páginas JSP

Após esses passos, a estrutura final do projeto será semelhante à imagem que segue:

1 – Criação do projeto web
No site do VRaptor, existem algumas opções de download. Dentre elas, você pode baixar o VRaptor com a sua documentação e suas bibliotecas ou pode optar por um projeto em branco, o qual, para rodar, precisa apenas ser importado no Eclipse.

Neste post vamos escolher a primeira opção e criar o projeto do zero diretamente na IDE.

O primeiro passo é criar o projeto web em branco no menu File -> New -> Other. Vá até a pasta Web e selecione a opção Dynamic Web Project. Após, informe o nome do seu projeto, que nesse caso definimos como vraptor, e selecione o tomcat como Target Runtime. Clique em finish e o projeto será criado.

2 – Adição das bibliotecas do VRaptor e JPA/Hibernate

Com o projeto em branco criado, podemos adicionar as bibliotecas do VRaptor e JPA/Hibernate na pasta lib que se encontra dentro da pasta WebContent.

No caso do VRaptor, os jars necessários são o arquivo vraptor-3.1.x e os demais arquivos jar contidos na pasta lib/mandatory.

Para configurar o Hibernate, serão necessários os seguintes arquivos:

  • hibernate3.jar
  • antlr-2.7.6.jar
  • commons-collections-3.1.jar
  • dom4j-1.6.1.jar
  • javassist-3.9.0.GA.jar
  • jta-1.1.jar
  • slf4j-api-1.5.8.jar
  • hibernate-jpa-2.0-api-1.0.0-CR-1.jar
  • postgresql-8.2-505.jdbc4.jar
  • Download

3 – Criação da base de dados

Nesse projeto, vamos apenas utilizar duas tabelas: grupo e usuario. Elas terão relacionamento um para vários, ou seja, cada grupo poderá ter vários usuários.

O nome da base será teste e o código de criação das tabelas é o seguinte:

/* sequences das tabelas */
CREATE SEQUENCE grupo_id_seq INCREMENT 1;

CREATE SEQUENCE usuario_id_seq INCREMENT 1;

/* criacao da tabela grupo */
CREATE TABLE grupo (
 id INTEGER NOT NULL DEFAULT nextval('grupo_id_seq'),
 nm_grupo VARCHAR(100) NOT NULL
);

/* definicao da PK da tabela grupo */
ALTER TABLE grupo ADD CONSTRAINT pkgrupo
 PRIMARY KEY (id);

/* criacao da tabela usuario */
CREATE TABLE usuario (
 id INTEGER NOT NULL DEFAULT nextval('usuario_id_seq'),
 grupo_id INTEGER NULL,
 nm_usuario VARCHAR(100) NOT NULL,
 ds_email VARCHAR(200) NOT NULL,
 ds_login VARCHAR(200) NOT NULL,
 ic_email_publico BOOL NOT NULL,
 id_tipo_usuario INTEGER NOT NULL
);

/* definicao da PK da tabela usuario */
ALTER TABLE usuario ADD CONSTRAINT pkusuario
 PRIMARY KEY (id);

/* definicao da FK grupo na tabela usuario */
ALTER TABLE usuario ADD CONSTRAINT fk_usuario_grupo
 FOREIGN KEY (grupo_id) REFERENCES grupo (id) ON UPDATE NO ACTION ON DELETE NO ACTION;

4 – Configuração do JPA/Hibernate

Para configurar o JPA/Hibernate, vamos precisar criar dois arquivos. O primeiro é o persistence.xml, que irá conter as propriedades de conexão com o banco de dados. O segundo é o orm.xml, que irá mapear as named queries utilizadas no sistema. Ambos os arquivos devem estar na pasta src/META-INF para que as bibliotecas do Hibernate os localizem.

Para o nosso projeto, a estrutura do persistence.xml ficará assim:

<?xml version="1.0" encoding="UTF-8"?>
<persistence version="1.0" xmlns="http://java.sun.com/xml/ns/persistence">
    <persistence-unit name="vraptor">
    <provider>org.hibernate.ejb.HibernatePersistence</provider>
    <class>br.com.k2studio.vraptor.entity.Grupo</class>
    <class>br.com.k2studio.vraptor.entity.Usuario</class>
        <properties>
            <property name="hibernate.dialect" value="org.hibernate.dialect.PostgreSQLDialect" />
            <property name="hibernate.connection.url" value="jdbc:postgresql://localhost:5432/teste" />
            <property name="hibernate.connection.driver_class" value="org.postgresql.Driver" />
            <property name="hibernate.connection.username" value="postgres" />
            <property name="hibernate.connection.password" value="postgres" />
        </properties>
     </persistence-unit>
</persistence>

E, dentro desse contexto, vamos configurar o orm.xml e declarar a named query que vamos utilizar para buscar os grupos e usuários cadastrados:

<?xml version="1.0" encoding="UTF-8"?>
<entity-mappings version="1.0"
     xmlns="http://java.sun.com/xml/ns/persistence/orm"
     xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
     xsi:schemaLocation="http://java.sun.com/xml/ns/persistence/orm http://java.sun.com/xml/ns/persistence/orm_1_0.xsd">

     <named-query name="selectGrupos">
          <query>SELECT obj FROM Grupo obj ORDER BY obj.nmGrupo</query>
     </named-query>

     <named-query name="selectUsuarios">
          <query>SELECT obj FROM Usuario obj ORDER BY obj.nmUsuario</query>
     </named-query>

</entity-mappings>

5 – Criação da Factory
Para que o JPA se conecte ao banco de dados, é necessária a criação de uma Factory Manager que irá, através dos dados do persistence.xml, prover as conexões com o banco. Por ser um objeto que, uma vez instanciado, faz o gerenciamento dessas conexões, criaremos uma classe Singleton para que esse objeto seja instanciado apenas uma vez.

Classe JPAFactory.java:

package br.com.k2studio.vraptor.jpa;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

public class JPAFactory {

     private static EntityManagerFactory factory;

     private JPAFactory() {};

     public static EntityManager getEntityManager() {
          if(factory == null) {
               factory = Persistence.createEntityManagerFactory("vraptor");
          }
          return factory.createEntityManager();
     }

}

6 – Criação da entidade base:

Classe BaseEntity.java

package br.com.k2studio.vraptor.jpa;

public abstract class BaseEntity {
	public abstract Integer getId();
	public abstract void setId(Integer id);
}

7 – Criação do DAO
A classe GenericDAO é uma classe genérica para tratar a persistência e consulta aos dados. Como faremos apenas uma tela de CRUD simples nesse projeto, não haverá necessidade de criar DAO´s mais especializados. Mas caso você tenha essa necessidade, recomendo que crie seus DAO´s extendendo a classe GenericDAO.

package br.com.k2studio.vraptor.dao;

import java.util.List;

import javax.persistence.EntityManager;
import javax.persistence.Query;

import br.com.caelum.vraptor.ioc.Component;
import br.com.k2studio.vraptor.jpa.BaseEntity;
import br.com.k2studio.vraptor.jpa.JPAFactory;

@Component
public class GenericDAO {

     protected EntityManager manager;

     public GenericDAO() {
          manager = JPAFactory.getEntityManager();
     }

     public BaseEntity insert(BaseEntity entity) {
          manager.getTransaction().begin();
          manager.persist(entity);
          manager.getTransaction().commit();
          return entity;
     }

     public BaseEntity update(BaseEntity entity) {
          manager.getTransaction().begin();
          manager.merge(entity);
          manager.getTransaction().commit();
          return entity;
     }

     public void remove(BaseEntity entity) {
          entity = selectById(entity);
          manager.getTransaction().begin();
          manager.remove(entity);
          manager.getTransaction().commit();
     }

     public BaseEntity selectById(BaseEntity entity) {
          entity = manager.find(entity.getClass(), entity.getId());

          return entity;
     }

     public List<BaseEntity> selectByNamedQuery(String namedQuery) {
          return selectByNamedQuery(namedQuery, new Object[0]);
     }

     public List<BaseEntity> selectByNamedQuery(String namedQuery, Object ... parameters) {
          try {
               Query query = manager.createNamedQuery(namedQuery);
               if(parameters != null && parameters.length > 0) {
                    for (int i = 0; i < parameters.length; i++) {
                         query.setParameter(i + 1, parameters[i]);
                    }
               }
               List list = query.getResultList();
               return list;
          } catch (Exception ex) {
               ex.printStackTrace();
          }
          return null;
     }

}

8- Criação das classes entidades:
O mapeamento das tabelas em entidades é relativamente simples, contudo, como estamos utilizando um banco Postgre, a declaração da chave primária merece um pouco de atenção, visto que a mesma faz uso de uma SEQUENCE para determinar o valor da coluna ID.

Classe Grupo.java:

package br.com.k2studio.vraptor.entity;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class Grupo extends br.com.k2studio.vraptor.jpa.BaseEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@SequenceGenerator(name="GRUPO_ID_GENERATOR", sequenceName="GRUPO_ID_SEQ")
	@GeneratedValue(generator="GRUPO_ID_GENERATOR")
	private Integer id;

	@Column(name="nm_grupo")
	private String nmGrupo;

	/*Getters/Setters*/
}

Classe Usuario.java:

package br.com.k2studio.vraptor.entity;

import java.io.Serializable;
import javax.persistence.*;

@Entity
public class Usuario extends br.com.k2studio.vraptor.jpa.BaseEntity implements Serializable {
	private static final long serialVersionUID = 1L;

	@Id
	@SequenceGenerator(name="USUARIO_ID_GENERATOR", sequenceName="USUARIO_ID_SEQ")
	@GeneratedValue(generator="USUARIO_ID_GENERATOR")
	private Integer id;

	@Column(name="ds_email")
	private String dsEmail;

	@Column(name="ds_login")
	private String dsLogin;

	@Column(name="ic_email_publico")
	private boolean icEmailPublico;

	@Column(name="id_tipo_usuario")
	private Integer idTipoUsuario;

	@Column(name="nm_usuario")
	private String nmUsuario;

	//uni-directional many-to-one association to Grupo
	@ManyToOne(fetch=FetchType.EAGER)
	private Grupo grupo;

	/*Getters/Setters*/
}

9 – Classe Controller

package br.com.k2studio.vraptor.controller;

import java.util.List;

import br.com.caelum.vraptor.Path;
import br.com.caelum.vraptor.Post;
import br.com.caelum.vraptor.Resource;
import br.com.caelum.vraptor.Result;
import br.com.k2studio.vraptor.dao.GenericDAO;
import br.com.k2studio.vraptor.entity.Usuario;
import br.com.k2studio.vraptor.jpa.BaseEntity;

@Resource
public class UsuarioController {

     private final GenericDAO dao;
     private final Result result;

     public UsuarioController(GenericDAO dao, Result result) {
          this.result   = result;
          this.dao      = dao;
     }

     @Path("/usuario/lista")
     public void lista() {
          List<BaseEntity> usuarios = dao.selectByNamedQuery("selectUsuarios");
          result.include("usuarios", usuarios);
     }

     @Path("/usuario/formulario")
     public void formulario() {

     }

     @Path("/usuario/editar/{usuario.id}")
     public void editar(Usuario usuario) {
          usuario = (Usuario) dao.selectById(usuario);
          if(usuario != null) {
               result.include("usuario", usuario);
          }
          result.redirectTo(this.getClass()).formulario();
     }

     @Post
     @Path("/usuario/salvar")
     public void salvar(Usuario usuario) {
          if(usuario != null) {
               if(usuario.getId() == null) {
                    dao.insert(usuario);
               } else {
                    dao.update(usuario);
               }
          }
          lista();
          result.redirectTo(this.getClass()).lista();
     }

     @Path("/usuario/excluir/{usuario.id}")
     public void excluir(Usuario usuario) {
          if(usuario != null && usuario.getId() != null) {
               dao.remove(usuario);
          }
          lista();
          result.redirectTo(this.getClass()).lista();
     }

}

10 – Páginas JSP

lista.jsp

<%@page contentType="text/html"%>
<%@page pageEncoding="iso-8859-1"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
     <head>
          <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
          <title>VRaptor - Usuário : Lista</title>
     </head>
     <body>
          <center>
               <a href="<c:url value="/usuario/formulario"/>">Novo</a>
               <table width="500" border="1">
                    <thead>
                         <tr>
                              <td width="50">ID</td>
                              <td width="300">Nome</td>
                              <td width="75">Editar</td>
                              <td width="75">Excluir</td>
                         </tr>
                    </thead>
                    <tbody>
                         <c:forEach items="${usuarios}" var="usuario">
                              <tr>
                                   <td>${usuario.id}</td>
                                   <td>${usuario.nmUsuario}</td>
                                   <td><a href="<c:url value="/usuario/editar/${usuario.id}"/>">Editar</a> </td>
                                   <td><a href="<c:url value="/usuario/excluir/${usuario.id}"/>">Excluir</a></td>
                              </tr>
                         </c:forEach>
                    </tbody>
               </table>
          </center>
     </body>
</html>

formulario.jsp

<%@page contentType="text/html"%>
<%@page pageEncoding="iso-8859-1"%>
<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<html>
     <head>
          <meta http-equiv="Content-type" content="text/html; charset=iso-8859-1" />
          <title>VRaptor - Usuário : Lista</title>
     </head>
     <body>
          <center>
               <div style="width: 400; text-align: left;">
                    <a href="<c:url value="/usuario/lista"/>">Voltar</a>
               </div>
               <form action="<c:url value="/usuario/salvar"/>" method="post">
                    <table width="400">
                         <tr>
                              <td width="100" align="right">ID</td>
                              <td width="300"><input name="usuario.id" type="text" readonly value="${usuario.id}"> </td>
                         </tr>
                         <tr>
                              <td width="100" align="right">Nome</td>
                              <td width="300"><input name="usuario.nmUsuario" type="text" value="${usuario.nmUsuario}"> </td>
                         </tr>
                         <tr>
                              <td width="100" align="right">E-mail</td>
                              <td width="300"><input name="usuario.dsEmail" type="text" value="${usuario.dsEmail}"> </td>
                         </tr>
                         <tr>
                              <td width="100" align="right">Login</td>
                              <td width="300"><input name="usuario.dsLogin" type="text" value="${usuario.dsLogin}"> </td>
                         </tr>
                         <tr>
                              <td width="100" align="right">E-mail Público</td>
                              <td width="300"><input type="checkbox" name="usuario.icEmailPublico" <c:if test="${usuario.icEmailPublico}">checked</c:if>></td>
                         </tr>
                         <tr>
                              <td width="100" align="right">Tipo Usuário</td>
                              <td width="300">
                                   <INPUT TYPE=RADIO NAME="usuario.idTipoUsuario" VALUE="1" <c:if test="${usuario.idTipoUsuario == 1}">checked</c:if>>Usuário<BR>
                                   <INPUT TYPE=RADIO NAME="usuario.idTipoUsuario" VALUE="2" <c:if test="${usuario.idTipoUsuario == 2}">checked</c:if>>Administrador<BR>
                              </td>
                         </tr>
                         <tr>
                              <td colspan="2" align="right">
                                   <input type="submit" value="Salvar">
                              </td>
                         </tr>
                    </table>
               </form>
          </center>
     </body>
</html>
Resultado final

Listagem:

Formulário de cadastro:

Download do projeto: Download



Share on Facebook

Responses to Introdução ao VRaptor – Crud

  1. rodrigo disse:

    cara,

    sou novo em java EE e vraptor..

    Preciso criar o web.xml que o eclipse nao criou automatico..

    poderia disponibilizar o projeto para download?

    O link que vc deixou nao funciona

  2. João disse:

    Não terias um exemplo de CRUD usando vRaptor + ExtJs? Cara to quebrando a cabeça para fazer o vRaptor criar o objeto a partir dos dados que estão no request submit do form do extJs.

  3. Fabiano disse:

    Daniel,
    Estou tentando reproduzir esse seu exemplo dando uma customizada simples. Inclui no grupo uma propriedade com uma coleção de usuários. Mas não está dando certo. Qual seria a melhor forma pra isso?

    @OneToMany(cascade=CascadeType.ALL, mappedBy=”grupo”, fetch=FetchType.EAGER, orphanRemoval=true)
    private Collection usuarios;

    Isso bastaria ou eu deveria modificar algo mais, a named query, por exemplo?

  4. daniel disse:

    Sim, fiz um post sobre isso, segue o link: Integração ExtJS com VRaptor

  5. daniel disse:

    Fabiano,
    Você possue o atributo Grupo na sua classe Usuario?
    Outra coisa, você utilizou Collection por algum motivo? Eu particularmente prefiro utilizar List.
    No seu caso ficaria assim:
    @OneToMany(mappedBy=”grupo”)
    private List usuarios;

    E é bom tomar alguns cuidados com o fecth e o cascade. O primeiro pode trazer muitos dados desnecessários. E o segundo pode remover coisas que não deveria.
    Se ainda não resolver, poderia colocar o inicio do StackTrace para podermos visualizar o erro?

    Abraço
    Daniel

  6. Fabiano disse:

    Oi Daniel,
    Sim, coloquei o atributo na classe Usuario:

    @ManyToOne
    private Grupo grupo

    Usei o Collection porque vi um exemplo com ele, mas já alterei pra List.

    Consegui resolver o problema. Muito obrigado!

Post a comment