Páginas

quarta-feira, 28 de novembro de 2012

Porque vale a pena estudar e utilizar padrões de projeto?



        Sente-se desanimado em meio a tantas siglas e palavras desconhecidas? Talvez ache que programador tem que colocar logo a mão na massa (ou no teclado) e sair programando. Porque então dedicar tempo para estudar padrões de projeto?
   
        Vale muito a pena estudar padrões de projeto. Todos nós nos beneficiamos dos padrões em diversas áreas da vida. Pense por exemplo no corpo humano: o que aconteceria se cada indivíduo tivesse seus órgãos internos em um local diferente do corpo? Quanto trabalho daria ao cirurgião localizar primeiro onde se encontra tal órgão, entender suas particularidades para então começar uma cirurgia? Felizmente nossos corpos seguem um padrão, duas pernas, dois olhos, coração localizado no peito etc. E isso facilita sua 'manutenção'. Essa metáfora pode ser aplicada ao desenvolvimento de software. O uso de padrões de desenvolvimento trás uma série de benefícios.

      Ainda não se convenceu com a metáfora acima de que é benéfico o uso de padrões? Então vamos utilizar outra metáfora: Imagine se alguém lhe pedisse para construir um automóvel do zero. Mesmo de posse das peças certas, é provável que leve vários anos para conseguir. E uma vez terminado, o produto final talvez não colabore para uma manutenção por terceiros. Agora se você visitasse primeiro uma linha de produção de uma montadora de automóveis, veria como cada peça é encaixada, qual o lugar de cada uma no conjunto etc. Ou seja, alguém já gastou um bom tempo entendendo funcionamento correto de um automóvel, onde cada peça deve ficar, como encaixá-las, e tornou esse conhecimento disponível para a montadora construir automóveis da maneira certa, segura e ágil. Isso se aplica ao desenvolvimento de software. Muitos já construíram software da maneira errada e aprenderam lições disso. Outros construíram software da maneira correta e observaram os benefícios resultantes. Esse conjunto de experiências proporcionam um excelente conhecimento disponível. Podemos dizer que utilizar padrões de projeto é se beneficiar da experiência adquirida por outros.

        Se convenceu de que vale a pena estudar e utilizar padrões de projeto?

       Em próximos posts falarei de alguns padrões de projeto que devem estar em todos os projetos: DAO, MVC, Factory. Também explicarei outros que irão trazer ainda mais benefícios, como o Command, Front Controller e DI (Injeção de Dependências).



       Gustavo Marques.

sábado, 17 de novembro de 2012

Tratando vários campos checkbox de mesmo nome com PHP

Em nossos formulários podemos ter uma lista de itens a serem selecionados pelo usuario. Esses campos podem ter o mesmo nome e devem ser recebidos na forma de array no script receptor. Isso é interessante pois se forem muitos itens ou de tamanho desconhecido (geralmente quando vem do banco) fica inviável ler campo a campo no PHP.
Veja como implementar:

Primeiramente o form:

<form action="gravar.php" method="post">
   <input type="checkbox" name="itens[]" value="1" /> Item 1<br/>
   <input type="checkbox" name="itens[]" value="2" /> Item 2<br/>
   <input type="checkbox" name="itens[]" value="3" /> Item 3<br/>
   <input type="submit" value="Enviar" /> 
</form>

Perceba que o nome deve ser terminado com '[]', para instruir o PHP de que se trata de um array.
O script:

<?php
$itens= $_REQUEST['itens'];

if (!empty($itens)) {                
      $qtd = count($itens);
       for ($i = 0; $i < $qtd; $i++) {
            echo $itens[$i];//imprime o item corrente
       }
 }

?>

Com esse código você pode ter uma lista de 1000 checkbox que não faz diferença, não precisará ler um a um.


Gustavo Marques.

Validando, gravando e lendo campos tipo Date no padrão 'dd/mm/aaaa' com PHP + Mysql

Nossos formulários podem conter campos tipo date, tais como a data de nascimento. É interessante que guardemos essa informação no banco de dados com o tipo correto. Isso nos permite fazer operações de data com essa data guardada, por exemplo, buscar os usuários que possuem certa idade.

