Pular para conteúdo

Servlets, JSP e MVC (Java Web clássico)

Antes de Spring, JSF e das APIs REST, a web em Java era feita com servlets e JSP. Entender essa base explica o que os frameworks fazem por baixo (Spring MVC, JSF e Jakarta EE usam servlets), e ainda é cobrado em entrevistas e em manutenção de legado. Veja os frameworks modernos em Spring e JSF, e o protocolo HTTP em Backend.

Java EE/Jakarta EE e os contêineres

Definição: contêiner de servlets

Servlet container (Tomcat, Jetty) é o servidor que hospeda aplicações web Java: recebe as requisições HTTP, cria e gerencia as servlets e devolve as respostas. Um servidor de aplicação (WildFly, WebLogic, WebSphere) inclui o contêiner de servlets e mais serviços Jakarta EE (EJB, JMS, transações).

  • A aplicação é empacotada em um WAR (Web Application Archive) e implantada no contêiner. Estrutura típica: raiz com páginas (.html, .jsp), WEB-INF/ (inacessível pelo navegador), WEB-INF/web.xml (configuração), WEB-INF/classes e WEB-INF/lib (classes e JARs).
  • O contexto é o prefixo da URL (/agenda); uma aplicação em ROOT responde na raiz (/).
  • O Tomcat é o mais comum; o Jetty é pequeno e embutível. Hoje é comum empacotar o contêiner dentro da aplicação (Spring Boot com Tomcat embutido). Detalhes de classloaders em Java avançado.

Servlets

Definição: servlet

Classe Java que atende requisições HTTP: lê os dados da requisição e escreve a resposta (HTML, JSON, imagem). Estende HttpServlet e sobrescreve doGet, doPost etc.

@WebServlet("/adicionaContato")                         // mapeamento por anotação (Servlet 3+); antes era no web.xml
public class AdicionaContatoServlet extends HttpServlet {
    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        String nome  = req.getParameter("nome");        // parâmetros vêm sempre como texto
        String email = req.getParameter("email");
        new ContatoDao().adiciona(new Contato(nome, email));
        resp.sendRedirect("lista-contatos.jsp");        // redirect: novo GET (evita reenvio do POST)
    }
}
  • Ciclo de vida: o contêiner cria uma única instância da servlet (init), usa-a para todas as requisições, em threads diferentes (service → doGet/doPost) e a destrói ao final (destroy). Por isso uma variável de instância é compartilhada entre todos os usuários: servlets devem ser thread-safe (sem estado mutável compartilhado).
  • Métodos HTTP: GET, POST, PUT, DELETE, HEAD, OPTIONS...; formulários HTML4 só enviam GET e POST.
  • Converter parâmetros: tudo chega como String; converta datas, números e trate erros de conversão.
  • Escopos de dados: request (uma requisição), session (usuário), application/ServletContext (toda a aplicação); setAttribute/getAttribute.
  • Exceções: em vez de espalhar try/catch, configure páginas de erro centralizadas (<error-page> no web.xml).

JSP, EL e JSTL

Definição: JSP (JavaServer Pages)

Página HTML com trechos dinâmicos que o contêiner compila para uma servlet na primeira requisição. Resolve o incômodo de gerar HTML com out.println dentro do Java.

  • Scriptlets (<% código Java %>) misturam Java e HTML: o problema que o JSP supostamente resolveria volta. Evite: use EL e taglibs, e mantenha a lógica na servlet (o JSP só apresenta).
  • EL (Expression Language): ${contato.nome}, ${param.idade}, ${sessionScope.usuario}: acessa propriedades de beans (via getters) e procura o atributo nos escopos (page, request, session, application).
  • JSTL (JSP Standard Tag Library): c:forEach (itera coleção: items, var), c:if, c:choose, c:import (inclui cabeçalho/rodapé), c:url (monta URLs corretas com o contexto), fmt:formatDate/fmt:formatNumber (formatação).
  • Tagfiles: quando faltam tags, crie as suas em .tag (por exemplo, "campo de data com calendário"), com atributos recebidos por EL, eliminando repetição.
  • Inclusões: diretiva include (estática, em tempo de compilação) x jsp:include/c:import (dinâmica).
<%@ taglib uri="jakarta.tags.core" prefix="c" %>
<table>
  <c:forEach var="contato" items="${contatos}">
    <tr><td>${contato.nome}</td>
        <td><c:if test="${not empty contato.email}"><a href="mailto:${contato.email}">${contato.email}</a></c:if></td></tr>
  </c:forEach>
