segunda-feira, 29 de dezembro de 2014

Regex para validação de moeda

Olá amigos leitores. O tema do post dessa semana foi escolhido por uma necessidade que tive muito tempo atrás. Quando me deparei com o problema aplicar máscaras monetárias (R$) em campos de texto, resolvi construir uma solução própria. Poderia ter usado soluções prontas ? Sim, poderia mas, eu não queria ficar amarrado à soluções de terceiros.

Para resolver o problema, não queria criar uma função grande e de complexidade elevada sendo que, uma regex poderia lidar com esse problema. Então, vamos lá !!

A regex construída:

 ^R\$(\d{1,3}(\.\d{3})*|\d+)(\,\d{2})?$  

Esta regex aceita estes valores:
  • R$2,00
  • R$20,00
  • R$2.000,00
  • R$20.000,00
  • R$200.000,00
  • R$2.000.000,00
Mas, não aceita esses:
  • 2,00
  • 2
  • R$aaa44,00
  • B$20,00
  • $100,00
Importante: Note que o caracter usado para separar os reais dos centavos é o vírgula (,) e não o ponto (.).

Agora, vamos às partes das explicações. Vamos destrinchar a regex.

Os caracteres ^ e $, respectivamente, no início e fim da expressão regular denotam um intervalo fechado, ou seja, o texto que for avaliado só pode conter o dado monetário.

O caracter representa o próprio R do R$. Então, até aí, nenhum mistério. O $ possui significado especial nas regex, logo precisamos de uma barra de escape (\$) para que ela adote a representação de cifrão ($).

Com (\d{1,3}(\.\d{3})*|\d+) definimos que teremos ou algo desse tipo: 2.000 ou 2000. Vamos melhorar isso.

\d{1,3} -> \d representa um dígito. O {1,3} representa no mínimo 1 e no máximo 3 ocorrências. Então, quando temos \d{1,3} estamos querendo dizer que, teremos um dígito que terá no mínimo 1 e no máximo 3 ocorrências.
(....) -> Os parênteses () são usados para definir um subconjunto.
\. -> A barra de escape é usada no ponto (.) para definir o separador de milhar.
\d{3} -> Representa um dígito que será repetido três vezes.
* -> Representa que algo será repetido 0 ou infinitas vezes.
| -> Representa uma operação de ou.
\d+ -> Representa que um dígito será repetido no mínimo 1 e no máximo infinitas vezes.

Agora, que já deciframos uma parte da regex, falta a outra parte: (\,\d{2})?
Essa parte define os centavos logo, algo assim será aceito: ,00.

\, -> Caracter vírgula (,) com barra de escape para assumir a representação de vírgula.
\d{2} -> Ver explicação acima.
(....) -> Ver explicação acima.
? -> Representa que algo será repetido 0 ou 1 vez.

Agora que já esmiuçamos toda a regex, já entendemos como ela funciona e como ela aceita os valores descritos acima. É só pegar e usar.

Sugestões ? Críticas ? Elogios ? Deixe aí embaixo nos comentários ou, na página do facebook.

Página do facebook: https://www.facebook.com/precisoestudarsempre/
Leia Mais ››

terça-feira, 23 de dezembro de 2014

Listas encadeadas em Java

Olá caros leitores do blog Preciso Estudar Sempre, o tópico desta semana será sobre listas encadeadas. Escolhi esse tema porque acredito que é importante e porque não me lembro de ter falado sobre tal antes.

O conhecimento deste assunto é de grande importância no desenvolvimento de software pois, as listas encadeadas possuem uma estrutura bem diferente das listas tradicionais. Tal estrutura que pode nos ajudar em certas situações.

Antes que você se impressione com o assunto, eu já digo: "Fique tranquilo". Este tema é de fácil entendimento. Porém, é necessário de um pouco de conhecimento de programação.

Para os que já conhecem o assunto ou que já ouviram falar, já aviso que não falarei sobre listas duplamente encadeadas ou listas circulares porque senão o post ficará muito extenso e massante.

No Java, já existem estruturas prontas para listas encadeadas. Estou falando da LinkedList, clique aqui para ver a documentação. Mas, nesse post iremos criar nossa própria estrutura de lista encadeada.

Para realizar este estudo não é necessário ter uma IDE super moderna. Se você quiser usar o notepad não tem problema.

Primeiro, vamos entender o conceito das listas encadeadas. As listas tradicionais tem suas células organizadas todas juntas e posicionadas uma atrás da outra. Isso lhes garante velocidade em buscas e acesso randômico, ou seja, eu posso acessar qualquer posição que eu queira. Porém, existe uma desvantagem nesta estrutura. Quando eu preciso inserir ou remover elementos no meio da lista, o trabalho para reconstruir a lista com todos elementos é muito grande visto que, eu preciso remover os elementos que virão após o novo/removido elemento e depois recolocá-los, formando assim uma lista maior/menor.

http://voidexception.weebly.com/uploads/1/1/9/4/11944659/4652147_orig.jpg

Com as listas encadeadas não existe este problema porque suas células são organizadas de forma diferente. Nas listas tradicionais, cada elemento não tem conhecimento do próximo elemento ou do anterior porque estão todas juntas dentro da estrutura. Nas lista encadeadas, não. Cada elemento está "solto" na memória. Então, agora, você fica com aquela dúvida.

"Se os elementos estão soltos, como a lista é montada ? "

A resposta é simples, cada elemento possui uma referência somente para o próximo elemento. Como se formassem uma corrente, como se estivessem ligados (daí que vem o nome Linked List). Na figura abaixo, temos um exemplo perfeito de como é essa lista.

http://www.ime.usp.br/~pf/algoritmos/xfig/lista2a.gif

Os elos da lista são formados por ponteiros que possuem a referência para o próximo elemento. Quando não existe a referência para o próximo elemento, o ponteiro assume o valor nulo. Abaixo, temos uma relação de vantagens e desvantagens dessa estrutura.

Vantagens:
  • Linked lists são estruturas de dados dinâmicos que alocam a memória necessária enquanto o programa está funcionando.
  • Operações de inserir e deletar células (nodes) são facilmente implementadas.
  • Estruturas de dados lineares tais como, pilhas e filas são facilmente executadas com uma lista encadeada.
  • Eles podem reduzir o tempo de acesso e podem aumentar em tempo real sem overhead de memória.
Desvantagens:
  • Tem tendência de desperdiçar memória pelo fato dos ponteiros pediram novo espaço de armazenamento.
  • Nós em uma lista encadeada devem ser lidos do início.
  • Dificuldades surgem em listas encadeadas quando se tente percorrê-la de trás para frente. Tal tarefa é extremamente complicado. Adicionar um backpointer (ponteiro de ré) causa desperdício de memória.
Agora que já sabemos como a lista encadeada funciona, vamos ao exemplo prático. Nós criaremos uma lista encadeada que representa uma escala de indicação de empregos, ou seja, uma pessoa indica a outra para uma vaga de emprego mas, ela só pode indicar 1 pessoa e só conhece a pessoa que indicou.

Crie a classe Pessoa. Esta classe representa a pessoa.

 package pkg;  

 public class Pessoa { 
      private Integer id; 
      private String nome; 
      private String email; 
      public Pessoa() { 

      } 

      public Pessoa(Integer id, String nome, String email) { 
           this.id = id; 
           this.nome = nome; 
           this.email = email; 
      } 

      public Integer getId() { 
           return id; 
      } 

      public void setId(Integer id) { 
           this.id = id; 
      } 

      public String getNome() { 
           return nome; 
      } 

      public void setNome(String nome) { 
           this.nome = nome; 
      } 

      public String getEmail() { 
           return email; 
      } 

      public void setEmail(String email) { 
           this.email = email; 
      } 

      @Override 
      public String toString() { 
           return "Pessoa [id=" + id + ", nome=" + nome + ", email=" + email + "]"; 
      } 
 } 

