Fala galera, beleza?
Depois de um mês atípico (muito trabalho e organizando casamento) e um começo de mês com ombro deslocado, estou de volta para delírio de vocês heheheh (menos né?!).
Hoje vou falar sobre aplicações em tempo real utilizando o padrão ajax de atualização periódica (periodic refresh) e como o AngularJS pode nos ajudar a implementá-lo. Deixa eu te fazer uma pergunta, você gostaria de ficar apertando F5 para verificar se há uma nova notificação no Facebook? Ou se chegou aquele e-mail que você tanto esperava no Gmail? Eu acho que não, né?
A fim de tornar a experiência do usuário a mais agradável possível, muitas aplicações utilizam dados em tempo real (ou quase) e até criam uma certa dependência dessa tecnologia, pois sem ela jamais teriam se popularizado.
Vamos ver esse refresh em funcionamento? Você tem Twitter? Se sim, acesse ele e depois abra o console do browser (aperte F12, abestado!). Na aba network, você pode verificar que periodicamente o twitter faz um GET, para checar se há alguma novidade a ser exibida ao usuário. Conforme mostra a figura abaixo:
Para exemplificar, vamos criar uma simples sala de bate-papo. Para o backend, utilizei a plataforma Java e para o frontend, a implementação foi feita com AngularJS usando o service $timeout.
$timeout
A galera do AngularJS resolveu encapsular o window.setTimeout dentro desse service. Quando o $timeout é chamado, ele retorna uma promise que será resolvida quando o delay for concluído e a função de timeout, caso exista, for executada.
Esse service tem a seguinte estrutura:
$timeout([fn], [delay], [invokeApply], [Pass]);
- fn: A função a ser executada quando o delay acabar;
- delay: O tempo limite em milissegundos. Valor default é zero.
- invokeApply: Se o parâmetro for marcado como false o modelo de _durty checking _será ignorado, caso contrário, a função de tempo limite (fn) será chamada dentro do bloco $apply.
- Pass: Aqui você pode passar parâmetros para a função a ser executada (fn).
O $timeout ainda nos fornece uma maneira de cancelar as tarefas que estão agendadas. Para isso, há o método $timeout.cancel([promise]). Ele recebe como parâmetro uma promise _e, como resultado da execução, essa _promise será resolvida com uma rejeição (rejection).
Backend com Java
Para o backend, usei os frameworks RestEasy para expor a API e o provider Jackson para consumir e produzir os objetos em JSON. Além disso, o projeto está com maven, utiliza Java 8 e está sendo executado no Tomcat. Ahhh! Ia esquecendo, está hospedado no heroku.
A aplicação implementada é bem simples, mas como não é o foco desse post, fiz só o necessário para o frontend funcionar. Os fontes do projeto estão no github.
A API exposta para uso consiste em:
- GET /mensagens: listar as mensagens do chat;
- POST /mensagens: enviar uma nova mensagem para a sala de bate papo;
- DELETE /mensagens: apagar todas as mensagens da sala;
Frontend com AngularJS
Agora vamos falar da parte que mais nos interessa. Mas antes, como não sou lá essas coisas na parte de design, peguei a base do template para o chat nesse link aqui óh.
O gist abaixo apresenta a implementação da lógica necessária para realizar a atualização dos dados do nosso chat. O projeto completo pode ser visto no github e rodando aqui.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
(function() {
angular.module("app")
.factory("ChatFactory", function($http, $timeout) {
var promise;
var URL = "http://gf-chat.herokuapp.com/rest/mensagens/";
var mensagens = [];
var aberto = false;
var contador = 5;
return {
entrar: entrar,
listar: listar,
cadastrar: cadastrar,
isAberto: isAberto,
sair: sair,
getContador: getContador
};
function entrar() {
aberto = true;
ativarRefresh()
}
function ativarRefresh() {
contador--;
if (contador === 0) {
atualizar();
contador = 5;
}
promise = $timeout(ativarRefresh, 1000);
}
function sair() {
$timeout.cancel(promise);
aberto = false;
}
function atualizar() {
$http.get(URL)
.success(function(data) {
mensagens = data;
});
}
function cadastrar(usuario, texto) {
var msg = {
usuario: usuario,
texto: texto
}
$http.post(URL, msg);
}
function getContador() {
return contador;
}
function isAberto() {
return aberto;
}
function listar() {
return mensagens;
}
});
})();
Analisando o gist acima, o acesso ao chat é feito pelo método entrar (linha 19). Ele é o responsável por ativar o refresh periódico através do método ativarRefresh (linha 24). Perceba que dentro desse método implementei um contador. Esse contador é decrementado a cada um segundo (1000 milissegundos) e quando o seu valor for zero o método atualizar (linha 27) será chamado. O contador está sendo utilizado na tela para informar ao usuário quanto tempo falta para a sala ser atualizada.
Os outros métodos apresentados no gist são:
- cadastrar (linha 45): responsável por enviar ao servidor uma nova mensagem;
- sair (linha 33): é aqui que o método $timeout.cancel é chamado para finalizar a atualização periódica;
- getContador (linha 53): retornar o contador a fim de informar quanto tempo falta para a próxima atualização do chat;
- isAberto (linha 57): informar se o chat está aberto ou não.
- listar (linha 61): listar as mensagens da sala de bate-papo.
Então é isso pessoal, essa é uma das formas de termos uma aplicação em tempo real. Fico esperando suas dúvidas e sugestões.
Só mais duas coisinhas:
- Para fazer a barra de rolagem automática do chat usei essa diretiva aqui;
- Esse artigo foi baseado em um post do Java Code Geeks.
Abraços e até a próxima!