Crie a tabela no banco:

CREATE TABLE  `usuario`(
   `id` int(11) NOT NULL AUTO_INCREMENT,
   `nome` text NOT NULL,
   `nascimento` date NOT NULL,
   PRIMARY KEY (`id`)
)


Crie o formulário HTML:

Novo usuario:<br/>
<form action="gravar.php" method="post">
<input type="text" name="nome" /><br/>
<input type="text" name="nascimento" /> (dd/mm/aaaa)<br/>
<input type="submit" value="gravar" />
</form>

Perceba que a data a ser fornecida tem que seguir o padrão 'dd/mm/aaaa'

Crie o script gravar.php que guardará no banco (coloco o script de forma simplificada para não perder o foco do artigo, mas o ideal seria isolar o código que acessa o banco de dados em um objeto DAO)


<?php

//função que valida a data

function dataValida($dat) {
        try {
            $data = explode("/", $dat); // explode a string $dat em pedaços, usando / como referência
            $d = $data[0];
            $m = $data[1];
            $y = $data[2];

            // verifica se a data é válida!
            // 1 = true (válida)
            // 0 = false (inválida)
            $res = checkdate($m, $d, $y);
            if ($res == 1) {
                return true;
            } else {
                return false;
            }
        } catch (Exception $exc) {
            return false;
        }
    }


$furou = false;//controla a validação

if (trim($_REQUEST['nascimento']) == '' || !dataValida($_REQUEST['nascimento'])) {
            $furou = true;
}

if (trim($_REQUEST['nome']) == '') {
            $furou = true;
}
if($furou){
   echo 'Todos os campos são obrigatórios! Verifique o formato da data dd/mm/aaaa';
   //redirecione de volta para o formulário
}else{
   //ok, pode gravar
   $connection = mysql_connect('bancourl', 'usuario', 'senha');        
   $db = mysql_select_db($config->getDataBaseName(), $connection);        
   $sql = "insert into usuario(nome, nascimento) values ('".$_REQUEST['nome'])."', STR_TO_DATE('" . $_REQUEST['nascimento']) . "','%d/%m/%Y'))";
   mysql_query($sql);  
   echo mysql_error();
   mysql_close($connection);
}


?>

Observe que oriento o MySQL a usar o padrão 'dd/mm/aaaa' nesse trecho: '%d/%m/%Y'. Você pode alterar essa padrão por exemplo para dd-mm-aaaa usando: '%d-%m-%Y', mas lembre de alterar também a função em php onde fazemos a validação da data.

Para exibir a data cadastrada:


$connection = mysql_connect('bancourl', 'usuario', 'senha');        
   $db = mysql_select_db($config->getDataBaseName(), $connection);        
   $sql = "select nome, DATE_FORMAT(nascimento,'%d/%m/%Y') as nascimento from usuario";
   $result = mysql_query($sql);  
   while ($row = mysql_fetch_array($result)) {
      echo $row['nascimento'];// exibirá a data no formato dd/mm/aaaa
   }
   echo mysql_error();
   mysql_close($connection);



Fica a dica.

Gustavo Marques.

Gerando senhas aleatórias com PHP

Um sistema que possua uma base de usuários com login e senha precisa fornecer mecanismos para recuperação de senha. Isso é importante porque o usuário pode esquecer sua senha. Assim é comum encontrarmos o link 'esqueci minha senha' nos sistemas que possuem login.
Ao clicar nesse link podemos gerar uma senha randômica e enviá-la por email ao usuário.

Essa solução tem várias implementações, segue uma maneira

function gerarNovaSenha(){
   $letras = array(
            'a',
            'b',
            'c',
            'd',
            'e',
            'f',
            'g',
            'h',
            'i',
            'j',
            'k',
            'l',
            'm',
            'n',
            'o',
            'p',
            'q',
            'r',
            's',
            't',
            'u',
            'v',
            'x',
            'z',
            '0',
            '1',
            '2',
            '3',
            '4',
            '5',
            '6',
            '7',
            '8',
            '9'
        );
        shuffle($letras);       
        $novasenha = '';
        for ($i = 0; $i < 10; $i++) {//10 é o tamanho da nova senha, substitua conforme a necessidade
            $novasenha = $novasenha . $letras[$i];           
        }
        return $novasenha;
}

