Segunda-feira, Novembro 19, 2007

Framework Mentawai - Desenvolvimento Java para WEB.

Dae pessoal, to a tempos para postar aqui mas não consigo tempo para nada.

Estes dias ia iniciar um projeto e comecei pela escolha de um framework para utilizar. O pessoal da empresa em que eu trabalhava (a dois meses mudei de emprego, estado, cidade... e por isso de ter largado o blog um pouco) estava usando o Jboss SEAM para novas aplicações WEB. Eu gostei, fui em uma palestra sobre o Jboss Seam e tudo mais, mas no fim achei que ia usar uma bomba atômica para matar uma formiga. E depois, queria aprender algo realmente novo e que ninguém naquela sala tivesse trabalhado, por desafio mesmo. Então pensei em dar uma olhada nos frameworks brasileiros (não, não li a revista aquela com a matéria de capa sobre isso). De cara na home do site do primeiro candidato eu já vi o que mais me agradaria: sem XMLs e annotations!

Claro, estou falando do Mentawai. Projeto bem bacana que anda conquistando o mundo (ta isso foi por minha conta :) )!!!

Então como de costume, peguei o .jar do framework, criei um novo projeto no Eclipse e comecei a fuçar criando minha aplicação modelo, se eu conseguisse fazer ali meia dúzia de coisas que eu desejava na minha aplicação final ele seria o eleito.

Comecei pela lista:

  1. Não quero preencher beans na mão, o framework tem que pegar os formulários e popular objetos para mim.

  2. Tem que ter algum suporte a IoC sem que eu tenha que meter mais uma tonelada de .jars, como o do Spring e a penca de .jars que ele necessita, para isso e sem muito esforço também, não quero ter que ler mais uma documentação para aprender como usar um framework secundário.

  3. Bom, pela minha preguiça expressa acima eu também não quero ter que correr atrás de componentes como upload, envio de e-mail, etc... o eleito tinha que ter tudo isso.

  4. O Mentawai de cara já era um futuro eleito por não conter um só maldito XML e nem uma porcaria de annotation! Não, sério... na boa... aquela sopa de annotations ou aqueles duzentos arquivos XML não é prático.


Meu exemplo era o mais simples: uma tela de acesso ou cadastro. Ok, vamos complicar um pouco, mas nem tanto, tinha que ter suporte a internacionalização e salvar algumas coisas sobre o usuário em cookies.

Em 4 minutos (na verdade 3 e alguns segundos) eu tinha feito a primeira tela da minha aplicação seguindo a documentação no site do framework.

Toda a configuração da aplicação é feita em uma classe, ou seja, é em Java! Não tem como o cara colocar um caractere inválido, esquecer de fechar uma tag ou fazer qualquer barbeiragem neste arquivo pois o mesmo é compilado. Ótimo, gostei muito disso.

Depois da minha primeira página parti para a forma de pegar os dados do formulário de cadastro em um objeto já preenchido pelo framework. Moleza. Isso foi muito fácil de fazer também.

Login... tenho que criar a forma do cara entrar na minha aplicação e recuperar os dados dele da sessão. Também não foi difícil. Tive uns problemas aqui mas foram barbeiragens minhas :) o frame estava certo!

Comecei a achar que estava no mundo perfeito!

Passei para a internacionalização. Aqui eu tive que apelar para o fórum. Mas fui socorrido em minutos.

A única coisa que ainda falta eu implementar é usar mensagens parametrizadas na internacionalização. Exemplo: O usuário {0} deletou {1}. Mas, diz o inventor do monstro, que há como fazer e eu que não li a documentação corretamente. Devo tirar um tempinho essa semana para descobrir como fazer.

Então minha aplicação ficou assim:

