Desarrollo de Páginas Web Dinámicas con JSP y JSTL

Introducción

Anteriormente, al trabajar con Servlets, la generación de páginas web se realizaba a través de respuestas del servidor. Este enfoque presentaba varias limitaciones:

  • Dificultad en el desarrollo: Requería heredar de clases base, sobrescribir métodos y configurar web.xml o anotaciones.
  • Complejidad en las modificaciones: Cualquier cambio implicaba recompilar, desplegar y reiniciar el servidor.
  • Elaboración de la visualización: Implicaba obtener flujos de salida y usar println() para imprimir cada línea, resultando en código poco legible.
  • Colaboración complicada: Los diseñadores de UI se centraban en la estética y los desarrolladores en la lógica Java, pero la comunicación y la integración de ambos aspectos era difícil.

JSP (JavaServer Pages)

JSP es una tecnología que simplifica el desarrollo de Servlets. Permite incrustar código Java directamente dentro de etiquetas HTML para crear páginas web dinámicas de manera eficiente.

  • Propósito: Sustituye la parte de visualización de un Servlet. Un archivo .jsp reemplaza a un archivo XxxJSP.java.

Desarrollo con JSP (Énfasis Principal)

Creación de un JSP

Para crear un archivo JSP, simplemente se genera un archivo *.jsp dentro del directorio web, al mismo nivel que WEB-INF.

Incrustación de Código Java en JSP

El código Java se puede integrar en el HTML utilizando etiquetas especiales.


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Mi Primera Página JSP</title>
</head>
<body>
   La hora actual es: <%= new java.util.Date() %>
</body>
</html>
   

La etiqueta <%= ... %> se utiliza para insertar la expresión Java directamente en la página, mostrando la fecha y hora del sistema actual.

Acceso a un JSP

Para acceder a una página JSP, se utiliza la siguiente estructura en el navegador: http://ip:puerto/ruta_del_proyecto/nombre_del_recurso.

JSP y Servlets

  • Relación: Un archivo JSP se traduce a un Servlet dentro del contenedor web y se ejecuta como tal. En esencia, JSP es una abstracción de alto nivel sobre Servlets.
  • Diferencias: JSP facilita enormemente la creación y modificación de páginas HTML en comparación con la gestión de múltiples sentencias println() en Servlets.
    • Servlet: Requiere heredar de HttpServlet, configuración (web.xml o anotaciones), recompilación, despliegue y reinicio del servidor para cambios. El código HTML se imprime línea por línea.
    • JSP: Permite escribir código Java directamente en el HTML. Las modificaciones se reflejan simplemente refrescando la página en el navegador.

Principio de Funcionamiento de JSP

Cuando se solicita un archivo .jsp, el servidor web (como Tomcat) lo convierte en código Java, lo compila a un archivo .class y luego lo ejecuta. El resultado de esta ejecución se envía como respuesta al cliente.

Ubicación de los Archivos Generados por JSP

En entornos de desarrollo como IntelliJ IDEA con Tomcat, los archivos Java y .class generados a partir de los JSPs se encuentran típicamente en:

C:\Usuarios\<nombre_usuario>\AppData\Local\JetBrains\IntelliJIdea2020.1\tomcat\<nombre_proyecto>\work\Catalina\localhost\<contexto_aplicacion>\org\apache\jsp</contexto_aplicacion></nombre_proyecto></nombre_usuario>

(AppData puede ser una carpeta oculta).

Desarrollo Integrado de JSP y HTML

Scripts

Los scripts permiten la inclusión de sentencias, variables, métodos y expresiones Java dentro de un JSP.

Script Ordinario

Sintaxis: <% Java code %>


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Uso de Scripts</title>
</head>
<body>
   <%
       // En JSP, los scripts ordinarios permiten incrustar código Java.
       int a = 10; // Define una variable local.
       System.out.println(a); // Imprime en la consola del servidor.
       out.println(a); // Imprime en la página del cliente.
   %>
</body>
</html>
   

Nota: Los scripts ordinarios admiten toda la sintaxis Java excepto la definición de funciones. Los scripts no pueden anidarse entre sí ni con etiquetas HTML.

Script de Declaración

Sintaxis: <%! Variable declaration, Method declaration %>


<%!
   int b = 20; // Define una variable global.
   public void test() { // Define un método sin valor de retorno.
       System.out.println("Hola");
   }
   public int test1() { // Define un método con valor de retorno.
       return 100;
   }
%>
   

Nota: Las variables declaradas en este script son globales. Los métodos declarados aquí deben ser llamados desde un script ordinario o de expresión. Si un método tiene un valor de retorno, se puede invocar usando un script de expresión.

Script de Expresión

Sintaxis: <%= Java expression %>


<%@ page import="java.util.Date" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Uso de Scripts de Expresión</title>
</head>
<body>
   <%= test1() %> <br></br>
   <%= "¡Hoy hace buen tiempo!" %> <br></br>
   <%= 666 %> <br></br>
   <%= new Date() %> <br></br>