Crie a classe Celula. Esta classe representa a célula (posição ou node) da lista. Como vimos acima, cada célula precisa da referência do próximo e isso é feito através do atributo proximo.

 package pkg;  

 public class Celula { 
      private Celula proximo; 
      private Pessoa valor; 
      public Celula getProximo() { 
           return proximo; 
      } 

      public void setProximo(Celula proximo) { 
           this.proximo = proximo; 
      } 

      public Pessoa getValor() { 
           return valor; 
      } 

      public void setValor(Pessoa valor) { 
           this.valor = valor; 
      } 
 } 

Crie a classe ListaEncadeada. Esta classe representa a lista encadeada. Note que ela não guarda suas células em nenhum tipo de array ou vetor. As únicas referências que ela tem para suas células são os atributos primeiro e ultimo. A partir deste dois atributos, será realizada as operações na lista. O atributo posicaoAtual é usado para as operações iteração e recuperação do objeto do laço.

 package pkg;  
 public class ListaEncadeada { 
      private Celula primeiro; 
      private Celula ultimo; 
      private Celula posicaoAtual; 
      /** 
       * Adiciona uma pessoa no fim da lista. 
       * @param valor 
       */ 
      public void adicionar(Pessoa valor){ 
           Celula celula = new Celula(); 
           celula.setValor(valor); 
           if(primeiro == null && ultimo == null){ 
                primeiro = celula; 
                ultimo = celula; 
           } else { 
                ultimo.setProximo(celula); 
                ultimo = celula; 
           } 
      } 
      /** 
       * Remove uma pessoa do fim da lista. 
       */ 
      public void remover(){ 
           if(primeiro.getProximo() != null){ 
                Celula celula = this.recuperarPenultimo(this.primeiro); 
                ultimo = celula; 
                celula.setProximo(null); 
           } else { 
                primeiro = ultimo = null; 
           } 
      } 
      /** 
       * Recupera o penultimo elemento da lista 
       * @param celula 
       * @return 
       */ 
      private Celula recuperarPenultimo(Celula celula){ 
           if(celula.getProximo().equals(ultimo)){ 
                return celula; 
           } 
           return recuperarPenultimo(celula.getProximo()); 
      } 
      public boolean temProximo(){ 
           if(primeiro == null){ 
                return false; 
           } else if (posicaoAtual == null){ 
                posicaoAtual = primeiro; 
                return true; 
           } else { 
                boolean temProximo = posicaoAtual.getProximo() != null ? true : false; 
                posicaoAtual = posicaoAtual.getProximo(); 
                return temProximo; 
           } 
      } 
      public Celula getPosicaoAtual(){ 
           return this.posicaoAtual; 
      } 
 } 

Agora, crie a classe Principal. Esta classe contém o método main e a partir dele, chamamos os método da lista.

 package pkg;  
 public class Principal { 
      public static void main(String[] args) { 
           ListaEncadeada listaEncadeada = new ListaEncadeada(); 
           Principal principal = new Principal(); 
           principal.adicionarPessoa(listaEncadeada); 
           principal.remover(listaEncadeada); 
           while(listaEncadeada.temProximo()){ 
                System.out.println(listaEncadeada.getPosicaoAtual().getValor()); 
           } 
      } 
      private void adicionarPessoa(ListaEncadeada listaEncadeada){ 
           Pessoa p1 = new Pessoa(1, "João", "jp@gmail.com"); 
           Pessoa p2 = new Pessoa(2, "Maria", "maria@gmail.com"); 
           Pessoa p3 = new Pessoa(3, "Bruno", "bruno@gmail.com"); 
           Pessoa p4 = new Pessoa(4, "José", "jose@gmail.com"); 
           Pessoa p5 = new Pessoa(5, "Mário", "mario@gmail.com"); 
           Pessoa p6 = new Pessoa(6, "Eduardo", "dudu@gmail.com"); 
           listaEncadeada.adicionar(p1); 
           listaEncadeada.adicionar(p2); 
           listaEncadeada.adicionar(p3); 
           listaEncadeada.adicionar(p4); 
           listaEncadeada.adicionar(p5); 
           listaEncadeada.adicionar(p6); 
      } 
      private void remover(ListaEncadeada listaEncadeada){ 
           listaEncadeada.remover(); 
           listaEncadeada.remover(); 
           listaEncadeada.remover(); 
      } 
 } 

Não entrei muito a fundo nas operações que são possíveis realizar em uma lista encadeada porque, eu ficaria um mês todo escrevendo este post e no fim disponibilizaria uma API muito extensa. O meu intuito com esse post é apenas dar um guia introdutório do assunto visando, dar insumos suficientes para que os leitores possa andar "pelas suas próprias pernas".

Para baixar o projeto completo, clique aqui.

Sugestões ? Críticas ? Elogios ? Deixe aí nos comentários ou na página do facebook.

https://www.facebook.com/precisoestudarsempre/

Referências:
http://www.ime.usp.br/~pf/algoritmos/aulas/lista.html
http://en.wikipedia.org/wiki/Linked_list
http://docs.oracle.com/javase/7/docs/api/java/util/LinkedList.html
Leia Mais ››

quarta-feira, 17 de dezembro de 2014

Entendendo o SMTP

Eu sempre tive bastante dúvida sobre esse assunto. Como funcionam os protocolos de email ? Como a troca de mensagens é realizada ? Na faculdade, esse tema é abordado mas, de uma forma muito superficial logo, isso não me deixou satisfeito.

Então, o post dessa semana será: "Entendendo o SMTP".

Acredito que a melhor fonte de pesquisa para este assunto seja sua RFC (Request for Comment), a RFC 5321.

De acordo com a RFC, para realizar uma transferência de mensagem para um servidor SMTP, um SMTP client estabelece uma canal de transmissão de duas vias para um servidor. Um SMTP client determina o endereço de um determinado servidor SMTP pela resolução de um domínio de destino para um servidor de Mail eXchanger ou um servidor final.

Um servidor SMTP pode ser ou o destino final ou um destino intermediário (pode assumir o papel de um SMTP client após receber a mensagem) ou um gateway (pode transportar a mensagem à frente usando algum protocolo diferente do SMTP). Os comandos SMTP são gerados pelo SMTP Client e enviados ao servidor SMTP. Respostas SMTP são enviadas do servidor para o cliente em resposta aos comandos.


Em outras palavras, transferência de mensagens podem ocorrer em uma única conexão entre o original SMTP-remetente e o final SMTP-destinário, ou podem ocorrer em uma série de pulos através de sistemas intermediários. Em outros casos, uma vez que o servidor publicou uma resposta de sucesso no fim do dado da mensagem, uma transferência de responsabilidade pela mensagem ocorre: o protocolo requer que o servidor deve aceitar a responsabilidade de também entregar mensagem ou reportar apropriadamente a falha da entrega, caso ocorra (veja seções 6.1, 6.2 e 7.8 da RFC).

Uma vez que o canal de transmissão foi estabelecido e o inicial handshaking é feito, o SMTP Client, normalmente, inicia uma transação de mensagem. Tal transação consiste em um série de comandos para especificar o remetente e destinatário da mensagem e transmissão do conteúdo da mesma (incluindo qualquer linha na seção de cabeçalho ou outra estrutura). Quando a mesma mensagem é enviada para vários recipientes, este protocolo encoraja a transmissão de uma única cópia dos dados para todos os recipientes do mesmo servidor de destino (ou servidor retransmissor intermediário).