Passos da aplicação:

  1. Ao acessar o endereço da aplicação no navegador o usuário é redirecionado para a action Preparesystem. Esta action tem a função de ler possíveis dados do usuário armazenados anteriormente, como o último login que acessou o sistema, idioma escolhido anteriormente pelo usuário, etc... Depois de feito isso o usuário é redirecionado para a página principal do sistema.

  2. Na página principal o usuário tem duas opções: fazer login ou cadastrar-se no sistema.

  3. Quando o usuário executa login ele é redirecionado para a action Login. Nesta action é injetado o objeto User pelo controle de IoC do Mentawai. Ou seja, é pego na requisição os dados do formulário e postos em um objeto sem a intervenção do desenvolvedor (magavilha!). Depois de aplicada a regra de acesso ao sistema o usuário é redirecionado para a home, caso o login tenha sido bem sucedido, ou para a primeira página do sistema novamente onde serão exibidas as mensagens de erro, caso o login não tenha sido bem sucedido. Note que quem faz a validação da requisição é uma classe externa a action, chamada LoginValidator. Talvez essa seja a grande jogada deste framework, poder separar muito bem as coisas em objetos com propósitos distintos.

  4. Quando o usuário vai se cadastrar no sistema ele é redirecionado para a página com o formulário de cadastro. Por trás desta página há a action Register que, assim como a action Login, recebe um objeto já preenchido com os dados do formulário. Também a exemplo da action Login, a validação está em uma classe externa chamada RegisterValidator. Se o cadastro for efetivado com sucesso o usuário é redirecionado para uma página de boas vindas de onde ele tem a opção de ir para a home do sistema.


E estamos aí, ela funciona mesmo! Olha a cara dela que espetáculo! :)


Tela inicial da aplicação

Assim começa a aplicação.



Tela inicial da aplicação em inglês

Versão em inglês.



Tela cadastro

Tela de cadastro.



Tela de boas-vindas

Boas-vindas para usuários que se cadastram.



Tela inicial para usuários logados

Home para usuários logados.


Quem quiser baixar os fontes e olhar como foi feito: http://www.mentaframework.org/files/. Enviei para o criador do framework minha app para que ela fique disponível como exemplo de uso.

Era isso pessoal. Encorajo-os a usar o framework, cadastrassem no fórum, e darem algum valor pelo o que é desenvolvido com tanto esforço pelos programadores tupiniquins!

Abraços a todos.

OBS.: Não postem comentários sobre perguntas referentes ao framework aqui, e sim no fórum deles! Postem comentários sobre a minha aplicação, erros de português, falando do blog... enfim.

Adicionar esta notícia no Linkk

Quarta-feira, Setembro 19, 2007

Wiki sobre MySQL em português!

Dae galera, quem visita o blog com frequência sabe que eu me dedico aqui a postar coisas sobre Java e sobre MySQL.


Sobre Java porque é o que eu faço profissionalmente e sobre MySQL porque é o SGBD que mais uso nos meus projetos particulares.


Depois de anos participando da lista MySQL-Br do Yahoo! Brasil o pessoal criou uma página de Wiki para facilitar buscas por conteúdos e artigos.


Bem, o site do Wiki começou hoje, e não tem nada ainda. Mas vale a pena ficar de olho e de vez em quando dar uma passadinha por lá.


Os endereços:


Da lista no Yahoo! Brasil: http://br.groups.yahoo.com/group/mysql-br/


Do Wiki: http://mysql-br.wikidot.com.


Colaborações serão sempre bem-vindas!

Marcadores: , , , ,

Adicionar esta notícia no Linkk

Quarta-feira, Setembro 05, 2007

Internacionalização em Java

Dae pessoal, não faz tanto tempo assim que postei algum “drop” de sabedoria aqui. Então vamos a mais um: internacionalização!

Diretamente das definições da Sun: “internacionalização é o processo de projetar uma aplicação, de modo que ela possa ser adaptada a varias linguagens e regiões sem mudanças de engenharia.” – leia-se mudanças no código.

Bom, você já deve ter ouvido ou lido em algum código o prefixo “i18n” ou “l10n”. i18n é a abreviação de internationalization, pois do primeiro i ao último n há 18 letras. O l10n é a abreviação de localization e segue a mesma regra do número de caracteres entre l e n.

Existem certas características em um programa internacionalizado, como:

• Dado uma localização (Locale), o mesmo binário do programa deve funcionar em qualquer lugar;
• Os dados textuais do programa (mensagens de erro, mensagens de tela, rótulos, etc...) não devem estar atribuídos de forma “hardcode” aos elementos dentro dos códigos do programa e sim externados em um arquivo apropriado;
• Suporte a outros idiomas não deve requerer nova compilação do programa;
• Dados dependentes de localização, como formatação de datas e campos monetários, devem ser apresentados de acordo com a região do usuário e seu idioma;

