Controlador PersonaControladorServlet - eliizquierdo/material_programacion_avanzada2026 GitHub Wiki
📦 Proyecto:
mini-crud0(Fase 1) — ⬇️ Descargar ZIP · ☁️ Abrir en Codespace
Controlador en Java Web (Servlet)
Vamos a analizar cómo este servlet actúa como controlador dentro de una aplicación Java web.
¿Qué hace este código?
- Maneja solicitudes HTTP GET y POST
- Interactúa con un objeto de tipo PersonaDAO (modelo de acceso a datos)
- Redirige a formularios o vistas según la acción recibida
- Implementa el patrón Post-Redirect-Get (PRG)
Solicitudes GET:
action=agregar→ abre/WEB-INF/vista/persona-form.jsp(formulario)action=listar→ ejecutalistar()→ abre/WEB-INF/vista/persona-lista.jsp- Sin action o action desconocida → ejecuta
listar()por defecto
Solicitudes POST:
action=agregar→ procesa datos y aplica PRG (Post-Redirect-Get)
Nota: La firma de los métodos
doGetydoPostincluyethrows ServletException, IOExceptionaunque no siempre escribamos código que lance esas excepciones. Esto es porque la API del servlet define que estos métodos pueden lanzar esos errores al procesar la petición (por ejemplo, si falla un forward o al escribir en la respuesta). Por tanto, siempre debemos mantener esa parte de la firma al sobrescribirlos.
Analicemos el código:
package controlador;
import java.io.IOException;
import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.*;
import modelo.dao.PersonaDAO;
import modelo.vo.PersonaVO;
@WebServlet("/persona")
public class PersonaControladorServlet extends HttpServlet {
private final PersonaDAO dao = new PersonaDAO();
// ======================== GET ========================
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
String action = request.getParameter("action");
if (action == null)
action = "";
switch (action) {
case "agregar": // mostrar formulario de alta (GET)
request.getRequestDispatcher("/WEB-INF/vista/persona-form.jsp")
.forward(request, response);
break;
case "listar": // listar explícito
listar(request, response);
break;
default: // sin action o desconocida → listar
listar(request, response);
break;
}
}
// ======================== POST ========================
@Override
protected void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("UTF-8");
String action = request.getParameter("action");
if (action == null) {
response.sendRedirect(request.getContextPath() + "/persona");
return;
}
switch (action) {
case "agregar":
agregar(request, response);
break;
default:
response.sendRedirect(request.getContextPath() + "/persona");
}
}
// ===================== Acciones privadas =====================
private void agregar(HttpServletRequest request, HttpServletResponse response)
throws IOException {
int codigo = Integer.parseInt(request.getParameter("codigo"));
String nombre = request.getParameter("nombre");
dao.agregar(new PersonaVO(codigo, nombre));
response.sendRedirect(request.getContextPath() + "/persona"); // PRG → listar
}
private void listar(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("personas", dao.getLista());
request.getRequestDispatcher("/WEB-INF/vista/persona-lista.jsp")
.forward(request, response);
}
}
1) Encabezado del servlet
@WebServlet("/persona")
public class PersonaControladorServlet extends HttpServlet {
private final PersonaDAO dao = new PersonaDAO();
¿Qué hace?
- La anotación
@WebServlet("/persona")indica que este servlet atiende la URL/persona - Hereda de
HttpServlet, por lo que sobrescribedoGet()ydoPost()para manejar las solicitudes del navegador - Esto nos permite programar acciones diferentes según el tipo de solicitud que se recibe del navegador
El atributo dao
private final PersonaDAO dao = new PersonaDAO();
Esta línea declara un atributo de instancia del servlet. Veamos qué significa cada parte:
private→ solo es visible dentro dePersonaControladorServlet. Nadie de afuera puede acceder al DAO directamente.final→ la referenciadaono puede reasignarse. Una vez que apunta al objetoPersonaDAOcreado al iniciar el servlet, siempre apuntará a ese mismo objeto. No significa que el objeto sea inmutable; significa que no se puede escribirdao = new PersonaDAO()en otro lugar del código.new PersonaDAO()→ se crea una instancia del DAO cuando Tomcat inicializa el servlet.
¿Por qué final y no static?
Con static, el atributo pertenecería a la clase en lugar de a la instancia, y sería compartido entre todas las instancias del servlet:
// Con static: UN solo DAO compartido por TODAS las instancias de la clase
private static final PersonaDAO dao = new PersonaDAO();
// Sin static (lo que usamos): UN DAO por instancia del servlet
private final PersonaDAO dao = new PersonaDAO();
private final |
private static final |
|
|---|---|---|
| Pertenece a | La instancia del servlet | La clase |
| Cuántos objetos DAO | Uno por instancia | Uno compartido por todas |
| Cuándo se crea | Al instanciar el servlet | Al cargar la clase |
En la práctica, Tomcat normalmente crea una sola instancia del servlet para atender todas las peticiones, por lo que en este caso el efecto es similar. Sin embargo, usar static introduce un acoplamiento global innecesario y puede causar problemas si el DAO guardara estado entre peticiones. La convención en diseño MVC es preferir atributos de instancia (final sin static).
💡 Para explorar más: se puede consultar esta explicación adicional generada con IA: Gemini — ¿Por qué
finaly nostatic?
2) Procesar solicitudes GET (mostrar datos o formularios)
@Override
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
Vamos a procesar solicitudes GET, que son las que se envían, por ejemplo, cuando se carga una página en el navegador.
Dentro de este método:
String action = request.getParameter("action");
if (action == null)
action = "";
switch (action) {
case "agregar": // mostrar formulario de alta
request.getRequestDispatcher("/WEB-INF/vista/persona-form.jsp")
.forward(request, response);
break;
case "listar": // listar explícito
listar(request, response);
break;
default: // sin action o desconocida
listar(request, response);
break;
}
¿Qué pasa aquí?
action=agregar → formulario de alta
Envía al usuario a /WEB-INF/vista/persona-form.jsp, un formulario vacío para crear una persona nueva.
action=listar o (default)
Si action = listar o es distinta, se llama a listar(...) para mostrar todas las personas en /WEB-INF/vista/persona-lista.jsp.
2.1) Método auxiliar: listar
private void listar(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setAttribute("personas", dao.getLista());
request.getRequestDispatcher("/WEB-INF/vista/persona-lista.jsp")
.forward(request, response);
}
¿Qué hace?
Pide la lista al DAO, la guarda como atributo personas y hace forward al JSP del listado para que se renderice la tabla.
3) Procesar solicitudes POST (enviar datos)
@Override
protected void doPost(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
Aquí vamos a manejar datos que el usuario envía a través del formulario, como cuando hace clic en "Agregar".
request.setCharacterEncoding("UTF-8");
String action = request.getParameter("action");
if (action == null) {
response.sendRedirect(request.getContextPath() + "/persona");
return;
}
switch (action) {
case "agregar":
agregar(request, response);
break;
default:
response.sendRedirect(request.getContextPath() + "/persona");
}
¿Qué pasa aquí?
- Se establece UTF-8 para que los acentos lleguen bien
- Según action, se deriva a
agregaro por defecto a listar (aquí se usa un switch, pensando que más adelante se agregarán más acciones)
3.1) Agregar (alta)
private void agregar(HttpServletRequest request, HttpServletResponse response)
throws IOException {
int codigo = Integer.parseInt(request.getParameter("codigo"));
String nombre = request.getParameter("nombre");
dao.agregar(new PersonaVO(codigo, nombre));
response.sendRedirect(request.getContextPath() + "/persona"); // PRG → listar
}
Flujo:
- Lee código y nombre del formulario de alta
- Crea el PersonaVO y lo agrega en el DAO
- Aplica PRG (Post/Redirect/Get) para volver al listado
4) Aplicar patrón PRG (Post → Redirect → Get)
Luego de cada operación POST se llama a:
response.sendRedirect(request.getContextPath() + "/persona"); // PRG → listar
¿Por qué?
- Evita el reenvío del formulario si el usuario actualiza la página
- Fuerza a que el navegador haga un GET al listado, lo que deja la UI en un estado consistente
Continuemos con MODELO- DAO/VO
📋 Palabras clave
PersonaControladorServlet · doGet · doPost · @WebServlet · action · getParameter · PRG · sendRedirect · forward · switch · PersonaDAO · PersonaVO · Controlador MVC
🧠 Autoevaluación — Mini-CRUD con MVC
← VISTA: Listar Personas · 🏠 Inicio · PersonaDAO y PersonaVO →