</body>
</html>
   

Nota: Los scripts de expresión pueden llamar a funciones con valor de retorno. No deben incluir punto y coma al final.

Comentarios JSP

Los comentarios en JSP tienen dos propósitos:

  • <%-- Comentario JSP --%>: Este comentario no se envía al navegador ni se compila.
  • <!-- Comentario HTML -->: Este comentario se puede ver en el código fuente de la página web en el navegador.

<%-- Este comentario JSP no se mostrará en la página --%>
<!-- Este comentario HTML se mostrará en el código fuente -->
   

Directivas JSP

Las directivas configuran atributos relacionados con la página JSP completa.

  • <%@ page ... %>: Define atributos de la página, como el lenguaje de script, la página de error, la gestión de caché, etc.
  • <%@ include ... %>: Incluye el contenido de otro archivo.
  • <%@ taglib ... %>: Importa definiciones de bibliotecas de etiquetas.

Directiva page

Sintaxsi: <%@ page attribute1="value1" attribute2="value2" %>

Atributos comunes incluyen:

  • contentType: Define el tipo MIME y la codificación de caracteres de la página.
  • errorPage: Especifica la página a la que se redirigirá si ocurre una excepción.
  • isErrorPage: Indica si la página actual puede actuar como manejador de errores.
  • import: Importa clases Java necesarias.
  • language: Define el lenguaje de script (por defecto, Java).
  • session: Determina si se usa la sesión (true por defecto, crea sesión inmediatamente; false, crea al usarla).
  • pageEncoding: Especifica la codificación de la página JSP.

Directiva include

Sintaxis: <%@ include file="ruta/al/archivo" %>

Incluye estáticamente el contenido de otro archivo (JSP, HTML, texto) en el momento de la compilación. El contenido incluido se trata como parte del archivo JSP actual.


<%@ include file="header.jsp" %>
...
<%@ include file="footer.jsp" %>
   

Precaución: Puede causar conflictos de nombres y no se recomienda su uso intensivo.

Directiva taglib

Sintaxis: <%@ taglib uri="ruta_biblioteca_etiquetas" prefix="prefijo" %>

Importa bibliotecas de etiquetas estándar o personalizadas.


<%@ taglib url="http://java.sun.com/jsp/jstl/core" prefix="c" %>
   

Etiquetas de Acción

Sintaxis: <jsp:action_name attribute="value" />

Las etiquetas de acción son comandos que se ejecutan en tiempo de ejecución.

jsp:include

Sintaxis: <jsp:include page="URL_relativa" />

Realiza una inclusión dinámica, incorporando el resultado de la salida de otro recurso.


<jsp:include page="index.jsp" />
   

Diferencia con <%@ include %>: jsp:include inserta el contenido generado en tiempo de ejecución, mientras que la directiva include inserta el código fuente en tiempo de compilación.

jsp:useBean

Sintaxis: <jsp:useBean id="nombre" class="paquete.NombreClase" />

Carga un JavaBean para su uso en la página JSP.


<jsp:useBean id="usuario" class="com.ejemplo.modelo.Usuario" />
   

Las propiedades del bean se pueden modificar o acceder usando jsp:setProperty y jsp:getProperty.

jsp:setProperty

Establece el valor de una propiedad de un JavaBean.

Sintaxis: <jsp:setProperty name="nombreBean" property="nombrePropiedad" value="valor" />


<jsp:useBean id="usuario" class="com.ejemplo.modelo.Usuario" />
<jsp:setProperty name="usuario" property="nombre" value="Mundo" />
   
jsp:getProperty

Obtiene el valor de una propiedad de un JavaBean, lo convierte a cadena y lo imprime.

Sintaxis: <jsp:getProperty name="nombreBean" property="nombrePropiedad" />


<jsp:useBean id="usuario" class="com.ejemplo.modelo.Usuario" />
<jsp:setProperty name="usuario" property="nombre" value="Mundo" />
<jsp:getProperty name="usuario" property="nombre" />
   
jsp:forward

Sintaxis: <jsp:forward page="URL_relativa" />

Redirige la solicitud a otra página.


<jsp:forward page="otraPagina.jsp" />
   
jsp:param

Sintaxis: <jsp:param name="nombreParametro" value="valorParametro" />

Se utiliza dentro de otras etiquetas de acción (como jsp:include o jsp:forward) para pasar parámetros.


<jsp:forward page="procesar.jsp">
   <jsp:param name="idUsuario" value="123" />
</jsp:forward>
   

Para obtener el parámetro en la página de destino: <%= request.getParameter("idUsuario") %>

Objetos Incorporados

JSP proporciona varios objetos predefinidos que se pueden usar directamente:

