Por que eu devo ler este artigo:

Este artigo apresenta uma introdução ao desenvolvimento de aplicações com foco na web. Ao longo do artigo serão apresentadas conceituações técnicas sobre as tecnologias necessárias à criação de uma aplicação, visando descomplicar a vida de quem está entrando neste mercado.

Deste modo, é importante aos desenvolvedores que desejam iniciar o desenvolvimento de soluções voltadas para o ambiente da web. A estes, serão apresentados conceitos, além de uma abordagem prática, do que é utilizado no mercado Java para o segmento web.

O desenvolvimento de aplicações desktop com Java SE (Java Standard Edition) e suas bibliotecas AWT, Swing e Applets se tornou bastante difundido com o aumento no uso da linguagem Java. Isto se deve, dentre outros motivos, à portabilidade das aplicações desenvolvidas, uma das grandes inovações do Java.

Neste cenário de aplicações desktop, imagine uma aplicação que foi criada para o controle de acesso de uma empresa, sendo esta instalada em 200 máquinas. Quando essa aplicação sofrer alguma alteração negocial e precisar ser atualizada, todas as versões instaladas nas máquinas da empresa precisarão passar por uma atualização.

Assim, as dificuldades de manutenção, atualização e distribuição de aplicações desktop, aliadas à necessidade de instalação de uma versão do aplicativo nas máquinas do usuário, motivou a busca por uma melhor forma de distribuir aplicações que fossem acessadas por vários usuários e pudessem estar disponíveis em qualquer lugar.

Seguindo o exemplo anterior, se nossa aplicação estivesse em um ponto centralizado, onde seu acesso fosse distribuído, onde as alterações fossem efetuadas em apenas uma única versão da aplicação, e não houvesse a necessidade de instalação desta aplicação nas máquinas do usuário, teríamos uma melhor disponibilidade de nossa aplicação, assim como um melhor controle sobre suas alterações.

Este ponto centralizado veio com a utilização da plataforma web no desenvolvimento de aplicações.

No desenvolvimento web, o cliente usa um navegador (browser) para acessar a aplicação, necessitando apenas a instalação do navegador em sua máquina. Como a utilização dos navegadores foi difundida com a popularização da Internet, a plataforma web foi beneficiada neste ponto.

Mas o que é essencial para criarmos aplicações web utilizando a linguagem Java? Segundo o Netbeans.org, uma aplicação Java Web gera páginas web interativas, que podem conter vários tipos de linguagens de marcação (HTML, XHTML, XML, entre outras) e conteúdo dinâmico, sendo estas páginas compostas por componentes web como: JavaServer Pages (JSP), servlets e JavaBeans.

Esses componentes são responsáveis pelo armazenamento temporário dos dados que serão transitados a cada requisição/resposta em uma página na web.

Com base em tudo o que falamos até aqui, neste artigo iremos lembrar a trajetória do Java na plataforma web, iniciando com uma breve análise sobre o protocolo HTTP, e falando sobre a importância dos servlets e do JSP no desenvolvimento de aplicações. Depois mostraremos o panorama atual dos principais frameworks de mercado voltados ao desenvolvimento web.

O protocolo HTTP

A comunicação entre navegadores e uma aplicação web é realizada por meio de requisições e respostas definidas pelo protocolo HTTP. Sendo assim, os desenvolvedores de aplicações web devem estar preparados para trabalhar com o protocolo HTTP, conhecendo este a fundo.

O protocolo HTTP permite a clientes e servidores interagir e trocar informações de uma maneira simples e confiável, com a utilização de URIs (Uniform Resource Indentifier) para identificar dados na Internet. Estes identificadores, aliados às localizações dos documentos no servidor, são chamados de URLs (Uniform Resource Locators).

URLs fazem referência a arquivos, diretórios ou objetos situados em um servidor web e que serão acessados a partir de um navegador ou diretamente a partir de outras aplicações.

Como exemplo de URL, temos: //www.devmedia.com.br/revistas, onde:

  • http:// – define o protocolo a ser utilizado para obtenção do recurso;
  • www.devmedia.com.br – define o host, isto é, o nome do computador onde o recurso reside. Este nome é traduzido em um endereço IP, que identifica o servidor na Internet;
  • /revistas – define a localização do recurso no servidor web.

Servlets

Para armazenarmos nossos recursos em um servidor web, utilizamos um contêiner web. Ele será responsável pelo envio e recebimento de requisições HTTP, além de garantir que nossa aplicação seja acessada de forma simultânea por vários usuários, e que todo conteúdo do sistema seja gerado de forma dinâmica. No mercado existem alguns contêineres web famosos, como o Tomcat e o Jetty.

Também existem os servidores de aplicação, que implementam toda ou parte da especificação Java EE (Java Enterprise Edition), como TomEE, JBoss AS, GlassFish, dentre outros.

O contêiner web é responsável por gerenciar o ciclo de vida dos nossos recursos, mapear uma URL para um recurso particular e garantir que o requisitante da URL possua os direitos de acesso corretos a este recurso. Estes recursos Java que possuem o ciclo de vida controlado pelo contêiner web são denominados servlets.

Os servlets foram definidos a partir de uma especificação Java que está atualmente na versão 3.1 e se encontra detalhada na JSR-340. O objetivo dos Servlets era padronizar a interface dos recursos disponibilizados pelo contêiner web. Os servlets utilizam o protocolo HTTP para realizar o processamento dos dados de um formulário HTML e recuperar informações que são transmitidas a partir desse protocolo, fornecendo conteúdo dinâmico, como dados vindos de uma consulta no banco de dados.

Até a especificação 2.5, para a criação de um Servlet o desenvolvedor necessitava criar a sua classe herdando da classe HttpServlet e, além disto, configurá-lo corretamente no arquivo web.xml. Com a versão 3.0, a declaração do Servlet passou a ser feita também através do uso de anotações.

Para criamos um Servlet, precisamos realizar os seguintes passos:

  • Criar uma classe Java;
  • Fazer com que esta classe herde da classe javax.servlet.http.HttpServlet;
  • Reescrever o método service(), de HttpServlet;
  • Utilizar a anotação @WebServlet para definir a URL que será utilizada para acessar este Servlet no contêiner web ou realizar esta configuração diretamente no web.xml.
