O padrão de projeto MVC (Model View Controller) é um dos padrões de projeto mais presentes no desenvolvimento de aplicações atualmente. Conforme os autores do livro “Core J2EE Design Patterns”, se o processamento da informação da camada de apresentação não for encapsulado, tem-se uma probabilidade alta de ser criado um sistema com um alto acoplamento e difícil manutenção e extensão.

A separação de conceitos que o MVC fornece aos projetistas e desenvolvedores permite que as modificações realizadas tanto na camada de negócio quanto na interface com usuário sejam muito mais simples e independentes.

Os desenvolvedores de aplicações Web são os que mais utilizam e se beneficiam desse padrão, mas isso não significa que ele seja restrito apenas a esse tipo de aplicação.

No restante do artigo veremos o que é o MVC, como podemos implementá-lo como um POJO e como ele é implementado na nova plataforma Java EE 7.

Padrão MVC

Quando o padrão de projeto MVC está sendo estudado é interessante saber o que significa cada camada e o que ela contém.

Na camada Modelo tem-se as informações da aplicação e a lógica de negócio relacionadas. O Model (Modelo) pode ser representado por um objeto ou um grafo complexo de objetos relacionados. Nas aplicações Java EE, a informação é encapsulada nos objetos de domínio frequentemente implantados (deployed) no servidor de aplicação por meio de um módulo EJB.

As informações precisam ser transportadas entre as camadas e para isso utiliza-se o DTO (Data Transfer Object). Por exemplo, para transportar os dados a serem armazenados numa base de dados podemos utilizar um DTO contendo essas informações, então acessamos a camada de acesso ao banco de dados passando o DTO que contém os dados e só após isso os dados podem ser armazenados no banco de dados.

A camada View (Visualização) é a representação visual da informação contida na camada de Modelo. Um subconjunto do Modelo é representado em uma única View. Assim, ela é como um filtro para a informação contida no Modelo. Dessa forma, o usuário interage com a informação dele por meio de uma representação visual da View. Além disso, o usuário invoca a lógica de negócio que, por sua vez, age sobre os dados do Modelo.

A outra camada é o Controller (Controlador), que é responsável por ligar as duas camadas anteriores, ou seja, o Controller liga a View ao Modelo e direciona o fluxo da aplicação. Isto permite escolher qual View será exibida ao usuário em resposta à entrada e a lógica de negócio que será processada em cima dela. Assim, o Controller recebe uma mensagem da View, que por sua vez encaminha ao Model. Este prepara uma resposta e envia de volta ao Controller que escolhe a View adequada e a envia ao usuário.

O padrão MVC abrange o cliente e camada intermediária de uma arquitetura de múltiplas camadas. Em um ambiente Java EE, o Model é localizado na camada de negócio, normalmente na forma de um módulo EJB (Enterprise JavaBeans). Portanto, nas aplicações empresariais utilizamos um EJB para implementar o Model.

O Controller e a View estão localizados na camada Web. A View normalmente é construída utilizando JavaServer Faces (JSF), JavaServer Pages (JSP) ou utilizando frameworks como Primefaces.

O Controller normalmente é um Servlet que recebe requisições Hypertext Transfer Protocol (HTTP) do usuário.

Na próxima seção veremos mais detalhes de como implementar esse padrão junto ao JavaEE

Implementando o MVC

Existem diferentes formas para implementar o MVC, sendo as duas mais citadas na bibliografia atual e mais utilizada nos ambientes corporativos analisadas a seguir:

  • MVC Tipo I: Este tipo é uma abordagem centrada na página, na qual a View e o Controller existem como uma entidade referenciada como View-Controller, ou seja, eles estão ligados. Nesta abordagem, a lógica do Controller é implementada dentro da View, assim como ocorre no JSF. Todas as tarefas que o Controller realiza, incluindo a recuperação de atributos de requisição HTTP e parâmetros, além de invocar a camada de negócio e gerenciar sessões HTTP, são embutidos na View usando scriptlets e tag libraries. Este tipo acopla a geração da View com o fluxo da aplicação, tornando a manutenção bastante complicada. Também sobrecarrega a View com funcionalidades que poderiam estar desacopladas.
  • MVC Tipo II: Neste tipo de modelo MVC os problemas com manutenção encontrados no Tipo I são resolvidos movendo a lógica do Controller para fora da View, colocando-o em um Servlet. Assim, o JSF se preocupa apenas com a apresentação dos dados para View.