Objeto Tipo Descripción
request javax.servlet.http.HttpServletRequest Información sobre la solicitud del cliente.
response javax.servlet.http.HttpServletResponse Para enviar respuestas al cliente.
session javax.servlet.http.HttpSession Gestiona la información de la sesión del usuario (activado por session="true").
application javax.servlet.ServletContext Representa el contexto de la aplicación web.
config javax.servlet.ServletConfig Configuración del Servlet.
exception java.lang.Throwable Excepción ocurrida (disponible si isErrorPage="true").
out javax.servlet.jsp.JspWriter Para escribir en el flujo de salida de la respuesta.
pageContext javax.servlet.jsp.PageContext Proporciona acceso a todos los demás objetos y gestiona los ámbitos.
page java.lang.Object Referencia a la instancia del Servlet actual (this).

Cuatro Ámbitos Principales

Los objetos de ámbito almacenan y recuperan datos con diferentes alcances:

  • pageContext: Ámbito de la página actual.
  • request: Válido para una única solicitud.
  • session: Válido para una única sesión de usuario (se pierde al cerrar el navegador).
  • application: Válido para toda la aplicación web (se pierde al reiniciar el servidor).
Objeto pageContext

El objeto pageContext, una instancia de javax.servlet.jsp.PageContext, representa la página JSP completa y gestiona los ámbitos.

  • Almacenar valores: pageContext.setAttribute("nombre", valor);
  • Obtener valores: pageContext.getAttribute("nombre");
  • Permite acceder a los otros 8 objetos incorporados y gestionar sus ámbitos.

<%
   pageContext.setAttribute("nombre", "valor"); // Válido solo en esta página.
%>
   
Obtener Otros Objetos Incorporados desde pageContext

<%
   HttpServletRequest req = pageContext.getRequest();
   HttpServletResponse res = pageContext.getResponse();
   HttpSession ses = pageContext.getSession();
   ServletContext app = pageContext.getServletContext();
   JspWriter writer = pageContext.getOut();
   Throwable ex = pageContext.getException();
   Object pageObj = pageContext.getPage();
   ServletConfig conf = pageContext.getServletConfig();
%>
   
Operaciones de Ámbito con pageContext

<%
   /* Almacenar en otros ámbitos */
   pageContext.setAttribute("paginaScope", "valorPagina", PageContext.PAGE_SCOPE);
   pageContext.setAttribute("requestScope", "valorRequest", PageContext.REQUEST_SCOPE);
   pageContext.setAttribute("sessionScope", "valorSession", PageContext.SESSION_SCOPE);
   pageContext.setAttribute("applicationScope", "valorApplication", PageContext.APPLICATION_SCOPE);

   /* Obtener desde otros ámbitos */
   String valPagina = (String) pageContext.getAttribute("paginaScope", PageContext.PAGE_SCOPE);
   String valRequest = (String) pageContext.getAttribute("requestScope", PageContext.REQUEST_SCOPE); // O usando request.getAttribute("requestScope")
   String valSession = (String) pageContext.getAttribute("sessionScope", PageContext.SESSION_SCOPE); // O usando session.getAttribute("sessionScope")
   String valApplication = (String) pageContext.getAttribute("applicationScope", PageContext.APPLICATION_SCOPE); // O usando application.getAttribute("applicationScope")

   // Búsqueda en todos los ámbitos (page, request, session, application)
   String valorEncontrado = (String) pageContext.findAttribute("requestScope");
%>
   

Integración

Reemplazo de Servlets por JSPs en el proyecto EmpProject para la visualización, utilizando scripts para mostrar datos.

showAllEmp.jsp


<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Consulta de Todos los Empleados</title>
</head>
<body>

<form action='/EmpProject/manager/safe/showInsertEmp.jsp'>
<p><input type='submit' value='Nuevo'></p>
</form>
<table border='1'>
   <tr>
       <td>ID</td>
       <td>Nombre</td>
       <td>Salario</td>
       <td>Edad</td>
       <td colspan='2'>Acciones</td>
   </tr>
   <%
       List<Emp> empList = (List<Emp>) request.getAttribute("empList");
       if (empList != null) {
           for (Emp emp : empList) {
   %>
       <tr>
           <td><%=emp.getId()%></td>
           <td><%=emp.getName()%></td>
           <td><%=emp.getSalary()%></td>
           <td><%=emp.getAge()%></td>
           <td><a href="<%=request.getContextPath()+"/manager/safe/removeEmpController?id="+emp.getId()%>">Eliminar</a></td>
           <td><a href="<%=request.getContextPath()+"/manager/safe/showEmpController?id="+emp.getId()%>">Modificar</a></td>
       </tr>
   <%
           }
       }
   %>
</table>

</body>
</html>
   

showInsertEmp.jsp


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Alta de Empleado</title>
</head>
<body>

<form action='/EmpProject/manager/safe/insertEmpController' method='post'>
   <p>Nombre:<input type='text' name='name'></p>
   <p>Salario:<input type='text' name='salary'></p>
   <p>Edad:<input type='text' name='age'></p>
   <p><input type='submit' value='Enviar'></p>