Listagem 1. Código da classe HelloWorldServlet

      package devmedia;
       
      @WebServlet("/HelloWorld")
      public class HelloWorldServlet extends HttpServlet {
          private static final long serialVersionUID = 1L;
       
          public HelloWorldServlet() 
          {
              super();
          }
        
          protected void service(HttpServletRequest request,  HttpServletResponse response)
            throws ServletException, IOException
          {
               PrintWriter out = response.getWriter();
               out.print("<HTML><H1>Hello World!</H1></HTML>");
               out.close();
        }
      }

Um exemplo de Servlet pode ser visualizado na Listagem 1. Nele, o método service() é executado toda vez que uma requisição HTTP é realizada para a URL definida na anotação @WebServlet.

Esse método recebe dois parâmetros. O primeiro é a referência do objeto de HttpServletRequest que armazena todos os dados da requisição.

O segundo parâmetro é a referência do objeto de HttpServletResponse, que armazenará o conteúdo gerado pelo Servlet. No método service() estamos instanciando a classe PrinterWriter, que será responsável pela escrita do texto que será visualizado no navegador durante a execução do Servlet. Neste exemplo estamos solicitando a escrita da frase “Hello World!”, lembrando que nossa saída contém tags HTML porque esta é a linguagem reconhecida pelo navegador de internet.

Caso não quiséssemos utilizar a anotação @WebServlet, poderíamos configurar nosso Servlet no web.xml como mostrado na Listagem 2.

Listagem 2. Configuração do Servlet no arquivo web.xml
<web-app>
        <servlet>
          <servlet-name>HelloWorldServlet
          </servlet-name>
          <servlet-class>devmedia.HelloWorldServlet
          </servlet-class>
        </servlet>
        <servlet-mapping>
          <servlet-name>HelloWorldServlet
          </servlet-name>
          <url-pattern>/HelloWorld</url-pattern>
        </servlet-mapping>
      </web-app>

Para demonstrar a execução de nosso servlet, iremos utilizar a IDE Eclipse Kepler e o contêiner web Tomcat 7.0. Os endereços para download dessas ferramentas estão na seção Links.

Após o download e instalação das ferramentas, primeiramente iremos adicionar o contêiner web em nossa IDE. Para isto, na aba Servers, clique sobre a opção No servers are available. Click this link to create a new server..., como mostra a Figura 1.

Ao clicar nesta opção será apresentada uma tela para escolha do contêiner web, como podemos visualizar na Figura 2. Depois, clique no botão Next para partirmos para a próxima tela, onde a localização da instalação do contêiner web precisa ser informada (ver Figura 3). Após esta escolha, clique na opção Finish.

Inclusão do contêiner web na IDE Eclipse
Figura 1. Inclusão do contêiner web na IDE Eclipse
Seleção do contêiner web na IDE Eclipse
Figura 2. Seleção do contêiner web na IDE Eclipse
Informação da localização da instalação do contêiner web na IDE Eclipse
Figura 3. Informação da localização da instalação do contêiner web na IDE Eclipse

Com o servidor devidamente instalado em nossa IDE, iremos efetuar a criação de nosso projeto web. Para isto, acesse a opção File > New > Dynamic Web Project, como pode ser visualizado na Figura 4. Para a criação do projeto, precisamos definir o seu nome e escolher o contêiner web onde ele será instalado. Também é preciso verificar a versão da especificação de servlets que usaremos, neste caso a 3.0.

Depois disto, clicamos em Next. Na próxima tela iremos configurar onde nossas classes Java serão armazenadas no projeto. Após isto, clicamos novamente em Next, e por fim marcamos a opção Generate web.xml deployment descriptor para que o arquivo web.xml seja gerado automaticamente pela IDE em nosso projeto, como é mostrado na Figura 5. Após esta marcação, clique na opção Finish. Pronto, nosso projeto está criado.

Criação de projeto Web na IDE Eclipse
Figura 4. Criação de projeto Web na IDE Eclipse
Seleção da geração automática do arquivo
    web.xml
Figura 5. Seleção da geração automática do arquivo web.xml

Com o projeto devidamente criado, vamos dar início ao nosso teste utilizando servlets. Para isto, acesse a opção File > New > Servlet na IDE. Será exibida uma tela para configurarmos o Servlet. Devemos informar então o nome, HelloWorldServlet, e o pacote onde ele ficará, devmedia. Depois, apenas clique em Next, de acordo com a Figura 6.

Tela de criação de um servlet na IDE Eclipse
Figura 6. Tela de criação de um servlet na IDE Eclipse

Na tela seguinte, iremos configurar o mapeamento URL de nosso servlet, ou seja, a URL responsável por acessar o servlet. Assim, na opção URL mappings, devemos clicar na opção Add para adicionarmos o mapeamento URL /HelloWorld e depois clicar no botão Next. Feito isso, devemos selecionar o método service(), que terá como conteúdo as tags HTML que exibirão a mensagem “Hello World” no navegador, e depois clicar no botão Finish.

Com nosso servlet criado, podemos inserir em nossa classe o conteúdo mostrado na Listagem 1.

Com isso estamos prontos para executar o servlet no servidor Tomcat. Para isto, precisamos apenas adicionar o projeto nesse servidor. Fazemos isto clicando sobre o servidor na aba Servers e depois na opção Add and Remove, de acordo com a Figura 7. Será exibida a tela de adição/remoção de projetos. Então, basta clicarmos sobre o nome do nosso projeto e no botão Add para adicioná-lo ao servidor. Após isto clicamos no botão Finish.

Selecionando a opção de Adição/Remoção de projetos no servidor web
Figura 7. Selecionando a opção de Adição/Remoção de projetos no servidor web

Agora basta executarmos o Tomcat para poder visualizar o conteúdo de nossa Servlet diretamente no navegador. Para isto, devemos clicar sobre o servidor, novamente na aba Servers, e na opção Run (veja a Figura 8). Note também, destacado em vermelho, que existe o mesmo ícone para acesso rápido na barra inferior da IDE.

