Ответ 1
Примечание. Мне сложно думать о каких-либо "скрытых функциях" для JSP/Servlet. По-моему, "лучшие практики" - лучшая формулировка, и я могу думать о любом из них. Это также зависит от вашего опыта работы с JSP/Servlet. После многих лет развития вы больше не видите эти "скрытые возможности". В любом случае, я перечислил некоторые из тех небольших "лучших практик", о которых я в течение многих лет обнаружил, что многие стартеры не знают об этом полностью. Они будут классифицированы как "скрытые возможности" в глазах многих стартеров. Во всяком случае, вот список:)
Скрыть страницы JSP из прямого доступа
Поместив JSP файлы в папку /WEB-INF
, вы можете скрыть их от прямого доступа, например, http://example.com/contextname/WEB-INF/page.jsp
. Это приведет к 404
. Затем вы можете получить к ним доступ только с помощью RequestDispatcher
в Servlet или используя jsp:include
.
Запрос на предварительный запрос для JSP
Большинство из нас знают о Servlet doPost()
в пост -процесс запроса (форма отправки), но большинство из них не знают, что вы можете использовать метод Servlet 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
по адресной строке браузера или простой ванильной ссылке для ее запуска. См. Также, например. doGet и doPost в сервлетах.
Динамический включает
Вы можете использовать EL в jsp:include
:
<jsp:include page="/WEB-INF/${bean.page}.jsp" />
bean.getPage()
может просто вернуть действительное имя файла.
EL может получить доступ к любому получателю
EL не требует, чтобы объект для доступа был полноправным джавабеем. Наличие метода no-arg с префиксом get
или is
более чем достаточно для доступа к нему в EL. Например:.
${bean['class'].name}
Это возвращает значение bean.getClass().getName()
, где метод getClass()
фактически унаследован от Object#getClass()
. Обратите внимание, что class
указывается с использованием "символа привязки" []
по указанным здесь причинам instanceof для проверки на языке экспрессии EL.
${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 ${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 © <fmt:formatDate value="${date}" pattern="yyyy" /></p>
Это печатает (на данный момент), как показано ниже: "Copyright & copy; 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, а остаток - как "бизнес-действия" (пусть сервлет действует как контролер страницы). См. Также, например. Веб-приложения с шаблонами проектирования.
Повторный ввод пользовательского ввода с помощью ${param}
Неявный EL-объект ${param}
, который ссылается на HttpServletRequest#getParameterMap()
, может использоваться для повторного отображения пользовательского ввода после отправки формы в JSP
<input type="text" name="foo" value="${param.foo}">
В основном это означает, что request.getParameterMap().get("foo")
. См. Также, например. Как сохранить значения полей формы HTML в JSP после отправки формы в Servlet?
Не забудьте предотвратить XSS! См. Следующую главу.
JSTL для предотвращения XSS
Чтобы ваш сайт не был XSS, все, что вам нужно сделать, - это (re) показать пользовательский > данные с использованием JSTL fn:escapeXml
или 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
назад, который, в свою очередь, имеет несколько методов getter (которые можно использовать в 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; }
Заполнять commasepared строку из List/Array с помощью LoopTagStatus
:
Другим полезным LoopTagStatus
является isLast()
:
<c:forEach items="${items}" var="item" varStatus="loop">
${item}${!loop.last ? ', ' : ''}
<c:forEach>
Это приводит к чему-то вроде item1, item2, item3
.
EL-функции
Вы можете объявить методы утилиты public static
как функции EL (например, JSTL функции), чтобы вы могли использовать их в 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']}
Это было так далеко. Может быть, я добавлю еще более рано или поздно.