</form>

</body>
</html>
   

showUpdateEmp.jsp


<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>Modificar Información de Empleado</title>
</head>
<body>

<%
   Emp emp = (Emp) request.getAttribute("emp");
%>
<form action='/EmpProject/manager/safe/updateEmpController' method='post'>
<p>ID:<input type='text' name='id' value=<%=emp.getId()%> readonly></p>
<p>Nombre:<input type='text' name='name' value=<%=emp.getName()%>></p>
<p>Salario:<input type='text' name='salary' value=<%=emp.getSalary()%>></p>
<p>Edad:<input type='text' name='age' value=<%=emp.getAge()%>></p>
<p><input type='submit' value='Actualizar'></p>
</form>
</body>
</html>
   

Expresión de Lenguaje (EL)

Concepto

EL (Expression Language) simplifica la escritura en JSP, permitiendo acceder a datos de los ámbitos de forma concisa.

Propósito

Reemplaza las llamadas a ambito.getAttribute("nombre").

Aplicación (Tipos Primitivos y Cadenas)

  • ${ambito.nombre}: Accede a un dato de un ámbito específico (ej. ${requestScope.usuario}).
  • ${nombre}: Busca el dato en los ámbitos en orden (pageScope, requestScope, sessionScope, applicationScope). Asegúrate de que el nombre sea único.

Caso de Uso de EL


<body>
   <%
       request.setAttribute("key1", "valor1");
       session.setAttribute("key2", "valor2");
       application.setAttribute("key3", "valor3");
   %>
   <%-- Acceso a través de objetos de ámbito --%>
   <h1><%= request.getAttribute("key1") %></h1>
   <h1><%= session.getAttribute("key2") %></h1>
   <h1><%= application.getAttribute("key3") %></h1>
   <hr/>
   <%-- Acceso a través de EL --%>
   <h1>${requestScope.key1}</h1>
   <h1>${sessionScope.key2}</h1>
   <h1>${applicationScope.key3}</h1>
   <hr/>
   <h1>${key1}</h1>
   <h1>${key2}</h1>
   <h1>${key3}</h1>
</body>
   

Diferencia entre EL y Scripts JSP

  • <%= request.getAttribute("nombre") %>: Devuelve null si no se encuentra.
  • ${requestScope.nombre}: Devuelve una cadena vacía ("") si no se encuentra.

Aplicación (Tipos de Referencia)

Al acceder a propiedades de objetos con EL, solo se pueden invocar métodos get que sigan las convenciones de nomenclatura.


<%@ page import="com.dz.entity.User" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
   <title>EL Accediendo a Objetos</title>
</head>
<body>
   <%
       User user = new User("Mundo", "123");
       request.setAttribute("usuario", user);
   %>
   ${usuario}<br> <!-- Imprime la representación del objeto -->
   ${usuario.username}<br> <!-- Llama a usuario.getUsername() -->
   ${usuario.password}<br> <!-- Llama a usuario.getPassword() -->
</body>
</html>
   

Aplicación (Arrays y Colecciones)

EL puede acceder a elementos de arrays, Listas y Mapas. Los Set no se pueden acceder directamente por índice.


	<%
       int[] array = {1, 2, 3, 4, 5};
       request.setAttribute("miArray", array);

       List<String> lista = new ArrayList<>();
       lista.add("A");
       lista.add("B");
       lista.add("C");
       request.setAttribute("miLista", lista);

       Map<String, String> mapa = new HashMap<>();
       mapa.put("ES", "España");
       mapa.put("US", "Estados Unidos");
       mapa.put("UK", "Reino Unido");
       request.setAttribute("miMapa", mapa);
   %>
   <%-- Acceso EL --%>
   ${miArray[0]} <br>
   ${miArray[1]} <br>
   <hr>
   ${miLista[0]} <br>
   ${miLista.get(1)} <br> <!-- Método get también es posible -->
   <hr>
   ${miMapa["ES"]} <br>
   ${miMapa.US} <br>
   

Operadores EL

Operador Descripción
. Acceso a propiedad de bean o entrada de mapa.
[] Acceso a elemento de array o lista.
+ Suma.
- Resta.
* Multiplicación.
/ o div División.
% o mod Módulo.
== o eq Igualdad.
!= o ne Desigualdad.
< o lt Menor que.
> o gt Mayor que.
<= o le Menor o igual que.
>= o ge Mayor o igual que.
&& o and Y lógico.
|| o or O lógico.
! o not Negación lógica.
empty Comprueba si un valor es nulo o vacío.
Ejecución de Operaciones con EL

	<%
       request.setAttribute("num", 100);
       request.setAttribute("cadenaVacia", "");
       request.setAttribute("valorNulo", null);
   %>
   <h1>Operadores Aritméticos</h1>
   <h1>${num + 2}</h1>
   <h1>${num - 2}</h1>
   <h1>${num * 2}</h1>
   <h1>${num div 2}</h1>
   <h1>${num mod 2}</h1>
   <hr>
   <h1>Operadores Relacionales</h1>
   <h1>${num eq 101}</h1>
   <h1>${num ne 101}</h1>
   <h1>${num lt 101}</h1>
   <h1>${num gt 101}</h1>
   <h1>${num le 101}</h1>
   <h1>${num ge 101}</h1>
   <hr>
   <h1>Operadores Lógicos</h1>
   <h1>${num > 100 and num < 200}</h1>
   <h1>${num > 100 or num < 200}</h1>
   <h1>${not (num > 100)}</h1>
   <hr>
   <h1>Operador empty</h1>
   <h1>${empty cadenaVacia}</h1>
   <h1>${empty valorNulo}</h1>
   

