====== 05 - Servlets ====== Un **servlet** es un componente Java que procesa peticiones HTTP dentro de un contenedor. El desarrollador escribe el método que responde; el contenedor se ocupa de sockets, hilos, parseo y envío. ===== 1. Un servlet ===== @WebServlet("/books") public class BookServlet extends HttpServlet { @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { String id = request.getParameter("id"); response.setContentType("application/json"); response.setCharacterEncoding("UTF-8"); response.getWriter().print("{\"id\":" + id + "}"); } @Override protected void doPost(HttpServletRequest request, HttpServletResponse response) throws IOException { // procesar el cuerpo y crear el recurso response.setStatus(HttpServletResponse.SC_CREATED); } } ^ Elemento ^ Función ^ | ''HttpServlet'' | Clase base con el ciclo de vida gestionado por el contenedor | | ''doGet'' / ''doPost'' | Responden a los métodos HTTP correspondientes | | ''HttpServletRequest'' | Petición: parámetros, cabeceras, cuerpo | | ''HttpServletResponse'' | Respuesta: estado, cabeceras, cuerpo | | ''@WebServlet'' | Asocia el servlet con una ruta | ===== 2. Ciclo de vida ===== * **''init()''** — el contenedor crea el servlet una vez al arrancar (o a la primera petición). * **''service()''** — cada petición delega en ''doGet''/''doPost''. **Una sola instancia** atiende todas las peticiones, cada una en un hilo del pool del contenedor. * **''destroy()''** — el contenedor lo retira al parar. @WebServlet("/counter") public class CounterServlet extends HttpServlet { private int counter = 0; // ¡compartido por todas las peticiones! @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException { counter++; // condición de carrera entre peticiones concurrentes response.getWriter().print(counter); } } El estado de instancia del servlet es compartido: las reglas de hilos del tema 03 se aplican tal cual. El estado por petición debe ser local o gestionarse con cuidado. ===== 3. Filtros ===== Un **filtro** se ejecuta en la cadena antes (o después) del servlet. Sirve para lógica transversal: registro, compresión, **autenticación**. @WebFilter("/*") public class TokenFilter implements Filter { @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { String header = ((HttpServletRequest) request).getHeader("Authorization"); if (header != null && header.startsWith("Bearer ")) { // validar el token; si es válido, continuar chain.doFilter(request, response); } else { ((HttpServletResponse) response).setStatus(401); } } } ''chain.doFilter(...)'' pasa al siguiente filtro o al servlet; sin llamarlo, la petición termina ahí. ===== 4. Qué resuelve y qué no ===== ^ Resuelve el contenedor ^ Sigue siendo responsabilidad del desarrollador ^ | Sockets, pool de hilos, HTTP | Qué hace cada ruta (la lógica) | | Enrutado a servlets por ruta | Estructura de la aplicación | | Parseo de parámetros y cabeceras | Reglas de negocio y acceso a datos | | Devolución de errores de protocolo | Cuerpo y formato de los datos (JSON) | Un servlet atiende muchas peticiones con una sola instancia: no guardes en sus campos nada que pertenezca a una petición concreta. La autenticación por token se resuelve con filtros que validan la cabecera ''Authorization''; sin sesiones de servidor.