Poderá incluir ainda nesse array simbolos '#@*&-_=+' e também caracteres em maiúscula para diversificar ainda mais.

Gustavo Marques.

quarta-feira, 7 de novembro de 2012

CRUD no Banco de Dados com Java e JDBC parte 2 - Criando seu Servlet

No post anterior expliquei como criar o seu DAO, ou seja, a camada de sua aplicação que irá acessar o banco de dados.

Vamos agora criar o nosso Servlet que irá utilizar os serviços oferecidos pelo nosso DAO.

Servlet

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package servlets;

import java.io.IOException;
import java.io.PrintWriter;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 *
 * @author User
 */
public class ListarProdutos extends HttpServlet {

    /**
     * Processes requests for both HTTP
     * <code>GET</code> and
     * <code>POST</code> methods.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    protected void processRequest(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        //variável que controla para qual view rotear após a execução desse Servlet
        String view = "";
        //Vamos criar uma conexão com o banco de Dados para passar ao nosso Dao.
        //É esse servlet que irá gerenciar a conexão
        java.sql.Connection con = null;
        try {
            con = Conexao.fabricar();//padrão factory, classe descrita depois desse servlet.
            con.setAutoCommit(false);//permitindo transações
            ProdutoDao dao = new ProdutoDao(con);
            List<Produto> produtos = dao.listarTodos();
            con.commit();
            //manda para a view
            request.setAttribute("produtos",produtos);
            view = "listagem.jsp";
        } catch(Exception ex){
            view = "erro.jsp";
            try{
               con.rollback();
           }catch(Exception ex2){}
        }finally {            
            try{
               con.close();
           }catch(Exception ex3){}
        }
        request.getRequestDispatcher(view).foward(request, response);
    }

    // <editor-fold defaultstate="collapsed" desc="HttpServlet methods. Click on the + sign on the left to edit the code.">
    /**
     * Handles the HTTP
     * <code>GET</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Handles the HTTP
     * <code>POST</code> method.
     *
     * @param request servlet request
     * @param response servlet response
     * @throws ServletException if a servlet-specific error occurs
     * @throws IOException if an I/O error occurs
     */
    @Override
    protected void doPost(HttpServletRequest request, HttpServletResponse response)
            throws ServletException, IOException {
        processRequest(request, response);
    }

    /**
     * Returns a short description of the servlet.
     *
     * @return a String containing servlet description
     */
    @Override
    public String getServletInfo() {
        return "Short description";
    }// </editor-fold>
}

Não esqueça de registrar seu Servlet no arquivo web.xml, logo abaixo da tag <web-app> inclua:

web.xml


   <servlet>
        <servlet-name>ListarProdutos</servlet-name>
        <servlet-class>servlets.ListarProdutos</servlet-class>
    </servlet>
    <servlet-mapping>
        <servlet-name>ListarProdutos</servlet-name>
        <url-pattern>/ListarProdutos</url-pattern>
    </servlet-mapping>

Agora a classe Fábrica de Conexões:

Conexao.java

public class Conexao {

    public static Connection fabricar() throws Exception {       
        Class.forName("com.mysql.jdbc.Driver").newInstance();
        return DriverManager.getConnection("jdbc:mysql://localhost/banco" ,"usuario" ,"senha" );
    }
}

No próximo post implementaremos a View com JSP e JSTL.

Gustavo Marques.

segunda-feira, 5 de novembro de 2012

Fazendo download de arquivos pelo navegador com java a partir de sua aplicação web

Muitas são as situações que exigem a implementação de download de arquivo. Podemos gerar um relatorio em pdf dinamicamente e disponibiliza-lo para download pelo navegador, ou baixar imagens, arquivos zip etc. Porém as vezes não podemos simplesmente passar o caminho do arquivo via url para o usuario digitar na barra de endereços. Um exemplo disso são .war magros. Os usuários vão fazendo uploads mas os arquivos não ficam em uma pasta do war, mas sim em uma pasta do servidor fora do contexto da aplicação, por exemplo C:\arquivos. Os usuarios do sistema web não podem acessar essa pasta do servidor pelo browser, pois está fora do contexto da aplicação.
Assim devemos criar um objeto java.io.File com a localizaçao do arquivo que queremos servir e escrevê-lo no HttpServletResponse.

