З специфікації JSP 1.2, настійно рекомендується використовувати бібліотеку стандартних тегів JSP (JSTL) у вашій веб-програмі, щоб зменшити потребу в JSP-скриптах на ваших сторінках. Сторінки, які використовують JSTL, в цілому легше читати та підтримувати.
...
Де можливо, уникайте сценаріїв JSP, коли бібліотеки тегів забезпечують еквівалентну функціональність. Це робить сторінки простішими для читання та обслуговування, допомагає відділити ділову логіку від логіки презентації, а ваші сторінки легше перетворюються на сторінки в стилі JSP 2.0 (специфікація JSP 2.0 підтримує, але не підкреслює використання сценаріїв).
...
В дусі прийняття моделі дизайну-контролера (MVC) для зменшення зв'язку між рівнем презентації та бізнес-логікою сценарії JSP не повинні використовуватися для написання бізнес-логіки. Скоріше, сценарії JSP використовуються при необхідності для перетворення даних (також званих "об'єктами цінності"), повернених після обробки запитів клієнта, у належний готовий для клієнтів формат. Вже тоді це краще зробити з сервлетом переднього контролера або спеціальним тегом.
Якщо ви хочете викликати один і той же код Java на кожен запит, менший або більше, незалежно від запитуваної сторінки, наприклад, перевірити, чи користувач увійшов у систему, тоді застосуйте фільтр і запишіть код відповідно doFilter()
методом. Наприклад:
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws ServletException, IOException {
if (((HttpServletRequest) request).getSession().getAttribute("user") == null) {
((HttpServletResponse) response).sendRedirect("login"); // Not logged in, redirect to login page.
} else {
chain.doFilter(request, response); // Logged in, just continue request.
}
}
Якщо їх відображено на відповідних <url-pattern>
сторінках, що цікавлять сторінки JSP, вам не потрібно копіювати один і той же фрагмент коду загальних сторінок JSP.
Якщо ви хочете викликати якийсь код Java для попередньої обробки запиту, наприклад, попередньо завантаживши якийсь список із бази даних для відображення в якійсь таблиці, якщо необхідно на основі деяких параметрів запиту, тоді реалізуйте сервлет і запишіть код відповідно doGet()
методом. Наприклад:
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
List<Product> products = productService.list(); // Obtain all products.
request.setAttribute("products", products); // Store products in request scope.
request.getRequestDispatcher("/WEB-INF/products.jsp").forward(request, response); // Forward to JSP page to display them in a HTML table.
} catch (SQLException e) {
throw new ServletException("Retrieving products failed!", e);
}
}
Цей спосіб поводження з винятками простіше. Доступ до БД не відбувається в середині візуалізації JSP, але набагато до того, як буде показано JSP. Ви все ще маєте можливість змінювати відповідь, коли доступ до БД кидає виняток. У наведеному вище прикладі відображатиметься сторінка помилки за замовчуванням 500 сторінок, яку ви все одно можете налаштувати <error-page>
в web.xml
.
Якщо ви хочете викликати якийсь код Java для обробки після запиту, наприклад, обробку форми подання, тоді реалізуйте сервлет і запишіть код відповідно doPost()
методом. Наприклад:
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
String username = request.getParameter("username");
String password = request.getParameter("password");
User user = userService.find(username, password);
if (user != null) {
request.getSession().setAttribute("user", user); // Login user.
response.sendRedirect("home"); // Redirect to home page.
} else {
request.setAttribute("message", "Unknown username/password. Please retry."); // Store error message in request scope.
request.getRequestDispatcher("/WEB-INF/login.jsp").forward(request, response); // Forward to JSP page to redisplay login form with error.
}
}
Таким чином , має справу з різними напрямками сторінки результату простіше: повторне відображенням форми з помилками перевірки в разі помилки (в даному прикладі ви можете повторно відобразити з допомогою ${message}
в EL ), або просто приймати до бажаної цільової сторінці в разі успіху.
Якщо ви хочете викликати якийсь код Java для управління планом виконання та / або призначенням запиту та відповіді, тоді реалізуйте сервлет відповідно до шаблону переднього контролера MVC . Наприклад:
protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
Action action = ActionFactory.getAction(request);
String view = action.execute(request, response);
if (view.equals(request.getPathInfo().substring(1)) {
request.getRequestDispatcher("/WEB-INF/" + view + ".jsp").forward(request, response);
} else {
response.sendRedirect(view);
}
} catch (Exception e) {
throw new ServletException("Executing action failed.", e);
}
}
Або просто прийняти рамку MVC на зразок JSF , Spring MVC , Wicket тощо, щоб ви закінчилися лише сторінкою JSP / Facelets та класом JavaBean без необхідності користувацького сервлета.
Якщо ви хочете викликати якийсь код Java для управління потоком всередині сторінки JSP, вам потрібно схопити (існуючий) таліг управління потоком, як ядро JSTL . Наприклад, відображення List<Product>
в таблиці:
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
...
<table>
<c:forEach items="${products}" var="product">
<tr>
<td>${product.name}</td>
<td>${product.description}</td>
<td>${product.price}</td>
</tr>
</c:forEach>
</table>
З тегами XML-стилів, які добре вписуються серед усіх цих HTML, код краще читається (і, таким чином, краще піддається обробці), ніж купа сценаріїв з різними дужками відкриття та закриття ( "Куди, до біса, належить ця закриваюча дужка?" ). Простий посібник - налаштувати веб-додаток, щоб викинути виняток, коли сценарії все ще використовуються, додаючи наступний фрагмент до web.xml
:
<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>
У Facelets , наступник JSP, який є частиною Java EE при умови MVC Framework JSF , це вже НЕ можливо використовувати скріптлет . Таким чином ви автоматично змушені робити речі "правильним способом".
Якщо ви хочете викликати якийсь код Java для доступу та відображення даних "задніх днів" всередині сторінки JSP, тоді вам потрібно використовувати EL (мову вираження) ${}
. Наприклад, повторне відображення поданих вхідних значень:
<input type="text" name="foo" value="${param.foo}" />
В ${param.foo}
відображає підсумковий документ request.getParameter("foo")
.
Якщо ви хочете , щоб викликати деякі утиліти Java код безпосередньо на сторінці JSP (зазвичай public static
методи) то вам необхідно визначити їх як функції EL. У JSTL є стандартний таліб функцій , але ви також можете легко створювати функції самостійно . Ось приклад того, як JSTL fn:escapeXml
корисний для запобігання XSS- атак .
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>
...
<input type="text" name="foo" value="${fn:escapeXml(param.foo)}" />
Зауважте, що чутливість XSS жодним чином не пов'язана з Java / JSP / JSTL / EL / будь-якою, цю проблему потрібно враховувати у кожному веб-додатку, який ви розробляєте. Проблема сценаріїв полягає в тому, що вони не забезпечують вбудованих запобіжників, принаймні, не використовують стандартний Java API. Наступник Facelet у JSP вже невірно вийшов з HTML, тому вам не потрібно турбуватися про отвори XSS у Facelets.