</table>

MVC com servlet controladora

Um JSP que cria ContatoDao e consulta o banco mistura responsabilidades. O padrão MVC separa Model (regras e dados), View (JSP) e Controller (servlet):

  1. A requisição chega à servlet, que executa a lógica e guarda o resultado na requisição (req.setAttribute("contatos", lista)).
  2. Ela encaminha (RequestDispatcher.forward) ao JSP, que só exibe (EL + JSTL). O forward é interno ao servidor (a URL não muda); o redirect é uma nova requisição do navegador.
  3. Coloque os JSPs em WEB-INF/jsp para que não possam ser acessados diretamente pelo navegador.

Do if/else ao Front Controller e ao Command

Uma servlet com if (acao.equals("AdicionaContato")) ... else if ... cresce sem fim e é "propensa a erros". A solução evolui assim:

sequenceDiagram
    participant N as Navegador
    participant C as ControllerServlet (único ponto de entrada)
    participant L as Lógica (Command)
    participant J as JSP
    N->>C: GET /mvc?logica=RemoveContato&id=5
    C->>L: instancia a classe pelo nome (Class.forName) e chama executa()
    L-->>C: devolve "/WEB-INF/jsp/lista.jsp"
    C->>J: forward
    J-->>N: HTML
  • Cada ação vira uma classe que implementa uma interface (Logica com String executa(req, resp)): padrão Command.
  • Uma servlet controladora única (Front Controller) lê o parâmetro, instancia a lógica por reflexão e encaminha ao JSP que a lógica indicar.
  • Isolar a criação de objetos por Class.forName é uma forma de Factory. Esse é exatamente o papel que Spring MVC (DispatcherServlet), Struts, VRaptor e JSF automatizam (Spring MVC).

Filtros

Definição: filtro (Filter)

Classe que intercepta requisições e respostas antes e depois da servlet/JSP, para tratar requisitos não funcionais transversais (logging/auditoria, autenticação, compressão, abrir e fechar a conexão com o banco por requisição), sem acoplar isso às servlets.

@WebFilter("/*")
public class TempoDeRequisicaoFilter implements Filter {
    public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {
        long ini = System.currentTimeMillis();
        chain.doFilter(req, resp);                       // passa adiante (próximo filtro ou a servlet)
        System.out.println("levou " + (System.currentTimeMillis() - ini) + " ms");
    }
}

Filtros formam uma cadeia (ordem definida no web.xml); são o antepassado dos interceptors do Spring e dos middlewares do Express (Node.js). Autenticação: um filtro (ou interceptor) verifica a sessão e redireciona ao login (Segurança).

Recursos da Servlet API

  • init-param e context-param no web.xml: parâmetros de configuração fora do código (usados por Spring e VRaptor).
  • welcome-file-list: página aberta quando o cliente acessa um diretório.
  • Listeners: ServletContextListener executa código no início e fim da aplicação (inicializar cache, pool, configurações globais); também existem para sessão e atributos.
  • Sessão: HttpSession guarda o estado do usuário no servidor (identificada por cookie JSESSIONID); em cluster, exige replicação ou sessão externa.

Onde cada peça foi parar

Peça clássica Hoje
Servlet + Front Controller DispatcherServlet (Spring MVC), controladores REST
JSP + JSTL Thymeleaf, JSF/Facelets, front-end SPA (Angular)
Filtros Filtros/interceptors do Spring, Spring Security
web.xml Anotações e auto-configuração (Spring Boot)
JDBC + DAO JPA/Spring Data (Acesso a dados)

Para responder em entrevista

Pergunta Ideias para a resposta
"Ciclo de vida de uma servlet?" init (uma vez), service/doGet/doPost por requisição (várias threads), destroy; uma instância só
"Por que uma servlet deve ser thread-safe?" O contêiner usa uma única instância para todas as requisições; estado de instância é compartilhado
"forward x redirect?" Forward é interno ao servidor (mesma requisição, URL não muda); redirect manda o navegador fazer outra requisição (evita reenvio de POST)
"O que é Front Controller?" Ponto único de entrada que despacha para ações; base do Spring MVC
"Para que servem filtros?" Preocupações transversais: log, autenticação, transação por requisição
"Por que evitar scriptlets?" Misturam lógica e apresentação; use EL/JSTL e coloque a lógica na servlet/serviço