Executando o servidor web
Figura 8. Executando o servidor web

Para acompanharmos a execução de nosso servidor web, acesse a aba Console da IDE. Através desta opção visualizamos as informações de inicialização. O servidor estará pronto quando informar no log a frase: “INFO: Server startup in XXX ms”, onde XXX é o tempo que o servidor levou para terminar seu processo de inicialização.

A partir disso podemos visualizar o conteúdo do nosso servlet diretamente no navegador. Para isto, no navegador, acesse o endereço URL do servlet (http://localhost:8080/devmedia/HelloWorld) conforme demonstra a Figura 9. Ao acessá-lo iremos visualizar o print da frase “Hello World!”, codificado no método service().

Em destaque na Figura 9 temos o botão de acesso ao navegador de internet interno da própria IDE; porém, podemos utilizar qualquer navegador (Internet Explorer, Google Chrome, Firefox, entre outros) para os nossos testes.

Acessando a Servlet no navegador
Figura 9. Acessando a Servlet no navegador
Nota: O endereço localhost:8080 indica o host:porta de nosso servidor, onde o host teria o nome de localhost por ser uma execução local, e a porta seria 8080 por ser a porta padrão HTTP do servidor Tomcat.

Assim, temos nossa primeira página com conteúdo dinâmico utilizando servlets em Java.

Os servlets são poderosos no que fazem, mas o elevado grau de dificuldade de se relacionar com o protocolo HTTP, já que temos que trabalhar diretamente com o controle das requisições e o envio das respostas, fez com que novas soluções fossem pensadas para aumentar a produtividade de desenvolvimento para o ambiente web.

Além disto, o fato de misturarmos HTML com código Java torna as classes volumosas, deixando o código muito verboso e com a clara necessidade de separação dessas duas linguagens em lugares distintos, porém de uma forma que consigam interagir entre si. A solução foi a criação das JSPs.

JavaServer Pages

A tecnologia JSP, acrônimo de JavaServer Pages, é uma linguagem de script baseada em uma especificação Java, a JSR-245, que está atualmente na versão 2.1 e é utilizada para criação de páginas com conteúdo dinâmico.

O uso de páginas JSP fez com que o conteúdo HTML, antes contido em servlets, ficasse em um arquivo separado, com a extensão .jsp.

Além do conteúdo HTML é possível a utilização de scriptlets nas páginas JSP. Os scriptlets são códigos escritos dentro dos delimitadores <% e %> que servem para embutir nessas páginas trechos de código Java puro, como demonstra a Listagem 3.

Listagem 3. Página JSP utilizando scriptlets
<html>
        <body>
          <% 
            String mensagem = "Boas Vindas!";
            out.println(mensagem);
         %>
        </body>    
      </html>

O uso de scriptlets nas páginas JSP fez com que os códigos que antes ficavam apenas nas classes Java fossem colocados em arquivos JSP, incluindo a realização dos imports das classes Java utilizadas. Assim, para fazer uma listagem, por exemplo, o trecho de código Java se mistura ao código HTML, de modo semelhante ao mostrado na Listagem 4, fazendo com que a manutenção deste tipo de código se torne um pouco mais difícil do que se o código estivesse isolado apenas na classe Java. Esta complexidade de manutenção faz com que os scriptlets sejam considerados uma má prática de programação.

Listagem 4. Página JSP efetuando a listagem de usuários
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
          pageEncoding="ISO-8859-1"%>
      <%@ page import="java.util.*, devmedia.dao.UsuarioDao, devmedia.entity.Usuario" %>
      <html>
        <head>
         <title>Usuários do Sistema</title>
        </head>
        <body>
         <h1>Lista de Usuários do Sistema</h1>
         <table border="1">
      <%
      UsuarioDao dao = new UsuarioDao();
      List<Usuario> usuarios = dao.getLista();
       
      for (Usuario usuario : usuarios ) {
      %>
        <tr>
         <td> <%=usuario.getNome()%> </td>
          <td> <%=usuario.getEndereco()%> </td>
        </tr>
      <%
      }
      %>
      </table>
        </body>    
      </html>

Expression Language

Visando diminuir a quantidade de código Java presente nas páginas JSP, surgiram as Expression Language (EL). Estas facilitam o acesso aos dados armazenados em componentes JavaBeans, sendo possível, com a sua utilização, acessar o valor destes componentes em páginas JSP.

As ELs permitem a criação de expressões aritméticas e lógicas. Dentro de uma expressão EL você pode usar inteiros, números de ponto flutuante, strings, constantes de verdadeiro e falso para valores booleanos, e nulos. Na Listagem 5 temos um exemplo de uso de Expression Language, que deve ser sempre declarada com o pattern ${}. Dito isto, devemos informar dentro deste pattern o valor a ser verificado. Nesse caso, temos ${4 > 3}, que como resultado terá o valor true.

Listagem 5. Exemplo Expression Language (EL)
<c:if test="${4 > 3}" >
       <h1> Item executado com sucesso! </h1>
      </c:if>

Para acessar atributos de um objeto JavaBean usamos a seguinte sintaxe: ${bean.propriedade}, onde bean representa o JavaBean a ser acessado e propriedade o atributo. Ao utilizar esta sintaxe, o método get da propriedade do JavaBean é invocado.

Vejamos outro exemplo: suponha a existência do bean Usuario com a propriedade Endereco, que também é um Bean. Se desejarmos exibir a propriedade Bairro do Bean Endereco, devemos utilizar a seguinte sintaxe: ${usuario.endereco.bairro}.

Podemos também acessar coleções como Arrays, Lists e Maps diretamente em nossas JSPs. Para isto, considerando um ArrayList como variável de escopo, este seria acessado com a seguinte sintaxe: ${arrayList[posiçãoDaEntrada]}, onde com um ArrayList para representar as Cidades, usaríamos a sintaxe: ${cidades[1]}, ou no caso de uma HashMap para representar os Estados, teríamos ${estados[“DF”]}.

STL: Java Standard Tag Library

A JSTL, acrônimo de JavaServer Pages Standard Tag Library, é uma biblioteca padrão de tags que encapsula funcionalidades comuns a muitas aplicações JSP. Ela tem como objetivo a padronização das tags de modo a permitir a implantação de aplicativos em qualquer contêiner web, otimizando sua utilização. As bibliotecas da JSTL também são denominadas taglibs<< /span>.

A JSTL possui em seu conjunto de tags:

  • Tags de iteração e condicionais (visando o controle do fluxo nas páginas JSP) que são representadas pela biblioteca Core;
  • Tags para manipulação de documentos XML que são representadas pela biblioteca XML;
  • Tags de internacionalização que são representadas pela biblioteca FTM;
  • Tags para acesso a banco de dados usando SQL que são representadas pela biblioteca SQL>;
  • Funções de uso comum que são representadas pela biblioteca Functions.

Um exemplo de tag é a <c:if>, mostrada na Listagem 5, que faz parte da biblioteca Core. Por representarem um padrão, as taglibs no JSP são recomendadas como boa prática de programação.

Para seu uso, precisamos apenas baixar os arquivos .jar da JSTL API e JSTL Implementation, cujo endereço para download se encontra na seção Links, e adicioná-los à pasta lib da nossa aplicação. Para usarmos as taglibs em uma página JSP, devemos inserir um cabeçalho, como mostrado na Listagem 6, para importarmos a biblioteca, sempre apontando para a URI que é responsável por identificar a biblioteca no pacote que foi baixado.

Agora podemos utilizar os componentes da biblioteca Core, a partir do prefixo c, em nossa JSP, como demonstra a Listagem 7. Nesta listagem temos um código com JSTL que exibirá a mesma tabela criada na Listagem 4.

Listagem 6. Exemplo de importação da biblioteca Core
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
Listagem 7. Exemplo de utilização da biblioteca JSTL na página JSP listaUsuarios.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
          pageEncoding="ISO-8859-1"%>
      <%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
      <html>
        <head>
         <title>Usuários do Sistema</title>
        </head>
        <body>
         <jsp:useBean id="dao" class="devmedia.dao.UsuarioDAO"/>
         <h1> Lista de Usuários do Sistema</h1>
      <table border="1">
        <c:forEach var="usuario" items="${dao.lista}">
          <tr>
            <td>${usuario.nome}</td>
         <td>${usuario.endereco}</td>
          </tr>
        </c:forEach>
      </table>
        </body>    
      </html>
    

Note que empregamos na Listagem 7 a tag <c:forEach>. Esta efetua a iteração em uma lista de itens que é representada pelo conteúdo do atributo lista da classe UsuarioDAO. Esta lista será acessada a partir do método getLista() da classe UsuarioDAO, que pode ser visualizada na Listagem 8.

O método getLista() nos retornará uma lista de objetos do tipo Usuario>, classe esta que é mostrada na Listagem 9. Na Listagem 7 também utilizamos a tag <jsp:useBean>, sendo responsável por instanciar a classe UsuarioDAO. Em nossa página JSP esta instância será acessada a partir da variável dao. Em resumo, na tag <c:forEach>, quando chamamos items=“${dao.lista}”<< /span>, o atributo lista está fazendo referência ao método getLista() da classe UsuarioDAO.

Listagem 8. Código da classe UsuarioDao
package devmedia.dao;
       
      import java.util.ArrayList;
      import java.util.List;
       
      import devmedia.entity.Usuario;
       
      public class UsuarioDao {
       private List<Usuario> lista;
       
       public List<Usuario> getLista() {
        return lista;
       }
       
       public UsuarioDao() {
        lista = new ArrayList<Usuario>();
        criaListaEmMemoria(lista);
       }
       
       private void criaListaEmMemoria(List<Usuario> lista) {
        lista.add(new Usuario("Fernando", "Rua sem esquina, n. 1"));
        lista.add(new Usuario("Beatriz", "Rua com esquina, n. 4"));
       }
      }
Listagem 9. Código da classe Usuario
package devmedia.entity;
       
      public class Usuario {
       
       private String nome;
       
       private String endereco;
       
       public Usuario(String nome, String endereco) {
        this.nome = nome;
        this.endereco = endereco;
       }
       
       public String getNome() {
        return nome;
       }
       
       public void setNome(String nome) {
        this.nome = nome;
       }
       
       public String getEndereco() {
        return endereco;
       }
       
       public void setEndereco(String endereco) {
        this.endereco = endereco;
       }
      }

Ao inicializarmos o servidor e chamarmos nossa página JSP pelo endereço http://localhost:8080/devmedia/listaUsuarios.jsp, iremos visualizar nossa listagem de usuários, criada com a utilização das taglibs da JSTL em nossa página JSP, como mostra a Figura 10.

Acessando a página listaUsuarios.jsp
Figura 10. Acessando a página listaUsuarios.jsp

Com o uso da JSTL em páginas JSP, também é possível a criação de tags próprias utilizando arquivos tagfiles. Estes permitem ao desenvolvedor criar tags personalizadas, para uso em suas aplicações, evitando assim repetições de código nas páginas JSP.

JSP ou Servlets?

Como vimos, podemos utilizar servlets para trabalharmos sobre o protocolo HTTP, interceptando suas requisições, exibindo conteúdo HTML de nossa escolha e enviando-o como resposta ao navegador do usuário, assim como podemos utilizar páginas JSP para trabalharmos com conteúdo dinâmico, acessando nossas classes Java para exibirmos listagens vindas diretamente do banco de dados, por exemplo.

Mas a pergunta que não quer calar é: Seria melhor utilizarmos servlets ou JSP em nossas aplicações? Para responder essa pergunta, vamos analisar os pontos de cada uma das tecnologias. Com servlets, temos o controle do protocolo HTTP. Assim, controlamos nossas requisições e respostas, além de podermos implementar alguma regra pertinente ao negócio e realizarmos acessos ao banco de dados da aplicação, sendo possível escrevermos o código de saída que será apresentado ao usuário, tudo em uma mesma classe.

Com JSP, temos a construção de páginas nas quais podemos utilizar trechos de código Java, ou tags da biblioteca JSTL, para apresentar conteúdo dinâmico ao usuário, acessando assim classes Java, que podem trazer listagens vindas do banco de dados, por exemplo, mas ficamos desamparados na implementação das regras de negócio, visto que o foco do JSP, por ser uma linguagem de script, é a apresentação de conteúdo.

Percebemos então que os servlets possuem o foco na camada de negócio da aplicação, enquanto as JSPs possuem foco na camada de apresentação. Deste modo, temos que nossa melhor resposta está na utilização de ambos, servlets e JSP, empregando o melhor de cada tecnologia.

MVC – Model, View e Controller

Como vimos, podemos utilizar servlets em conjunto com JSPs para termos sistemas dinâmicos, onde os servlets trabalham no controle do que será recebido e enviado como resposta às requisições advindas do navegador, e as JSPs atuam na exibição do conteúdo no navegador do usuário.

Com isto, temos nos servlets o papel de controlador, atuando na camada de Controle do padrão MVC, recebendo as requisições do HTTP, orquestrando as interações entre o negócio, nossas entidades e o banco de dados, devolvendo uma resposta que será exibida por nossas JSPs.

Por sua vez, temos nas JSPs a representação da camada de Visão, ou Apresentação, que renderizará o que nosso usuário irá visualizar. Nossas entidades, que representam o domínio de nossa aplicação, estarão na camada de Modelo, e serão responsáveis pelas regras de negócio, lógica e funções, como pode ser visto na Figura 11.

Arquitetura MVC em aplicações Web
Figura 11. Arquitetura MVC em aplicações Web

Para demonstrar o que acabamos de analisar, iremos criar uma aplicação web dinâmica e que utilize a arquitetura MVC. Para isto, vamos colocar a mão na massa e criar um cadastro de usuários. Iniciaremos com a criação de nossa página JSP, cujo código é mostrado na Listagem 10. Nesta página temos os campos de um formulário para a captura dos dados dos usuários que serão informados pelo usuário do sistema.

Para controle das requisições de cadastramento dos usuários da aplicação, vamos implementar o servlet CadastraUsuarioServlet, que pode ser visualizado na Listagem 11. Também usaremos a classe Usuario, já mostrada na Listagem 9, como a entidade que desejamos armazenar em nosso banco de dados.

Listagem 10. Código da página cadastraUsuario.jsp
<%@ page language="java" contentType="text/html; charset=ISO-8859-1"
          pageEncoding="ISO-8859-1"%>
      <html>
        <head>
         <title>Cadastro de Usuários</title>
        </head>
        <body>
         <form action="cadastraUsuario">
           <h1>Cadastro de Usuários no Sistema</h1>
        <table>
            <tr>
             <td>Nome:</td>
              <td><input name="nome"></td>
            </tr>
           <tr>
             <td>Endereço:</td>
           <td><input name="endereco"></td>
           </tr>
           <tr>
            <td>
                <input type="submit" value="Salvar">
            </td>
           </tr>
         </table>
      </form>
        </body>    
      </html>
Listagem 11. Código do servlet CadastraUsuarioServlet

package devmedia;
       
      import java.io.IOException;
      import javax.servlet.RequestDispatcher;
      import javax.servlet.ServletException;
      import javax.servlet.annotation.WebServlet;
      import javax.servlet.http.HttpServlet;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import devmedia.dao.AbstractDAO;
      import devmedia.dao.UsuarioDAO;
      import devmedia.entity.Usuario;
       
      @WebServlet("/cadastraUsuario")
      public class CadastraUsuarioServlet extends HttpServlet {
       private static final long serialVersionUID = 1L;
       
       AbstractDAO<Usuario> dao;
          
          public CadastraUsuarioServlet() {
              super();
              dao = new UsuarioDAO();
          }
       
       protected void service(HttpServletRequest request, HttpServletResponse response) 
         throws ServletException, IOException {
        
        Usuario usuario = new Usuario((String) request.getParameter("nome"),
                 (String) request.getParameter("endereco"));
        dao.adicionar(usuario);
        RequestDispatcher rd = request.getRequestDispatcher("/sucesso.jsp");
        rd.forward(request,response);
       }
      }

Em nossa classe CadastraUsuarioServlet teremos toda a interação com o protocolo HTTP, onde recuperaremos os parâmetros nome e endereço que são informados pelo usuário em nossa página JSP e criaremos uma instância da entidade Usuario com estas informações. Esta instância será repassada à nossa classe responsável pela persistência dos dados no banco de dados.

Após a gravação das informações do usuário, utilizaremos a classe RequestDipatcher para redirecionarmos o usuário para uma página de sucesso na gravação dos dados. O código desta pode ser visualizado na Listagem 12.

Listagem 12. Código da página sucesso.jsp

      <%@ page language="java" contentType="text/html; charset=ISO-8859-1"
          pageEncoding="ISO-8859-1"%>
      <html>
        <head>
          <title>Sucesso</title>
        </head>
        <body>
          <h1>Usuário cadastrado com sucesso.</h1>
        </body>
      </html>

Como banco de dados, adotaremos a versão 5.0.45 do MySQL. Sendo assim, ele deve ser baixado e instalado, estando seu endereço para download e alguns materiais para referência na seção Links, em caso de dúvidas. Para conexão com o banco de dados, iremos utilizar a API JDBC. Esta contém classes para envio de instruções SQL ao banco de dados.

Para finalizarmos, devemos baixar também o driver de conexão do banco de dados, cujo endereço se encontra na seção Links. Este é um arquivo JAR e deve ser acrescentado à pasta lib da aplicação.

No MySQL, criaremos um banco de dados denominado devmedia e uma tabela de nome usuário, de acordo com a Listagens 13.

Listagem 13. Script de criação do banco de dados devmedia e da tabela usuario
CREATE DATABASE devmedia; 
      CREATE TABLE usuario(id BIGINT NOT NULL AUTO_INCREMENT, 
      nome VARCHAR(255), endereco VARCHAR(255),  primary key (id)); 

Para auxiliar a criação de nossas conexões com o banco de dados, implementaremos a classe FabricaConexao, mostrada na Listagem 14. Esta será responsável por fabricar conexões com o banco de dados para realizarmos acessos aos dados. Nesta classe temos que efetuar algumas configurações, de acordo com a instalação do MySQL.

Sendo assim, para o atributo urlConexaoBD, informe o endereço da base de dados; neste caso, “jdbc:mysql://localhost:3306/devmedia ”. Para o atributo usuario, deve ser informado o usuário de acesso à base de dados, e no atributo senha, a senha cadastrada no momento da instalação. Nossa classe FabricaConexao faz uso da classe DriverManager para obter uma conexão com o banco de dados.

A classe DriverManager é responsável pela comunicação do driver com o banco de dados, e a partir do método getConexao() da classe FabricaConexao iremos utilizar o método getConnection() da classe DriverManager. Este método tentará localizar um driver adequado dentre aqueles carregados na inicialização da aplicação para realizar a conexão com o banco de dados.

Para obtermos uma instância da classe FabricaConexao, invocamos o método estático getInstance(), já que deixamos o construtor desta classe privado para controlar a criação de novas instâncias dela, de maneira à sempre verificar se já existe uma instância dessa classe para retorná-la ou se é preciso criar uma nova.

Listagem 14. Código da classe FabricaConexao
package devmedia.dao;
       
      import java.sql.Connection;
      import java.sql.DriverManager;
      import java.sql.SQLException;
       
      public class FabricaConexao {
            String driverConexaoBD = "com.mysql.jdbc.Driver";
            String urlConexaoBD = "jdbc:mysql://localhost:3306/devmedia";
            String usuario = "root";
            String senha = "";
       
            private static FabricaConexao fabricaConexao = null;
       
            private FabricaConexao() {
                  try {
                         Class.forName(driverConexaoBD);
                  } catch (ClassNotFoundException e) {
                         throw new RuntimeException(e);
                  }
            }
       
            public Connection getConexao() throws SQLException {
                  Connection conn = null;
                  conn = DriverManager.getConnection(urlConexaoBD, usuario, senha);
                  return conn;
            }
       
            public static FabricaConexao getInstance() {
                  if (fabricaConexao == null) {
                         fabricaConexao = new FabricaConexao();
                  }
                  return fabricaConexao;
            }
      }

Para acesso aos dados, implementaremos as classes AbstractDAO, que conterá o que for comum a todos os DAOs da aplicação (veja o código na Listagem 15), e a classe UsuarioDAO, que herdará da classe AbstractDAO e ficará responsável pelos acessos às informações da entidade Usuario (veja o código na Listagem 16).

Nota: DAO, acrônimo de Data Access Object, é um padrão de projeto responsável pelo acesso aos dados, sendo encarregado de abstrair e encapsular os detalhes de obtenção das informações armazenadas pela aplicação, seja em memória ou em um banco de dados.

Na classe AbstractDAO iremos obter uma conexão que será utilizada em sua filha, a classe UsuarioDAO. AbstractDAO também definirá os métodos adicionar(T objeto) e getLista(), onde utilizando Generics podemos abstrair o objeto que será adicionado ou listado, de acordo com a entidade com a qual estamos lidando. Em nosso exemplo, UsuarioDAO está representando o acesso aos dados da entidade Usuario.

Listagem 15. Código da classe AbstractDAO
package devmedia.dao;
       
      import java.sql.Connection;
      import java.sql.SQLException;
       
      public abstract class AbstractDAO<T> {
            
            protected Connection conn;
       
            public AbstractDAO() {
                  try {
                         conn = FabricaConexao.getInstance().getConexao();
                  } catch (SQLException e) {
                         throw new RuntimeException(e);
                  }
            }
            
      public abstract List<T> getLista();     
            
      public abstract void adicionar(T objeto);
      }

Na classe UsuarioDAO vamos implementar os métodos abstratos da classe pai AbstractDAO. Deste modo, no método getLista() iremos, a partir da conexão criada por FabricaConexao, criar uma instância da classe PreparedStatement, um recurso do JDBC usado para executar as instruções de banco de dados com alta eficiência. Também utilizaremos uma instância de ResultSet para armazenarmos o resultado da execução de nossa consulta.

A partir desse ResultSet recuperaremos as informações vindas do banco e alimentaremos cada uma de nossas entidades Usuario, que estarão contidas na lista que será retornada por esse método.

Já no método adicionar(), empregamos a classe PreparedStatement para inserir as informações da entidade Usuario no banco de dados.

Listagem 16. Código da classe UsuarioDAO
package devmedia.dao;
       
      import java.sql.PreparedStatement;
      import java.sql.ResultSet;
      import java.sql.SQLException;
      import java.util.ArrayList;
      import java.util.List;
      import devmedia.entity.Usuario;
       
      public class UsuarioDAO extends AbstractDAO<Usuario>{
            private List<Usuario> lista;
            
            public UsuarioDAO() {
                  super();
                  lista = new ArrayList<Usuario>();
            }
            
            public List<Usuario> getLista() {
                  try {
                         PreparedStatement ptmt = conn.prepareStatement
                           ("select * from usuario");
                         ResultSet rs = ptmt.executeQuery();
                         while(rs.next()){
      Usuario usuario = new Usuario(rs.getString("nome"), 
      rs.getString("endereco"));
                                lista.add(usuario);
                         }
                         rs.close();
                         ptmt.close();
                  } catch (SQLException e) {
                         throw new RuntimeException(e);
                  }
                  return lista;
            }
       
            public void adicionar(Usuario usuario) {
                  try {
                         PreparedStatement ptmt = conn.prepareStatement
                           ("insert into usuario(nome, 
                            endereco) values (?, ?)");
                         ptmt.setString(1, usuario.getNome());
                         ptmt.setString(2, usuario.getEndereco());
                         ptmt.executeUpdate();
                         ptmt.close();
                  } catch (SQLException e) {
                         throw new RuntimeException(e);
                  }
            }
       
      }

Observando nosso exemplo, podemos destacar cada uma das camadas da arquitetura MVC nas classes criadas. Temos a apresentação dos resultados, ou seja, a View de nossa aplicação, em nossas páginas JSP. Já no servlet CadastraUsuarioServlet, que é responsável por efetuar o controle da requisição recebida da camada de apresentação, efetuar o processamento necessário e enviar uma resposta à camada de apresentação, temos o nosso Controller.

E por fim, mas não menos importante, temos a classe Usuario, que representa nossa entidade. Na arquitetura MVC, esta classe atuaria na camada Model, e em conjunto com as demais entidades do sistema, seria responsável pelo modelo de domínio da aplicação.

Por facilitar o uso do padrão arquitetural MVC e também por abstrair as interações com o protocolo HTTP, alguns frameworks ficaram famosos.

Entre os frameworks voltados para a camada de Controle, que têm como objetivo descomplicar a criação de objetos para esta camada, temos os baseados em Ações (Action-Based) e os baseados em Componentes (Component-Based). Entre eles, podemos destacar:

Action-Based:

  • Struts;
  • SpringMVC.

Component-Based:

  • JSF;
  • Apache Wicket;
  • Apache Tapestry.

Além destes, temos também os frameworks voltados para a camada de Modelo e para a camada de Visão, dos quais, citam-se:

Camada de Modelo:

  • Hibernate/JPA;
  • EclipseLink/JPA.

Camada de Visão:

  • JSP;
  • Facelets;
  • Velocity.

Struts

Quando os servlets foram criados, logo foi percebido que eles eram uma ferramenta rápida e poderosa para o desenvolvimento de aplicações web, já que eram extensíveis, e logo seu uso tornou-se difundido em aplicações JSP.

Ao longo da utilização dos servlets, percebeu-se que as implementações que empregavam o padrão MVC eram muito próximas umas das outras, e muito código era genérico, ou seja, o mesmo código era utilizado por diversas aplicações, independente das funcionalidades destas aplicações.

Devido a essas semelhanças surgiram alguns frameworks visando reaproveitar esses códigos genéricos, criando assim implementações reaproveitáveis seguindo o padrão MVC. Dentre eles, o de maior destaque foi o Apache Struts, um dos primeiros frameworks para a camada de Controller na plataforma Java.

O projeto Struts foi criado em maio de 2000, por Craig R. McClanahan, para fornecer um framework MVC padrão para o desenvolvimento de aplicações web em Java, e em julho de 2001, a primeira versão, o Struts 1.0, foi lançado oficialmente.

O Struts contava com a separação provida pela arquitetura MVC, além de validações de dados dos formulários, internacionalização e integração com outras tecnologias adotadas pelo mercado, o que viabilizava maior produtividade na implementação.

À época o Struts foi considerado um grande avanço para a comunidade Java, tanto que sua adoção nos projetos, principalmente no mercado de grandes empresas, foi alta, sendo sua primeira versão utilizada até hoje.

Arquitetura do framework Struts em aplicações Web
Figura 12. Arquitetura do framework Struts em aplicações Web

A arquitetura do framework Struts se baseia no MVC, sendo que representando a camada Controller temos um servlet chamado de ActionServlet. Este atua como o controlador que recepciona todas as requisições advindas do navegador, encaminhando estas requisições de acordo com as configurações XML efetuadas no arquivo struts-config.xml.

Temos também a classe Java denominada Action, que é baseada em ações a serem executadas junto aos objetos de negócio, como podemos visualizar na Figura 12.

Com a alta utilização, as deficiências do Struts foram aparecendo. Dentre elas podemos destacar as excessivas configurações em XML que precisavam ser realizadas, fazendo com que simples alterações gerassem grandes impactos na aplicação, além do grande uso de herança das classes do framework Struts, o que gerava um alto acoplamento.

Dessa forma, na busca por alternativas a estes problemas, os desenvolvedores do Struts implementaram uma nova versão, baseada no projeto WebWork, um framework concorrente que possuía ideias que iam de encontro com as alternativas de melhoria do framework Struts.

Assim, em 2005 surgiu a segunda versão do framework, o Struts 2, que é continuado até hoje. No entanto, esta versão não obteve o mesmo sucesso da primeira, e não foi adotado em larga escala pelas empresas, já que existiam mais opções no mercado, além de já ter sido lançada uma especificação Java baseada no uso de componentes web, o JSF.

Dentre as melhorias adotadas no Struts 2 podemos destacar:

  • Uso de convenções ao invés de configurações. Assim, os nomes das classes passaram a indicar as ações que estas representavam – por exemplo, a classe CadastrarUsuarioAction indica a ação de Cadastrar – e os valores dos resultados retornados passaram a indicar os nomes das páginas JSP a serem renderizadas;
  • Uso de anotação ao invés de configuração XML, aumentando a produtividade e mantendo as configurações mais visíveis e fáceis de serem assimiladas;
  • Conversão de valores dos campos de formulários baseados em String em objetos ou tipos primitivos, removendo a necessidade de prover este código de infraestrutura na classe da ação;
  • Suporte a injeção de dependências, reduzindo assim o acoplamento entre as camadas do aplicativo, tornando-o muito mais simples e fácil de testar;
  • Integração com plug-ins disponibilizados por terceiros, necessitando que o framework venha apenas com as funcionalidades básicas.

Spring MVC

O framework Spring foi criado por Rod Johnson baseado em padrões de Inversão de Controle e Injeção de Dependência, não tendo foco no desenvolvimento web. Ele é composto pelos módulos mostrados na Figura 13.

Spring Framework e seus módulos
Figura 13. Spring Framework e seus módulos

No módulo Spring Core temos as principais funcionalidades do Spring. A classe BeanFactory deste se destaca como o elemento chave. Esta classe é uma implementação do padrão Factory e é responsável por diminuir o acoplamento entre a configuração e a lógica de programação da aplicação.

No módulo Spring DAO temos uma camada de abstração para o padrão JDBC. Esta abstração diminui grande parte da codificação necessária para interagir com bancos de dados. No módulo ORM temos a integração do Spring com outros frameworks para persistência de objetos, como Hibernate e iBatis. Já no módulo Spring AOP temos uma implementação de Orientação a Aspectos que permite a definição de pointcuts e method interceptors.

O módulo Spring Web, por sua vez, provê funcionalidades específicas para projetos web, como componentes para upload de arquivos e suporte à utilização de Inversão de Controle. Enquanto isso, o módulo Spring MVC fornece uma implementação de framework web baseada em ações e similar ao Struts, sendo criada para atender a demanda de desenvolvimento web a partir da arquitetura MVC, trabalhando em conjunto com todos os módulos do framework Spring.

Por fim, vale ressaltar que o Spring MVC atua na camada de Controller, e podemos destacar as seguintes vantagens em sua utilização:

  • Uso de anotações para viabilizar a navegação entre páginas;
  • Facilidade de integração com outros frameworks e demais componentes do Spring;
  • Suporte a vários frameworks da camada de Visão, como Velocity, Freemarker e JSP;
  • Integração com as validações do framework Hibernate Validator.

JavaServer Faces

O JSF, acrônimo de JavaServer Faces, nasceu de uma especificação Java, a JSR-127, em 2001, sendo lançada sua primeira release em 2004. Baseado na arquitetura MVC, surgiu da necessidade de se ter um framework que fosse orientado à interface, como o Swing para aplicações desktop, porém sendo robusto para lidar com aplicações web. Atualmente, ele se encontra na segunda versão, o JSF 2.2, que foi concebido sobre a especificação JSR 344.

Por ser uma especificação, várias empresas se propõem a implementar versões para o JSF. Dentre as implementações mais famosas, temos:

  • Mojarra: implementação de referência do JSF, e a mais utilizada;
  • MyFaces: implementação open source da Apache;
  • ADF Faces: implementação open source da Oracle.

Cada uma destas implementações nos oferece apenas componentes básicos, que na grande maioria dos sistemas corporativos não é suficiente, sendo necessária àutilização de conjuntos de componentes complexos e ricos. Entre algumas das soluções Java que fornecem bons conjuntos de componentes, podemos destacar: o RichFaces, PrimeFaces e Tomahawk.

Ser uma especificação Java facilitou na rápida aceitação do JSF no mercado, principalmente para as grandes empresas, que precisam ter ao menos alguma garantia de continuidade da tecnologia. Esta aceitação fez com que o mercado passasse a utilizar componentes em suas aplicações para a criação da interface com o usuário.

O controle fornecido pelo JSF sobre o que acontece nos componentes é viabilizado graças ao armazenamento das representações de cada elemento como um objeto em uma árvore de componentes. Cada elemento desta árvore guarda o estado atual dos componentes da tela e, a cada evento disparado, é feita uma requisição para o JSF, que se encarrega de atualizar as informações nesta árvore no início da requisição.

Além disso, como o JSF tem um modelo de componentes extensível, é possível a criação de novos componentes que se encaixam nas necessidades de sua aplicação. Esta extensibilidade foi aproveitada na construção dos frameworks RichFaces, PrimeFaces, entre outros, que criaram componentes úteis e práticos, como componentes de layout, temas, componentes drag-and-drop e gráficos.

Com o JSF já consolidado, sua nova versão, o JSF 2.2, veio para corrigir alguns problemas da primeira e acrescentar importantes funcionalidades, como o suporte nativo a Ajax, o que aumentou o dinamismo no desenvolvimento, e principalmente o uso de anotações, o que diminuiu as configurações com XML da primeira versão. Destaque também para a integração do JSF 2.2 com o restante da Java EE 7.

Hibernate/JPA

As aplicações criadas com Java possuem a orientação a objetos como o seu principal paradigma. No entanto, quando necessitamos interagir com bancos de dados, precisamos também trabalhar com o paradigma relacional. Neste contexto, visando facilitar a integração Objeto-Relacional, as ferramentas ORM (Object-Relational Mapping) ganharam espaço entre os desenvolvedores.

O Hibernate é uma ferramenta ORM que surgiu em 2001 por iniciativa de Gavin King e logo se tornou amplamente utilizado. Ele conta com uma grande diversidade de recursos para o mapeamento objeto relacional. Atualmente, como líder de mercado, o Hibernate tem alguns dos seus recursos utilizados como base para a especificação JPA (ver BOX 1).

BOX 1: JPA, acrônimo de Java Persistence API, é uma especificação que em sua primeira versão fez parte da especificação do EJB 3.0, a JSR-220. Já em sua segunda versão, a JPA 2.0, teve sua própria especificação, a JSR-317.

Vale lembrar que o Hibernate é largamente adotado como implementação da JPA mesmo sendo o EclipseLink a implementação de referência desta especificação. Entre os concorrentes mais comuns do Hibernate estão: o EclipseLink, da Eclipse Foundation; o TopLink, da Oracle; e o OpenJPA, da Apache.

As ferramentas ORM são utilizadas com o intuito de aproximar nossos objetos Java das nossas tabelas do banco de dados, além de abstrair o uso do SQL puro e as interações com o JDBC, que são criadas de forma mais fácil por esses frameworks.

Por ser uma especificação, usamos o JPA nas aplicações a fim de diminuir o acoplamento com algum framework específico, pra que assim, em caso de migração entre fornecedores de uma implementação do JPA, a complexidade desta migração seja reduzida.

Conclusões

Este artigo abordou uma introdução ao desenvolvimento web com Java, apresentando desde o seu início, suas dificuldades com a utilização de servlets e JSPs, até a atualidade, que conta com a facilidade do uso de frameworks que auxiliam na produtividade no desenvolvimento das aplicações.

Como vimos, as especificações Java voltadas para web, inicialmente com servlets e JSP, tiveram uma grande aceitação no mercado, mas a demora em encontrar soluções para abstrair as dificuldades de se trabalhar com o protocolo HTTP fez com que frameworks de terceiros ganhassem espaço.

Neste contexto, vale destacar inicialmente a fundação Apache, com seu framework Struts, visto que mesmo com sua primeira versão, que conta com conceitos hoje defasados, descontinuada, ainda persiste em boa parte das aplicações de grandes empresas do mercado, sendo possível um programador ter que prestar manutenção em aplicações que utilizem este framework com frequência.

Atualmente, o destaque do desenvolvimento web está na grande utilização das especificações Java, que com o JSF como carro chefe, vem ganhando cada vez mais espaço no mercado com tecnologias como JPA, EJB, CDI, e demais especificações da plataforma Java EE (agora na versão 7), dando a segurança de continuidade que as empresas precisam para criar suas aplicações.


Links: