Made in Brazil
coluna
VRaptor 3: guerrilha web
Como esse framework web ataca diretamente os
pequenos problemas do dia-a-dia.
Lucas Cavalcanti
([email protected]): é formando em
Ciência da Computação pelo IME-USP, é desenvolvedor
e consultor pela Caelum há 3 anos, além de
contribuir com projetos como o VRaptor3, Calopsita e
SeleniumDSL.
O VRaptor é um framework que há 5 anos vem ganhando
bastante espaço no mercado brasileiro. Nascido no IMEUSP e hoje com o apoio do Centro de Competência de
Software livre da USP, a versão 3.0 traz novidades e
simplificações voltadas a Rest, Injeção de Dependências,
AJAX, integração com outros frameworks e testabilidade.
Adriano Almeida
([email protected]): é formado em
Sistemas de Informação pela Faculdade de Informática e
Administração Paulista, e atua como instrutor, consultor
e desenvolvedor pela Caelum. Participa também de
projetos opensource, como o VRaptor2, VRaptor 3 e
MirrorDSL.
S
ão duas as formas principais de se trabalhar para a web:
com frameworks baseados em componentes visuais
(como JSF e Tapestry) e frameworks baseados em ações (como
Struts, Webwork e Rails). O VRaptor 3 é um framework MVC para
a Web baseado em ações, com forte inspiração no Rails, Webwork
e Waffle.
Nascido no departamento de computação do IME-USP, essa
terceira versão do framework conta com o apoio do Centro de
Competência em Software Livre da USP e já é usado por diversas
empresas, como você pode conferir nos depoimentos do site.
Neste artigo, conheceremos diversos recursos do framework, mas
é interessante salientar que com apenas a injeção de dependên-
6
www.mundoj.com.br
cias, parâmetros e validação já é possível fazer 90% do trabalho do
dia-a-dia, e com um código limpo, desacoplado e fácil de testar.
Começando
O VRaptor 3 necessita de alguns jars como dependências. Para facilitar o
processo, no site www.vraptor.com.br está disponível para download um
projeto vazio (blank-project), que consiste em um zip com a estrutura
básica de um projeto web no Eclipse, contendo todas suas dependências.
Também vem com a configuração mínima do web.xml, facilitando o início do uso do framework. Você pode descompactá-lo e importá-lo como
projeto do Eclipse.
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Resources
Para trabalharmos com o VRaptor 3, precisamos criar as classes que
contêm a lógica de negócio da nossa aplicação, e que saibam modificar nossas entidades e depois redirecionar o resultado para as páginas
adequadas. Essas classes farão papel de Controllers da nossa aplicação.
Para isso, basta criarmos uma classe simples, que esteja anotada com @
Resource. Isso identifica que esta classe será um recurso que pode ser
acessado via web. Essa classe deve ter os métodos que serão invocados
no momento em que determinada URI for acessada pelo navegador.
Listagem 3. Formulário para inclusão de aluno, apontando para /alunos/
adiciona.
<form action=”/alunos/adiciona”>
<input type=”text” name=”novoAluno.nome”/>
<input type=”submit” value=”enviar”/>
</form>
Para receber esses dados em nossa classe, basta criarmos um método
adiciona em nosso controlador, que receba um parâmetro chamado
novoAluno, e então o VRaptor popula o objeto fazendo as devidas conversões de tipo. Veja a Listagem 4.
Para este artigo, vamos criar uma aplicação de exemplo que controla os
alunos de uma escola.
Listagem 4. Controller de alunos com método para adicionar o aluno novo!
Considerando uma simples entidade Aluno com id e nome, vamos então
criar uma lógica que lista todos os alunos do nosso banco de dados e
renderizá-los em uma view (jsp).
@Resource
public class AlunosController {
public void adiciona(Aluno novoAluno) {
// futuramente usaremos o DAO
System.out.println(“gravando aluno” + novoAluno.getNome());
}
Listagem 1. Controller de alunos com método para listar todos os alunos.
@Resource
public class AlunosController {
public List<Aluno> lista() {
// vamos trocar por um dao futuramente:
List<Aluno> alunos = new ArrayList<Aluno>();
alunos.add(new Aluno(1, “Lucas”));
alunos.add(new Aluno(2, “Adriano”));
return alunos;
}
public List<Aluno> lista() {
// ...
}
}
Relembrando, após a adição desse usuário, o VRaptor por padrão faz o
dispatch para /WEB-INF/jsp/alunos/adiciona.jsp.
}
Note que a convenção do VRaptor 3 é bastante intuitiva: para chegar
ao método lista() do AlunosController, basta chamar a URI /alunos/
lista. Após executar o método, o redirecionamento padrão será para
a página em /WEB-INF/jsp/alunos/lista.jsp – ou seja, <nome_do_
controller>/<nome_do_metodo> para a URI e /WEB-INF/jsp/<nome_
do_controller>/<nome_do_metodo>.jsp para a view.
O que devemos ter no lista.jsp? Precisamos iterar sobre a lista retornada
pelo método. Aqui o VRaptor possui novamente uma convenção: se você
retornou uma lista de alunos, a variável disponível no JSP será alunoList.
Ou seja, o <nome_da_classe>List. Se fosse retornado apenas uma referência a Aluno, a variável seria apenas aluno.
O JSP então ficaria como na Listagem 2.
Listagem 2. Listando os alunos no jsp à variável alunoList, que contém o
retorno do método lista().
<ul>
<c:forEach items=”${alunoList}” var=”aluno”>
<li>${aluno.nome}</li>
</c:forEach>
</ul>
Recebendo parâmetros e populando entidades
Precisamos também cadastrar alunos. Para isso, temos um JSP como o da
Listagem 3, como o usual.
Por último um truque para não ter de acessar diretamente o form.jsp,
aproveitando a criação de URIs simples, podemos criar um método apenas com esse intuito, sem corpo:
public void form() {
}
Com isso, podemos acessar a URI /alunos/form e o jsp com o formulário
em branco será apresentado!
Componentes e injeção
Para tornar nosso exemplo mais real, queremos utilizar um DAO para
inserir e listar nossos alunos. De onde viria esse DAO? Como o VRaptor
usa injeção de dependências, podemos recebê-lo no construtor. E, para
que o VRaptor saiba qual AlunoDao colocar no construtor, basta anotar a
implementação com @Component, como mostra a Listagem 5.
O VRaptor utiliza por padrão o Spring como container de IoC, então você
pode usar todos os recursos do Spring, como suas anotações e integrações
com outros frameworks, configurados no seu application-context.xml.
Há diversos objetos que já estão registrados para injeção. Por exemplo, se
você precisar de algo muito específico de HttpSession, HttpServletRequest,
HttpServletResponse, basta declarar essa necessidade em seu construtor!
7
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Listagem 5. AlunoDao e injeção pelo construtor.
Listagem 6. Usando o Result para redirecionar para outra lógica.
@Component
public class AlunoDao {
// métodos
}
@Resource
public class AlunosController {
private AlunoDao dao;
private Result result;
@Resource
public class AlunosController {
public AlunosController(AlunoDao dao, Result result) {
this.dao = dao;
this.result = result;
}
private AlunoDao dao;
public AlunosController(AlunoDao dao) {
this.dao = dao;
}
public void lista() {
// código para listar os alunos
}
public void form() {
}
public void adiciona(Aluno aluno) {
dao.save(aluno);
}
public List<Aluno> lista() {
return dao.listAll();
}
}
Com os poucos exemplos que vimos até aqui, já é possível construir grande
parte da sua aplicação web, que gira em torno de receber parâmetros, trabalhar com dependências, e renderizar o resultado nas páginas desejadas.
Caso você já tenha trabalhado com VRaptor2, é importante ter em mente
que o @Component do VRaptor3 não tem a mesma semântica que o do
VRaptor2. No VRaptor3, ele simplesmente indica que um objeto da classe
anotada poderá ser injetado como dependência para outro componente
ou recurso.
public void adiciona(Aluno aluno) {
dao.save(aluno);
result.use(Results.logic()).redirectTo(AlunosController.class).lista();
}
}
Disponibilizando mais dados para a view
Vimos como disponibilizar para o JSP o retorno do método. Mas como
fazer se precisamos passar mais de um objeto para a view? Para isso,
usamos novamente o Result, que possui o método include para incluir
atributos na requisição, podendo assim usá-los na renderização da página. Um exemplo de código está na Listagem 7
Listagem 7. Disponibilizando a lista dos alunos para a view através da
variável ${listaDeAlunos}.
public void lista() {
List<Aluno> alunos = dao.listAll();
// podemos incluir vários objetos como atributo da requisição
result.include(“listaDeAlunos”, alunos);
Mudando o redirecionando após a execução
da lógica
Adicionando validação nas lógicas
Após salvar um aluno, geralmente queremos redirecionar o usuário para
a listagem de alunos, ou seja, precisamos executar a lógica de listagem
que está no método lista() do AlunosController. É a interface Result que
disponibiliza dados do nosso Controller para um JSP e é responsável por
redirecionar o usuário para lógicas ou views diferentes. Para obter uma
instância de Result, basta recebê-la no construtor do AlunosController, e
o VRaptor fará a mágica com a injeção de dependências, como mostra a
Listagem 6.
A validação das informações submetidas pelo usuário é uma das questões mais delicadas em uma aplicação web. As validações podem ser
feitas no lado do cliente, através de javascript, ou no lado do servidor,
utilizando recursos da própria linguagem e do framework em uso. A
validação no VRaptor3 é feita através da interface Validator, que fornece
duas formas de fazer as validações: a clássica e a fluente.
Note que usamos o result que foi injetado pelo VRaptor e pedimos para
usar uma lógica, redirecionando para o método lista do AlunosController.
Na forma clássica, você faz as validações dos dados verificando se os
valores seguem as suas regras ou não, e caso não sigam, você adiciona
as mensagens de erro. Ou seja, se o nome do aluno é obrigatório, basta
checar isso como feito na Listagem 8.
Poderíamos, também, em vez de redirecionarmos para uma lógica, enviar
a requisição para uma página jsp diferente do convencionado, usando o
método forward:
result.use(Results.page()).forward("/WEB-INF/jsp/alunos/adicionou.jsp");
8
}
www.mundoj.com.br
Você precisa falar para o VRaptor onde ele deve ir caso ocorra algum erro
de validação. Isso é feito da mesma forma que com o Result, mas usando
o método do validator: onErrorUse. Ao executar esse método, se algum
erro de validação ocorrer, a página indicada vai ser renderizada com as
mensagens de erro disponíveis na variável errors, e você pode visuailizálas como na Listagem 9.
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Listagem 8. Validando a obrigatoriedade do nome na forma clássica.
public class AlunosController {
private AlunoDao dao;
private Result result;
private Validator validator;
public AlunosController(AlunoDao dao, Result result, Validator validator) {
//atribui dao e result
this.validator = validator;
}
public void adiciona(Aluno aluno) {
if (aluno.getNome().isEmpty()) {
No nosso caso, como trabalhamos com o recurso Aluno, gostaríamos de ter
as seguintes URIs:
GET - /alunos – Listagem dos alunos
GET - /alunos/1 – Visualizar o aluno com id 1
POST - /alunos – Adicionar novo aluno
PUT - /alunos/2 – Atualizar os dados do aluno com id 2
DELETE - /alunos/1 – Remover o aluno com id 1
Note que as URIs se repetem, mudando apenas o método HTTP utilizado.
O VRaptor3 fornece uma forma de se trabalhar utilizando os seus recursos
com URIs no estilo REST. Para isso, basta utilizar as anotações @Path em
conjunto com as anotações @Get, @Post, @Delete ou @Put nos métodos do
seu controller, como na seguinte forma. Portanto, para termos um controller
que suporte as operações básicas em alunos (CRUD), teríamos um controller
de acordo com a Listagem 10.
validator.add(new ValidationMessage(“erro”, “nomeObrigatorio”);
}
Listagem 10. Utilizando os métodos HTTP nos seus recursos.
validator.onErrorUse(Results.page()).of(AlunosController.class).form();
dao.save(aluno);
@Resource
public class AlunosController {
result.use(Results.logic()).redirectTo(AlunosController.class).lista();
@Path(“/alunos”) @Post
public void adiciona(Aluno aluno) {
//código para adicionar um aluno
}
}
}
@Path(“/alunos”) @Get
public List<Aluno> lista() {
//código para listar os alunos
}
Listagem 9. Mostrando os erros numa jsp.
<ul>
<c:forEach items=”${errors}” var=”erro”>
<li>${erro.category} - ${erro.message}</li>
</c:forEach>
</ul>
@Path(“/alunos/{aluno.id}”) @Delete
public void remove(Aluno aluno) {
//código para remover um aluno
}
Na forma fluente, a sintaxe é um pouco diferente da forma clássica, no
entanto, ela deixa o código de validação mais legível, como abaixo:
@Path(“/alunos/{aluno.id}”) @Put
public void altera(Aluno aluno) {
//código para alterar um aluno
}
validator.checking(new Validations() {{
if (that(aluno.getNome() != null, “erro”, “nomeObrigatorio”)) {
@Path(“/alunos/{aluno.id}”) @Get
public Aluno visualiza(Aluno aluno) {
//código para visualizar um aluno
}
//só entra se a validação passou
that(!aluno.getNome().isEmpty(), “erro”, “nomeObrigatorio”);
}
}
}});
validator.onErrorUse(Results.page()).of(AlunosController.class).form();
A vantagem da forma fluente em relação à forma clássica é a forma de
ler o código da validação. Você pode ler o código acima como: Valide que
o nome do aluno não é uma string vazia. Você ainda pode usar a API do
projeto Hamcrest para criar validações mais complexas e legíveis.
Trabalhando com REST
Repare que você pode passar parâmetros nas URIs do @Path, e os valores
passados serão populados e passados como argumento. Ou seja, se eu
chamar a URI /alunos/5 via GET, o aluno passado para o método visualiza
vai ter o id igual a 5. Lembre-se que alguns browsers ainda não suportam
os métodos PUT e DELETE, então você deve usar javascript para mudar o
método da requisição, ou passar o parâmetro _method com o valor do
método desejado, como na Listagem 11.
Listagem 11. Mudando o método da requisição.
Uma das funcionalidades mais interessantes do VRaptor3 é o fato de suportar os diversos métodos HTTP, além dos tradicionais GET e POST. O uso desses
outros métodos é uma prática adotada em aplicações que seguem o estilo
REST, em que as URIs representam recursos e as operações executadas sobre
esses recursos são diferenciadas através do método HTTP da requisição.
<form action=”/alunos/1”><!-- form de alteração -->
<input type=”hidden” name=”_method” value=”PUT”/>
...
</form>
9
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Outra opção para definir as rotas seria centralizar as configurações das
URIs das lógicas numa classe que implementa a interface RoutesConfiguration, sendo possível especificar rotas como na Listagem 12. A ideia
é dizer: a rota para a URI /alunos com o método GET é a classe AlunosController método lista(): routeFor("/alunos").with(HttpMethod.GET).
is(AlunosController.class).lista();
Listagem 14. Resultado gerado em JSON.
{
“nome”: “Adriano Almeida”,
“endereco”: “Rua dos Pássaros, 999” ,
“email”: “[email protected]”
},
{
Listagem 12. Centralizando a configuração das URIs.
“nome”:”Lucas Cavalcanti”,
“endereco”: “Rua dos Peixes, 777” ,
“email”: “[email protected]”
@Component
public class CustomRoutes implements RoutesConfiguration {
public void config(Router router) {
new Rules(router) {
public void routes() {
routeFor(“/alunos”).with(HttpMethod.GET).
is(AlunosController.class).lista();
routeFor(“/alunos/{aluno.id}”).with(HttpMethod.DELETE).
is(AlunosController.class).delete(null);
}
}
}
}
Mudando o formato da view e ajax
Nem sempre queremos que o formato de saída da nossa lógica seja html.
Para usar views de outros formatos podemos usar o header Accepts
da requisição, ou o parâmetro _format. Por exemplo, se chamarmos: /
alunos?_format=json, o VRaptor vai devolver a view /WEB-INF/jsp/alunos/lista.json.jsp, e dentro desse jsp você pode gerar o seu JSON com
os atributos da requisição. Em geral vai ser usada a view: WEB-INF/jsp/
{controlador}/{logica}.{formato}.jsp
Logo, para gerar o JSON para uma lista de alunos, podemos fazer um
código parecido com o da Listagem 13, que tem como saída a Listagem
14. Para facilitar, você pode também poderia utilizar as bibliotecas que
serializam como JSON, como o XStream e o FlexJSON.
Listagem 13. View para gerar json: lista.json.jsp.
<c:forEach var=”aluno” items=”${alunoList}”>
{
“nome”: “${aluno.nome}”,
“endereco”: “${aluno.endereco}”,
“email”: “${aluno.email}”
},
</c:forEach>
{}
},
{}
]}
Já para realizar o Upload do arquivo, o VRaptor disponibiliza a interface
UploadedFile, que provê acesso a informações do arquivo que está sendo
enviado. Inclusive, é possível acessar o conteúdo do arquivo propriamente dito.
Um exemplo de como se trabalhar com Download e Upload de arquivos
com VRaptor3 está na Listagem 15.
Listagem 15. Exemplo de Download e Upload de arquivo.
@Resource
public class AlunosController {
public File download() {
File file = //cria o arquivo
return file;
}
public void upload(UploadedFile file) {
InputStream stream = file.getFile();
//salva onde você quiser:
IOUtils.copy(stream, new PrintWriter(“um arquivo”));
}
}
Testando as lógicas
Usar injeção de dependências, além de desacoplar seu código através
de um design mais simples, facilita a criação de testes unitários. No entanto, alguns controllers recebem objetos Result e Validator, com suas
interfaces fluentes que dificultam a passagem de implementações falsas
(Mocks) dessas interfaces. Por isso, o VRaptor disponibiliza duas classes
para ajudar a testar as lógicas: a MockResult e a MockValidator.
Então, para criar o seu controller com mock, basta fazer:
]}
AlunosController controller = new AlunosController(alunoDao,
new MockResult(), new MockValidator());
Como fazer download e upload de arquivos
Para trabalhar com Download de arquivos no VRaptor 3, a única coisa necessária é retornar um java.io.File no método da sua lógica. Dessa forma,
quando o usuário acessar a lógica determinada, esse arquivo será aberto
pelo navegador ou disponibilizado para download – dependendo das
configurações do navegador.
10 www.mundoj.com.br
Esses mocks não tratam as chamadas feitas a eles, então fica fácil criar
testes que ignoram qual foi a view escolhida, os atributos adicionados e
a validação feita. Mesmo assim, você pode (e deve) inspecionar os atributos que foram incluídos no result e saber se houve erros de validação
durante a execução da sua lógica, através de outros métodos disponibilizados pelo MockResult e MockValidator. Veja nas Listagens 16 e 17.
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Listagem 16. Inspecionando atributos incluídos.
Listagem 18. ComponentFactory para criar Session do Hibernate a
serem injetadas.
public class AlunosControllerTest {
@Test
public void testaSeAListaDeAlunosFoiIncluida() {
MockResult result = new MockResult();
AlunosController controller = new AlunosController(alunoDao, result,
new MockValidator());
controller.lista();
Assert.assertNotNull(result.included(“listaDeAlunos”));
}
@Component
@RequestScoped
public class SessionCreator implements ComponentFactory<Session> {
private SessionFactory factory;
private Session session;
}
public SessionCreator(SessionFactory factory) {
this.factory = factory;
}
Listagem 17. Verificando erros de validação.
public Session getInstance() {
return this.session;
}
@PostConstruct
public void create() {
this.session = factory.openSession();
}
public class AlunosControllerTest {
@Test(expected=ValidationError.class)
public void testaSeAlunoInvalidoDaErroDeValidacao() {
AlunosController controller = new AlunosController(alunoDao,
new MockResult(), new MockValidator());
Aluno aluno = new Aluno(); // aluno sem nome é inválido
controller.adiciona(aluno); // lança exception
}
@PreDestroy
public void destroy() {
this.session.close();
}
}
}
Trabalhando com Hibernate e JPA
Trabalhando com bibliotecas como o Hibernate e a JPA, gostaríamos de
poder receber nas nossas classes Session's e EntityManager's no construtor, para não ter de ficar abrindo e fechando esses recursos e transações
dentro de todos os controladores (são recursos caros, merecem ser
tratados em algum lugar específico). Para fazer isso, usamos a interface
ComponentFactory, que cria um componente responsável por instanciar
classes que têm um ciclo de vida mais complicado.
Nos ComponentFactories, na verdade em qualquer componente, você
pode ter um método anotado com @PostConstruct que será invocado
assim que o escopo do componente foi iniciado, e um método anotado
com @PreDestroy, que será invocado logo antes do escopo ser destruído.
Por default, componentes são de escopo de request, e podemos alterar
isso através das anotações @ApplicationScoped, @SessionScoped e @
RequestScoped. Por exemplo, se o componente é @RequestScoped, o @
PostConstruct será invocado quando começar a requisição e o @PreDestroy quando a requisição terminar. Isso é bem útil para gerenciar recursos
caros, como sessões, conexões ao banco e sockets.
Um exemplo de como fazer um ComponentFactory de Session está na
Listagem 18.
E quem vai popular o construtor do SessionCreator com uma SessionFactory? Da mesma forma podemos criar ComponentFactories para
SessionFactory! E então anotaríamos esse componente com @ApplicationScoped. Quando fosse necessário instanciar um SessionCreator, o
SessionFactory seria fornecido através do método getInstance de um
SessionFactoryCreator, que implementasse ComponentFactory<Sessio
nFactory>. Com isso, teríamos um código extremamente desacoplado
e fácil de testar.
Ambas factories, dada sua popularidade, já vêm com o VRaptor. Por
padrão não são registradas, para que você mesmo possa criar a sua, caso
queira utilizá-las, basta estendê-las e anotá-las com @Component e os
respectivos escopos. Consulte a documentação para mais detalhes.
Interceptadores
Podemos interceptar as requisições, no mesmo estilo que uma Servlet
Filter, e aproveitar a injeção de dependência e outros recursos já oferecidos pelo VRaptor. É um excelente lugar para gerenciarmos a transação da
sessão do hibernate, por exemplo, criando a transação antes da execução
do Controller e commitando, caso tudo tenha corrido normalmente dentro da sua lógica.
Com o VRaptor, nós conseguimos este comportamento implementando
a interface Interceptor. Note que praticamente todos os nossos controllers precisam de uma session para executar, portanto é interessante
interceptarmos todas as requisições que chegam para a nossa aplicação.
Para isso, ao implementarmos a interface Interceptor, temos que escrever o método accepts, que indica se determinado método deverá ou não
ser interceptado. Um exemplo dessa situação está na Listagem 19.
Até mesmo um interceptador pode aproveitar da injeção de dependências, e ele receberá a Session do ComponentFactory que criamos anteriormente. Mais facilidades para testes e desacoplamento de dependências!
Trabalhando com objetos na sessão
Na nossa aplicação, os alunos também poderão efetuar Login, para que
dessa forma possam depois executar funcionalidades que dependem da
identificação do usuário.
11
.BEFJO#SB[JMt73BQUPSHVFSSJMIBXFC
Listagem 19. Interceptor para gerenciar transações.
Listagem 21. Controller para fazer o login do usuário.
@Intercepts
@RequestScoped
public class TransactionInterceptor implements br.com.caelum.vraptor.
Interceptor {
@Resource
public class LoginController {
private AlunoLogado alunoLogado;
public LoginController(AlunoLogado alunoLogado) {
this.alunoLogado = alunoLogado;
}
private final Session session;
public TransactionInterceptor(Session session) {
this.session = session;
}
public void intercept(InterceptorStack stack, ResourceMethod method,
Object instance) throws InterceptorException {
Transaction transaction = null;
try {
transaction = session.beginTransaction();
stack.next(method, instance); // passa para proximo interceptador
transaction.commit();
} finally {
if( transaction.isActive() ) {
transaction.rollback();
}
}
}
public boolean accepts(ResourceMethod method) {
return true; //Indica que todas os controllers serão interceptados
}
@Path(“/login”)
public void login(Aluno aluno) {
//Faz aqui as regras para a validação do login
//Defino o aluno e a hora atual no componente que está na sessão
alunoLogado.efetuaLogin(aluno, Calendar.getInstance());
}
}
para todos os jsp que forem acessados dentro da sessão. Para termos
esse comportamento, bastaria receber no nosso componente UsuarioLogado a HttpSession no construtor, e no momento de efetuarmos o login,
invocarmos o método setAttribute da HttpSession:
public void efetuaLogin(Aluno aluno, Calendar horario) {
this.aluno = aluno;
this.horarioDoLogin = horario;
}
Para deixar um objeto na sessão, poderíamos receber HttpSession por
injeção de dependências, mas isso deixa nosso código mais acoplado à
API de Servlets, que é difícil de testar. Podemos criar um @Component,
cujo seu escopo seja de sessão (@SessionScoped), que guardará as informações referentes a esse Aluno, como na Listagem 20.
Listagem 20. Componente para guardar as informações do aluno na sessão.
@Component
@SessionScoped
public class UsuarioLogado {
private Aluno aluno;
private Calendar horarioDoLogin;
public void efetuaLogin(Aluno aluno, Calendar horario) {
this.aluno = aluno;
this.horarioDoLogin = horario;
}
// getters
}
Dessa forma, um controller encarregado de fazer o login da nossa aplicação, bastaria receber em seu construtor UsuarioLogado, e no momento
do login, definir quem é o usuário logado e a hora do login, invocando o
método efetuaLogin() como exemplificado na Listagem 21.
Ainda é possível também exibir nas páginas da aplicação informações
sobre o usuário logado, como o nome dele e a hora em que ele fez o
login. Para isso, poderíamos usar o método include da interface Result,
no entanto, teríamos que fazer isso em todos os nossos controllers, pois
o jsp não possui acesso aos nossos componentes @SessionScoped a não
ser que os disponibilizemos no Result.
//Disponibilizando o aluno e o horario na HttpSession
this.session.setAttribute(“alunoLogado”, aluno);
this.session.setAttribute(“horarioDoLogin”, aluno);
}
Dessa forma, podemos mostrar o nome do usuário logado no jsp através
da Expression Language, com ${alunoLogado.nome}.
Considerações finais
Depois de 5 anos desde sua primeira versão, o VRaptor 3.0 traz significativas
mudanças focadas na facilidade de uso e testabilidade, como vimos no artigo.
Há ainda outros recursos que você pode explorar: você pode criar seu próprio
conversor para popular os parâmetros de métodos, estender os componentes
e interceptadores internos do framework, e até mesmo sobreescrever todo o
sistema de rotas, tratamento de erros (como customizar os 404) etc. Você pode
também usar o framework dentro do Google App Engine, tirando o proveito
do cloud computing, através de algumas pequenas configurações que podem
ser vistas na documentação do projeto.
O fórum de frameworks brasileiros no GUJ é atualmente a principal forma de
suporte ao VRaptor, onde sua dúvida será respondida prontamente, e já há
uma quantidade muito grande de mensagens a respeito:
http://guj.com.br/forums/show/23.java
Referências
t 4JUFPmDJBMFNQPSUVHVÐT
Uma solução que pode ser mais interessante é colocar esse aluno que
está logado dentro da HttpSession, e aí disponibilizarmos esse aluno
www.vraptor.com.br
t 'ØSVNPmDJBM
http://guj.com.br/forums/show/23.java
12 www.mundoj.com.br
Download

VRaptor 3: guerrilha web