Palabra Clave empty

empty devuelve true si el valor es null o una cadena vacía.


	<%
       request.setAttribute("cadenaVacia", "");
       request.setAttribute("valorNulo", null);
   %>
	<h1>Operador empty</h1>
   <h1>${empty cadenaVacia}</h1> <!-- true -->
   <h1>${empty valorNulo}</h1> <lt;!-- true -->
   

Objetos Implícitos de EL

EL define 11 objetos implícitos:

  1. pageScope
  2. requestScope
  3. sessionScope
  4. applicationScope
  5. param (parámetros de solicitud, como String)
  6. paramValues (parámetros de solicitud, como String[])
  7. header (cabeceras HTTP, como String)
  8. headerValues (cabeceras HTTP, como String[])
  9. initParam (parámetros de inicialización del contexto)
  10. cookie (valores de cookies)
  11. pageContext
Obtener el Contexto de la Aplicación

<%=request.getContextPath()%>
${pageContext.request.contextPath}
   
Obtener Objetos de Cookie

   <h1>${cookie.nombreUsuario}</h1> <!-- Obtiene el objeto cookie 'nombreUsuario' -->
   <h1>${cookie.nombreUsuario.value}</h1> <!-- Obtiene el valor de la cookie 'nombreUsuario' -->
   

JSTL (JavaServer Pages Standard Tag Library)

Problemas Actuales

  • EL es principalmente para obtener datos y realizar cálculos/condiciones simples, pero no para control de flujo complejo.
  • EL no soporta iteración directa sobre colecciones para generar listados dinámicos.

¿Qué es JSTL?

JSTL es una biblioteca estándar de etiquetas para JSP que proporciona funcionalidades para lógica de control, iteración y manipulación de datos.

Propósito de JSTL

Permite realizar operaciones lógicas sobre los datos obtenidos con EL y colaborar con EL para la visualización de datos.

Uso de JSTL

  1. Descargar los archivos JAR: standard.jar y jstl.jar.
  2. Copiar estos JARs en el directorio /WEB-INF/lib/ de tu proyecto.
  3. Importar la biblioteca de etiquetas en el JSP: <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

Etiquetas Principales

Etiqueta Condicional c:if

Sintaxis: <c:if test="condición">...</c:if>


	<%
       request.setAttribute("nombreUsuario", "admin");
   %>
   ${nombreUsuario}
	<%-- El atributo 'test' usa expresiones EL --%>
   <c:if test="${nombreUsuario eq 'admin'}">
       <h1>Bienvenido, ${nombreUsuario}</h1>
   </c:if>
   <c:if test="${nombreUsuario ne 'admin'}">
       <h1>Por favor, inicie sesión.</h1>
   </c:if>
   

Condiciones Múltiples c:choose, c:when, c:otherwise

Sintaxis:


   <c:choose>
       <c:when test="condición1">Resultado 1</c:when>
       <c:when test="condición2">Resultado 2</c:when>
       <c:otherwise>Resultado por defecto</c:otherwise>
   </c:choose>
   

	<%
       request.setAttribute("edad", 25);
   %>    
	<c:choose>
       <c:when test="${edad lt 18}"><h1>Menor de edad</h1></c:when>
       <c:when test="${edad ge 18 and edad lt 30}"><h1>Joven</h1></c:when>
       <c:when test="${edad ge 30 and edad lt 50}"><h1>Adulto</h1></c:when>
       <c:otherwise><h1>Mayor</h1></c:otherwise>
   </c:choose>
   

Iteración c:forEach

Sintaxis:


   <c:forEach 
       var="nombreVariable" 
       items="coleccion"
       begin="indiceInicio"
       end="indiceFin"
       step="incremento"
       varStatus="estadoIteracion">    
       <%-- Contenido del bucle --%>
   </c:forEach>
   

   <%
       List<String> lista = Arrays.asList("A", "B", "C", "D", "E");
       request.setAttribute("miLista", lista);
   %>
   <%-- varStatus proporciona información sobre la iteración actual --%>
   <%-- first: Es la primera iteración? --%>
   <%-- last: Es la última iteración? --%>
   <%-- count: Número de la iteración actual (comienza en 1) --%>
   <%-- index: Índice del elemento actual (comienza en 0) --%>
   
   <c:forEach var="valor" items="${miLista}" begin="0" end="4" step="1" varStatus="vs">
       <h1>${valor}&nbsp;&nbsp;${vs.first}&nbsp;&nbsp;${vs.last}&nbsp;&nbsp;${vs.count}&nbsp;&nbsp;${vs.index}</h1>
   </c:forEach>
   