Bom, se você tiver sons e imagens que possam fazer sentido internacionalizar, é uma boa idéia!

Vamos cortar o nhe nhe nhe e partir para a ação.

Vamos a um simples exemplo. Uma classe que deva imprimir:

Nome: Jean Jorge Michel
Nome de usuário: jmichel
Senha: minhasenhaultrasecreta

Porém os rótulos (nome, nome de usuário e senha) devem ser impressos corretamente para cada idioma (tá, não exageremos, vamos testar com português e inglês apenas).

Então vamos começar pelos fatos primeiros (como diria o grande sábio), criando os arquivos com a tradução do nosso programa. Para isso, no pacote estudo.internacionalizacao criei dois arquivos:

• ResourceBundle_pt_BR.properties;
• ResourceBundle_en_US.properties.

E o conteúdo de cada um deles (na ordem de criação):

name=Nome
password=Senha
username=Nome de usuário

name=Name
password=Password
username=Username

Agora no mesmo pacote criei a classe Internacionalizada.java:

package estudo.internacionalizacao;

import java.util.Locale;
import java.util.ResourceBundle;

public class Internacionalizada {

    public static void main(String[] args) {

        final Locale defaultLocale = Locale.getDefault();
        final ResourceBundle rbDefault = ResourceBundle.getBundle("estudo.internacionalizacao.ResourceBundle", defaultLocale);

        System.out.println(new StringBuilder().append(rbDefault.getString("name")).append(": Jean Jorge Michel"));
        System.out.println(new StringBuilder().append(rbDefault.getString("username")).append(": jmichel"));
        System.out.println(new StringBuilder().append(rbDefault.getString("password")).append(": minhasenhaultrasecreta").append("\n\n"));

        final Locale otherLocale = new Locale("en", "GB");
        final ResourceBundle rb = ResourceBundle.getBundle("estudo.internacionalizacao.ResourceBundle", otherLocale);

        System.out.println(new StringBuilder().append(rb.getString("name")).append(": Jean Jorge Michel"));
        System.out.println(new StringBuilder().append(rb.getString("username")).append(": jmichel"));
        System.out.println(new StringBuilder().append(rb.getString("password")).append(": minhasenhaultrasecreta"));
    }
}

Agora é só rodar e ver o resultado das duas saídas que devem parecer com isso:

Nome: Jean Jorge Michel
Nome de usuário: jmichel
Senha: minhasenhaultrasecreta


Name: Jean Jorge Michel
Username: jmichel
Password: minhasenhaultrasecreta

Lembra daquela Enum do post anterior? Poderia ser internacionalizada não? :)

Até mais! Bons códigos

Marcadores: , , , , ,

Adicionar esta notícia no Linkk

Quinta-feira, Agosto 16, 2007

Java Enum

Aeeee o blog está vivo! Eu andei sem tempo para postar aqui mas vamos lá...

A bola da vez é o tipo Enum do Java.
Uma enum (enumeração) é um conjunto de valores fixos (constantes) que podem ajudar o desenvolvedor a definir valores fixos que serão usados no sistema.

Use sempre que você quiser definir um conjunto de valores fixo como por exemplo os dias da semana, meses do ano, tipos de entidades, etc...

Vamos ao exemplo usando uma enum que armazene os dias da semana:

public enum DiasSemana {

    SEGUNDA, TERCA, QUARTA, QUINTA, SEXTA, SABADO, DOMINGO;

}

Ok, o exemplo é bem meia boca, mas vamos em frente. Por serem constantes os valores de uma enum são sempre grafados em maiúsculo.

Agora vamos fazer uma classe que utilize esses valores:

public class Agenda {
    public static void main(String[] args) {
    
        System.out.println(DiasSemana.QUINTA);
    
    }
}

A saída é: QUINTA.

