Скрытые возможности JSP / сервлета

Меня интересуют ваши уловки и т. Д., Используемые при написании JSP / Servlet. Я начну:

Я недавно узнал, как можно включить вывод одного тега JSP в атрибут другого тега:

<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>

person Community    schedule 26.03.2010    source источник


Ответы (1)


Примечание: мне трудно придумать какие-либо скрытые функции для JSP / Servlet. На мой взгляд, лучшие практики - это лучшая формулировка, и я могу вспомнить любую из них. Это также действительно зависит от вашего опыта работы с JSP / Servlet. Спустя годы разработки вы больше не видите этих скрытых функций. В любом случае, я перечислю некоторые из тех небольших передовых практик, о которых я за долгие годы обнаружил, что многие начинающие не полностью осведомлены об этом. Это было бы классифицировано как скрытые особенности в глазах многих начинающих. Во всяком случае, вот список :)


Скрыть страницы JSP от прямого доступа

Помещая файлы JSP в папку /WEB-INF, вы эффективно скрываете их от прямого доступа, например, http://example.com/contextname/WEB-INF/page.jsp. Это приведет к 404. После этого вы сможете получить к ним доступ только с помощью RequestDispatcher в сервлете. или используя jsp:include.


Предварительный запрос для JSP

Большинство знает о _ 6_ для публикации - обработки запроса (отправки формы), но большинство из них не знают, что вы можете использовать doGet(), чтобы предварительно обработать запрос JSP. Например:

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);
}

который используется для предварительной загрузки некоторых табличных данных, которые должны отображаться с помощью JSTL c:forEach:

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

