====== 07 - Front Controller ====== Con servlets, cada ruta necesita su componente. Cuando el número de rutas crece, aparecen problemas: configuración repetida, lógica transversal duplicada (autenticación, mapeo de errores) y nomenclatura inconsistente. El patrón **front controller** concentra toda la entrada en un único punto que enruta cada petición al código que la procesa. ===== 1. El problema ===== Sin front controller: /books -> BookServlet /books/42 -> BookDetailServlet /authors -> AuthorServlet /login -> LoginServlet Cada servlet repite: validación del token, parseo, traducción de errores. Con front controller: /* -> DispatcherServlet (único punto de entrada) ├── valida el token (una vez) ├── decide el controlador según la ruta └── traduce los errores (una vez) ===== 2. Implementación con servlets ===== @WebServlet("/*") public class DispatcherServlet extends HttpServlet { private final BookController bookController = new BookController(); private final AuthorController authorController = new AuthorController(); @Override protected void service(HttpServletRequest request, HttpServletResponse response) throws IOException { String path = request.getRequestURI(); // /books/42 String method = request.getMethod(); // GET if (path.startsWith("/books")) { bookController.handle(request, response); } else if (path.startsWith("/authors")) { authorController.handle(request, response); } else { response.sendError(HttpServletResponse.SC_NOT_FOUND); } } } public class BookController { public void handle(HttpServletRequest request, HttpServletResponse response) throws IOException { String method = request.getMethod(); switch (method) { case "GET" -> find(request, response); case "POST" -> create(request, response); default -> response.sendError(405); } } private void find(HttpServletRequest request, HttpServletResponse response) throws IOException { String id = extractId(request.getRequestURI()); // /books/42 -> 42 // delegar en el service, escribir la respuesta JSON } } ^ Componente ^ Responsabilidad ^ | ''DispatcherServlet'' | Punto de entrada único: filtra, enruta y traduce errores | | ''BookController'' | Gestiona las operaciones de un recurso según el método HTTP | | ''Service'' | La lógica (capas de la arquitectura por capas) | ===== 3. Lo que aporta ===== * **Punto único** para lógica transversal: token, errores, registro. * **Rutas expresivas:** una convención única (''/books'', ''/books/42'') en lugar de un servlet por cada caso. * **Componentes por recurso** (''controllers'') con responsabilidad clara. * Es exactamente la estructura que automatiza **Spring MVC** con su ''DispatcherServlet'': por eso entenderlo aquí hace trivial entender Spring en 2.º. @startuml actor Cliente participant "DispatcherServlet\n(front controller)" as FC participant "Filtro de tokens" as F participant "BookController" as BC participant "Service" as S Cliente -> F : petición F -> FC : token válido FC -> BC : /books/42, GET BC -> S : findById(42) S --> BC : Book BC --> FC : JSON FC --> Cliente : respuesta @enduml El front controller no sustituye a la arquitectura por capas: la completa. El dispatcher y los controladores son la capa de presentación; debajo siguen service y repositorio con sus responsabilidades.