Enums podem ter métodos, seus valores podem ter métodos, e toda enum “herda” métodos (nos materiais da SUN eles falam que o compilador adiciona tais métodos, não fala em herança propriamente dita e na documentação da classe o objeto Enum é filho de Object. Todas as enums que você criar serão filhas da classe java.lang.Enum e por não haver herança múltipla no Java você não pode fazer suas enums estenderem mais nada!) que facilitam a vida do desenvolvedor como o estático values() que retorna um array com os valores da enum ordenados pela declaração. Ex:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println(dia);
        }

    }
}

A saída é:

SEGUNDA
TERCA
QUARTA
QUINTA
SEXTA
SABADO
DOMINGO

Bem mas a nossa enum não está muito funcional, eu não exibiria em meu sistema essas entradas! ;)
Então vamos declarar métodos que formatem nossos valores para algo melhor:

public enum DiasSemana {

    SEGUNDA() {
        public String extenso() {
            return "segunda-feira";
        }
    },
    TERCA() {
        public String extenso() {
            return "terça-feira";
        }
    },
    QUARTA() {
        public String extenso() {
            return "quarta-feira";
        }
    },
    QUINTA() {
        public String extenso() {
            return "quinta-feira";
        }
    },
    SEXTA() {
        public String extenso() {
            return "sexta-feira";
        }
    },
    SABADO() {
        public String extenso() {
            return "sábado";
        }
    },
    DOMINGO() {
        public String extenso() {
            return "domingo";
        }
    };
    
    public String extenso() {
        return this.extenso();
    }
}

Vamos usar o recurso:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println(dia.extenso());
        }

    }
}

A saída é:

segunda-feira
terça-feira
quarta-feira
quinta-feira
sexta-feira
sábado
domingo

Beleza! Com isso foi ilustrado o fato de um tipo Enum poder ter métodos e seus atributos também.

Ainda brincando com a classe Agenda:

public class Agenda {
    public static void main(String[] args) {

        for(DiasSemana dia : DiasSemana.values()) {
            System.out.println("Valor: " + dia);
            System.out.println("Extenso: " + dia.extenso() + "\n");
        }

    }
}

A saída é:

Valor: SEGUNDA
Extenso: segunda-feira

Valor: TERCA
Extenso: terça-feira

Valor: QUARTA
Extenso: quarta-feira

Valor: QUINTA
Extenso: quinta-feira

Valor: SEXTA
Extenso: sexta-feira

Valor: SABADO
Extenso: sábado

Valor: DOMINGO
Extenso: domingo

Bom galera, foi uma passadinha rápida por aqui para postar algo. Até mais, obrigado pela visita, click nos patrocinadores :) e comentários.

Marcadores: , , ,

Adicionar esta notícia no Linkk

Quinta-feira, Julho 19, 2007

Mais de um mês parado mas ...

Dae pessoal, sei que o blog anda meio largado mas é por um bom motivo: estudando JBoss SEAN!
Parece ser muito bacana o negocio, e espero que resolva o meu problema de preguiça aguda na hora de implementar algumas coisas :P

Tirando isso to levando um coro para configurar um ambiente de trabalho no Windows Vista Home Premium assim como configurá-lo e conseguir navegar na internet sem me arrastar... mas enfim.

Esperam por um post sobre JBoss SEAN, JSF e afins.

A nova, nem tão nova, é que estou usando o Eclipse Europa agora... desisti do Lomboz.

Até a próxima pessoal.

Marcadores: , , ,

Adicionar esta notícia no Linkk

Quarta-feira, Junho 13, 2007

Prepared Statements no MySQL.

Esses tempos tinha uma pergunta pipocando em uma lista sobre MySQL onde uma pessoa queria fazer alguma coisa em um procedimento (procedure) e não conseguia. A solução que eu encontrei para ajudar a pessoa foi Prepared Statements.

Para ilustrar o seu uso criei uma tabela:

CREATE TABLE PEDIDO (
  CODPEDIDO  INT(3) ZEROFILL NOT NULL,
  CODCLIENTE INT(3) ZEROFILL NOT NULL,
  VALOR      DOUBLE          NOT NULL,
  STATUS     CHAR(1)         NOT NULL
);

Depois inseri dados:

INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(1, 1, 99.87, 'E');
INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(2, 2, 99.87, 'A');
INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(3, 3, 99.87, 'A');
INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(4, 2, 99.87, 'S');
INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(5, 2, 99.87, 'A');
INSERT INTO Pedido(CodPedido, CodCliente, Valor, Status) VALUES(6, 3, 99.87, 'E');

