Примітка: Мені важко придумати будь-які "приховані функції" для JSP / Servlet. На мою думку, "найкращі практики" - це краща формулювання, і я можу думати про будь-яку з них. Це також дійсно залежить від вашого досвіду роботи з JSP / сервлетом. Після багатьох років розвитку ви більше не бачите цих "прихованих функцій". У будь-якому випадку я перелічу деякі з тих маленьких "найкращих практик", про які я роками виявив, що багато початківців цього не до кінця знають. Вони б класифікувались як "приховані особливості" в очах багатьох початківців. У будь-якому разі, ось список :)
Приховати сторінки 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/*
) і просто Invoke 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}
Це повертає значення, 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
ітерацію над a 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
та відформатувати за допомогою JSTLfmt: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, а залишок як "ділові дії" (нехай сервлет виступає в ролі контролера сторінки ). Див. Також, наприклад, веб-додатки для дизайну .
Повторно відобразити введення користувача за допомогою ${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 , все, що вам потрібно зробити, це (повторно) відображати керовані користувачем дані за допомогою 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']}
На цьому все було. Можливо, я рано чи пізно додам ще трохи.