Скрытые возможности 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>
1 76

1 ответ:

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


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

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


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

большинство из них знают о Сервлет doPost() до post-обработка запроса (форма отправки), но большинство из них не знают, что вы можете использовать сервлет doGet() метод pre - обработка запроса на 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 по адресной строке браузера или ванильное ссылке, чтобы запустить его. См. также, например,метод dopost и doget С в сервлеты.


динамический включает в себя

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

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

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


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

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

${bean['class'].name}

возвращает значение bean.getClass().getName() здесь getClass() метод фактически наследуется от Object#getClass(). Обратите внимание, что class указывается с помощью "скобки нотации"[] по причинам, упомянутым здесь instanceof check in EL expression language.

${pageContext.session.id}

это возвращает значение pageContext.getSession().getId() что полезно в a. o.может ли апплет взаимодействовать с экземпляром сервлета.

${pageContext.request.contextPath}

возвращает значение pageContext.getRequest().getContextPath() что полезно в a. o.как использовать относительные пути без включения корневого имени контекста?


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, который в свою очередь getKey() и getValue() методы (так что вы можете просто получить доступ к нему в EL by ${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-адрес, чтобы использовать HttpServletRequest#getPathInfo() и 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 и остаток как "бизнес-действия" (пусть сервлет действуйте как контроллер страницы). См. также, например,шаблоны проектирования веб-приложений.


Redisplay пользовательский ввод с помощью ${param}

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

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

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


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

чтобы ваш сайт XSS, все, что вам нужно сделать, это (re)display управляемые пользователем данные с помощью JSTL fn:escapeXml или c:out.

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

чередуя <table> строк с LoopTagStatus

The 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 метод isLast():

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

что приводит к чему-то вроде item1, item2, item3.


EL функции

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

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']}

что это было так далеко. Может быть, я добавлю еще немного раньше или позже.