Padrão MVC

Programação Java para Web

Prof. Wagner Macedo

## Model-View-Controller - [Problemática](#sec-problematica) - [Padrão arquitetural MVC](#sec-padrao-mvc) - [Criando um framework MVC](#sec-framework-mvc)

Qual o problema?


        public class ExemploServlet extends HttpServlet {
          @Override
          protected void doGet(HttpServletRequest request,
                               HttpServletResponse response) throws IOException {
              // Obtém os dados enviados
              String txtNome = request.getParameter("nome");
              String txtIdade = request.getParameter("idade");
              // Processa os dados
              if (txtNome == null) {
                  txtNome = "[anônimo]";
              }
              String classeIdade = "menor";
              int idade = Integer.parseInt(txtIdade);
              if (idade >= 18) {
                  classeIdade = "maior";
              }
              // Devolve uma resposta com os dados
              PrintWriter conteudo = response.getWriter();
              conteudo.println("<html><head><meta charset=utf-8></head>");
              conteudo.println("<body>");
              conteudo.println("<b>" + txtNome + "</b> tem <b>"
                      + idade + "</b> anos (de " + classeIdade + ")");
              conteudo.println("</body></html>");
          }
        }
      

Qual o problema?

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%
    String txtNome = request.getParameter("nome");
    String txtIdade = request.getParameter("idade");

    if (txtNome == null) {
        txtNome = "[anônimo]";
    }
    String classeIdade = "menor";
    int idade = Integer.parseInt(txtIdade);
    if (idade >= 18) {
        classeIdade = "maior";
    }
%>
<html>
<head>
    <meta charset=utf-8>
</head>
<body>
    <b><%= txtNome %></b> tem <b><%= idade %></b> anos
    (de <%= classeIdade %>)
</body>
</html>

Resolve o problema?

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:set var="nome" value="${param['nome']}"/>
<c:set var="idade" value="${param['idade']}"/>

<c:if test="${nome == null}">
    <c:set var="nome" value="[anônimo]"/>
</c:if>

<html>
<head>
    <meta charset=utf-8>
</head>
<body>
    <b>${nome}</b> tem <b>${idade}</b> anos
    (de ${idade < 18 ? 'menor' : 'maior'})
</body>
</html>

Arquitetura em 3 camadas

MVC

Model


          public class Pessoa {
              private String nome;
              private int idade;

              // gets e sets
          }
        

View

<b>${pessoa.nome == null ? '[anônimo]' : pessoa.nome}</b>
tem <b>${pessoa.idade}</b> anos
(de ${pessoa.idade < 18 ? 'menor' : 'maior'})

Controller


        public class ExemploServlet extends HttpServlet {
            @Override
            protected void doGet(HttpServletRequest request, HttpServletResponse response)
                    throws IOException, ServletException {
                // Obtém os dados enviados
                String txtNome = request.getParameter("nome");
                String txtIdade = request.getParameter("idade");
                // Usando o model
                Pessoa p = new Pessoa();
                p.setNome(txtNome);
                p.setIdade(Integer.parseInt(txtIdade));
                // Ligando o model <-> view
                request.setAttribute("pessoa", p);
                // Usando a view
                RequestDispatcher rd = request.getRequestDispatcher("/exemplo-view.jsp");
                rd.forward(request, response);
            }
        }
      

Criando um framework MVC

Comportamento

  • http://localhost:8080/WebApp/ctrl?command=Noticias
  • http://localhost:8080/WebApp/ctrl?command=Produtos
  • http://localhost:8080/WebApp/ctrl?command=Registrar

Front Controller

FrontController


      public class FrontController extends HttpServlet {
        protected void processRequest(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            // Executa um comando conforme a URL
            try {
                String commandName = request.getParameter("command");

                Class<Command> c = (Class<Command>) Class.forName("commands." + commandName);
                Command command = c.newInstance();

                command.execute(request, response);
            }
            // Se o comando não existir, retorna HTTP 500
            catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
                throw new ServletException(e);
            }
        }

        @Override
        protected void doGet(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }

        @Override
        protected void doPost(HttpServletRequest request, HttpServletResponse response)
                throws ServletException, IOException {
            processRequest(request, response);
        }
      }
    

Command


      public abstract class Command {
          protected HttpServletRequest request;
          protected HttpServletResponse response;

          /**
           * Método onde deve ser implementado a lógica do comando
           */
          protected abstract void execute();

          /**
           * Método interno usado por FrontController
           */
          void execute(HttpServletRequest request, HttpServletResponse response) {
              this.request = request;
              this.response = response;

              execute();
          }

          // Métodos utilitários

          protected final void forward(String path) throws ServletException, IOException {
              RequestDispatcher rd = request.getRequestDispatcher(path);
              rd.forward(request, response);
          }

          ...
      }
    

Configurabilidade

Alguns parâmetros do FrontController estão fixos 😭

  • pacote Java dos comandos: commands.Acao
  • nome do parâmetro HTTP: ?command=Noticias

Passando parâmetros para o FrontController


      <servlet>
          <servlet-name>FrontController</servlet-name>
          <servlet-class>minimvc.FrontController</servlet-class>
          <init-param>
              <param-name>commandPackage</param-name>
              <param-value>fanese.web.commands</param-value>
          </init-param>
          <init-param>
              <param-name>paramName</param-name>
              <param-value>action</param-value>
          </init-param>
      </servlet>

      <servlet-mapping>
          <servlet-name>FrontController</servlet-name>
          <url-pattern>/ctrl</url-pattern>
      </servlet-mapping>
    

Lendo os parâmetros passados


      public class FrontController extends HttpServlet {
        private String commandPackage;
        private String paramName;

        @Override
        public void init() throws ServletException {
          commandPackage = getInitParameter("commandPackage");
          paramName = getInitParameter("paramName");
        }

        protected void processRequest(HttpServletRequest request,
                                      HttpServletResponse response) throws ... {
          // Executa um comando conforme a URL
          try {
            String commandName = request.getParameter(paramName);

            Class<Command> c = (Class<Command>)
                    Class.forName(commandPackage + "." + commandName);
            Command command = c.newInstance();

            command.execute(request, response);
          }
          ...
        }

        ...
      }
    
### Código completo do framework http://prof.wagnermacedo.com/framework-mvc
Leitura Recomendada 🔖
Apostila Caelum

Capítulo 7: FrontController

Capítulo 20: MVC e DAO

Dúvidas?

Este slide pode ser encontrado em:
http://prof.wagnermacedo.com/2017-2/PJW/10