Скрытые возможности JSP/Servlet
Меня интересуют ваши трюки и т. Д., Используемые при написании 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 ответ
Примечание. Мне трудно представить какие-либо "скрытые возможности" для JSP/Servlet. По моему мнению, "лучшие практики" - лучшая формулировка, и я могу думать о любой из них. Это также действительно зависит от вашего опыта работы с JSP/Servlet. После многих лет разработки вы больше не видите этих "скрытых возможностей". В любом случае, я перечислю некоторые из тех маленьких "лучших практик", о которых я за годы узнал, что многие начинающие не полностью осознают это. Они будут классифицированы как "скрытые функции" в глазах многих начинающих. Во всяком случае, вот список:)
Скрыть страницы JSP от прямого доступа
Размещая файлы JSP в /WEB-INF
папка, которую вы эффективно скрываете, например, от прямого доступа http://example.com/contextname/WEB-INF/page.jsp
, Это приведет к 404
, Вы можете получить к ним доступ только через RequestDispatcher
в сервлете или используя jsp:include
,
Запрос предварительной обработки для JSP
Большинство знает о сервлетах doPost()
пост- обработать запрос (отправка формы), но большинство не знает, что вы можете использовать сервлет 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. Наличие метода без аргументов с префиксом get
или же is
более чем достаточно для доступа к нему в EL. Например:
${bean['class'].name}
Это возвращает значение bean.getClass().getName()
где getClass()
Метод на самом деле наследуется от Object#getClass()
, Обратите внимание, что class
указывается с помощью "скобки" []
по причинам, указанным здесь, экземпляр проверки на языке выражений EL.
${pageContext.session.id}
Это возвращает значение pageContext.getSession().getId()
что полезно в ao. Может ли апплет связываться с экземпляром сервлета.
${pageContext.request.contextPath}
Это возвращает значение pageContext.getRequest().getContextPath()
что полезно в ao. Как использовать относительные пути без включения корневого контекста?
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 © 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, а остаток - как "бизнес-действия" (пусть сервлет действует как контроллер страницы). См. Также, например, веб-приложения Design Patterns.
Повторно отобразить пользовательский ввод, используя ${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 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
назад, который в свою очередь имеет несколько методов получения (которые могут быть использованы в 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), так что вы можете использовать их в 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']}
Это было так далеко. Может быть, я добавлю еще рано или поздно.