From dd0fde3a58125c7c5f4d5c6e0b22415e2d6efbbf Mon Sep 17 00:00:00 2001 From: angeliski Date: Sat, 15 Nov 2014 16:33:39 -0200 Subject: [PATCH 1/2] create cookbook about @ConversationScoped --- .../utilizando-conversation-scoped.html | 170 ++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html diff --git a/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html b/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html new file mode 100644 index 000000000..de7ea08c7 --- /dev/null +++ b/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html @@ -0,0 +1,170 @@ +--- +title: Utilizando o @ConversationScoped no VRaptor4 +--- + +# Utilizando o @ConversationScoped no VRaptor4 + +O VRaptor em sua versão 4 utiliza o CDI 1.1 como base. E uma das considerações a serem feitas quando usamos o CDI é o escopo de vida dos objetos. Sempre é preciso escolher com cuidado o escopo, levando em consideração qual vai ser a aplicação do objeto. +Utilizar o `@RequestScoped` onde é necessário um `@ApplicationScoped` pode ser desastroso. Um escopo muito util nesse cenário é o `@ConversationScoped` que nos permite um controle maior conforme a nossa necessidade. +A aplicação apresentada nesse tutorial está disponivel no GitHub: [ScoreCDI](https://github.com/angeliski/ScoreCDI). + + +Abaixo nosso Controller: + +~~~ +#!java +package br.com.angeliski.controller; + +import java.io.Serializable; +import java.util.Random; + +import javax.enterprise.context.Conversation; +import javax.enterprise.context.ConversationScoped; +import javax.inject.Inject; + +import br.com.caelum.vraptor.Controller; +import br.com.caelum.vraptor.Get; +import br.com.caelum.vraptor.Post; +import br.com.caelum.vraptor.Result; + +@Controller +@ConversationScoped +public class HomeController implements Serializable { + + private static final long serialVersionUID = 943045823176068998L; + private Result result; + private Conversation conversation; + private Integer resultado; + private int total; + + /** + * @deprecated CDI eyes only + */ + protected HomeController() { + this(null, null); + } + + @Inject + public HomeController(Result result, Conversation conversation) { + super(); + this.result = result; + this.conversation = conversation; + } + + @Get + public void index() { + } + + @Get + public void game() { + if (conversation.isTransient()) { + conversation.begin(); + } + result.include("cid", conversation.getId()); + gerarPergunta(); + } + + private void gerarPergunta() { + Random random = new Random(); + Integer primeiroValor = random.nextInt(100); + Integer segundoValor = random.nextInt(100); + + resultado = primeiroValor * segundoValor; + + result.include("primeiro", primeiroValor); + result.include("segundo", segundoValor); + } + + @Post + public void game(Integer resposta) { + if (resultado.equals(resposta)) { + total++; + } + gerarPergunta(); + result.include("cid", conversation.getId()); + } + + @Get + public void fim() { + if (!conversation.isTransient()) { + conversation.end(); + } + result.include("total", total); + } + +} + +~~~ + +A primeira distinção desse Controller é a anotação `@ConversationScoped` na classe. Isso indica para o CDI qual vai ser o escopo, mas cuidado: só isso não é suficiente para que a sua classe tenha um escopo maior que o escopo request. +Para que o escopo se torne persistente, não perdendo os dados a cada requisição, é necessário injetar um objeto Conversation e chamar seu método begin. Isso pode ser observado aqui: + +~~~ +#!java + + @Get + public void game() { + if (conversation.isTransient()) { + conversation.begin(); + } + result.include("cid", conversation.getId()); + gerarPergunta(); + } + +~~~ + + +Nesse método a conversação é iniciada. O Conversation tem um estado padrão conhecido como *transient*. Quando o método begin é acionado ele passa para o *long-running* mantendo os dados até que seja invocado o método end do Conversation. +Só que um detalhe importante deve ser observado. O CDI não tem como saber a qual objeto você está tratando. O único modo dele saber isso é você informando qual o identificador daquela conversação e isso é feito através do pârametro **cid**. +É necessário informar na url esse pârametro para que o CDI consiga recuperar o objeto correto. Observe que o pârametro cid é incluido no result para que seja possível utilizar ele na pagina. +O nome utilizado para incluir o *id* do Conversation no result não é fundamental. Ele poderia ser qualquer um, desde que fosse recuperado corretamente na pagina. Só é fundamental utilizar o pârametro **cid** quando a requisição for enviada para o servidor. +Observe como ficou a nossa pagina que vai utilizar esse parâmetro. + +~~~ +#!jsp + +<%@ taglib prefix="fmt" uri="http://java.sun.com/jsp/jstl/fmt"%> +<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core"%> + + + + +Score CDI + + + +

Sessão atual ${cid}

+

Quanto é ${primeiro} * ${segundo}?