O servidor responde com uma resposta para cada comando. Respostas podem indicar que o comando foi aceito, que comandos adicionais são esperados, ou que um condição de erro temporário ou permanente existe. Comandos que especifiquem o remetente ou recipientes pode incluir requisições de extensão de serviço SMTP server-permitted (ver seção 2.2 da RFC). O diálogo é propositalmente lock-step (trava e faço), one-at-a-time (um de cada vez), embora isso possa ser modificado por um acordo mútuo a partir de requisições de extensão tais como comandos de pipelining.

Uma vez que dada mensagem foi transmitida, o client pode ou pedir que a conexão seja encerrada ou iniciar outra transação. Mais adiante, um SMTP Client pode usar uma conexão para um servidor SMTP para serviços auxiliares tais como verificação de endereços de email ou recuperação de endereços dos participantes da mailing list.

Como dito acima, este protocolo provê mecanismos para a transmissão de mensagens. Historicamente, esta transmissão normalmente ocorria diretamente do servidor remetente para o servidor destinatário quando os dois estavam conectados ao mesmo serviço de transporte. Quando eles não estão conectados ao mesmo serviço de transporte, a transmissão ocorre via um ou mais servidor de retransmissão SMTP. Um caso muito comum na internet, atualmente, envolve submissão da mensagem original para um intermediário, servidor de submissão de mensagem, o qual é similar a uma retransmissão mas possui algumas propriedades adicionais. Um servidor intermediário que atue como ou um retransmissor SMTP ou como um gateway em alguns ambientes de transmissão é geralmente selecionado através do uso do mecanismo Mail eXchanger DNS.

É isso galera, espero ter trazido este conteúdo da RFC de forma bem clara e explicativa.

Dúvidas, sugestões ou críticas ? Deixe aí embaixo nos comentários ou pelo facebook do Preciso Estudar Sempre.

https://www.facebook.com/precisoestudarsempre/
   

Referência: http://tools.ietf.org/html/rfc5321#page-7
Leia Mais ››

quinta-feira, 4 de dezembro de 2014

Entendendo o SSL

Este assunto sempre me deixou bastante intrigado pois, eu sempre me perguntava o que era aquele https, na barra de endereço do meu browser. Então, decidi criar esse post para que, as pessoas possam ter um entendimento maior sobre esse assunto.

Hoje, nossa "aulinha" será mais teórica. Então, você que está ávido por alguma classe Java ou algum SQL, se acalme por favor. É importante citar que, para que você possa entender o assunto abordado, é de extrema necessidade que você entenda a arquitetura cliente-servidor.

Caso não conheça, clique aqui e leia sobre o assunto.

Na minha incansável procura pelo significado do https, notei que sera sempre levado pelas minhas fontes para textos que abordavam o protocolo de segurança SSL. Então, concluí que, eu precisava primeiro aprender mais sobre o protocolo para assim, entender consequentemente o que significa o tal https.

O SSL, abreviação para Secured Socket Layer, é um protocolo de segurança, conforme dito acima, que permite que aplicativos cliente/servidor possam trocar informações em total segurança, protegendo a integridade e a veracidade do conteúdo que trafega na Internet. Tal segurança só é possível através da autenticação das partes envolvidas na troca de informações.

Seu funcionamento é bastante simples. Quando você abre seu browser, digita algum site na barra de endereço e aperta Enter, uma requisição de acesso é realizada. Essa requisição verifica se existe algum certificado digital. Caso exista, é solicitado o envio deste certificado (tome como idéia este certificado como se fosse um documento de identidade). Após recebido é verificado se o certificado é confiável, válido e se está relacionado com o site que o enviou.

Caso o certificado seja confiável, uma chave pública é enviada pelo browser para o servidor. No momento que esta chave é recebida, o servidor compara a chave pública com sua chave particular. Caso sejam compatíveis, uma comunicação segura é iniciada. Uma mensagem que tenha sido criptografada com uma chave pública somente poderá ser decifrada com a sua chave privada (simétrica) correspondente.

A imagem abaixo foi retirada deste link e exemplifica bem o que estou dizendo. Com ela é possível um total entendimento de como o SSL funciona entre o browser e o servidor.


Agora sabemos o que se trata o nosso https, ele é nada mais, nada menos que uma requisição http segura onde, o s significa secured.

Espero ter ajudado e esclarecido este conceito na mente de vocês.

Sugestões ? Críticas ? Melhorias ? Deixe aí embaixo nos comentários ou comente também na página do facebook.

Preciso Estudar Sempre: https://www.facebook.com/precisoestudarsempre/

Referências:
http://www.techtudo.com.br/artigos/noticia/2012/01/o-que-e-ssl.html
http://www.tecmundo.com.br/seguranca/1896-o-que-e-ssl-.htm
http://www.webopedia.com/TERM/S/SSL.html
Leia Mais ››

domingo, 30 de novembro de 2014

Regex para validar URL

Como você faria para validar uma URL ? Na verdade, você sabe o que é uma URL ? Então para você que não sabe, URL é a sigla para Uniform Resource Locator e consiste em um endereço de um recurso disponível em uma rede.

A estrutura de uma URL é:

esquema://domínio:porta/caminho/recurso?querystring#fragmento

Agora que você já sabe o que é uma URL, voltamos à primeira pergunta: Como você faria para validar uma URL ?

Para responder à essa pergunta, você pode adotar duas abordagens. A primeira é: construir funções gigantescas e a segunda: construir uma regex.

A validação a qual, estou abordando, é de estrutura. Não há nenhuma questão semântica (de significado) por trás. Então, mãos à massa.

Em primeiro lugar, é importante ressaltar que eu não criei esta regex. Peguei ela do livro abaixo.


Este livro não é caro e é muito bom. Recomendo à todos.

