Pregunta ¿Cómo evitar el código de Java en los archivos JSP?


Soy nuevo en Java EE y sé que algo así como las siguientes tres líneas

<%= x+1 %>
<%= request.getParameter("name") %>
<%! counter++; %>

es una forma de codificación de la vieja escuela y en JSP versión 2 existe un método para evitar el código de Java en los archivos JSP. ¿Puede alguien decirme las líneas alternativas JSP 2 y cómo se llama esta técnica?


1522
2017-07-05 07:24


origen


Respuestas:


El uso de scriptlets (aquellos <% %> cosas en JSP de hecho, es muy desalentador desde el nacimiento de taglibs (me gusta JSTL) y EL (Lenguaje de Expresión, aquellos ${} cosas) allá por el 2001.

Las principales desventajas de scriptlets son:

  1. Reusabilidad: no puedes reutilizar scriptlets.
  2. Reemplazabilidad: no puedes hacer scriptlets abstractos.
  3. OO-habilidad: no puedes hacer uso de la herencia / composición.
  4. Depuración: Si scriptlet arroja una excepción hasta la mitad, todo lo que obtiene es una página en blanco.
  5. Testabilidad: Los scriptlets no son verificables por unidad.
  6. Mantenibilidad: por saldo se necesita más tiempo para mantener la lógica del código mezclado / desordenado / duplicado.

Sol Oracle mismo también recomienda en el Convenciones de codificación JSP para evitar el uso de scriptlets siempre que la misma funcionalidad sea posible mediante clases (de etiqueta). Aquí hay varias citas de relevancia:

A partir de la Especificación JSP 1.2, se recomienda encarecidamente que se use la JSP Standard Tag Library (JSTL) en su aplicación web para ayudar reducir la necesidad de scriptlets JSP en tus páginas Las páginas que usan JSTL son, en general, más fáciles de leer y mantener.

...

Donde sea posible, evitar scriptlets JSP siempre que las bibliotecas de etiquetas brinden una funcionalidad equivalente. Esto hace que las páginas sean más fáciles de leer y mantener, ayuda a separar la lógica empresarial de la lógica de presentación, y facilitará que sus páginas evolucionen en páginas de estilo JSP 2.0 (la especificación JSP 2.0 admite, pero resta importancia al 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 y la lógica comercial, Los scriptlets JSP no deberían ser usados para escribir lógica de negocios Por el contrario, los scriptlets JSP se utilizan si es necesario para transformar los datos (también denominados "objetos de valor") devueltos del procesamiento de las solicitudes del cliente en un formato adecuado preparado para el cliente. Incluso entonces, esto se haría mejor con un servlet de controlador frontal o una etiqueta personalizada.


Cómo reemplazar scriptlets depende completamente del único propósito del código / lógica. Más que a menudo, este código se debe colocar en una clase completa de Java:

  • Si quieres invocar el mismo Código Java en cada solicitud, menos o más, independientemente de la página solicitada, p. verificar si un usuario está conectado, luego implementar un filtrar y escribir el código en consecuencia en 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 mapea en un apropiado <url-pattern>cubriendo las páginas de interés de JSP, entonces no es necesario copiar la misma pieza de código en todas las páginas JSP.


  • Si desea invocar algún código Java para preproceso una solicitud, p. 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 implementar una servlet y escribir el código en consecuencia en 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 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. Aún tiene la posibilidad de cambiar la respuesta cada vez que el acceso a la base arroja una excepción. En el ejemplo anterior, se mostrará la página predeterminada de error 500 que de todos modos puede personalizar de <error-page> en web.xml.


  • Si desea invocar algún código Java para proceso después de una solicitud, p. procesar un formulario enviado, luego implementar un servlet y escribir el código en consecuencia en 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 forma, es más fácil tratar con diferentes destinos de página de resultados: volver a mostrar el formulario con errores de validación en caso de error (en este ejemplo en particular, puede volver a mostrarlo usando ${message} en EL), o simplemente llevarlo a la página de destino deseada 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, luego implementar un servlet según el Patrón de controlador frontal 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 adopta un framework MVC como JSF, Spring MVC, Postigo, 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, entonces necesitas tomar un taglib de control de flujo (existente) como Núcleo JSTL. P.ej. mostrando List<Product> en una mesa:

    <%@ 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 las etiquetas de estilo XML que se adaptan perfectamente a todo ese código HTML, el código es mejor legible (y, por lo tanto, mejor mantenible) que un grupo 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 lanzar una excepción cada vez que scriptlets todavía se usan 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 es parte de Java EE proporcionó el marco MVC JSF, ya es no posible de usar scriptlets. De esta manera, te obligan automáticamente a hacer las cosas "de la manera correcta".


  • Si desea invocar algún código Java para acceso y visualización datos de "back-end" dentro de una página JSP, entonces necesita usar EL (Expression Language), aquellos ${} cosas. P.ej. volver a mostrar los valores de entrada enviados:

    <input type="text" name="foo" value="${param.foo}" />
    

    los ${param.foo} muestra el resultado de request.getParameter("foo").


  • Si quieres invocar algunos utilidad Código Java directamente en la página JSP (típicamente public static métodos), entonces necesita definirlos como funciones EL. Hay un estándar funciones taglib 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 XSS  ataques.

    <%@ 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á específicamente relacionada con Java / JSP / JSTL / EL / lo que sea, este problema debe tenerse en cuenta en cadawebapplication que desarrollas. El problema de scriptlets es que no proporciona ninguna forma de prevenciones incorporadas, al menos no utilizando la API estándar de Java. El sucesor de JSP, Facelets, ya tiene un escape de HTML implícito, por lo que no tiene que preocuparse por los agujeros XSS en Facelets.

Ver también:


1852
2017-07-05 14:19



Como salvaguardia: deshabilite los scriptlets para siempre

Como otra pregunta está discutiendo, puede y siempre debe deshabilitar scriptlets en su web.xml descriptor de aplicación web.

Siempre lo haría para evitar que cualquier desarrollador agregue scriptlets, especialmente en empresas más grandes, donde tarde o temprano perderá información general. los web.xml la configuración se ve así:

<jsp-config>
  <jsp-property-group>
    <url-pattern>*.jsp</url-pattern>
     <scripting-invalid>true</scripting-invalid>
  </jsp-property-group>
</jsp-config>

207
2017-08-14 21:59



JSTL ofrece etiquetas para condicionales, bucles, conjuntos, obtiene, etc. Por ejemplo:

<c:if test="${someAttribute == 'something'}">
   ...
</c:if>

JSTL funciona con los atributos de solicitud: generalmente se configuran en la solicitud mediante un Servlet, que hacia adelante a la JSP.


102
2017-07-05 07:28



No estoy seguro de si entiendo esto correctamente.

Deberías leer algo sobre MVC. Spring MVC & Struts 2 son las dos soluciones más comunes.


56
2017-07-05 07:29



Puede usar etiquetas JSTL junto con expresiones EL para evitar mezclar código Java y HTML:

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

        <c:out value="${x + 1}" />
        <c:out value="${param.name}" />
    // and so on

    </body>
</html>

48
2017-07-05 08:45



También hay marcos basados ​​en componentes tales como Postigo que generan mucho HTML para ti. Las etiquetas que terminan en el HTML son extremadamente básicas y prácticamente no hay lógica que se mezcle. El resultado es casi vacío, como las páginas HTML con elementos HTML típicos. La desventaja es que hay muchos componentes en Postigo API para aprender y algunas cosas pueden ser difíciles de lograr bajo esas restricciones.


32
2018-03-22 18:24



En el patrón arquitectónico de MVC, los JSP representan la capa de Vista. Incrustar código java en JSP se considera una mala práctica. Puedes usar JSTL, freeMarker, velocidad con JSP como "motor de plantilla". El proveedor de datos para esas etiquetas Depende de los marcos con lo que estás tratando Struts 2 y webwork como una implementación para MVC Pattern usa OGNL "técnica muy interesante para exponer Beans Properties a JSP".


28
2018-02-04 10:41