Programação para Web II

Fagno Alves Fonseca <fagno.fonseca@ifto.edu.br> Mestre em Modelagem Computacional de Sistemas – UFT.

1. Vraptor

O VRaptor É um framework MVC opensource que traz alta produtividade para um desenvolvimento Java Web rápido e fácil com CDI.

1.1. Depedência

Para adicionar o Vraptor no seu projeto web com maven é necessário incluir a depência do framework atualmente em na versão 4 conforme a seguir.

Dependência do Vraptor 4
<dependency>
    <groupId>br.com.caelum</groupId>
    <artifactId>vraptor</artifactId>
    <version>4.2.0-RC5</version>
</dependency>

Na documentação do Vraptor indica que os Servidores de Aplicações já testados e suportados são Glassfish 4 e WildFly 8. Em nossos exemplos vamos utilizar o Glassfish 4.

É necessário alterar a versão da dependência do Guava.jar na servidor Glassfish.

Para alterar a versão da dependência do Guava no servidor Glassfish, acesse o diretório do mesmo em glassfish4/glassfish/modules. Você deve excluir o arquivo existente do Guava e adicionar a mesma versão utilizada pelo Vraptor, disponível aqui.

1.2. Definindo um Controller

Controller são classes contendo a lógica de negócio do seu sistema. É responsável por receber todas as requisições do usuário. Uma camada intermediária entre a camada de apresentação e a lógica.

Antes de criar nosso controller, vamos definir uma entidade para representar uma pessoa.

Entidade Pessoa
public class Pessoa{

    private Long id;
    private String nome;
    private int idade;

    //getters e setters

}

Após criada a classe Pessoa, vamos criar uma nova classe para representar o Controller e tratar as requisições web. Essa classe vai ser o Controller de pessoas.

A nova classe deve ser definida com o nome PessoasController. Para indicar que uma classe é um controller, você precisa anotá-la com a anotação @Controller conforme o exemplo a seguir.

Criando um Controller
import br.com.caelum.vraptor.Controller;

@Controller
public class PessoasController{
    ...
}

Anotando seu controller com @Controller, todos os seus métodos públicos serão acessíveis pela web. No exemplo a seguir, uma requisição à URI "http://localhost:8080/projetoexemplo/pessoas/lista" redirecionará para o método lista(). Ou seja, a convenção para a criação de URIs é /<nome_do_controller>/<nome_do_metodo>.

PessoasController
package com.mycompany.projetoexemplo.controller;

import br.com.caelum.vraptor.Controller;
import com.mycompany.projetoexemplo.model.Pessoa;
import java.util.ArrayList;
import java.util.List;

@Controller
public class PessoasController {

    public List<Pessoa> lista(){
        List<Pessoa> pessoas = new ArrayList();
        pessoas.add(new Pessoa("Pessoa 1"));
        pessoas.add(new Pessoa("Pessoa 2"));
        return pessoas;
    }

}

Ao terminar a execução do método, o VRaptor fará o dispatch da requisição para o JSP no diretório do seu projeto em /WEB-INF/jsp/pessoas/lista.jsp. Ou seja, a convenção para a view padrão é /WEB-INF/jsp/<nome_do_controller>/<nome_do_metodo>.jsp conforme figura a seguir.

vraptor web inf.png
Figura 1. Conversão para a view

Ao executar o projeto acima, a saída será a lista de pessoas conforme definido no projeto.

Outro exemplo que podemos definir é o método form(). Ao adicionar o método no controller conforme o exemplo a seguir, e criar o form.jsp em /WEB-INF/jsp/pessoas/form.jsp assim como feito com o lista.jsp na figura 1, podemos acessar o formulário através da URI "http://localhost:8080/projetoexemplo/pessoas/form".

PessoasController
...
    public void form(){
    }
...

Para visualizar a lista de pessoas através da requisição à URI "http://localhost:8080/projetoexemplo/pessoas/lista" você deve definiar seu arquivo lista.jsp conforme a seguir.

lista.jsp
...
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
    <title>Lista de Pessoas</title>
</head>
<body>
    <c:forEach items="${pessoaList}" var="pessoa">
        ${pessoa.nome}
    </c:forEach>
</body>
...

O retorno dos métodos do controller são exportados para a view. Ressalto dois pontos importantes que precisam ser destacados.

No caso do nosso método lista(), o retorno é uma lista de pessoas, sendo assim, a variável acessível no jsp será ${pessoaLista}.
Se o retorno for um tipo simples, o nome da variável exportada será o nome da classe com a primeira letra minúscula, neste caso, a variável na jsp será ${pessoa}.

1.3. Definindo o PessoaDao

