Um guia para o padrão Front Controller em Java
1. Visão geral
Neste tutorial, vamos nos aprofundar emFront ControllerPattern, parte deEnterprise Patterns conforme definido no livro deMartin Fowler“Patterns of Enterprise Application Architecture”.
Front Controller é definido como “um controlador que lida com todas as solicitações de um site”. Ele fica na frente de um aplicativo da Web e delega solicitações para recursos subsequentes. Ele também fornece uma interface para comportamentos comuns, como segurança, internacionalização e apresentação de visualizações específicas para determinados usuários.
Isso permite que um aplicativo altere seu comportamento em tempo de execução. Além disso, ajuda a ler e manter um aplicativo, impedindo a duplicação de código.
O Front Controller consolida todo o tratamento de solicitações canalizando as solicitações por meio de um único objeto de tratamento.
2. Como funciona?
OFront Controller Pattern é dividido principalmente em duas partes. Um único controlador de despacho e uma hierarquia de comandos. A UML a seguir descreve as relações de classe de uma implementação genérica do Front Controller:
Esse controlador único envia solicitações para comandos para acionar o comportamento associado a uma solicitação.
Para demonstrar sua implementação, vamos implementar o controlador em umFrontControllerServlete comandos como classes herdadas de umFrontCommand abstrato.
3. Configuração
3.1. Dependências do Maven
Primeiro, vamos configurar um novo projetoMaven WAR comjavax.servlet-api incluído:
javax.servlet
javax.servlet-api
4.0.0-b01
provided
bem comojetty-maven-plugin:
org.eclipse.jetty
jetty-maven-plugin
9.4.0.M1
/front-controller
3.2. Modelo
A seguir, definiremos uma classeModel e um modeloRepository. Usaremos a seguinte classeBook como nosso modelo:
public class Book {
private String author;
private String title;
private Double price;
// standard constructors, getters and setters
}
Este será o repositório, você pode procurar o código-fonte para implementação concreta ou fornecer um por conta própria:
public interface Bookshelf {
default void init() {
add(new Book("Wilson, Robert Anton & Shea, Robert",
"Illuminati", 9.99));
add(new Book("Fowler, Martin",
"Patterns of Enterprise Application Architecture", 27.88));
}
Bookshelf getInstance();
boolean add(E book);
Book findByTitle(String title);
}
3.3. FrontControllerServlet
A implementação do próprio Servlet é bastante simples. Estamos extraindo o nome do comando de uma solicitação, criando dinamicamente uma nova instância de uma classe de comando e executando-a.
Isso nos permite adicionar novos comandos sem alterar a base de código de nossoFront Controller.
Outra opção é implementar o Servlet usando lógica estática e condicional. Isso tem a vantagem de verificar erros em tempo de compilação:
public class FrontControllerServlet extends HttpServlet {
@Override
protected void doGet(HttpServletRequest request,
HttpServletResponse response) {
FrontCommand command = getCommand(request);
command.init(getServletContext(), request, response);
command.process();
}
private FrontCommand getCommand(HttpServletRequest request) {
try {
Class type = Class.forName(String.format(
"com.example.enterprise.patterns.front."
+ "controller.commands.%sCommand",
request.getParameter("command")));
return (FrontCommand) type
.asSubclass(FrontCommand.class)
.newInstance();
} catch (Exception e) {
return new UnknownCommand();
}
}
}
3.4. FrontCommand
Vamos implementar uma classe abstrata chamadaFrontCommand, que mantém o comportamento comum a todos os comandos.
Esta classe tem acesso aServletContext e seus objetos de solicitação e resposta. Além disso, ele lidará com a resolução da visualização:
public abstract class FrontCommand {
protected ServletContext context;
protected HttpServletRequest request;
protected HttpServletResponse response;
public void init(
ServletContext servletContext,
HttpServletRequest servletRequest,
HttpServletResponse servletResponse) {
this.context = servletContext;
this.request = servletRequest;
this.response = servletResponse;
}
public abstract void process() throws ServletException, IOException;
protected void forward(String target) throws ServletException, IOException {
target = String.format("/WEB-INF/jsp/%s.jsp", target);
RequestDispatcher dispatcher = context.getRequestDispatcher(target);
dispatcher.forward(request, response);
}
}
Uma implementação concreta desseFrontCommand abstrato seria aSearchCommand. Isso incluirá lógica condicional nos casos em que um livro foi encontrado ou quando o livro está ausente:
public class SearchCommand extends FrontCommand {
@Override
public void process() throws ServletException, IOException {
Book book = new BookshelfImpl().getInstance()
.findByTitle(request.getParameter("title"));
if (book != null) {
request.setAttribute("book", book);
forward("book-found");
} else {
forward("book-notfound");
}
}
}
Se o aplicativo estiver em execução, podemos acessar esse comando apontando nosso navegador parahttp://localhost:8080/front-controller/?command=Search&title=patterns.
OSearchCommand resolve para duas visualizações, a segunda visualização pode ser testada com a seguinte solicitaçãohttp://localhost:8080/front-controller/?command=Search&title=any-title.
Para completar nosso cenário, implementaremos um segundo comando, que é disparado como fallback em todos os casos, uma solicitação de comando é desconhecida para o Servlet:
public class UnknownCommand extends FrontCommand {
@Override
public void process() throws ServletException, IOException {
forward("unknown");
}
}
Esta visualização será alcançável emhttp://localhost:8080/front-controller/?command=Order&title=any-title ou deixando completamente de fora os parâmetrosURL.
4. Desdobramento, desenvolvimento
Como decidimos criar um projeto de arquivoWAR, precisaremos de um descritor de implantação da web. Com esteweb.xml, podemos executar nosso aplicativo da web em qualquer contêiner de Servlet:
front-controller
com.example.enterprise.patterns.front.controller.FrontControllerServlet
front-controller
/
Como última etapa, executaremos‘mvn install jetty:run' e inspecionaremos nossas visualizações em um navegador.
5. Conclusão
Como vimos até agora, agora devemos estar familiarizados com oFront Controller Patterne sua implementação como Servlet e hierarquia de comando.
Como de costume, você encontrará as fonteson GitHub.