Etiqueta c:url

Ayuda a la reescritura de URLs para mantener la sesión cuando las cookies están deshabilitadas (añadiendo jsessionid).


   <%-- Método antiguo: response.encodeRedirectURL --%>
   <a href="<%=response.encodeRedirectURL(request.getContextPath()+"/ruta/pagina.jsp") %>">Enlace</a><br>

   <%-- Nuevo método con c:url --%>
   <c:url var="enlace" context="${pageContext.request.contextPath}" value="/ruta/pagina.jsp"/>
   <a href="${enlace}">Enlace 2</a>

   <%-- En acciones de formulario --%>
   <form action="<c:url context='${pageContext.request.contextPath}' value='/ruta/procesar.jsp'></c:url>">
       <input type="submit" value="Enviar">
   </form>
   

Recomendación: Siempre use c:url para cualquier enlace o redirección.

Integración con JSTL y EL

Reemplazo de código de script por EL y JSTL en el proyecto EmpProject.

showAllEmp.jsp (con EL y JSTL)


<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page import="java.util.List" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
   <title>Consulta de Todos los Empleados</title>
</head>
<body>

<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showInsertEmp.jsp'></c:url>">
<p><input type='submit' value='Nuevo'></p>
</form>
<table border='1'>
   <tr>
       <td>ID</td>
       <td>Nombre</td>
       <td>Salario</td>
       <td>Edad</td>
       <td colspan='2'>Acciones</td>
   </tr>

   <c:forEach var="emp" items="${empList}">
       <tr>
           <td>${emp.id}</td>
           <td>${emp.name}</td>
           <td>${emp.salary}</td>
           <td>${emp.age}</td>

           <td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">Eliminar</a></td>
           <td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">Modificar</a></td>
       </tr>
   </c:forEach>
</table>

</body>
</html>
   

showUpdateEmpInfo.jsp (con EL y JSTL)


<%@ page import="com.dz.emp.entity.Emp" %>
<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
   <title>Modificar Información de Empleado</title>
</head>
<body>

<form action="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/updateEmpController'></c:url>" method='post'>
   <p>ID:<input type='text' name='id' value=${emp.id} readonly></p>
   <p>Nombre:<input type='text' name='name' value=${emp.name}></p>
   <p>Salario:<input type='text' name='salary' value=${emp.salary}></p>
   <p>Edad:<input type='text' name='age' value=${emp.age}></p>
   <p><input type='submit' value='Actualizar'></p>
</form>

</body>
</html>
   

showInsertEmp.jsp (con EL y JSTL)


<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<html>
<head>
   <title>Alta de Empleado</title>
</head>
<body>
<form action='<c:url context="${pageContext.request.contextPath}" value="/manager/safe/insertEmpController"></c:url>' method='post'>
<p>Nombre:<input type='text' name='name'></p>
<p>Salario:<input type='text' name='salary'></p>
<p>Edad:<input type='text' name='age'></p>
<p><input type='submit' value='Enviar'></p>
</form>
</body>
</html>
   

Framework MVC (Modelo-Vista-Controlador)

Concepto MVC

MVC es un patrón de diseño de software que divide una aplicación en tres componentes interconectados:

  • Modelo (Model): Representa los datos y la lógica de negocio.
  • Vista (View): La interfaz de usuario que presenta los datos al usuario.
  • Controlador (Controller): Maneja las interacciones del usuario, actualiza el modelo y selecciona la vista a mostrar.

Detalles del Patrón MVC

MVC es un patrón común en arquitecturas B/S:

  • Vista: La interfaz con la que interactúa el usuario (HTML, JSP, etc.).
  • Controlador: Gestiona el flujo de la aplicación, procesa solicitudes y decide qué vista mostrar.
  • Modelo: Representa los datos y la lógica de negocio (usualmente compuesto por Service, DAO y Entidades).

Ventajas

  • Bajo Acoplamiento: Los componentes son independientes, facilitando cambios.
  • Alta Mantenibilidad: Permite reemplazar o modificar módulos fácilmente.
  • Alta Reutilización: La lógica de acceso a datos puede servir a múltiples procesos de negocio.

Aplicación en Frameworks

MVC es la base de muchos frameworks Java como Struts y Spring MVC.

Paginación

Concepto

La paginación es esencial para mostrar grandes volúmenes de datos de forma manejable, dividiendo los resultados en páginas.

Estrategia de Implementación

