A partir de la especificación JSP 1.2, se recomienda encarecidamente utilizar la biblioteca de etiquetas estándar JSP (JSTL) en su aplicación web para ayudar a reducir la necesidad de scriptlets JSP en sus páginas. Las páginas que usan JSTL son, en general, más fáciles de leer y mantener.
...
Siempre que sea posible, evite los scriptlets JSP siempre que las bibliotecas de etiquetas proporcionen una funcionalidad equivalente. Esto hace que las páginas sean más fáciles de leer y mantener, ayuda a separar la lógica de negocios de la lógica de presentación y hará que sus páginas sean más fáciles de evolucionar a páginas de estilo JSP 2.0 (la especificación JSP 2.0 admite pero desestima el uso de scriptlets).
...
En el espíritu de adoptar el patrón de diseño modelo-vista-controlador (MVC) para reducir el acoplamiento entre el nivel de presentación de la lógica de negocios, los scriptlets JSP no deben usarse para escribir lógica de negocios. Por el contrario, los scriptlets JSP se usan si es necesario para transformar los datos (también llamados "objetos de valor") devueltos por el procesamiento de las solicitudes del cliente en un formato adecuado listo para el cliente. Incluso entonces, esto se haría mejor con un servlet controlador frontal o una etiqueta personalizada.
Si desea invocar el mismo código Java en cada solicitud, menos o más independientemente de la página solicitada, por ejemplo, verificando si un usuario ha iniciado sesión, luego implemente un filtro y escriba el código en consecuencia en el doFilter()
método. P.ej:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
} else {
chain.doFilter(request, response); // Logged in, just continue request.
}
}
Cuando se asigna en un sitio apropiado que <url-pattern>
cubre las páginas JSP de interés, entonces no necesita copiar y pegar el mismo fragmento de código en las páginas JSP generales.
Si desea invocar algún código Java para preprocesar una solicitud, por ejemplo, precargar una lista de una base de datos para mostrarla en alguna tabla, si es necesario en función de algunos parámetros de consulta, luego implemente un servlet y escriba el código correspondiente en el doGet()
método. P.ej:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productService.list(); // Obtain all products.
request.setAttribute("products", products); // Store products in request scope.
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
} catch (SQLException e) {
throw new ServletException("Retrieving products failed!", e);
}
}
De esta forma, lidiar con las excepciones es más fácil. No se accede a la base de datos en medio de la representación JSP, pero mucho antes de que se muestre la JSP. Todavía tiene la posibilidad de cambiar la respuesta cada vez que el acceso a la base de datos arroja una excepción. En el ejemplo anterior, la página predeterminada de error 500 se mostrará que de todos modos se puede personalizar por una <error-page>
en web.xml
.
Si desea invocar algún código Java para procesar posteriormente una solicitud, por ejemplo, procesar un envío de formulario, implemente un servlet y escriba el código correspondiente en el doPost()
método. P.ej:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirect to home page.
} else {
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
}
}
De esta manera tratar con diferentes destinos página de resultados es más fácil: volver a mostrar el formulario con los errores de validación en caso de un error (en este ejemplo particular se puede volver a mostrarlo usando ${message}
en EL ), o simplemente tomar a la página de destino deseado en caso de éxito.
Si desea invocar algún código Java para controlar el plan de ejecución y / o el destino de la solicitud y la respuesta, implemente un servlet de acuerdo con el Patrón del controlador frontal del MVC . P.ej:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
} else {
response.sendRedirect(view);
}
} catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
O simplemente adopte un marco MVC como JSF , Spring MVC , Wicket , etc. para que termine con solo una página JSP / Facelets y una clase JavaBean sin la necesidad de un servlet personalizado.
Si desea invocar algún código Java para controlar el flujo dentro de una página JSP, debe tomar un taglib de control de flujo (existente) como el núcleo JSTL . Por ejemplo, mostrar List<Product>
en una tabla:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
Con etiquetas de estilo XML que se ajustan bien a todo ese HTML, el código es mejor legible (y por lo tanto mejor mantenible) que un montón de scriptlets con varias llaves de apertura y cierre ( "¿A dónde diablos pertenece esta llave de cierre?" ). Una ayuda fácil es configurar su aplicación web para que arroje una excepción siempre que se sigan utilizando scriptlets agregando la siguiente pieza a web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
En Facelets , el sucesor de JSP, que forma parte del marco MVC JSF proporcionado por Java EE , ya no es posible utilizar scriptlets . De esta manera, se te obliga automáticamente a hacer las cosas "de la manera correcta".
Si desea invocar algún código Java para acceder y mostrar datos de "back-end" dentro de una página JSP, debe usar EL (lenguaje de expresión), esas ${}
cosas. Por ejemplo, volver a mostrar los valores de entrada enviados:
<input type="text" name="foo" value="${param.foo}" />
La ${param.foo}
muestra el resultado de request.getParameter("foo")
.
Si desea invocar algún código Java de utilidad directamente en la página JSP (generalmente public static
métodos), debe definirlos como funciones EL. Hay un taglib de funciones estándar en JSTL, pero también puede crear fácilmente funciones usted mismo . Aquí hay un ejemplo de cómo JSTL fn:escapeXml
es útil para prevenir ataques XSS .
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
Tenga en cuenta que la sensibilidad XSS no está relacionada de ninguna manera específicamente con Java / JSP / JSTL / EL / lo que sea, este problema debe tenerse en cuenta en cada aplicación web que desarrolle. El problema de los scriptlets es que no proporciona ninguna forma de prevención integrada, al menos no utilizando la API Java estándar. El sucesor de JSP, Facelets, ya tiene un escape de HTML implícito, por lo que no debe preocuparse por los agujeros XSS en Facelets.