Funciones ocultas de JSP/Servlet [cerrado]

Resuelto asked hace 14 años • 1 respuestas

Estoy interesado en sus trucos, etc., que se utilizan al escribir JSP/Servlet. Comenzaré:

Recientemente descubrí cómo se puede incluir la salida de una etiqueta JSP en un atributo de otra etiqueta:

<c:forEach items="${items}">
  <jsp:attribute name="var">
    <mytag:doesSomething/>
  </jsp:attribute>
  <jsp:body>
    <%-- when using jsp:attribute the body must be in this tag --%>
  </jsp:body>
</c:forEach>
 avatar Mar 26 '10 20:03
Aceptado

Nota: Me resulta difícil pensar en "funciones ocultas" para JSP/Servlet. En mi opinión, "mejores prácticas" es una mejor redacción y se me ocurre cualquiera de ellas. También depende realmente de su experiencia con JSP/Servlet. Después de años de desarrollo, ya no ves esas "funciones ocultas". De cualquier manera, enumeraré algunas de esas pequeñas "mejores prácticas" de las que descubrí con años que muchos principiantes no son plenamente conscientes de ellas. Estas se clasificarían como "características ocultas" a los ojos de muchos principiantes. De todos modos, aquí está la lista :)


Ocultar páginas JSP del acceso directo

Al colocar archivos JSP en /WEB-INFuna carpeta, los oculta efectivamente del acceso directo, por ejemplo http://example.com/contextname/WEB-INF/page.jsp. Esto dará como resultado un 404. Entonces solo podrá acceder a ellos mediante un RequestDispatcherservlet o usando jsp:include.


Solicitud de preproceso para JSP

La mayoría conoce los servlets doPost()para posprocesar una solicitud (envío de un formulario), pero la mayoría no sabe que se puede utilizar el doGet()método de servlet para preprocesar una solicitud para un JSP. Por ejemplo:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    List<Item> items = itemDAO.list();
    request.setAttribute("items", items);
    request.getRequestDispatcher("/WEB-INF/page.jsp").forward(request, response);
}

que se utiliza para precargar algunos datos tabulares que se mostrarán con la ayuda de JSTL c:forEach:

<table>
    <c:forEach items="${items}" var="item">
        <tr><td>${item.id}</td><td>${item.name}</td></tr>
    </c:forEach>
</table>

