Pregunta Funciones ocultas de JSP / Servlet [cerrado]


Estoy interesado en tus trucos, etc. usados ​​al escribir JSP / Servlet. Comenzaré:

Recientemente descubrí cómo puedes incluir el resultado 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>

73


origen


Respuestas:


Nota: Me resulta difícil pensar en cualquier "característica oculta" para JSP / Servlet. En mi opinión, "mejores prácticas" es una mejor redacción y puedo pensar en alguna de ellas. También realmente depende de tu experiencia con JSP / Servlet. Después de años de desarrollo, ya no ves esas "características ocultas". De cualquier modo, enumeraré algunas de esas pequeñas "mejores prácticas" de las cuales, en años, descubrí que muchos principiantes no son plenamente conscientes de ello. Esos serían categorizados como "características ocultas" en el ojo de muchos principiantes. De todos modos, aquí está la lista :)


Ocultar páginas JSP del acceso directo

Al colocar los archivos JSP en /WEB-INF carpeta que efectivamente los oculta del acceso directo, por ejemplo http://example.com/contextname/WEB-INF/page.jsp. Esto dará como resultado un 404. A continuación, solo puede acceder a ellos por un RequestDispatcher en Servlet o usando jsp:include.


Solicitud de preproceso para JSP

La mayoría conoce de Servlet doPost() a enviar-procesar una solicitud (un formulario enviado), pero la mayoría no sabe que puede usar Servlet's doGet() método para pre-procesar una solicitud de 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 un servlet en un url-pattern de /page (o /page/*) y solo invocar http://example.com/contextname/page por la barra de direcciones del navegador o un simple enlace de vainilla para ejecutarlo. Ver también p. doGet y doPost en Servlets.


Dinámico incluye

Puedes usar EL en jsp:include:

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

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


EL puede acceder a cualquier getter

EL no requiere por sí mismo que el objeto a ser accedido sea un de pleno derecho Javabean. La presencia de un método no-arg que está prefijado con get o is es más que suficiente para acceder a él en EL. P.ej.:

${bean['class'].name}

Esto devuelve el valor de bean.getClass().getName() donde el getClass() método es en realidad heredado de Object#getClass(). Tenga en cuenta que class se especifica usando "notación de llave" [] por las razones mencionadas aquí instancia de verificación en el lenguaje de expresión EL.

${pageContext.session.id}

Esto devuelve el valor de pageContext.getSession().getId() que es útil en a.o. ¿Puede un applet comunicarse con una instancia de un servlet?.

${pageContext.request.contextPath}

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


EL también puede acceder a Mapas

La siguiente notación EL

${bean.map.foo}

resuelve a bean.getMap().get("foo"). Si el Map la clave contiene un punto, puede usar la "notación de llave" [] con una clave citada:

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

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

${bean.map[otherbean.key]}

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


Iterar sobre el mapa con JSTL

Puedes usar c:forEach también para iterar sobre un Map. Cada iteración da una Map.Entry que a su vez tiene getKey() y getValue() métodos (para que pueda acceder a él en EL ${entry.key} y ${entry.value}) Ejemplo:

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

Ver también p. Depurando con jstl - ¿cómo exactamente?


Obtener la fecha actual en JSP

Puedes obtener la fecha actual con jsp:useBean y formatealo con la ayuda de JSTL fmt:formatDate

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

Esto imprime (a partir de ahora) de la siguiente manera: "Copyright © 2010".


URL fáciles y amigables

Una manera fácil de tener URL amigables es hacer uso de HttpServletRequest#getPathInfo() y JSP's escondidos en /WEB-INF:

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

Si mapea este servlet, por ejemplo /pages/*, luego una solicitud en http://example.com/contextname/pages/foo/bar mostrará de manera efectiva /WEB-INF/foo/bar.jsp. Puede dar un paso más al dividir el pathinfo en / y solo tome la primera parte como URL de la página JSP y el remanente como "acciones comerciales" (deje que el servlet actúe como un controlador de página) Ver también p. Diseños de diseño de aplicaciones basadas en web.


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

El objeto EL implícito ${param} que se refiere a la HttpServletRequest#getParameterMap() se puede usar 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"). Ver también p. ¿Cómo puedo conservar los valores de campo de formulario HTML en JSP después de enviar el formulario a Servlet?
¡No olvides evitar de XSS! Ver el siguiente capítulo.


JSTL para evitar XSS

Para evitar que su sitio XSS, todo lo que necesitas hacer es (re) mostrar controlado por el usuario datos usando JSTL fn:escapeXml o c:out.

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

Alterno <table> filas con LoopTagStatus

los varStatus atributo de JSTL c:forEach te da un LoopTagStatus volver, que a su vez tiene varios métodos getter (¡que se pueden usar en EL!). Por lo tanto, para comprobar 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>

Use CSS para darles un color de fondo diferente.

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

Rellenar una cadena compuesta por comas de Lista / Matriz con LoopTagStatus:

Otro útil LoopTagStatus método es el isLast():

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

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


Funciones EL

Usted puede declarar public static métodos de utilidad como funciones EL (como Funciones JSTL) para que pueda 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.tld que se ve de la siguiente manera:

<?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 usar 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 se ha reenviado, puede obtener la URL de solicitud original,

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

y la cadena de consulta de solicitud original por,

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

Eso fue todo lo lejos. Tal vez agregue algo más tarde o temprano.


149