O Status seria: E – Encerrado, A – Aberto, S – Suspenso.

Depois pode se criar o Prepared Statements, eu fiz dentro de um procedimento, mas poderia ser feito direto no console do MySQL que funcionaria.

Criando o procedimento (procedure):

CREATE PROCEDURE P_PEDIDOS_STATUS(IN STATUS CHAR(1))
BEGIN

  SET @StatusPedido = STATUS;

  PREPARE psmtp FROM 'SELECT CodPedido, CodCliente, Valor, Status FROM Pedido WHERE Status = (?) GROUP BY CodCliente ORDER BY CodPedido';
  EXECUTE psmtp USING @StatusPedido;

  DEALLOCATE PREPARE psmtp;

END;

Bom a finalidade aqui é selecionar todos os pedidos por status, para isso passamos por parâmetro o status que desejamos procurar:

Resultados:

mysql> call P_PEDIDOS_STATUS('E');
+-----------+------------+-------+--------+
| CodPedido | CodCliente | Valor | Status |
+-----------+------------+-------+--------+
|       001 |        001 | 99.87 | E      |
|       006 |        003 | 99.87 | E      |
+-----------+------------+-------+--------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

mysql> call P_PEDIDOS_STATUS('A');
+-----------+------------+-------+--------+
| CodPedido | CodCliente | Valor | Status |
+-----------+------------+-------+--------+
|       002 |        002 | 99.87 | A      |
|       003 |        003 | 99.87 | A      |
+-----------+------------+-------+--------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

mysql> call P_PEDIDOS_STATUS('S');
+-----------+------------+-------+--------+
| CodPedido | CodCliente | Valor | Status |
+-----------+------------+-------+--------+
|       004 |        002 | 99.87 | S      |
+-----------+------------+-------+--------+
1 row in set (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

Agora, e se quisermos ter um procedimento maluco que receba toda a minha query e a execute? Sei lá qual a finalidade disto (agora não me ocorre nada em mente que justifique, mas vai que você tem um relatório que muda muito pouco de uma query – por exemplo só o where ou o order by -  e pode generalizar a chamada passando a query ou parte dela? Sei lá!) então poderiamos “injetar” para o procedimento todo o comando a ser executado no SGBD:

CREATE PROCEDURE P_INJETA_SQL(IN SQLCOMMAND VARCHAR(500))
BEGIN

  SET @Command = SQLCOMMAND;

  PREPARE psmtp FROM @Command;
  EXECUTE psmtp;

  DEALLOCATE PREPARE psmtp;

END;

Teste:

mysql> CALL P_INJETA_SQL('SELECT CodPedido, CodCliente, Valor, Status FROM Pedido WHERE Status = ''E'' GROUP BY CodCliente ORDER BY CodPedido');
+-----------+------------+-------+--------+
| CodPedido | CodCliente | Valor | Status |
+-----------+------------+-------+--------+
|       001 |        001 | 99.87 | E      |
|       006 |        003 | 99.87 | E      |
+-----------+------------+-------+--------+
2 rows in set (0.00 sec)

Query OK, 0 rows affected (0.02 sec)

Beleza, afunfa!

Bom de asas a sua imaginação agora e qualquer coisa comenta aí! :D

Marcadores: , ,

Adicionar esta notícia no Linkk

Sexta-feira, Junho 01, 2007

Palestra sobre Hibernate e Jboss SEAM

Ontem fui a duas palestras na Targettrust, uma delas sobre Hibernate e a outra sobre o Jboss Seam.

Sai de lá me perguntando: porque eu fui? :) Com um monte de coisas que eu preciso estudar para finalmente marcar minha prova de certificação agora fiquei ansiando por aprender mais sobre o SEAM.

Muito boa a palestra, pena que teve seu tempo drasticamente encurtado mas mesmo assim muito legal.

O material está no blog do autor: http://www.juliocsmac.blogspot.com.

Bom, mais além eu irei escrever sobre o SEAM e tal...

Por hora é isso, a vida ta corrida! :P

Marcadores: , , , ,

Adicionar esta notícia no Linkk