Vamos ao código:

File arquivo = new File("C:\arquivos\relatorio.pdf");

//tipo de arquivo
response.setContentType("application/pdf");

//nome do arquivo a ser exibido na caixa de download do browser
response.setHeader("Content-Disposition", "attachment; filename=" + arquivo.getName()+ ";");

//manda os bytes do arquivo pelo response
URL url = arquivo.toURI().toURL();
BufferedInputStream leitor = new BufferedInputStream(url.openStream(), 4 * 1024);
OutputStream escritor = response.getOutputStream();
byte[] buffer = new byte[4 * 1024];
int size = 0;
while ((size = leitor.read(buffer, 0, buffer.length)) != -1) {
   escritor.write(buffer, 0, size);
}
escritor.close();
leitor.close();

Isso fará com que o browser do usuário exiba a caixa de download.

Se você não souber antecipadamente qual o tipo de arquivo que irá entregar, poderá definir em tempo de execução verificando a extensão do arquivo:


//pega a extensão do arquivo
String[] partes = arquivo.getNome().split("\\.");
int ultimaParte = partes.length - 1;
String extensao = partes[ultimaParte];

//seta o content type segundo a extensão
if (extensao.equals("doc")) {
   response.setContentType("application/msword");
}
if (extensao.equals("pdf")) {
   response.setContentType("application/pdf");
}
if (extensao.equals("pdf")) {
   response.setContentType("application/pdf");
}
if (extensao.equals("xls")) {
   response.setContentType("application/vnd.ms-excel");
}
if (extensao.equals("ppt")) {
   response.setContentType("application/vnd.ms-powerpoint");
}
if (extensao.equals("gzip")) {
   response.setContentType("application/gzip");
}
if (extensao.equals("zip")) {
   response.setContentType("application/zip");
}
if (extensao.equals("au") || extensao.equals("snd")) {
   response.setContentType("audio/basic");
}
if (extensao.equals("midi")) {
   response.setContentType("audio/midi");
}
if (extensao.equals("aiff")) {
   response.setContentType("audio/x-aiff");
}
if (extensao.equals("wav")) {
   response.setContentType("audio/x-wav");
}
if (extensao.equals("gif")) {
   response.setContentType("image/gif");
}
if (extensao.equals("jpg") || extensao.equals("jpeg")) {
   response.setContentType("image/jpeg");
}
if (extensao.equals("png")) {
   response.setContentType("image/png");
}
if (extensao.equals("tiff")) {
   response.setContentType("audio/tiff");
}
if (extensao.equals("bmp")) {
   response.setContentType("image/x-xbitmap");
}
if (extensao.equals("html") || extensao.equals("htm")) {
   response.setContentType("text/html");
}
if (extensao.equals("txt")) {
   response.setContentType("text/plain");
}
if (extensao.equals("xml")) {
   response.setContentType("text/xml");
}
if (extensao.equals("mpeg")) {
   response.setContentType("video/mpeg");
}


Gustavo Marques.

quinta-feira, 1 de novembro de 2012

Criando jogos em HTML 5 utilizando canvas

O html5, principalmente com a funcionalidade de canvas, possibilita a criação de jogos interessantes.
Nesse post mostrarei um exemplo breve de um jogo feito em html 5.
Nesse jogo controlaremos uma nave viajando pelo espaço.

Primeiro precisaremos de 2 imagens: Uma da nave e outra do espaço.
Nesse post eu expliquei como gerar imagens 2d por meio do blender. Vou usar uma como exemplo.



É importante que ela possua fundo transparente (.png).

Agora precisamos da imagem background:



Com essas duas imagens a disposição, já podemos programar nosso jogo.

Vamos ao código.
Para não ter um código sujo, vamos separar o html do javascript em arquivos separados.

jogo.html


