Из спецификации 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>
in 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, то вам нужно получить (существующий) taglib управления потоком, такой как ядро 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 (Expression Language), эти ${}
вещи. Например, повторное отображение введенных значений ввода:
<input type="text" name="foo" value="${param.foo}" />
В ${param.foo}
отображает итоговый документ request.getParameter("foo")
.
Если вы хотите вызывать некоторый служебный Java-код непосредственно на странице JSP (обычно это public static
методы), то вам нужно определить их как функции EL. В JSTL есть стандартные функции taglib , но вы также можете легко создавать функции самостоятельно . Вот пример того, как 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. Преемник JSP Facelets уже неявно экранирует HTML, поэтому вам не нужно беспокоиться о дырах XSS в Facelets.