Примітка: Мені важко придумати будь-які "приховані функції" для 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']}
На цьому все було. Можливо, я рано чи пізно додам ще трохи.