+
+ + +
+ + Finalizar! + + + +~~~ + +Você pode observar que a action do formulário faz o uso correto do **cid**. Quando essa requisição for enviada ao servidor, vai enviar junto o identificador correto. +Enquanto a requisição for feita enviando o **cid** o número exibido em Sessão atual vai continuar o mesmo, pois a conversação vai se manter. Você pode fazer um teste acessando diretamente '/home/game' sem enviar o cid no pârametro. +Vai ser iniciada uma nova conversação e o cid irá se modificar. + +Por fim temos o método que encerra o *long-running* através do método end: + + +~~~ +#!java + + @Get + public void fim() { + if (!conversation.isTransient()) { + conversation.end(); + } + result.include("total", total); + } + +~~~ + +Aqui é valido observar que caso você não encerre uma conversação, ela não vai se manter em memória por muito mais que dois minutos, que é o tempo padrão. Isso garante que diferente do `@SessionScoped` os recursos vão ser liberados antes, caso a aplicação não encerre o estado daquele objeto. +O timeout pode ser ajustado através do método setTimeout conforme a necessidade, mas normalmente não é preciso. \ No newline at end of file From 0c6b56dcdd0701225e4bbd147f9e1384c3ebe0d9 Mon Sep 17 00:00:00 2001 From: angeliski Date: Sat, 15 Nov 2014 23:17:23 -0200 Subject: [PATCH 2/2] add ` around class and method' names --- .../pt/cookbook/utilizando-conversation-scoped.html | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html b/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html index de7ea08c7..33ce7fe74 100644 --- a/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html +++ b/vraptor-site/content/pt/cookbook/utilizando-conversation-scoped.html @@ -97,7 +97,7 @@ ~~~ A primeira distinção desse Controller é a anotação `@ConversationScoped` na classe. Isso indica para o CDI qual vai ser o escopo, mas cuidado: só isso não é suficiente para que a sua classe tenha um escopo maior que o escopo request. -Para que o escopo se torne persistente, não perdendo os dados a cada requisição, é necessário injetar um objeto Conversation e chamar seu método begin. Isso pode ser observado aqui: +Para que o escopo se torne persistente, não perdendo os dados a cada requisição, é necessário injetar um objeto `Conversation` e chamar seu método `begin`. Isso pode ser observado aqui: ~~~ #!java @@ -114,10 +114,10 @@ ~~~ -Nesse método a conversação é iniciada. O Conversation tem um estado padrão conhecido como *transient*. Quando o método begin é acionado ele passa para o *long-running* mantendo os dados até que seja invocado o método end do Conversation. +Nesse método a conversação é iniciada. O `Conversation` tem um estado padrão conhecido como *transient*. Quando o método `begin` é acionado ele passa para o *long-running* mantendo os dados até que seja invocado o método `end` do `Conversation`. Só que um detalhe importante deve ser observado. O CDI não tem como saber a qual objeto você está tratando. O único modo dele saber isso é você informando qual o identificador daquela conversação e isso é feito através do pârametro **cid**. É necessário informar na url esse pârametro para que o CDI consiga recuperar o objeto correto. Observe que o pârametro cid é incluido no result para que seja possível utilizar ele na pagina. -O nome utilizado para incluir o *id* do Conversation no result não é fundamental. Ele poderia ser qualquer um, desde que fosse recuperado corretamente na pagina. Só é fundamental utilizar o pârametro **cid** quando a requisição for enviada para o servidor. +O nome utilizado para incluir o *id* do `Conversation` no result não é fundamental. Ele poderia ser qualquer um, desde que fosse recuperado corretamente na pagina. Só é fundamental utilizar o pârametro **cid** quando a requisição for enviada para o servidor. Observe como ficou a nossa pagina que vai utilizar esse parâmetro. ~~~ @@ -150,7 +150,7 @@

Sessão atual ${cid}

Enquanto a requisição for feita enviando o **cid** o número exibido em Sessão atual vai continuar o mesmo, pois a conversação vai se manter. Você pode fazer um teste acessando diretamente '/home/game' sem enviar o cid no pârametro. Vai ser iniciada uma nova conversação e o cid irá se modificar. -Por fim temos o método que encerra o *long-running* através do método end: +Por fim temos o método que encerra o *long-running* através do método `end`: ~~~ @@ -167,4 +167,4 @@

Sessão atual ${cid}

~~~ Aqui é valido observar que caso você não encerre uma conversação, ela não vai se manter em memória por muito mais que dois minutos, que é o tempo padrão. Isso garante que diferente do `@SessionScoped` os recursos vão ser liberados antes, caso a aplicação não encerre o estado daquele objeto. -O timeout pode ser ajustado através do método setTimeout conforme a necessidade, mas normalmente não é preciso. \ No newline at end of file +O timeout pode ser ajustado através do método `setTimeout` conforme a necessidade, mas normalmente não é preciso. \ No newline at end of file