Realizei algumas modificações e melhorias na regex. Pus ela para aceitar URLs de ftp e aceitar endereços que comecem sem o esquema. Segue abaixo.

 ((https?:\/\/)|(ftp:\/\/)|(^))([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+([a-zA-Z]{2,9})(:\d{1,4})?([-\w\/#~:.?+=&%@~]*)  

Vamos aplicar a regex no nosso código.

 function validarURL(url){  
      if(/((https?:\/\/)|(ftp:\/\/)|(^))([0-9a-zA-Z][-\w]*[0-9a-zA-Z]\.)+([a-zA-Z]{2,9})(:\d{1,4})?([-\w\/#~:.?+=&%@~]*)/.test(url)){  
           alert('Formato correto !');  
      } else {  
           alert('Formato incorreto !');  
      }  
 }  

Pronto !! Em poucas linhas já possuímos algo funcional. A função acima foi escrita em Javascript.

Dicas ? Sugestões ? Críticas ? Deixe aí nos comentários.

Referência:

http://pt.wikipedia.org/wiki/URL

Leia Mais ››

sexta-feira, 21 de novembro de 2014

Quebra de linha em Java (não é tão banal quanto você pensa)

Saudações leitores !!!

O objetivo deste post será mostrar que não é tão banal executar uma instrução de quebra linha em Java. Então, nesse momento você deve estar pensando:

"Porque ele tá complicando um assunto tão fácil ? É só aplicar um \n caso, queria pular linha e pronto !."

Então, eu respondo: "Não é tão banal assim !!". Existem particularidades que, se não forem consideradas podem causar uma certa dorzinha de cabeça.

Sem mais tardar, vamos começar a por a mão na massa. Pegue um café, acenda seu cigarro e vamos lá.

Existe mais de uma forma de pular linha em Java sem usar o \n. Você pode usar o seguinte comando:

 System.getProperty("line.separator");  

ou, você pode usar o \r ou (char) 13 ou (char) 10.

Agora, acalma-se pois, as explicações irão começar.

Devemos nos lembrar que estamos em um ambiente Windows e isso faz toda a diferença. O comando acima recupera os metacaracteres de quebra de linha do sistema operacional e para cada sistema operacional essa valor muda. Como estamos no Windows, os metacaracteres são o \n e o \r. No Unix é somente o \n e no Mac, somente o \r.

Você ainda deve estar se perguntando para que serve o (char)13 e o (char)10. Isto é nada mais, nada menos que, a invocação desses metacaracteres pelo seu keyCode, ou seja, atingiremos os mesmos resultados se executarmos essas expressões.

 System.out.println("foo" + (char)13 + "foo2");  
 System.out.println("foo" + (char)10 + "foo2");  
 System.out.println("foo" + '\n' + "foo2");  
 System.out.println("foo" + '\r' + "foo2");  
 System.out.println("foo" + System.getProperty("line.separator") + "foo2");  

Resultado esperado

 foo  
 foo2  

Agora que você entendeu o que é cada um, você se pergunta: "Qual devo usar ?"

Para dar uma boa resposta à essa pergunta, devemos nos questionar em qual contexto estamos. Se estivermos em um contexto de um sistema que terá de funcionar em qualquer plataforma, abono as abordagens: \n, \r, (char)10, (char)13; porque não serão soluções que funcionarão em qualquer SO, sobrando assim System.getProperty("line.separator").

Em situações em que sabemos que o sistema funcionará somente em uma plataforma, recomendo a sua própria abordagem de quebra de linha ou o System.getProperty("line.separator"). Porém, como programador, não recomendo você a usar o (char) 13 ou (char)10 para situações "mundanas" pois, você está adicionando complexidade desnecessária ao seu código, visto que existem soluções mais conhecidas por todos os desenvolvedores. Lembre que um dia o código que você escreveu, sofrerá manutenção por outras pessoas. É importante ressaltar também que para outro SO, os keyCodes podem mudar. Logo, você estará engessado em uma plataforma.

Galera, espero ter agregado um conteúdo de alto nível com este post. Se você achou erros, tem sugestões, elogios ou críticas, deixe aí embaixo nos comentários.

Até a próxima.


Leia Mais ››

quinta-feira, 13 de novembro de 2014

Regex para identificar possíveis causas de NullPointerException

 Olá amigos leitores, o objetivo do post de hoje será construir uma regex que possa identificar possíveis causas de NullPointerException em nosso código Java.

Para que você possa entender o que está sendo falado aqui, é de suma importância que você tenha algum conhecimento sobre regex.

Bem, vamos começar !!! Você sabe o que é um NullPointerException ?

NullPointerException é uma exceção da linguagem Java que, denota um acesso à algum conteúdo(atributo ou método) a partir de uma referência (instância) nula.

Vamos ao exemplo.

 public void foo(){  
      MinhaClasse obj = null;  
      obj.foo2();  
 }  

O código acima irá gerar um NullPointerException porque a instância obj é nula. Sendo assim, não será possível executar o método foo2(). Caso você possua dúvidas com a exceção NullPointerException, deixe sua dúvida nos comentários que eu responderei.

Agora, imagine que você está em um projeto onde existem vários programadores trabalhando ao mesmo tempo e você não tem idéia de como analisar ou, impedir que erros de NullPointer aconteçam por erro de escrita de código do desenvolvedor. Logo, você só tem uma única opção, que é: esperar e ver o que irá acontecer quando o programa for executado.

Pensando nisso, desenvolvi uma regex que pode ser usada no search da sua IDE favorita a fim de, identificar trechos de código que podem ser NullPointerException em potencial.

 [^\"\"]\.(equals|equalsIgnoreCase|startsWith|endsWith)\((\".*\")\)  

Vamos às explicações. Primeiro,  temos que ter noção de estamos trabalhando com intervalos abertos logo, não podemos usar o ^ e o $. Agora, vamos destrinchar ela.

[^\"\"] -> Intervalo de caracteres que não quero encontrar. Representa uma operação de complemento. O acento circunflexo é necessário nesta operação porque, ele que representa o complemento.
\. -> Representa o caracter ponto(.) de acesso à métodos. Utilizo a barra (\) pois o ponto (.) tem significado em regex.
(equals|equalsIgnoreCase|startsWith|endsWith) -> Represento a inferência lógica "or" onde, os valores são os métodos que queremos verificar.
\( -> Representa o caracter parênteses (. Utilizo a barra pois, o parênteses possui significado em regex.
(\".*\") -> Representa o qualquer coisa escrita entre aspas. O ponto (.) representa qualquer caracter e o asterisco (*) representa várias ocorrências de algo.
\) -> Representa o caracter parênteses ). Utilizo a barra pois, o parênteses possui significado em regex.

Viu ??? Não é difícil ! Agora é só usar e ser feliz !!! Boa sorte na sua otimização de código.

Dúvidas ? Sugestões ? Melhorias ? Comente aí embaixo.
Leia Mais ››

segunda-feira, 10 de novembro de 2014

Diferença entre NOW(), CURDATE(), CURTIME()

Olá a todos !!!

O objetivo desse post será dizer as diferenças entre as funções NOW(), CURDATE(), CURTIME() do MySQL. Pensei em fazer este post porque ele pode ajudar bastante gente que, precisa operar com datas e horários correntes.

Vamos às explicações !!!

A função NOW() retorna o dia e hora corrente no formato: yyyy-mm-dd hh:mm:ss. Já as funções CURDATE() e CURTIME() retornam, respectivamente, a data e hora corrente, nos respectivos formatos: yyyy-mm-dd e hh:mm:ss.

Pronto !!! Você já sabe o que precisa destas funções. Agora, vamos trabalhar !!!

Exemplos de uso:

1 - Inserção de dados em tabela

 INSERT INTO FUNCIONARIO (ID, NOME, DTA_ADMISSAO) VALUES (1, 'JOAO PAULO', CURDATE());  

 INSERT INTO FUNCIONARIO (ID, NOME, DTA_HORA_ADMISSAO) VALUES (1, 'JOAO PAULO', NOW());  

 INSERT INTO DESPERTADOR (ID, NOME, HR_DESPERTADOR) VALUES (1, 'ACORDAR PARA TRABALHAR', CURTIME());  

2 - Recuperação de dados

 SELECT F.*, CURTIME() AS HORA_INSTRUCAO_SELECT FROM FUNCIONARIO AS F;  

 SELECT F.*, CURDATE() AS DIA_ATUAL FROM FUNCIONARIO AS F;  

Agora, que vocês viram o quanto é fácil usar as funções dentro de uma querys, já podem começar a trabalhar. Lembre-se que também é possível usar as funções em instruções de update.

Dúvidas ? Sugestões ? Críticas ? Elogios ? Deixe nos comentários

Referências:
http://www.w3schools.com/sql/sql_dates.asp
http://www.w3schools.com/sql/func_now.asp

Leia Mais ››

segunda-feira, 3 de novembro de 2014

Subtração de datas em SQL

Caros leitores, a tutorial hoje será rápído pois, o assunto também não é muito extenso. É possível fazer subtração de datas por SQL ? Será que isso sempre tem que ser feito via linguagem de programação ? É difícil ?

Bem, vamos responder as perguntas na mesma ordem que foram feitas. Para a primeira pergunta, a resposta é: sim. Para a segunda pergunta, a resposta é: nem sempre. A resposta é "nem sempre" pois isso depende da vontade do desenvolvedor e do cenário em que ele está. Para a terceira pergunta, a resposta é: não, muito fácil.

Para subtrair as datas, usaremos a função do MySQL chamado DATEDIFF(data1, data2), onde os parâmetros são as datas que usaremos na nossa operação.

Exemplo:

Vamos subtrair 12/07/2014 de 13/09/2011.

 SELECT DATEDIFF('2014-07-12','2011-09-13') AS DATE_DIFF;  



O resultado esperado deve ser algo parecido com isto:


É importante notar algumas coisas:

  • Os parâmetros da função DATEDIFF devem ser datas válidas ou expressões date/time.
  • Caso seja usada expressões date/time, somente a parte referente à data será usada no cálculo.
Esta função é muito simples de usar. O uso dela quem define é você.

Sugestões ? Elogios ? Críticas ? Deixe nos comentários. Espero ter ajudado você que está lendo este post. Deixo abaixo o link que usei como referência.

Leia Mais ››

sexta-feira, 31 de outubro de 2014

Adicionar datas em SQL

Hoje apresentarei uma função SQL que não é muito usada, acredito. Essa função é a date_add(). Ela funciona de forma bem simples. Abaixo, deixo o link da onde eu aprendi essa função.

http://www.w3schools.com/sql/func_dateadd.asp

Agora, vamos ao nosso exemplo.

Crie a tabela PESSOA

 create table PESSOA (id int auto_increment primary key, nome varchar(100), data_nascimento date);  


Com a execução deste comando teremos uma estrutura igual a da tabela abaixo


Agora vamos inserir alguns dados

 insert into PESSOA (nome, data_nascimento) values ('Joao Paulo', '1990-03-28'); 
 insert into PESSOA (nome, data_nascimento) values ('Leonardo Rocha', '199
 2-02-05');
 insert into PESSOA (nome, data_nascimento) values ('Delson Junior', '1950-10-30');
IMPORTANTE: É importante notar que não é necessário incluir a coluna id na query de insert pois, ela é auto incrementável e a data segue o padrão YYYY-MM-DD pois, é esse o padrão do MySQL.

O resultado final deve ser algo desse tipo



Agora vamos a parte mais interessante. Execute a seguinte query.

 SELECT id,nome, DATE_ADD(data_nascimento, INTERVAL 45 DAY ) AS DataAniversario from PESSOA;  


O resultado atingido deve ser este:



IMPORTANTE: O alias DataAniversario é importante porque é o nome dado à coluna de datas de aniversário acrescidas de 45 dias. Sem esse alias a coluna não teria um nome.

A palavra chave DAY é do MySQL. Simboliza que o comando irá adicionar 45 dias à data. Abaixo segue uma listagem com todas as opções possíveis para acréscimo de data.


  • MICROSECOND
  • SECOND
  • MINUTE
  • HOUR
  • DAY
  • WEEK
  • MONTH
  • QUARTER
  • YEAR
  • SECOND_MICROSECOND
  • MINUTE_MICROSECOND
  • MINUTE_SECOND
  • HOUR_MICROSECOND
  • HOUR_SECOND
  • HOUR_MINUTE
  • DAY_MICROSECOND
  • DAY_SECOND
  • DAY_MINUTE
  • DAY_HOUR
  • YEAR_MONTH


Pronto galera, terminamos !! Agora não é mais necessário somar datas na sua linguagem de programação, já é possível fazer query no banco de dados trazendo os resultados prontos.

Dicas ? Críticas ? Sugestão de tema ? Deixa aí embaixo, nos comentários.
Leia Mais ››

segunda-feira, 27 de outubro de 2014

Primeiros passinhos - Reflection em Java

A proposta hoje aqui será mostrar um exemplo básico com reflection. Quem espera encontrar algo super complexo, irá se decepcionar. Como o nome do post já diz "Primeiros passinhos - Reflection em Java" e não "Últimos passos - Domine o Reflection".

É importante ressaltar que para um entendimento pleno do post é necessário que você, caro leitor, tenha conhecimentos básicos de java e OO.

Adianto para os desesperados de plantão que é possível baixar o projeto pronto, clicando aqui.

Vamos começar então !!!

O que é reflection ? Para que serve ? Como uso ?

Todas essas perguntas serão respondidas. Reflection, em português reflexão, consiste na técnica de através de uma representação compilada de sua classe (.class), ter total acesso à ela. Quando digo total acesso, quero dizer que com o .class em mãos, é possível invocar métodos, acessar atributos e annotations, inspecionar classes e interfaces, entre outras coisas e, tudo isso em tempo de execução.

Agora você pensa: "Mas cara, ninguém usa isso !!!!"

Então eu respondo: "Você está enganado, caro leitor. Isto é usado sim e é usado por diversos frameworks. Dentre alguns, posso citar: Hibernate, Struts e Spring MVC"

Nesse momento, você abre os olhos e se pergunta: "Como ????"

Então eu, mais uma vez, respondo: "Quando você usa o Struts ou o Spring MVC e suas tags na JSP, você escreve no atributo name delas algo parecido com isso?

objeto.atributo

É, então meu amigo, não queria te enganar mas, você usa reflection sim e o pior é que você se beneficia dela. Ouso dizer que com a reflection, você atinge o backstage da classe.

Então, agora só falta responder a última pergunta: "Como uso?" Logo, vamos aos nossos exemplos.

1 - Crie a classe Pessoa


1:  package br.com.pkg;  
2:  public class Pessoa {  
3:       private String codigo;  
4:       private String nome;  
5:       private String email;  
6:       public String empresa;  
7:       public String sobrenome;  
8:       public Integer idade;  
9:       public String getNome() {  
10:            return nome;  
11:       }  
12:       public void setNome(String nome) {  
13:            this.nome = nome;  
14:       }  
15:       public String getEmail() {  
16:            return email;  
17:       }  
18:       public void setEmail(String email) {  
19:            this.email = email;  
20:       }  
21:       public String getCodigo() {  
22:            return codigo;  
23:       }  
24:       public void setCodigo(String codigo) {  
25:            this.codigo = codigo;  
26:       }  
27:       public String getSobrenome() {  
28:            return sobrenome;  
29:       }  
30:       public void setSobrenome(String sobrenome) {  
31:            this.sobrenome = sobrenome;  
32:       }  
33:       public String getEmpresa() {  
34:            return empresa;  
35:       }  
36:       public void setEmpresa(String empresa) {  
37:            this.empresa = empresa;  
38:       }  
39:       public void classificar(Integer idade){  
40:            if(idade <= 5){  
41:                 System.out.println("Bebê");  
42:            } else if(idade > 5 && idade <= 11){  
43:                 System.out.println("Criança");  
44:            } else if(idade > 11 && idade <= 14){  
45:                 System.out.println("Pré adolescente");  
46:            } else if(idade > 14 && idade < 18){  
47:                 System.out.println("Adolescente");  
48:            } else if(idade >= 18 ){  
49:                 System.out.println("Adulto");  
50:            }  
51:       }  
52:       public Integer getIdade() {  
53:            return idade;  
54:       }  
55:       public void setIdade(Integer idade) {  
56:            this.idade = idade;  
57:       }  
58:  }  

2 - Crie a classe Principal


1:  package br.com.pkg;  
2:  import java.lang.reflect.Field;  
3:  import java.lang.reflect.InvocationTargetException;  
4:  import java.lang.reflect.Method;  
5:  import java.util.Scanner;  
6:  public class Principal {  
7:       public static void main(String[] args) {  
8:            Principal principal = new Principal();  
9:            Class clazz = Pessoa.class;  
10:            principal.exibirPackage(clazz);  
11:            principal.exibirMetodos(clazz);  
12:            principal.exibirAtributos(clazz);  
13:            Pessoa pessoa = principal.criarPessoa(clazz);  
14:            principal.invocarMetodo(pessoa);  
15:       }  
16:       private void exibirMetodos(Class clazz){  
17:            System.out.println("==== Métodos ====");  
18:            Method[] methods = clazz.getMethods();  
19:            for(Method method : methods){  
20:              System.out.println("Método: " + method.getName());  
21:            }  
22:            System.out.println("\n");  
23:       }  
24:       private void exibirAtributos(Class clazz){  
25:            System.out.println("==== Atributos ====");  
26:            /*só funciona para atributos públicos*/  
27:            Field[] fields = clazz.getFields();  
28:            for(Field f : fields){  
29:                 System.out.println("Atributo: " + f.getName() + " - Tipo: " + f.getType());  
30:            }  
31:            System.out.println("\n");  
32:       }  
33:       private void exibirPackage(Class clazz){  
34:            System.out.println("==== Package ====");  
35:            System.out.println("Package: " + clazz.getPackage().getName() + "\n\n");  
36:       }  
37:       private Pessoa criarPessoa(Class clazz){  
38:            System.out.println("==== Criação de objeto ====");  
39:            Scanner entrada = null;  
40:            Pessoa pessoa = new Pessoa();  
41:            try{  
42:                 entrada = new Scanner(System.in);  
43:                 Field fieldEmpresa= null;  
44:                 Field fieldSobrenome = null;  
45:                 Field fieldIdade = null;  
46:                 try {  
47:                      fieldEmpresa = clazz.getField("empresa");  
48:                      fieldSobrenome = clazz.getField("sobrenome");  
49:                      fieldIdade = clazz.getField("idade");  
50:                 } catch (NoSuchFieldException e) {  
51:                      e.printStackTrace();  
52:                 } catch (SecurityException e) {  
53:                      e.printStackTrace();  
54:                 }  
55:                 System.out.println("Digite o nome da empresa: ");  
56:                 pessoa.setEmpresa(entrada.nextLine());  
57:                 System.out.println("Digite o sobrenome: ");  
58:                 pessoa.setSobrenome(entrada.nextLine());  
59:                 System.out.println("Digite a idade: ");  
60:                 pessoa.setIdade(Integer.valueOf(entrada.nextLine()));  
61:                 try {  
62:                      System.out.println("Exibição dos dados: " + fieldEmpresa.get(pessoa) + ", " + fieldSobrenome.get(pessoa) + ", " + fieldIdade.get(pessoa));  
63:                 } catch (IllegalArgumentException e) {  
64:                      e.printStackTrace();  
65:                 } catch (IllegalAccessException e) {  
66:                      e.printStackTrace();  
67:                 }  
68:            } finally {  
69:                 entrada.close();  
70:            }  
71:            return pessoa;  
72:       }  
73:       private void invocarMetodo(Pessoa pessoa){  
74:            System.out.println("==== Invocação de método ====");  
75:            try {  
76:                 Method metodo = pessoa.getClass().getMethod("classificar", new Class[]{Integer.class});  
77:                 System.out.println("Tipo de retorno do método: " + metodo.getReturnType());  
78:                 System.out.println("Tipo de parâmetros: " + metodo.getParameterTypes());  
79:                 try {  
80:                      metodo.invoke(pessoa, pessoa.getIdade());  
81:                 } catch (IllegalAccessException e) {  
82:                      e.printStackTrace();  
83:                 } catch (IllegalArgumentException e) {  
84:                      e.printStackTrace();  
85:                 } catch (InvocationTargetException e) {  
86:                      e.printStackTrace();  
87:                 }  
88:            } catch (NoSuchMethodException e) {  
89:                 e.printStackTrace();  
90:            } catch (SecurityException e) {  
91:                 e.printStackTrace();  
92:            }  
93:       }  
94:  }  

IMPORTANTE

Acredito que o código está auto-explicativo mas, caso você tenha alguma dúvida, deixe-a nos comentários.

O método getMethods() e o getFields() só recuperam, respectivamente, métodos e atributos públicos. Para acesso a métodos e atributos privados, recomendo que acesse o link abaixo.

http://tutorials.jenkov.com/java-reflection/private-fields-and-methods.html

Também é importante notar que caso o método que se esteja tentando acessar é estático, é necessário passar null como primeiro argumento do método invoke. Isto acontece porque como sabemos recursos estáticos não pertencem a instância e sim a própria classe. Esta regra também é aplicada ao acesso a atributos de estáticos.

Abaixo deixo um site, o qual usei como guia para este post. Recomendo-o pois, o material escrito nele está muito bom.

http://tutorials.jenkov.com/java-reflection/index.html

Dúvidas, sugestões ou assuntos ? Deixe-os aí embaixo.
Leia Mais ››

sexta-feira, 17 de outubro de 2014

Dica de ferramenta

Caros leitores, esse post será uma dica rápida. Fui apresentado à uma ferramenta muito boa para print screen, seu nome é ScreenHunter Free. Essa ferramenta é boa porque é possível disparar os prints com o F6 e salvar automaticamente em um lugar configurável, tornando assim ágil o processo.

Link para download: http://www.baixaki.com.br/download/screenhunter-free.htm

Leia Mais ››

Hello World com Struts 2 - XML

Hoje iremos desmistificar como fazer um projeto simples com struts 2, usando sua abordagem XML. É importante que a pessoa que vá seguir este tutorial já tenha certas noções de Java, Java Web, Maven e Eclipse.

Já presenciei muita gente ficando confusa quando começavam a estudar struts 2, por diversos motivos:
  • A API é diferente se comparada com a do struts 1.
  • Não existe mais struts-config.xml.
  • As taglibs mudaram.
  • Outros milhares de motivos.
Minha proposta nesse post é mostrar o quão é simples o struts 2. Primeiro, devo dar total mérito ao grande mestre Mkyong porque foi de lá que tive a idéia de fazer esse post e inclusive, aprendi lá, a fazer meu primeiro projeto struts 2. Caso você não conheça o site dele, está abaixo.

http://www.mkyong.com/

Eu uso muito o site dele pois, lá existem vários tutoriais e manuais bem escritos e que ajudam muito os desenvolvedores a resolver seus problemas. Recomendo.

Se você é do tipo de pessoa que prefere baixar logo o projeto, segue link: https://www.dropbox.com/s/oppmiq9eyi8geny/workspace_helloworldstruts2.rar?dl=0

Porém, sem mais delongas. Vamos começar.

Passo 1 - Ambiente

Precisaremos dessas ferramentas:

  • Eclipse Luna 4.4.0
  • Apache Tomcat 7.0.54 (clique aqui para baixar)
  • Maven

Precisaremos de um projeto com esta arquitetura.


Caso você não saiba como montar um ambiente assim, recomendo fortemente que você dê uma olhada nesse post: http://precisoestudarsempre.blogspot.com.br/2014/07/como-criar-um-projeto-no-eclipse-com.html

Passo 2 - Dependências

Abra seu pom.xml e ponha a seguinte dependência.

        <dependency>
<groupId>org.apache.struts</groupId>
<artifactId>struts2-core</artifactId>
<version>2.3.1.2</version>
</dependency>

Passo 3 - Configuração

Abra o web.xml e ponha a configuração abaixo.

         <filter>
<filter-name>struts2</filter-name>
<filter-class>
                org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter
                </filter-class>
</filter>

<filter-mapping>
<filter-name>struts2</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>

Nesse momento, você se pergunta: "Porque eu preciso declarar esse filtro ?" Esse filtro é necessário e importante porque ele que é responsável por fazer o dispatching das requisições, ou seja, ele que redireciona a requisição HTTP para sua action correta.

Passo 4 - Mapeamento

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE struts PUBLIC
"-//Apache Software Foundation//DTD Struts Configuration 2.0//EN"
"http://struts.apache.org/dtds/struts-2.0.dtd">

<struts>

<package name="cliente" namespace="/Cliente" extends="struts-default">
<action name="IniciarCadastro">
<result>/WEB-INF/pages/cad-cliente.jsp</result>
</action>
<action name="Cadastrar" class="action.ClienteAction">
<result name="SUCCESS">/WEB-INF/pages/det-cliente.jsp</result>
</action>
</package>

</struts>

A única observação que faço aqui é que os atributos name e namespace são diferentes. O primeiro atributo só representa um nome a fim de, identificar o package. O segundo representa espaço de nomes da requisição, exemplo:

http://localhost:8080/HelloWorldStruts2/Cliente/Cadastrar.action

Passo 5 - Montagem da action

public class ClienteAction {
private Cliente cliente;
 
public String execute() {
cliente.setId(1L);
cliente.setNome(cliente.getNome().toUpperCase());
return "SUCCESS";
}

public Cliente getCliente() {
return cliente;
}

public void setCliente(Cliente cliente) {
this.cliente = cliente;
}
}

Para criar uma action não é necessário estender alguma classe. Basta ter um método execute e pronto. Porém, em alguns exemplos você irá ver alguns desenvolvedores utilizando a classe ActionSupport ou a interface Action. Não se espante !! Essas classes oferecem métodos utilitários para ajudar o desenvolvedor.

Passo 6 - JSP

No nosso projeto existem duas JSPs. A primeira é um formulário de cadastro e a outra somente exibe os dados cadastrados.

Formulário de cadastro
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head></head>
<body>
<h1>Struts 2 Hello World Example</h1>

<s:form action="Cadastrar" >
<s:textfield name="cliente.nome" label="Nome" />
<s:textfield name="cliente.email" label="E-mail" />
<s:textfield name="cliente.dataNascimento" label="Data de Nascimento" />
<s:submit />
</s:form>

</body>

</html>

Reparem que o nome especificado na action é o mesmo que foi definido no struts.xml. A tag <s:textfield> cria um campo de texto, o atributo name representa o objeto que armazenará o dado e o atributo label dispensa explicação. A tag <s:submit> cria um <input type="submit">.

Exibição de dados
<%@ page contentType="text/html; charset=UTF-8"%>
<%@ taglib prefix="s" uri="/struts-tags"%>
<html>
<head></head>
<body>
<h1>Struts 2 Hello World Example</h1>

<h4>
Dados do cliente
</h4>

Id: <s:property value="cliente.id" /><br/>
Nome: <s:property value="cliente.nome" /><br/>
E-mail: <s:property value="cliente.email" /><br/>
Data de Nascimento: <s:date name="cliente.dataNascimento" format="dd/MM/yyyy"/>

<br/>
<br/>
<a href="javascript:history.back()">Voltar</a>
</body>
</html>


A tag <s:property> exibe algo que esteja no request e a tag <s:date> é utilizada para datas. Ela oferece a opções de formatação e exibição.

Acesse: http://localhost:8080/HelloWorldStruts2/Cliente/IniciarCadastro.action

Abaixo, deixo alguns links muito bons para consulta:

Documentação do <s:date> - http://struts.apache.org/release/2.3.x/docs/date.html
Documentação da classe StrutsPrepareAndExecuteFilter - http://struts.apache.org/release/2.1.x/struts2-core/apidocs/org/apache/struts2/dispatcher/ng/filter/StrutsPrepareAndExecuteFilter.html
Struts 2 Hello World Example Mkyong - http://www.mkyong.com/struts2/struts-2-hello-world-example/
Download do projeto pronto: https://www.dropbox.com/s/oppmiq9eyi8geny/workspace_helloworldstruts2.rar?dl=0
Download do Tomcat: https://www.dropbox.com/s/ufln5t05aaqb59d/apache-tomcat-7.0.54.rar?dl=0

Caso eu tenha deixado algum ponto solto ou, cometi algum erro. Deixe sua contribuição nos comentários.
Leia Mais ››

quarta-feira, 15 de outubro de 2014

Tutorial Struts 2 + JasperReports

Caros leitores, foi muito difícil encontrar um tutorial ou manual de Struts 2 + Jasper Reports que fosse rico em detalhes. Encontrei uns tutoriais que explicavam como eu podia fazer mas, não diziam quais eram as versões de libs utilizadas. Isso causou horas e horas de tentativas e erros. Então, para solucionar eu tive que testar as várias combinações de versões de libs mas, enfim cheguei a combinação correta.

Caso você seja aquele tipo de pessoa apressada, disponibilizo aqui o projeto pronto para estudo. Clique aqui para baixar o projeto e, aqui para baixar o tomcat.

Então, sem mais firulas, vamos à lista de ingredientes.

  • Eclipse Luna (4.4.0)
  • Maven
  • Struts 2.3.1.2
  • Jasper Reports 5.1.0
  • Struts2 Jasper Reports plugin 2.3.16.3
  • Javax Servlet 2.5
  • Tomcat 7.0.54
Neste post não irei abordar como confeccionar o jrxml. No projeto já existem um jrxml e um jasper prontos. Logo, não se preocupe.

Mãos à massa !!!

Crie uma action chamada JasperAction e faça essa classe herdar de ActionSupport. Crie um atributo do tipo ArrayList com o nome de myList, crie seus métodos get e set; e um método execute, com essa assinatura.

public String execute() throws Exception {}

O atributo myList representa o datasource do nosso relatório. Datasource é a fonte de dados usada para o relatório. Essa fonte pode ser expressa de algumas formas, dentre as quais temos:uma conexão de banco, uma lista de objetos ou um data source vazio (JREmptyDataSource). No nosso exemplo será uma lista de objetos do tipo Person.

Crie a classe Person. Essa classe possuirá os atributos:
  • id - Long
  • name - String
  • lastName - String
Crie os gets e sets e os seguintes construtores:


    public Person() {
    }
    public Person(String name, String lastName) {
        this.name = name;
        this.lastName = lastName;
    }
    public Person(Long id, String name, String lastName) {
        this.id = id;
        this.name = name;
        this.lastName = lastName;
    }

Agora basta criar objetos do tipo Person e adicioná-los à lista. Feito isso, pronto !! Nossa action já está terminada. Agora você se pergunta:

"Mas, eu sei que no struts 1 eu precisava invocar as classes do Jasper, passando como parâmetro o caminho do jrxml, o datasource e os possíveis parâmetros o qual, é um HashMap. Depois disso, gero um array de bytes e passo isso para o response, defino um content type, um content disposition (habilitar para download), realizo o write, faço o flush e o close do response. Aonde está tudo isso aí !?"

Bem, vamos as respostas. De fato ainda é necessário definir os parâmetros dentro de um HashMap mas, isso foi melhorado. Mas, essa melhora não só afeta a passagem de parâmetros do relatório mas, como afeta toda a forma de se utilizar Jasper Reports com Struts 2. Agora, não é mais necessário executar todos esses passos que eram feitos no Struts 1 basta, eu definir meu datasource e parâmetros. Feito isso, o Struts 2 lida com o resto. Mas, como ele lida ?

Vá ao struts.xml e mapeie sua action desta forma.

<package name="jasper" namespace="/Jasper" extends="jasperreports-default">
   <action name="myJasperTest" class="action.JasperAction">
       <result name="success" type="jasper">
           <param name="location">/WEB-INF/jasper/template.jasper</param>
           <param name="contentDisposition">attachment;filename="arq.pdf"</param>
           <param name="dataSource">myList</param>
           <param name="format">PDF</param>
       </result>
   </action>
</package>

Não irei explicar aqui o que significa as tags <package>, <action>, <result>, <param>. Caso queira maiores explicações, acesse os links abaixo:


Quero que neste momento você note em duas coisas. A primeira é o extends do meu package e a segunda é o type="jasper" do meu result. Tanto o extends quanto o type estão definidos no plugin Struts 2 Jasper Reports. Lá é definido que os parâmetros (<param>) definidos no mapeamento irão para uma classe específica do plugin (JasperReportsResult) e ela irá fazer todo aquele processamento de geração do relatório.

Note a inversão de controle (IoC) acontecendo de forma linda. S2 S2 S2

O parâmetro location simboliza aonde está o arquivo jasper, o parâmetro contentDisposition simboliza como o arquivo será disponibilizado. No nosso caso, será um download. O parâmetro de dataSource é o que foi falado no início do tópico. Porém, repare que o mesmo nome escrito aí, é o mesmo nome do atributo da nossa action. Isto é necessário pois, um "get" será realizado. Por último, temos o parâmetro format que, como o nome já diz é o formato do arquivo.

Agora, é só abrir o browser e acessar essa url.


Gostou ? Não gostou ? Achou coisa errada ? Comente abaixo que iremos resolver juntos.

OBSERVAÇÃO: Caso você tenha alguma curiosidade de saber como o plugin funciona ou ver como funciona a questão do extends e do type, baixe o JAR do plugin, descompacte-o com o WinRar e veja o arquivo struts-plugin.xml.
Leia Mais ››

quinta-feira, 9 de outubro de 2014

Java + FTP - É possível ?

Construir um projeto Java que precise utilizar de um servidor FTP, é possível ? Terei de usar ferramentas externas para ter acesso aos arquivos ? O que é FTP ?

Todas essas perguntas serão respondidas hoje. Vamos começar pelo começo. FTP é a sigla para File Transfer Protocol o qual, é um protocolo da camada de Aplicação do modelo OSI. Como o próprio nome já diz, esse protocolo é usado para transferência de arquivos. Não entrarei a fundo na explicação do FTP. O que você precisa saber para este tópico está escrito neste parágrafo.

Construir um projeto Java que precise utilizar de um servidor FTP, é possível ? Sim, é possível e não somente, é possível como, é fácil também.

Terei de usar ferramentas externas para ter acesso aos arquivos ? Não. Salvo somente os casos em que seja obrigatório usar alguma ferramenta externa ou, seja de vontade do próprio desenvolvedor.

Agora que já sabemos que é possível trabalhar com Java + FTP, vamos ao exemplo.

Primeira etapa - Montar o ambiente

Montar um ambiente Java + FTP é fácil. Precisamos de:

  • Eclipse Luna (4.4.0)
  • Maven (se quiser)
  • Jar Commons Net 3.3 (caso não use Maven)
Caso você não queira usar o Maven, sem problemas. Baixe o JAR do Commons Net, clicando aqui. No nosso exemplo usaremos o Maven. Crie um Maven Project com o archtype quickstart. Caso você possua alguma dúvida com a criação do projeto, nosso amigo Mkyong realizou uma ótima contribuição, através do link.Com o projeto criado, insira a seguinte dependência:

<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.3</version>
</dependency>

Depois de ter inserido a dependência, já podemos começar a programar.

Segunda etapa - Programação

Para habilitar o FTP na sua máquina é necessário realizar algumas configurações no Windows, clique aqui para mais informações. Com seu servidor FTP habilitado e criado, vamos para o Java.

Crie uma classe com o nome de App. Depois de ter criado a classe, vamos criar duas constantes (LOGIN e PASSWORD).

private static final String LOGIN = "meu_usuario";
private static final String PASSWORD = "minha_senha";

Crie um método main e crie um método chamado gerarConexao(). Este método será responsável por gerar a conexão FTP e retornar o objeto que representa o mesmo.

private FTPClient gerarConexao() throws SocketException, IOException{
    FTPClient ftpClient = new FTPClient();
    ftpClient.connect("127.0.0.1"); //Conecta ao Servidor FTP
    ftpClient.login(LOGIN, PASSWORD); //efetua o login no Servidor
    //ftpClient.changeWorkingDirectory("minha_pasta"); //Muda o diretório de trabalho do servidor
    return ftpClient;
}

O código acima é bem tranquilo. Creio que não necessito fazer mais explicações.

Com o nosso método de realizar conexões feito, podemos trabalhar diretamente com os arquivos. Vamos agora, listar todos os arquivos do servidor. Construa o método lerArquivos(FTPClient ftpClient). Este método recebe uma instância de FTPClient o qual, representa nossa conexão.

private void lerArquivos(FTPClient ftpClient) throws IOException{
    FTPFile[] arqs = ftpClient.listFiles(); //lista os arquivos
        System.out.println ("Listando arquivos: \n");
        for (FTPFile f : arqs){
        System.out.println(f.getName() + " - " + f.getType()); //imprimo o nome do arquivo e seu tipo
        }
}

O método acima também é bem tranquilo. Abaixo, listo alguns métodos de listagem de arquivos.
  • listFiles() - Retorna uma lista de Objetos do tipo FTPFile. Para mais informações sobre a classe, clique aqui.
  • listNames(String caminho) – Mesmo que o anterior, mas passando como parâmetro o caminho do diretório a ser listado.
  • listNames() - Retorna um array de Strings contendo o nome dos arquivos no diretório de trabalho atual.
Agora vamos escrever um método para por arquivos no nosso servidor FTP. Escreva o método escreverArquivo(FTPClient ftpClient). Este método recebe uma instância de FTPClient 
qual, representa nossa conexão.

private void escreverArquivo(FTPClient ftpClient) throws IOException{    
    FileInputStream novoArq = new FileInputStream("C:\\minha_pasta\\arquivo_origem.txt");
    if(ftpClient.storeFile("nome_novo_arquivo.txt", novoArq)){
    System.out.println("Arquivo armazenado com sucesso!");
    } else {
    System.out.println("Erro ao armazenar o arquivo.");
    }
}

O método acima cria um novo arquivo no FTP com o nome especificado no primeiro parâmetro do método storeFile. Este método retorna um boolean que, informa se a criação foi feita com sucesso ou não. O parâmetro novoArq representa o arquivo de origem da gravação.

Nosso último método, terá a tarefa de realizar o download de um arquivo que está no FTP. Construa o método recuperarArquivo(FTPClient ftpClient). Este método recebe uma instância de FTPClient o qual, representa nossa conexão.

private void recuperarArquivo(FTPClient ftpClient) throws IOException{
    FileOutputStream fos = new FileOutputStream("C:\\minha_pasta\\arquivo_download.txt");
    if (ftpClient.retrieveFile("arquivo_fonte.txt", fos ))
    System.out.println("Download efetuado com sucesso!");
    else
            System.out.println ("Erro ao efetuar download do arquivo.");
}

Acima, é possível notar que o método retrieveFile recebe dois parâmetros. O primeiro parâmetro representa o nome do arquivo que será feito o download e o segundo representa o destino do arquivo. Este método retorna um boolean que, indica se houve êxito ou não.

Precisamos de um método agora para realizar desconexão do nosso programa com o servidor FTP. Escreva o método logout(FTPClient ftpClient). Este método recebe uma instância de FTPClient o qual, representa nossa conexão.

private void logout(FTPClient ftpClient) throws IOException{
    ftpClient.logout();
    ftpClient.disconnect();
}

Este método dispensa explicações. Por último, temos o método main que chama todos os outros métodos.

public static void main( String[] args ) throws SocketException, IOException 
    {
    App app = new App();
    FTPClient ftpClient = app.gerarConexao();
    app.lerArquivos(ftpClient);
    app.escreverArquivo(ftpClient);
    app.recuperarArquivo(ftpClient);
    app.logout(ftpClient);
    }

Caso você queira baixar o projeto, clique aqui.

É possível notar, que trabalhar com Java e FTP é simples. Procurei por uma abordagem 100% Java mas, não achei. Quem souber, deixe nos comentários sua contribuição. A API Commons Net faz todo o trabalho pesado e para o desenvolvedor só fica a tarefa de processar os arquivos.

Referências:
http://www.devmedia.com.br/desenvolvendo-um-cliente-ftp/3547
Leia Mais ››