Вопрос-ответ

How to avoid using scriptlets in my JSP page?

Как избежать использования скриптлетов на моей странице JSP?

Мне сказали, что использование скриптлетов (<%= ... %>) на моих страницах JSP не такая уж отличная идея.

Может кто-нибудь с немного большим опытом работы с java / jsp, пожалуйста, подскажите мне, как изменить этот код, чтобы он был более "оптимальным для практики", каким бы это ни было?

Этот JSP на самом деле является моей главной страницей декоратора sitemesh. В основном в моем веб-дизайне есть полоса вкладок и подменю, и я хочу каким-то образом выделить текущую вкладку и показать правильное подменю, посмотрев на URI текущего запроса.

<%@ taglib uri="http://www.opensymphony.com/sitemesh/decorator" prefix="decorator" %>

<html>
<head>
<title>My Events - <decorator:title /></title>
<link href="<%= request.getContextPath() %>/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
<a
<%= request.getRequestURI().contains("/events/") ? "class='selected'" : "" %>
href='<%= request.getContextPath() %>/events/Listing.action'>Events</a>
<a
<%= request.getRequestURI().contains("/people/") ? "class='selected'" : "" %>
href='<%= request.getContextPath() %>/people/Listing.action'>People</a>
</div>

<div class="submenu">
<% if(request.getRequestURI().contains("/events/")) { %>
<a href="Listing.action">List of Events</a>
|<a href="New.action">New Event</a>
<% } %>
<% if(request.getRequestURI().contains("/people/")) { %>
<a href="Listing.action">List of People</a>
|<a href="New.action">New Person</a>
<% } %>
&nbsp;
</div>

<div class="body">
<decorator:body />
</div>

</body>
</html>

Спасибо всем

Переведено автоматически
Ответ 1

Я думаю, это поможет больше, если вы увидите своими глазами, что это действительно можно сделать полностью без скриптлетов.

Вот переписывание 1 в 1 с помощью, среди прочего, JSTL (просто зайдите jstl-1.2.jar в /WEB-INF/lib) ядра и функций taglib:

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<html>
<head>
<title>My Events - <decorator:title /></title>
<link href="${pageContext.request.contextPath}/assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
<a
${fn:contains(pageContext.request.requestURI, '/events/') ? 'class="selected"' : ''}
href="${pageContext.request.contextPath}/events/Listing.action">
Events</a>
<a
${fn:contains(pageContext.request.requestURI, '/people/') ? 'class="selected"' : ''}
href="${pageContext.request.contextPath}/people/Listing.action">
People</a>
</div>

<div class="submenu">
<c:if test="${fn:contains(pageContext.request.requestURI, '/events/')}">
<a href="Listing.action">List of Events</a>
|<a href="New.action">New Event</a>
</c:if>
<c:if test="${fn:contains(pageContext.request.requestURI, '/people/')}">
<a href="Listing.action">List of People</a>
|<a href="New.action">New Person</a>
</c:if>
&nbsp;
</div>

Вот более оптимизированный вариант перезаписи, обратите внимание, что я использовал c:set для "кэширования" результатов выражения для повторного использования и что я использую HTML <base> тег, чтобы не указывать контекстный путь в каждой ссылке (просто сделайте все относительные URL на вашей веб-странице относительно него - без косой черты!):

<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/functions" prefix="fn" %>

<c:set var="isEvents" value="${fn:contains(pageContext.request.requestURI, '/events/')}" />
<c:set var="isPeople" value="${fn:contains(pageContext.request.requestURI, '/people/')}" />

<html>
<head>
<title>My Events - <decorator:title /></title>
<base href="${pageContext.request.contextPath}">
<link href="assets/styles.css" rel="stylesheet" type="text/css" />
</head>
<body>

<div class="tabs">
<a ${isEvents ? 'class="selected"' : ''} href="events/Listing.action">Events</a>
<a ${isPeople ? 'class="selected"' : ''} href="people/Listing.action">People</a>
</div>

<div class="submenu">
<c:if test="${isEvents}">
<a href="Listing.action">List of Events</a>|<a href="New.action">New Event</a>
</c:if>
<c:if test="${isPeople}">
<a href="Listing.action">List of People</a>|<a href="New.action">New Person</a>
</c:if>
&nbsp;
</div>

На самом деле это можно оптимизировать больше, если вы соберете все эти "жестко запрограммированные" значения, такие как events и people, и свяжете тексты в a Map в области приложения и используете под каждым JSTL <c:forEach> для отображения вкладок.

Что касается вашего актуального вопроса, вы можете отключить скриптлеты (и получать ошибки времени выполнения при их использовании), добавив следующую запись в webapp web.xml. Это может помочь определить наблюдаемые скриптлеты.

<jsp-config>
<jsp-property-group>
<url-pattern>*.jsp</url-pattern>
<scripting-invalid>true</scripting-invalid>
</jsp-property-group>
</jsp-config>

Чтобы узнать больше об EL, ознакомьтесь с руководством по Java EE, часть II, глава 5. Неявные объекты EL, такие как ${pageContext} описаны здесь. Чтобы узнать больше о JSTL, ознакомьтесь с руководством по Java EE, часть II, глава 7. Обратите внимание, что JSTL и EL - это две разные вещи. JSTL - это стандартный taglib, а EL просто позволяет программно обращаться к внутренним данным. Хотя он обычно используется в taglibs, таких как JSTL, его также можно использовать отдельно в тексте шаблона.

Ответ 2