A principal diferença entre o Tipo I e o Tipo II é onde a lógica do Controller está localizada, sendo que no Tipo I ela está na View e no Tipo II ela está separada da View como num Servlet, ou seja, uma classe separada usada para estender a lógica.

O Tipo II do MVC é implementado por diversos frameworks como o Spring MVC, Struts, Grails e Wicket.

A partir da próxima seção veremos como implementar o Tipo I do MVC.

Implementando o padrão MVC em Código Puro (POJO)

O padrão MVC pode ser implementado utilizando as tecnologias web do Java, determinando onde redirecionar o usuário com base na requisição do usuário. Isso também ajuda a manter a única responsabilidade do Controller.

Primeiramente começamos definido-o, pois é no Controller que implementaremos a resposta a qualquer requisição HTTP GET feita no caminho /usuarios/*. O mapeamento deste relacionamento é definido no arquivo web.xml conforme mostrado na Listagem 1.

Listagem 1. Exemplo de implementação do web.xml definindo o Controller da aplicação.


  <servlet>
           <servlet-name>FrontController</servlet-name>
           <servlet-class>br.com.devmedia.mvc.pojo.FrontController</servlet-class>
  </servlet>
  <servlet-mapping>
           <servlet-name>FrontController</servlet-name>
           <url-pattern>/usuarios/*</url-pattern>
  </servlet-mapping>

Nesse código mapeamos a classe Controller que está localizada em br.com.devmedia.mvc.pojo.FrontController para quaisquer requisições realizadas por meio da URL "/usuarios/*". Portanto, toda requisição feita para esta URL é redirecionada para a classe FrontController, que fará o processamento inicial da solicitação.

Como a plataforma Java EE 7 suporta a nova especificação Servlets 3.0, podemos simplesmente anotar a classe Controller como @WebServlet({"/usuarios/*"}), dispensando o uso do arquivo web.xml.

Quando essas solicitações forem realizadas, o método doGet() será invocado no Servlet. No exemplo da Listagem 2 temos uma implementação de exemplo do Controller. Neste código, o objeto Action é retornado do AbstractActionFactory, que determina a localização da View a ser retornada ao usuário.

Listagem 2. Exemplo de implementação de um Controller.


  package br.com.devmedia.mvc.pojo;
   
  import java.io.IOException;
  import javax.servlet.ServletException;
  import javax.servlet.annotation.WebServlet;
  import javax.servlet.http.HttpServlet;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
   
  public class FrontController extends HttpServlet {
   
           protected void doGet(HttpServletRequest request, HttpServletResponse response)
                     throws ServletException, IOException {
   
                     Action action = AbstractActionFactory.getInstance().getAction(request);
                     String view = action.execute(request, response);
   
                     //chama a view passando como parâmetro a requisição recebida e um objeto de resposta
                     getServletContext().getRequestDispatcher(view).forward(request,response);
           }
  }

No exemplo tem-se que o AbstractActionFactory cria uma instância da classe ActionFactory. O método getAction() aceita um objeto HttpServletRequest, que contém uma referência para o URI da localização solicitada, utilizando-a para determinar qual objeto Action retornar ao Controller.

O código da Listagem 3 mostra um exemplo da classe AbstractActionFactory e da classe ActionFactory. Pode-se verificar que há um mapeamento dos caminhos de requisições URI e dos objetos Action no Map action. Um objeto Action é escolhido do mapa baseado na solicitação da URI e retornado ao Controller.

Listagem 3. Exemplo de implementação das fábricas.


  package br.com.devmedia.mvc.pojo;
   
  public class AbstractActionFactory {
   
           private final static ActionFactory actionFactory = new ActionFactory();
   
           //Retorna uma instância única de ActionFactory
           public static ActionFactory getInstance() {
                     return actionFactory;
           }
  }
   
  package br.com.devmedia.mvc.pojo;
   
  import java.util.HashMap;
  import java.util.Map;
  import javax.servlet.http.HttpServletRequest;
   
  public class ActionFactory {
   
           private Map<String, Action> actions = new HashMap<>();
   
           private Action action;
   
           public ActionFactory() {
                     actions.put("GET/usuarios", new HomeAction());
                     actions.put("GET/usuarios/listausuarios", new ListaUsuariosAction());
           }
   
           public synchronized Action getAction(HttpServletRequest request) {
   
                     String path = request.getServletPath() + request.getPathInfo();
   
                     String actionKey = request.getMethod() + path;
   
                     System.out.println(actionKey);
   
                     action = actions.get(actionKey);
   
                     if(action == null){
                              action = actions.get("GET/usuarios");
                     }
   
                     return action;
           }
  }

A implementação concreta de Action deve fornecer uma implementação para o método execute(). Este é o responsável por executar a lógica de negócio necessária para gerar a página que o usuário requisitou. Entre outras coisas, ele pode realizar uma consulta à base de dados para obter a informação, executar cálculos ou gerar um arquivo.

No código da Listagem 4temos a implementação do método execute(), que constrói uma lista de usuários que são adicionados como um atributo para o objeto de requisição. Após isso, ele retorna a localização da View para ser exibida ao usuário. A informação agora armazenada no objeto request é acessada pela página listausuario.jsp e exibida.

Listagem 4. Exemplo de uma classe Action.


  package br.com.devmedia.mvc.pojo;
   
  import java.util.ArrayList;
  import java.util.List;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
   
  public class ListaUsuariosAction implements Action {
           public String execute(HttpServletRequest request, HttpServletResponse response) {
   
                     //Normalmente esses dados são buscados de um módulo EJB que busca às informações na base de dados
                     List<String> listaUsuario = new ArrayList<>();
   
                     listaUsuario.add("Wander Wildner");
                     listaUsuario.add("Carlos Gerbase");
                     listaUsuario.add("Luciana Tomasi");
                     listaUsuario.add("Heron Heinz");
   
                     request.setAttribute("listausuarios", listaUsuario);
   
                     return "/WEB-INF/pages/listausuarios.jsp";
           }
  }

O objeto Action retorna para o Controller, que recebe a localização da página para a qual deverá enviar os objetos request e response, conforme mostra o exemplo a seguir e que já foi mostrado anteriormente no código do Controller:

String view = action.execute(request, response);
getServletContext().getRequestDispatcher(view).forward(request,
response);

No exemplo da Listagem 5 temos uma página JSP que acessa a variável requestScope e retorna a lista “listaUsuario” criada em ListUserAction. Após isso, realiza-se uma iteração sobre a coleção e exibe-se os nomes.

Listagem 5. Exemplo de implementação da página listausuario.jsp que foi solicitada pelo usuário.


  <%@ 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" %>
  <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN""http://www.w3.org/TR/html4/loose.dtd">
   
  <html>
           <head>
                     <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
                     <title>Lista de Usuários</title>
           </head>
   
           <body>
                     <h1 > Os usuários da nossa banda favorita são: </h1 >
                     <c:forEach items="${requestScope.listausuarios}" var="usuario" >
                              <br> ${usuario}
                     </c:forEach >
           </body>
  </html>

Esse exemplo mostrou como pode-se criar uma implementação do padrão MVC. Na próxima seção será visto como implementar essa mesma aplicação usando as vantagens da plataforma Java EE 7.

Implementando o padrão MVC na Plataforma Java EE 7

Utilizando os pojos tínhamos que escrever a lógica do Controller, o mapeamento das URLs para classes Controller e escrever bastante código para a implementação completa do MVC. Porém, a plataforma Java EE simplificou bastante a implementação do padrão MVC. Assim, precisamos apenas concentrar os esforços na View e no Model, pois o FacesServlet cuida da implementação do Controller para os desenvolvedores. Nas próximas seções falaremos um pouco mais sobre o FacesServlet.

FacesServlet

O FacesServlet cuida do gerenciamento das requisições do usuário e entrega a View para o usuário, assim como o nosso Controller implementado anteriormente. Ele gerencia o ciclo de vida das aplicações que usam o JSF para construir a interface com o usuário. Todas as requisições do usuário passam pelos FacesServlet.

Agora vamos exemplificar como fazer um MVC utilizando FacesServlet e JSF. É importante ressaltar que a linguagem de declaração da view para JSF é chamada facelets. Os facelets são substitutos dos JSPs e são escritos em XHTML usando CSS (Cascading Style Sheets).

O JSF inclui conceitos de backing beans. Esses são POJOs (Plain Old Java Objects) anotados com @Named e @RequestScope. Anteriormente à plataforma Java EE 7 eles eram anotados com @ManagedBean, acessíveis por meio de uma página JSF enquanto durava a solicitação HTTP, porém o tipo do escopo pode ser alterado, mas isso é melhor estudado em artigos específicos para JSF. Podemos nos referir a esses métodos diretamente no JSF.

No código da Listagem 6 reescrevemos a classe ListaUsuariosAction utilizando o backing bean.

Listagem 6. Classe ListaUsuariosAction reescrita como um backing bean


  package com.devchronicles.mvc.javaee;
   
  import java.util.ArrayList;
  import java.util.List;
  import javax.enterprise.context.RequestScoped;
  import javax.inject.Named;
   
  @RequestScoped
  @Named
  public class ListaUsuariosAction {
   
  private List<String> listaUsuario = new ArrayList<>();
   
  public List<String> getListaUsuario() {
  return listaUsuario;
  }
   
  public String execute() {
                     listaUsuario.add("Wander Wildner");
                     listaUsuario.add("Carlos Gerbase");
                     listaUsuario.add("Luciana Tomasi");
                     listaUsuario.add("Heron Heinz");
   
  return "/WEB-INF/pages/listausuarios.xhtml";
  }
}

O próximo passo é criar um arquivo index.xhtml, que é o ponto inicial de contato do usuário com a nossa aplicação. Este arquivo substitui o home.jsp e é chamado diretamente pelo browser. A proposta deste JSF é chamar o método execute() em ListaUsuariosAction, que prepara a informação para a View listausuarios.xhtml.

O código da Listagem 7 mostra como este método é chamado.

Listagem 7. Exemplo de uma página para o padrão MVC.


  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:h="http://java.sun.com/jsf/html">
  <h:head>
  <title>Bem-vindo à aplicação de Exemplo devmedia</title>
  </h:head>
   
  <h:body>
  <h1>Interaja com a nossa aplicação abaixo</h1>
   
  <h:form>
  <h2>Clique aqui para ver uma <h:commandLink value="lista de usuários"
  action="#{listaUsuariosAction.execute}"/>.</h2>
  </h:form>
  </h:body>
  </html>

Usamos a tag h:commandLink e referenciamos o backing bean e o método execute() no elemento action. O método é chamado diretamente pelo JSF. Este gera a lista de usuários, retorna a localização da View que exibirá a lista e, por fim, invoca o método getListaUsuario(), exibindo a lista de usuários.

Segue o código da Listagem 8 que apresenta às informações retornadas ao usuário.

Listagem 8. View que exibe a informação do Model.


  <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
  "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
  <html xmlns="http://www.w3.org/1999/xhtml"
  xmlns:ui="http://java.sun.com/jsf/facelets"
  xmlns:h="http://java.sun.com/jsf/html">
  <head>
  <title>Lista de Usuários</title>
  </head>
   
  <body>
  <h1>Os usuários da nossa banda favorita são:</h1>
  <ui:repeat value="#{listaUsuariosAction.listaUsuario}" var="usuario">
  <h:outputText value="#{usuario}" />
  <br/>
  </ui:repeat>
  </body>
  </html>

Quando realizamos o deploy da aplicação, a View index.xhtml exibe o link, que quando clicado exibe a lista de usuários como a seguir:

Os usuários da nossa banda favorita são:
Wander Wildner
Carlos Gerbase
Luciana Tomasi
Heron Heinz

Apenas isso já é necessário para construirmos uma aplicação utilizando a plataforma Java EE 7. Isso reduz bastante o esforço dos programadores em funcionalidades padrão que podem ser solucionadas por uma plataforma tão robusta quanto a Java EE 7, poupando assim o tempo e permitindo concentrar-se na lógica de negócio da aplicação.

Bibliografia

[1] Erich Gamma, Ricard Helm, Ralph Johnson, John Vlissides. Design Patterns: Elements of Reusable Object-Oriented Software (Addison-Wesley, 1994).

[2] Eric Freeman, Elisabeth Robson, Bert Bates, Kathy Sierra. Head First Design Patterns. O'Reilly Media, 2004.

[3] Deepak, A.; Dan, M.; John, C.; Core J2EE Patterns: Best Practices and Design Strategies (2nd Edition). Prentice Hall, 2003.