Сопоставьте такой сервлет с url-pattern из /page (или /page/*) и просто вызовите http://example.com/contextname/page с помощью адресной строки браузера или простой ванильной ссылки для его запуска. См. Также, например, doGet и doPost в сервлетах.


Динамический включает

Вы можете использовать EL в jsp:include:

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

bean.getPage() может просто вернуть действительное имя страницы.


EL может получить доступ к любому получателю

EL сам по себе не требует, чтобы объект, к которому должен быть осуществлен доступ, был полноценным Javabean. Наличие метода no-arg с префиксом get или is более чем достаточно для доступа к нему в EL. Например.:

${bean['class'].name}

Это возвращает значение _21 _ где метод getClass() фактически унаследован от Object#getClass(). Обратите внимание, что class указывается в скобках [] по причинам, указанным здесь instanceof check in Язык выражения EL.

${pageContext.session.id}

Это возвращает значение _27 _ что полезно в ао Может ли апплет взаимодействовать с экземпляром сервлета .

${pageContext.request.contextPath}

Это возвращает значение _29 _ что полезно в ао Как использовать относительные пути без включения корня контекста имя?


EL также может получить доступ к картам

Следующие обозначения EL

${bean.map.foo}

разрешается в bean.getMap().get("foo"). Если ключ Map содержит точку, вы можете использовать нотацию скобок [] с ключом в кавычках:

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

который разрешается в bean.getMap().get("foo.bar"). Если вам нужен динамический ключ, используйте также фигурные скобки, но без кавычек:

${bean.map[otherbean.key]}

который разрешается в bean.getMap().get(otherbean.getKey()).


Итерировать по карте с помощью JSTL

Вы также можете использовать c:forEach для перебирать Map. Каждая итерация дает Map.Entry, который в Turn имеет методы getKey() и getValue() (так что вы можете просто получить к нему доступ в EL с помощью ${entry.key} и ${entry.value}). Пример:

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

См. Также, например, Отладка с помощью jstl - как именно?


Получить текущую дату в JSP

Вы можете получить текущую дату с помощью jsp:useBean и отформатировать ее с помощью JSTL. fmt:formatDate

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

Это печатается (на данный момент) следующим образом: Copyright © 2010.


Легко понятные URL-адреса

Простой способ создать удобный URL-адрес - использовать _ 49_ и JSP скрыты в /WEB-INF:

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

Если вы отобразите этот сервлет, например, на /pages/*, тогда запрос на http://example.com/contextname/pages/foo/bar будет эффективно отображать /WEB-INF/foo/bar.jsp. Вы можете сделать еще один шаг, разделив pathinfo на / и выбрав только первую часть как URL-адрес страницы JSP, а остаток как бизнес-действия (пусть сервлет действует как контроллер страницы). См. Также, например, веб-приложений шаблонов проектирования.


Повторно отображать вводимые пользователем данные с помощью ${param}

Неявный объект EL ${param}, который ссылается на HttpServletRequest#getParameterMap() можно использовать для повторного отображения введенных пользователем данных после отправки формы в JSP:

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

В основном это то же самое, что и request.getParameterMap().get("foo"). См. Также, например, Как можно Я сохраняю значения полей формы HTML в JSP после отправки формы сервлету?
Не забудьте предотвратить XSS! См. Следующую главу.


JSTL для предотвращения XSS

Чтобы предотвратить использование вашего сайта XSS, все, что вам нужно сделать, это (повторно) отобразить < надежные> контролируемые пользователем данные с использованием JSTL _ 61_ или c:out < / а>.

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

Чередование <table> строк с LoopTagStatus

Атрибут varStatus в JSTL c:forEach дает вы LoopTagStatus, вернувшийся в свою очередь, имеет несколько методов получения (которые можно использовать в EL!). Итак, чтобы проверить четность строк, просто проверьте 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>

который фактически закончится

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

Используйте CSS, чтобы задать им другой цвет фона.

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

Заполните строку с разделителями-запятыми из списка / массива с помощью LoopTagStatus:

Еще один полезный метод LoopTagStatus - _75 _:

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

В результате получается что-то вроде item1, item2, item3.


EL функции

Вы можете объявить public static служебные методы как функции EL (например, как JSTL functions), чтобы вы могли использовать их в EL. Например.

package com.example;

public final class Functions {
     private Functions() {}

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

с /WEB-INF/functions.tld, которые выглядят следующим образом:

<?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>

который можно использовать как

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

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

Получить исходный URL-адрес запроса и строку запроса

Если JSP был перенаправлен, вы можете получить исходный URL-адрес запроса,

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

и исходную строку запроса запроса,

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

Вот и все. Может, рано или поздно я добавлю еще.

person Community    schedule 26.03.2010
comment
Это одна из самых обширных записей в Stackoverflow. Никаких уловок, как вы сказали, но хорошие знания и общепринятые методы, которые должен знать каждый достойный внимания. Для чередующихся строк таблицы лучше использовать современный синтаксис CSS и раскрасить с помощью tr: nth-child (even), это сделает ваш HTML-вывод еще чище. - person Photodeus; 11.07.2010
comment
Всегда идеальный мистер БалусC :) - person Muhammad Hewedy; 06.12.2010
comment
Вау, такой информативный ответ и отличные общие практики, огромное спасибо BlausC. - person palAlaa; 12.12.2010
comment
Я слышал, что использование Date для получения года не рекомендуется. Могу ли я использовать Календарь для форматирования? - person itsraja; 21.04.2011
comment
+1 Мой второй фаворит от BalusC после его паттерна дизайна, использованного в JDK. - person zawhtut; 29.04.2011
comment
LoopTagStatus +1 - красиво! - person Wojtek Owczarczyk; 05.11.2011
comment
@BalusC: Может ли jsp также содержать метод do Post? Еще одна вещь: во второй скрытой функции - запрос предварительной обработки, когда вы получаете запрос, вы пересылаете его сразу после добавления новых атрибутов? Как это скрытая функция? Я думаю, вы также можете выполнить предварительную обработку в сервлете. Перед обработкой запроса перенаправьте его другому сервлету или jsp после вставки новых атрибутов в запрос. Я что-то упустил? - person Ashwin; 23.04.2012