Padrões de Projeto na Camada de Apresentação
A base do desenvolvimento web em Java utiliza conceitos fundamentais de design patterns para garantir a interoperabilidade entre o servidor, o protocolo e a aplicação.
- Padrão Adaptador: Atua como uma ponte entre o protocolo HTTP, a especificação de Servlets e a aplicação Java Web. Ele isola a lógica de negócio, protegendo métodos internos contra sobrecargas indevidas através de interfaces ou classes abstratas.
- Template Method: Define o esqueleto do algoritmo principal em uma classe abstrata (marcado como
final), enquanto delega a implementação de passos específicos para as subclasses, promovendo a reutilização de código e padronização do fluxo de execução.
Especificações de Servlet e Gerenciamento de Contexto
O contêiner web (como o Tomcat) é responsável por instanciar e gerenciar os componentes da especificação Servlet.
Configuração Individual (ServletConfig)
Cada instância de Servlet possui seu próprio objeto de configuração. Abaixo, uma representação reestruturada de como esses dados podem ser encapsulados:
public class ConfiguradorServlet {
private final Map<String, String> parametrosIniciais;
private final String nomeComponente;
public String obterParametroInicial(String chave) {
return parametrosIniciais.get(chave);
}
public String identificarComponente() {
return nomeComponente;
}
// O contêiner injeta o contexto global aqui
public ContextoAplicacao obterContextoGlobal() {
return ContextoAplicacao.getInstancia();
}
}
Objeto de Requisição (HttpServletRequest)
Representa a requisição HTTP. O servidor web converte os dados brutos do protocolo em um objeto orientado a interfaces. O ciclo de vida deste objeto é extremamente curto, limitado ao processamento da requisição.
public class ExtratorDadosRequisicao {
// Armazenamento interno baseado em Map<String, String[]>
public String recuperarPrimeiroValor(String nomeParametro) {
String[] valores = obterMapaParametros().get(nomeParametro);
return (valores != null && valores.length > 0) ? valores[0] : null;
}
public void despacharParaRecursoInterno(String caminhoRelativo) {
// Encaminhamento interno (Forward).
// O caminho não deve conter o nome do contexto do projeto.
// A URL no navegador do cliente não é alterada.
}
}
Contexto da Aplicação (ServletContext)
Existe apenas uma instância por aplicação web. Funciona como um repositório global (escopo de aplicação) e um mecanismo de cache em memória.
public class GerenciadorContextoGlobal {
private final Map<String, Object> cacheAplicacao = new ConcurrentHashMap<>();
public String resolverCaminhoAbsoluto(String recurso) {
// Retorna o caminho real no sistema de arquivos do servidor
return "/opt/tomcat/webapps/minhaapp/" + recurso;
}
public void salvarNoCache(String identificador, Object valor) {
cacheAplicacao.put(identificador, valor);
}
public Object buscarNoCache(String identificador) {
return cacheAplicacao.get(identificador);
}
}
Mecanismos de Cache no Ecossistema Java
O gerenciamento de memória e performance em Java Web utiliza diversas estratégias de cache em diferentes níveis:
- Pool de Strings: Literal strings são verificadas no pool; se existirem, a referência é reutilizada.
- Pool de Inteiros: Cacheia referências para valores entre -128 e 127.
- Pools de Conexão e Threads: Reutilização de recursos pesados de banco de dados e processamento.
- Redis / ServletContext: Caches de dados distribuídos e de escopo de aplicação, respectivamente.
- Cache HTTP GET: Requisições GET são cacheadas pelo navegador e por proxies intermediários, mapeando uma URL para um recurso estático.
Anatomia do Protocolo HTTP
O HTTP é um protocolo sem estado que define a comunicação cliente-servidor.
- Requisição: Composta por Linha de Requisição (Método, URI, Versão), Cabeçalhos, uma Linha em Branco e o Corpo (presente em métodos como POST).
- Resposta: Composta por Linha de Status (Versão, Código, Descrição), Cabeçalhos, Linha em Brenco e o Corpo da Resposta.
Roteamento de Recursos: Forward vs Redirect
- Encaminhamento (Forward): Ocorre inteiramente no servidor. A mesma requisição e resposta são compartilhadas. O cliente não percebe a troca de recurso. Ideal para passar dados via escopo de requisição.
- Redirecionamento (Redirect): O servidor instrui o cliente a fazer uma nova requisição para uma nova URL. Ocorre no navegador, a URL muda, e os objetos de requisição/resposta são novos. O método HTTP resultante é sempre GET. Obrigatório quando o destino é um domínio ou projeto diferente.
Regra de ouro: Utilize Forward para navegação interna e cache de dados; utilize Redirect após operações de mutação de estado (como inserção de dados) para evitar reenvio de formulários ao atualizar a página.
JSP e Renderização Dinâmica
O JavaServer Pages (JSP) é uma especificação da Java EE que atua como uma camada de visualização. O contêiner traduz o arquivo JSP para uma classe Java que estende HttpServlet. A lógica de renderização dinâmica é inserida dentro do método service (ou _jspService), permitindo a mesclagem de HTML com processamento de dados vindos da requisição.
Gerenciamento de Estado: Sessões e Cookies
Como o HTTP é sem estado, mecanismos de escopo são necessários para manter o contexto do usuário.
- Escopo de Sessão (HttpSession): Mantido no servidor. Na primeira requisição, o servidor cria a sessão, gera um ID único e o envia ao cliente. Nas requisições subsequentes, o cliente devolve esse ID.
- Cookies: Mecanismo do lado do cliente para armazenar o ID da sessão (ex:
JSESSIONID). Podem ser persistidos em disco ou mantidos em memória. O navegador os envia automaticamente para o domínio e caminho configurados. - Reescrita de URL: Fallback utilizado quando os cookies estão desabilitados no navegador. O ID da sessão é anexado diretamente na URL (ex:
/app;jsessionid=XYZ).
Escopos de Dados (Scopes)
Os dados podem ser armazenados em diferentes níveis de visibilidade, do menor para o maior escopo:
- Page Scope: Visível apenas na página JSP atual.
- Request Scope: Visível durante o ciclo de vida de uma única requisição (incluindo forwards).
- Session Scope: Visível para todas as requisições do mesmo usuário (sessão ativa).
- Application Scope: Visível para todos os usuários e sessões da aplicação web.
A Expression Language (EL) facilita a leitura desses dados, buscando o atributo automaticamente na ordem dos escopos (ex: ${usuario}).
Componentes Auxiliares: Filtros e Listeners
Filtros (Filters)
Seguem a especificação Servlet e são inicializados na startup da aplicação (diferente dos Servlets, que podem ter inicialização preguiçosa). Operam como Singletons e implementam o padrão Chain of Responsibility. A ordem de execução pode ser definida via configuração (XML ou Anotações) e funciona de maneira similar a um stack (pilha), onde a requisição passa por todos os filtros até o Servlet, e a resposta percorre o caminho inverso.
Listeners
Funcionam como ganchos (hooks) de eventos do ciclo de vida do contêiner. Permindo a execução de código customizado em momentos específicos, como a inicialização ou destruição do ServletContext, HttpSession ou ServletRequest. São amplamente utilizados para configurar recursos globais, carregar caches ou limpar conexões quando a aplicação sobe ou cai.