Кроме того, является <%= request.getContextPath() %> приемлемым использованием скриптлетов, к которому не так часто относятся неодобрительно?


Это может быть непопулярное мнение, но если все, что вы делаете, это простые условные обозначения и вставки текста, я не могу найти особых недостатков в использовании скриптлетов. (Обратите внимание на если)

Я бы, вероятно, использовал JSTL и язык выражений, но в основном потому, что на нем можно меньше печатать, а поддержка IDE может быть лучше (но хорошая JSP IDE также может обнаружить отсутствующие закрывающие скобки и тому подобное).

Но принципиально (как в "не использовать логику в шаблонах") Я не вижу никакой разницы между

<% if(request.getRequestURI().contains("/events/")) { %>

и

${fn:contains(pageContext.request.requestURI, '/events/') 
Ответ 3

Скриптлеты - не самая плохая вещь в мире. Важное соображение - подумать о том, кто будет поддерживать код. Если его веб-дизайнеры не имеют большого опыта работы с Java, вам, вероятно, лучше использовать библиотеки тегов. Однако, если сопровождением занимаются разработчики Java, им может быть проще перейти на скриптлеты.

Если вы в конечном итоге используете библиотеку тегов и JSTL, вы ожидаете, что сопровождающий также изучит библиотеку тегов и будет знать JSTL. Некоторых разработчиков это устроит, поскольку они хотят или уже обладают этим навыком, но для некоторых разработчиков, которым приходится иметь дело с JSP только раз в несколько месяцев или около того, может быть намного менее болезненной работа с четко написанными скриптлетами, написанными на приятной, знакомой Java.

Ответ 4

Это не прямой ответ на ваш вопрос (и уже есть несколько хороших ответов, поэтому я не буду пытаться дополнять его), но вы упомянули:


Может кто-нибудь с немного большим опытом работы с java / jsp, пожалуйста, подскажите мне, как изменить этот код, чтобы он был более "оптимальным для практики", каким бы это ни было?


На мой взгляд, наилучшей практикой в отношении JSP является то, что его следует использовать строго как механизм создания шаблонов, и не более (т. Е. В нем нет бизнес-логики). Использование JSTL, как многие отмечали, определенно помогает вам достичь этого, но даже с JSTL многое легко сделать в JSP.

Лично мне нравится следовать правилам, изложенным в Обеспечении строгого разделения моделей и представлений в движках создания шаблонов Теренсом Парром при разработке на JSP. В статье упоминается назначение движков шаблонов (разделение модели и представления) и характеристики хорошего движка шаблонов. В ней подробно рассматривается JSP и указывается, почему он не является хорошим движком шаблонов. Неудивительно, что JSP в основном слишком мощный и позволяет разработчикам делать слишком много. Я настоятельно рекомендую прочитать эту статью, она поможет вам ограничиться "хорошими" частями JSP.

Если вы читаете только один раздел в этой статье, прочтите главу 7, которая включает следующие правила:



  1. представление не может изменять модель ни путем прямого изменения объектов данных модели, ни путем вызова методов в модели, которые вызывают побочные эффекты. То есть шаблон может обращаться к данным из модели и вызывать методы, но такие ссылки не должны вызывать побочных эффектов. Это правило частично возникает из-за того, что ссылки на данные не зависят от порядка. Смотрите Раздел 7.1.

  2. представление не может выполнять вычисления для зависимых значений данных потому что вычисления могут измениться в будущем, и в любом случае они должны быть аккуратно инкапсулированы в модель. Например, представление не может вычислять цены продажи книг как “цена в долларах * .90”. Чтобы быть независимым от модели, представление не может делать предположения о значении данных.

  3. представление не может сравнивать зависимые значения данных, но может проверять свойства данных, такие как наличие / отсутствие или длину многозначного значения данных. Тесты типа $ BloodPressure<120 должны быть перенесены в модель, поскольку врачи предпочитают продолжать снижать максимальное систолическое давление у нас. Выражения в представлении должны быть заменены тестом на наличие значения, имитирующего логическое значение, такого как $bloodPressureOk!= null Вывод шаблона может быть обусловлен данными модели и вычислениями, условие просто должно быть вычислено в модели. Даже простые тесты, которые выделяют отрицательные значения красным цветом, должны быть вычислены в модели; правильный уровень абстракции обычно представляет собой что-то более высокое, например, “отдел x теряет деньги”.

  4. представление не может делать предположения о типе данных. Некоторые предположения о типах очевидны, когда представление предполагает, что значением данных является дата, например, но возможны более тонкие предположения о типах: если шаблон предполагает, что $userId является целым числом, разработчик не может изменить это значение на нечисловое в модели, не нарушая шаблон. Это правило запрещает индексирование массива, такое как ColorCode [$ topic] и $ name [$ ID] Представление также не может вызывать методы с аргументами, потому что (статически или динамически) предполагается тип аргумента, если только нельзя гарантировать, что метод модели просто рассматривал их как объекты. Кроме того, графические дизайнеры не программисты; ожидать, что они будут вызывать методы и знать, что передавать, нереально.

  5. Данные из модели не должны содержать информацию об отображении или компоновке. Модель не может передавать в представление какую-либо информацию об отображении, замаскированную под значения данных. Это включает в себя отказ от передачи имени шаблона для применения к другим значениям данных.


Кстати, Теренс создал свой собственный движок для создания шаблонов под названием String Template, который, предположительно, действительно хорошо справляется с обеспечением соблюдения этих правил. У меня нет личного опыта работы с этим, но я хотел бы проверить это в моем следующем проекте.

java jsp