<html>
    <head>
        <title>Jogo</title>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.3/jquery.min.js" type="text/javascript"></script>
    </head>
    <body>
    <center>
        <h1>Meu Primeiro jogo em html 5</h1>
        <br/>

<br/>
        <canvas id="game" width="500" height="500" style="border: 1px solid #000000;">
            <p>Seu navegador não suporta HTML5!</p>
        </canvas>
        <script src="codigo.js"></script>     
    </center>
</body>
</html>


Nesse código temos o elemento <canvas> onde desenharemos com javascript. Agora vamos ao arquivo codigo.js

codigo.js


// cria o contexto grafico no canvas
var drawingCanvas = document.getElementById('game');
var ctx = drawingCanvas.getContext('2d');

var framecount = 0;


// carrega imagens
// Criando Background e seus objetos
var bgReady = false;
var bgImage = new Image();
bgImage.onload = function () {
    bgReady = true;
};

bgImage.src = 'bg.jpg';

var naveReady = false;
var naveImage = new Image();
naveImage.onload = function () {
    naveReady = true;
};
naveImage.src = 'nave.png';

//objetos do jogo
var nave = {
    speed:256,
    x:220,
    y:440,
    w:60,
    h:60,
    currentImage:null
};


//teclado
var keysDown = {};
addEventListener('keydown', function (e) {
    keysDown[e.keyCode] = true;
}, false);
addEventListener('keyup', function (e) {
    delete keysDown[e.keyCode];
}, false);


// frame update
var update = function(modifier){
    if (38 in keysDown) { // Jogador vai para cima
        //verifica se já está no limite
        if(nave.y >= 0){
            nave.y -= nave.speed * modifier;          
        }
    }
    if (40 in keysDown) { // Jogador vai para baixo
        if(nave.y <= 500-nave.h){
            nave.y += nave.speed * modifier;          
        }
    }
    if (37 in keysDown) { // Jogador vai para esquerda
        if(nave.x >= 0){
            nave.x -= nave.speed * modifier;          
        }
    }
    if (39 in keysDown) { // Jogador vai para direita
        if(nave.x <= 500 - nave.w){
            nave.x += nave.speed * modifier;          
        }
    }




    framecount++;
}

//render game
var render = function(){
    //clear no canvas
    //ctx.fillStyle = 'rgb(1, 1, 1)';
    //ctx.fillRect(0, 0, 500, 500);
 
    if (bgReady) {
        ctx.drawImage(bgImage, 0, 0);
    }
    if (naveReady) {
        ctx.drawImage(naveImage, nave.x, nave.y);
    }
    // pinta o framecount
    ctx.fillStyle = 'rgb(250, 250, 250)';
    ctx.font = '10px Verdana';
    ctx.textAlign = 'left';
    ctx.textBaseline = 'top';
    ctx.fillText('Frame: ' + framecount, 390, 480);

}

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

//iniciando o game
var then = Date.now();
setInterval(main, 1);


Não se assuste! Leia os comentários que está bem claro. Veja as explicações abaixo na ordem dos comentários:

1- Iniciamos o contexto do canvas.

2- Carregamos as imagens do jogo. Observe que coloquei 2 variáveis booleanas para saber quando as imagens foram carregadas e assim poder pintalas no canvas.

3- Criamos o objeto nave (sprite) com as propriedades de localização no canvas e suas dimensões.

4- Registramos as teclas pressionadas.

5- Entramos agora na função update. Ela será executada a cada frame. Se você não entende esse conceito de frame e game loop leia esse post. Dentro da função update atualizamos a posição da nave, verificando sempre se ela já atingiu o limite do cenário. A variavel framecont eu adicionei só para vocês observarem que durante um jogo o game loop acontece. Ela vai sendo incrementada e exibida a cada frame.

6- A função render é responsável por pintar na tela o estado atual do jogo, nesse caso a posição atual da nave. Observe que pintamos utilizando os métodos de ctx. Ele funciona como o graphics do java 2d.

7- A função main é o game loop. Ela será executada no intervalo definido na ultima linha setInterval();


Gustavo Marques

Veja também

Related Posts Plugin for WordPress, Blogger...