Se recuperan solo los datos necesarios para la página actual. Por ejemplo, para mostrar 20 registros por página:

SELECT * FROM tabla LIMIT 0, 20; -- Página 1
SELECT * FROM tabla LIMIT 20, 20; -- Página 2
SELECT * FROM tabla LIMIT 40, 20; -- Página 3

Implementación del Código

  1. Definir el número de elementos por página.
  2. Calcular el número total de páginas.
  3. Escribir la consulta SQL para la paginación.
  4. Configurar la visualización de la paginación en el JSP.

Preparación de la Base de Datos

CREATE TABLE emp (
    id INT PRIMARY KEY AUTO_INCREMENT,
    NAME VARCHAR(20) NOT NULL,
    salary DOUBLE NOT NULL,
    age INT NOT NULL
) CHARSET=utf8;
-- Insertar datos de ejemplo
INSERT INTO emp(NAME, salary, age) VALUES('Empleado1', 1000, 18);
-- ... (insertar más registros) ...

Archivo de Configuración de Base de Datos db.properties

# Configuración de conexión
driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/emp?useUnicode=true&characterEncoding=UTF-8
username=root
password=root
# Pool de conexiones
initialSize=10
maxActive=50
minIdle=5
maxWait=5000

Clase PageBean (o Page)

Esta clase contiene la información necesaria para la paginación:

  • pageIndex: Número de página actual.
  • pageSize: Elementos por página.
  • totalCounts: Total de registros.
  • totalPages: Total de páginas.
  • startRows: Fila de inicio para la consulta.