Asigne dicho servlet a url-patternof /page(o /page/*) y simplemente invoque http://example.com/contextname/pagemediante la barra de direcciones del navegador o un enlace simple para ejecutarlo. Véase también, por ejemplo, doGet y doPost en Servlets .


Dinámico incluye

Puedes usar EL en jsp:include:

<jsp:include page="/WEB-INF/${bean.page}.jsp" />

Simplemente bean.getPage()puede devolver un nombre de página válido.


EL puede acceder a cualquier captador

EL no requiere per se que el objeto al que se accederá sea un Javabean completo . La presencia de un método sin argumentos que tiene el prefijo geto ises más que suficiente para acceder a él en EL. P.ej:

${bean['class'].name}

Esto devuelve el valor de dónde se hereda realmente bean.getClass().getName()el método . Tenga en cuenta que se especifica utilizando "notación de llaves" por los motivos mencionados aquí. instancia de verificación en lenguaje de expresión EL .getClass()Object#getClass()class[]

${pageContext.session.id}

Esto devuelve el valor del pageContext.getSession().getId()cual es útil en ao ¿ Puede un subprograma comunicarse con una instancia de un servlet ?

${pageContext.request.contextPath}

Esto devuelve el valor del pageContext.getRequest().getContextPath()cual es útil en ao ¿Cómo usar rutas relativas sin incluir el nombre de la raíz del contexto?


EL también puede acceder a Maps

La siguiente notación EL

${bean.map.foo}

resuelve a bean.getMap().get("foo"). Si la Mapclave contiene un punto, puede utilizar la "notación de llaves" []con una clave entrecomillada:

${bean.map['foo.bar']}

que resuelve bean.getMap().get("foo.bar"). Si desea una clave dinámica, utilice también la notación entre llaves, pero sin comillas:

${bean.map[otherbean.key]}

que resuelve bean.getMap().get(otherbean.getKey()).


Iterar sobre el mapa con JSTL

c:forEachTambién puedes usarlo para iterar sobre un archivo Map. Cada iteración proporciona un método Map.Entryque a su vez tiene getKey()métodos getValue()(para que pueda acceder a él en EL mediante ${entry.key}y ${entry.value}). Ejemplo:

<c:forEach items="${bean.map}" var="entry">
    Key: ${entry.key}, Value: ${entry.value} <br>
</c:forEach>

Véase también, por ejemplo, Depuración con jstl: ¿cómo exactamente?


Obtener la fecha actual en JSP

Puede obtener la fecha actual jsp:useBeany formatearla con la ayuda de JSTLfmt:formatDate

<jsp:useBean id="date" class="java.util.Date" />
...
<p>Copyright &copy; <fmt:formatDate value="${date}" pattern="yyyy" /></p>

Esto se imprime (a partir de ahora) como sigue: "Copyright © 2010".


URL fáciles de usar

Una forma sencilla de tener URL amigables es utilizar HttpServletRequest#getPathInfo()JSP ocultos en /WEB-INF:

protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
    request.getRequestDispatcher("/WEB-INF" + request.getPathInfo() + ".jsp").forward(request, response);
}

Si asigna este servlet, por ejemplo , se mostrará efectivamente /pages/*una solicitud . Puede ir un paso más allá dividiendo la información de ruta y tomando solo la primera parte como URL de la página JSP y el resto como "acciones comerciales" (deje que el servlet actúe como controlador de página ). Véase también, por ejemplo, Patrones de diseño de aplicaciones basadas en web .http://example.com/contextname/pages/foo/bar/WEB-INF/foo/bar.jsp/


Volver a mostrar la entrada del usuario usando${param}

El objeto EL implícito ${param}que hace referencia a se HttpServletRequest#getParameterMap()puede utilizar para volver a mostrar la entrada del usuario después de enviar un formulario en JSP:

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

Esto básicamente hace lo mismo que request.getParameterMap().get("foo"). Véase también, por ejemplo, ¿Cómo puedo conservar los valores de los campos del formulario HTML en JSP después de enviar el formulario al Servlet?
¡No olvides prevenir el XSS! Ver el siguiente capítulo.


JSTL para prevenir XSS

Para evitar que su sitio tenga XSS , todo lo que necesita hacer es (re)mostrar datos controlados por el usuario usando JSTL fn:escapeXmlo c:out.

<p><input type="text" name="foo" value="${fn:escapeXml(param.foo)}">
<p><c:out value="${bean.userdata}" />

<table>filas alternas conLoopTagStatus

El varStatusatributo de JSTL c:forEachle brinda un LoopTagStatusrespaldo que a su vez tiene varios métodos getter (¡que se pueden usar en EL!). Entonces, para verificar si hay filas pares, simplemente verifique si loop.getIndex() % 2 == 0:

<table>
    <c:forEach items="${items}" var="item" varStatus="loop">
        <tr class="${loop.index % 2 == 0 ? 'even' : 'odd'}">...</tr>
    <c:forEach>
</table>

que efectivamente terminará en

<table>
    <tr class="even">...</tr>
    <tr class="odd">...</tr>
    <tr class="even">...</tr>
    <tr class="odd">...</tr>
    ...
</table>

Utilice CSS para darles un color de fondo diferente.

tr.even { background: #eee; }
tr.odd { background: #ddd; }

Complete una cadena separada por comas de Lista/Matriz con LoopTagStatus:

Otro LoopTagStatusmétodo útil es el isLast():

<c:forEach items="${items}" var="item" varStatus="loop">
    ${item}${!loop.last ? ', ' : ''}
<c:forEach>

Lo que resulta en algo como item1, item2, item3.


funciones EL

Puede declarar public staticmétodos de utilidad como funciones EL (como funciones JSTL ) para poder usarlos en EL. P.ej

package com.example;

public final class Functions {
     private Functions() {}

     public static boolean matches(String string, String pattern) {
         return string.matches(pattern);
     }
}

con /WEB-INF/functions.tldlo que queda como sigue:

<?xml version="1.0" encoding="UTF-8" ?>
<taglib 
    xmlns="http://java.sun.com/xml/ns/javaee"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-jsptaglibrary_2_1.xsd"
    version="2.1">
   
    <tlib-version>1.0</tlib-version>
    <short-name>Custom_Functions</short-name>
    <uri>http://example.com/functions</uri>
    
    <function>
        <name>matches</name>
        <function-class>com.example.Functions</function-class>
        <function-signature>boolean matches(java.lang.String, java.lang.String)</function-signature>
    </function>
</taglib>

que se puede utilizar como

<%@taglib uri="http://example.com/functions" prefix="f" %>

<c:if test="${f:matches(bean.value, '^foo.*')}">
    ...
</c:if>

Obtenga la URL de solicitud original y la cadena de consulta

Si el JSP ha sido reenviado, puede obtener la URL de solicitud original mediante:

${requestScope['javax.servlet.forward.request_uri']} 

y la cadena de consulta de solicitud original por,

${requestScope['javax.servlet.forward.query_string']}

Eso fue todo hasta el momento. Tal vez agregue algunos más tarde o temprano.

BalusC avatar Mar 26 '2010 19:03 BalusC