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 endoGet/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.