No exemplo, utilizamos uma lista de pessoas definida dentro do métodos lista(). Agora vamos definir um Dao para para acesso aos dados das pessoas no banco de dados. Iremos utilizar uma conexão JDBC, pois nosso objetivo nete capítulo é conhecer as funcionalidades do Vraptor.

PessoaDao.java
package com.mycompany.projetoexemplo.model.dao;

import com.mycompany.projetoexemplo.model.Conexao;
import com.mycompany.projetoexemplo.model.Pessoa;
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;


public class PessoaDao{

    /**
     * Método para add uma pessoa
     * @param pessoa
     */
    public boolean salvar(Pessoa pessoa) {
        try {
            //criar um objeto Connection para receber a conexão
            Connection con = Conexao.criarConexao();
            //comando sql
            String sql = "insert into tb_pessoa (nome, idade) values (?,?)";
            PreparedStatement ps = con.prepareStatement(sql);
            //referênciar o parâmetro do método para a ?
            ps.setString(1, pessoa.getNome());
            ps.setInt(2, pessoa.getIdade());

            if(ps.executeUpdate()==1)
                return true;

        } catch (SQLException ex) {
            Logger.getLogger(PessoaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }


    /**
     * Método para deletar uma pessoa
     * @param id
     */
    public boolean excluir(int id) {
        try {
            //criar um objeto Connection para receber a conexão
            Connection con = Conexao.criarConexao();
            //comando sql
            String sql = "delete from tb_pessoa where id = ?";
            PreparedStatement ps = con.prepareStatement(sql);
            //referênciar o parâmetro do método para a ?
            ps.setInt(1, id);

            if(ps.executeUpdate()==1)
                return true;

        } catch (SQLException ex) {
            Logger.getLogger(PessoaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }

    /**
     * Método para atualizar os dados de uma pessoa
     * @param pessoa
     */
    public boolean update(Pessoa pessoa) {
        try {
            //criar um objeto Connection para receber a conexão
            Connection con = Conexao.criarConexao();
            //comando sql
            String sql = "update tb_pessoa set nome=?, idade=? where id=?";
            PreparedStatement ps = con.prepareStatement(sql);
            //referênciar o parâmetro do método para a ?
            ps.setString(1, pessoa.getNome());
            ps.setInt(2, pessoa.getIdade());
            ps.setInt(3, pessoa.getId());

            if (ps.executeUpdate()==1)
                return true;

        } catch (SQLException ex) {
            Logger.getLogger(PessoaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return false;
    }

    /**
     * Método para retornar uma pessoa pelo Id
     */
    public Pessoa buscarPessoa(int id) {
        try {
            //criar um objeto Connection para receber a conexão
            Connection con = Conexao.criarConexao();
            //comando sql
            String sql = "select * from tb_pessoa where id = ?";
            PreparedStatement ps = con.prepareStatement(sql);
            //referênciar o parâmetro do método para a ?
            ps.setInt(1, id);
            //ResultSet, representa o resultado do comando SQL
            ResultSet rs = ps.executeQuery();
            if (rs.first()) {
                Pessoa p = new Pessoa();
                p.setId(rs.getInt("id"));
                p.setNome(rs.getString("nome"));
                p.setIdade(rs.getInt("idade"));
                return p;
            }
        } catch (SQLException ex) {
            Logger.getLogger(PessoaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

    /**
     * Método para retornar uma lista de pessoas
     */
    public List<Pessoa> buscarPessoas() {
        try {
            //criar um objeto Connection para receber a conexão
            Connection con = Conexao.criarConexao();
            //comando sql
            String sql = "select * from tb_pessoa";
            PreparedStatement ps = con.prepareStatement(sql);
            //ResultSet, representa o resultado do comando SQL
            ResultSet rs = ps.executeQuery();
            //cria uma lista de pessoas para retornar
            List<Pessoa> pessoas = new ArrayList();
            //laço para buscar todas as pessoas do banco
            while (rs.next()) {
                Pessoa p = new Pessoa();
                p.setId(rs.getInt("id"));
                p.setNome(rs.getString("nome"));
                p.setIdade(rs.getInt("idade"));
                //add pessoa na lista
                pessoas.add(p);
            }
            //retorna a lista de pessoas
            return pessoas;
        } catch (SQLException ex) {
            Logger.getLogger(PessoaDAO.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }

}

Para efetuar a conexão com o banco de ados, vamos utilizar a classe Conexão conforme exemplo a seguir.

Conexao.java
package com.mycompany.projetoexemplo.model.jdbc;

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.SQLException;
import java.util.logging.Level;
import java.util.logging.Logger;

public class Conexao {

    public static void main(String[] args) {
        //testar conexão
        System.out.println(Conexao.criarConexao());
    }


    /**
     * método estático que retorna uma conexão
     */
    public static Connection criarConexao(){
        try {
            //carregar o driver de conexão
            Class.forName("com.mysql.jdbc.Driver");
            //parâmetros
            String url = "jdbc:mysql://localhost:3306/banco";
            String usuario = "root";
            String senha = "senha";
            //retorna a conexão com o banco de dados
            return DriverManager.getConnection(url, usuario, senha);

        } catch (ClassNotFoundException ex) {
            Logger.getLogger(Conexao.class.getName()).log(Level.SEVERE, null, ex);
        } catch (SQLException ex) {
            Logger.getLogger(Conexao.class.getName()).log(Level.SEVERE, null, ex);
        }
        return null;
    }


}

1.4. Implementando ações de CRUD no controller

Com nossa classe PessoaDao pronta podemos definir as operações necessárias no controlador com todas as operações de CRUD.

Conexao.java
package com.mycompany.projetoexemplo.controller;

import br.com.caelum.vraptor.Controller;
import br.com.caelum.vraptor.Result;
import com.mycompany.projetoexemplo.model.dao.PessoaDao;
import com.mycompany.projetoexemplo.model.Pessoa;
import java.util.List;

@Controller
public class PessoasController {

    PessoaDAO dao = new PessoaDAO();

    /**
     * Método para carregar o form.jsp
     */
    public void form() {
    }

    /**
     * Método para gramar uma pessoa no banco
     * @param pessoa
     * @param result
     */
    public void salvar(Pessoa pessoa, Result result) {

        //Condicional necessária por que estamos utilizando o form.jsp para adicionar e atualizar uma Pessoa.
        if (pessoa.getId() == null) {
            dao.salvar(pessoa);
        } else {
            dao.update(pessoa);
        }
        //Redireciona e executa o método list()
        result.redirectTo(this).lista();
    }

    public void excluir(int id, Result result){
        dao.excluir(id);
        result.redirectTo(this).lista();
    }

    public void editar(int id, Result result) {
        Pessoa encontrado = dao.buscarPessoa(id);
        result.include(encontrado);
        //redireciona mas não executa o método form()
        result.of(this).form();
    }

    public List<Pessoa> lista() {
        return dao.buscarPessoas();
    }

}

Para adicionar um novo registro, precisamos definir o atributo "name" dos nossos inputs para pessoa.id, pessoa.nome, pessoa.idade. Nosso método salvar() no PessoasController() possui como parametro o nome pessoa, deste modo, o VRaptor vai popular os seus campos nome e idade, usando os seus setters da classe Pessoa, com os valores digitados nos inputs. Então, usando os nomes corretamente nos inputs do form, basta definir o método salvar() conforme definido anteriormente no controller.

${linkTo[PessoasController].salvar} aponta para o método salvar no PessoaController.
Form.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>FORM</h1>
        <form action="${linkTo[PessoasController].salvar}" method="post">
            <input type="hidden" name="pessoa.id">
            <input type="text" name="pessoa.nome"  placeholder="Nome">
            <input type="text" name="pessoa.idade" placeholder="Idade">
            <input type="submit" value="Enviar">
        </form>
    </body>
</html>

Depois de adicionar um registro no banco estamos carregando a listagem de objetos utilizando o método redirectTo(), apontando o this por parâmetro que faz referência ao próprio PessoaController para chamar o método lista() logo a seguir. Fazemos o mesmo, também no método excluir após a exclusão.

Para editar uma pessoa estamos utilizando o form.jsp que é utilizado para adicionar. O método editar no euxilia neste processo, pois ao receber o Id do objeto a ser editado, carregamos os dados do mesmo no banco e depois fazemos a inclusão desse objeto no form.jsp utilizando o método include(). Este método é responsável por preencher o form.jsp com os dados da pessoa a ser editada.

Observe no código a seguir, que os dados do objeto serão carregados devido o atributo "value" dos inputs do formulário conforme o exemplo.

Form.jsp
<%@page contentType="text/html" pageEncoding="UTF-8"%>
<!DOCTYPE html>
<html>
    <head>
        <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
        <title>JSP Page</title>
    </head>
    <body>
        <h1>FORM</h1>
        <form action="${linkTo[PessoasController].salvar}" method="post">
            <input type="hidden" name="pessoa.id" value="${pessoa.id}">
            <input type="text" name="pessoa.nome" value="${pessoa.nome}" placeholder="Nome">
            <input type="text" name="pessoa.idade" value="${pessoa.idade}" placeholder="Idade">
            <input type="submit" value="Enviar">
        </form>
    </body>
</html>

2. Referências