package com.dz.emp.entity;
public class Page {
```

private Integer pageIndex; // Número de página actual

    ```
private Integer pageSize; // Elementos por página
```

private Integer totalCounts; // Total de registros

    ```
private Integer totalPages; // Total de páginas
```

private Integer startRows; // Fila de inicio (calculada)


    ```
// Constructor con página y tamaño
```

public Page(Integer pageIndex, Integer pageSize) {

        ```
this.pageIndex = pageIndex;
    ```

this.pageSize = pageSize;

        ```
this.startRows = (pageIndex - 1) * pageSize;
```

}


    ```
// Constructor con solo página, tamaño fijo a 5
```

public Page(Integer pageIndex) {

        ```
this(pageIndex, 5);
```

}


    ```
// Getters y Setters...
```

// Lógica para calcular totalPages al establecer totalCounts

    ```
public void setTotalCounts(Integer totalCounts) {
    ```

this.totalCounts = totalCounts;

        ```
this.totalPages = (totalCounts % pageSize == 0) ? totalCounts / pageSize : (totalCounts / pageSize) + 1;
```

}

    ```
// ... resto de getters y setters
}

Interfaz EmpDao

package com.dz.emp.dao;
import com.dz.emp.entity.Emp;
import com.dz.emp.entity.Page;
import java.util.List;
public interface EmpDao {
```

// ... otros métodos ...

    ```
List<Emp> selectAll(Page page); // Para consulta paginada
```

long selectCounts(); // Para obtener el total de registros

}

    

#### Implementación `EmpDaoImpl`

 

import org.apache.commons.dbutils.QueryRunner;

import org.apache.commons.dbutils.handlers.BeanListHandler;

import org.apache.commons.dbutils.handlers.ScalarHandler;

import java.sql.SQLException;

import java.util.List;

// Asumiendo una clase DbUtils para obtener conexiones


public class EmpDaoImpl implements EmpDao {

    ```
private QueryRunner queryRunner = new QueryRunner();
```

@Override

    ```
public List<Emp> selectAll(Page page) {
    ```

try {

            ```
return queryRunner.query(DbUtils.getConnection(),
                                    ```

"SELECT * FROM emp LIMIT ?, ?",

                                        ```
new BeanListHandler<Emp>(Emp.class),
                                    ```

page.getStartRows(), page.getPageSize());

        ```
} catch (SQLException e) {
        ```

e.printStackTrace();

        ```
}
    ```

return null;

    ```
}
```

@Override

    ```
public long selectCounts() {
    ```

try {

            ```
return queryRunner.query(DbUtils.getConnection(),
                                    ```

"SELECT COUNT(*) FROM emp",

                                        ```
new ScalarHandler<Long>());
    ```

} catch (SQLException e) {

            ```
e.printStackTrace();
    ```

}

        ```
return 0;
```

}

    ```
// ... otros métodos ...
}

Interfaz EmpService

package com.dz.emp.service;
import com.dz.emp.entity.Emp;
import com.dz.emp.entity.Page;
import java.util.List;
public interface EmpService {
```

// ... otros métodos ...

    ```
List<Emp> showAllEmp(Page page); // Método para obtener datos paginados
}

Implementación EmpServiceImpl

import java.util.ArrayList;
// Asumiendo DbUtils para transacciones
public class EmpServiceImpl implements EmpService {
```

private EmpDao empDao = new EmpDaoImpl();


    ```
@Override
```

public List<Emp> showAllEmp(Page page) {

        ```
List<Emp> empList = new ArrayList<>();
    ```

try {

            ```
DbUtils.begin(); // Iniciar transacción
        ```

long count = empDao.selectCounts();

            ```
page.setTotalCounts((int) count); // Actualizar el total de registros y páginas en Page
        ```

List<Emp> data = empDao.selectAll(page);

            ```
if (data != null) {
            ```

empList = data;

            ```
}
        ```

DbUtils.commit(); // Confirmar transacción

        ```
} catch (Exception e) {
        ```

DbUtils.rollback(); // Revertir transacción

            ```
e.printStackTrace();
    ```

}

        ```
return empList;
```

}

    ```
// ... otros métodos ...
}

Controlador ShowAllEmpController

import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.List;
@WebServlet("/manager/safe/showAllEmpController")
public class ShowAllEmpController extends HttpServlet {
```

protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ```
String pageIndexStr = request.getParameter("pageIndex");
    ```

if (pageIndexStr == null) {

            ```
pageIndexStr = "1"; // Página por defecto si no se especifica
    ```

}

        ```
int pageIndex = Integer.parseInt(pageIndexStr);
    ```

Page page = new Page(pageIndex); // Crear objeto Page


        ```
EmpService empService = new EmpServiceImpl();
    ```

List<Emp> empList = empService.showAllEmp(page);


        ```
if (empList != null) {
        ```

request.setAttribute("pageInfo", page); // Pasar información de paginación a la vista

            ```
request.setAttribute("empList", empList); // Pasar la lista de empleados
        ```

request.getRequestDispatcher("/manager/safe/showAllEmp.jsp").forward(request, response);

        ```
} else {
        ```

// Manejar el caso de error o lista vacía

            ```
response.getWriter().write("Error al cargar empleados.");
    ```

}

    ```
}
```

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

        ```
doPost(request, response); // Reenviar GET a POST
```

}

}

    

### `showAllEmp.jsp` (con Paginación usando EL y JSTL)

<%@ page contentType="text/html;charset=UTF-8" language="java" %> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>

<c:if test="${empty empList}">
    <tr>
        <td colspan="6">No hay empleados para mostrar.</td>
    </tr>
</c:if>

<c:forEach var="emp" items="${empList}">
    <tr>
        <td>${emp.id}</td>
        <td>${emp.name}</td>
        <td>${emp.salary}</td>
        <td>${emp.age}</td>
        <td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/removeEmpController?id=${emp.id}'></c:url>">Eliminar</a></td>
        <td><a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showEmpController?id=${emp.id}'></c:url>">Modificar</a></td>
    </tr>
</c:forEach>
    <%-- Botón "Anterior" solo si no estamos en la primera página --%>
    <c:choose>
        <c:when test="${pageInfo.pageIndex gt 1}">
            <a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${pageInfo.pageIndex - 1}'/>">Anterior</a>
        </c:when>
        <c:otherwise>
            <span>Anterior</span> <!-- O un enlace deshabilitado -->
        </c:otherwise>
    </c:choose>

    <%-- Mostrar número de página actual y total --%>
    <span class="current">Página ${pageInfo.pageIndex} de ${pageInfo.totalPages}</span>

    <%-- Botón "Siguiente" solo si no estamos en la última página --%>
    <c:choose>
        <c:when test="${pageInfo.pageIndex lt pageInfo.totalPages}">
            <a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${pageInfo.pageIndex + 1}'/>">Siguiente</a>
        </c:when>
        <c:otherwise>
            <span>Siguiente</span> <!-- O un enlace deshabilitado -->
        </c:otherwise>
    </c:choose>

    <!-- Enlace a la última página -->
    <a href="<c:url context='${pageContext.request.contextPath}' value='/manager/safe/showAllEmpController?pageIndex=${pageInfo.totalPages}'/>">Última</a>
</c:if>

### Diagrama de Ejecución

Cuando el usuario solicita la página de empleados, el flujo es:

1. El navegador envía una solicitud a `/manager/safe/showAllEmpController`.
2. El `ShowAllEmpController` (un Servlet) recibe la solicitud.
3. Extrae el parámetro `pageIndex` (si existe).
4. Crea un objeto `Page` con la información de paginación.
5. Llama al `EmpService` para obtener la lista de empleados y la información de paginación.
6. El `EmpService` interactúa con `EmpDao` para obtener los datos y el total de registros.
7. El `EmpDao` ejecuta consultas SQL con `LIMIT` y `COUNT(\*)`.
8. Los datos y el objeto `Page` se guardan en el `request`.
9. La solicitud se reenvía a `/manager/safe/showAllEmp.jsp`.
10. El JSP utiliza EL y JSTL para mostrar la lista de empleados y los controles de paginación.

</body></html>

Etiquetas: jsp java Servlets web development EL

Publicado el 6-11 04:45