Как избежать использования скриптлетов на моей странице 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>

Спасибо всем


person Chris    schedule 02.02.2010    source источник
comment
Кстати, является ли «‹% = request.getContextPath ()% ›» приемлемым использованием скриптлетов, на которое не так сильно возражают?   -  person Chris    schedule 03.02.2010
comment
Вам следует начать использовать фейслеты для создания шаблонов. Заставляет вас правильно кодировать.   -  person Andrew Dyster    schedule 03.02.2010
comment
Вы говорите, что вместо Sitemesh используйте фейслеты?   -  person Chris    schedule 03.02.2010
comment
возможный дубликат stackoverflow .com / questions / 3177733 /   -  person Bozho    schedule 21.10.2010


Ответы (7)


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

Вот перезапись один на один с помощью, среди прочего, 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, и свяжете тексты в Map в области приложения и будете использовать под каждым JSTL <c:forEach> для отображения вкладок.

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

<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 - это стандартная библиотека тегов, а EL просто позволяет программно получить доступ к внутренним данным. Хотя он обычно используется в библиотеках тегов, таких как JSTL, его также можно использовать отдельно в тексте шаблона.

person BalusC    schedule 03.02.2010
comment
Если вы сравните шаблоны до и после, вы увидите, что они почти одинаковы. Я не понимаю, почему последнее автоматически лучше, чем первое (кроме того, что выглядит немного чище). - person Ree; 15.07.2010
comment
@Ree - Честно говоря, я думаю, что самым большим преимуществом JSTL является то, что он не дает вам свободы писать любой код, который приходит на ум в вашем JSP. JSTL предоставляет вам большинство инструментов, необходимых для написания шаблонов, но не контроллеров, менеджеров бизнес-логики или объектов доступа к данным. - person RustyTheBoyRobot; 08.06.2012

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

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

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

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

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

и

${fn:contains(pageContext.request.requestURI, '/events/') 
person Thilo    schedule 03.02.2010
comment
Ок, отлично! Я думал, что я единственный, кто придерживается такого мнения! - person Chris; 03.02.2010
comment
Я думаю, что контекст здесь - одна из лучших практик, которая особенно важна, когда вы не единственный, кто разрабатывает или поддерживает шаблон. Несмотря на то, что функционально в вашем примере нет никакой разницы, вы установили приоритет использования скриптлетов, и кто-то, кто не знает, может добавить какой-то произвольный Java-код, который изменяет состояние модели. Просто надо подумать. Мне нравится идея отключить их, как упоминалось выше BalusC. - person Cole Stanfield; 27.11.2012

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

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

person Spike Williams    schedule 03.02.2010

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

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

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

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

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

  1. представление не может изменять модель, напрямую изменяя объекты данных модели или вызывая методы модели, вызывающие побочные эффекты. То есть шаблон может получать доступ к данным из модели и вызывать методы, но такие ссылки не должны иметь побочных эффектов. Это правило возникает частично из-за того, что ссылки на данные должны быть нечувствительными к порядку. См. Раздел 7.1.
  2. представление не может выполнять вычисления на основе зависимых значений данных, потому что вычисления могут измениться в будущем, и в любом случае они должны быть аккуратно инкапсулированы в модель. Например, представление не может вычислить цены продажи книг как «цена в долларах * 0,90». Чтобы быть независимым от модели, представление не может делать предположений о значении данных.
  3. представление не может сравнивать зависимые значения данных, но может проверять такие свойства данных, как наличие / отсутствие или длину многозначного значения данных. Такие тесты, как $ bloodPressure ‹120, необходимо перенести в модель, поскольку врачи стараются снижать максимальное систолическое давление на нас. Выражения в представлении должны быть заменены тестом на наличие значения, имитирующего логическое значение, например $ bloodPressureOk! = Null Вывод шаблона может зависеть от данных модели и вычислений, условное выражение просто должно быть вычислено в модели. . Даже простые тесты, которые делают отрицательные значения красными, должны быть вычислены в модели; правильный уровень абстракции - это обычно что-то более высокое, например, «отдел x теряет деньги».
  4. представление не может делать предположения о типе данных. Некоторые предположения о типах очевидны, когда представление предполагает, что значением данных является, например, дата, но появляются более тонкие предположения о типах: если шаблон предполагает, что $ userID является целое число, программист не может изменить это значение на нечисловое в модели без нарушения шаблона. Это правило запрещает индексирование массивов, например colorCode [$ topic] и $ name [$ ID]. Кроме того, представление не может вызывать методы с аргументами, потому что (статически или динамически) существует предполагаемый тип аргумента, если только нельзя гарантировать модель метод просто рассматривал их как объекты. Кроме того, графические дизайнеры не программисты; ожидать, что они вызовут методы и будут знать, что передать, нереально.
  5. данные из модели не должны содержать информацию об отображении или макете. Модель не может передавать какую-либо отображаемую информацию в представление, замаскированное под значения данных. Это включает в себя отказ от передачи имени шаблона для применения к другим значениям данных.

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

person Jack Leow    schedule 03.02.2010

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

e.g.

  <c:if test="${your condition}">
       Your Content
  </c:if>

заменит ваши операторы if.

person Vincent Ramdhanie    schedule 03.02.2010

Предпочтительной альтернативой скриптлетам является язык выражений JSTL; здесь - хороший обзор. Вам нужно будет добавить taglib следующим образом:

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

Например, JSTL предоставляет набор неявных объектов, которые дают вам то, что вам нужно; тот, который вам нужен, pageContext.request.

Таким образом, вы можете заменить <%request.getRequestURI%> на ${pageContext.request.requestURI}.

Вы можете выполнять условные выражения, используя теги <c:if>.

person Jacob Mattison    schedule 03.02.2010
comment
JSTL! = Язык выражений. JSTL - это стандартная библиотека тегов java.sun.com/products/jsp/ jstl / 1.1 / docs / tlddocs Язык выражений - это ${} вещи java.sun.com/javaee/5/docs/tutorial/doc/bnahq.html - person BalusC; 03.02.2010
comment
На будущее: мне повезло больше с 'java.sun.com/jsp/jstl/ core 'в моем taglib uri (вместо java.sun.com/jstl/core) - person Chris; 03.02.2010
comment
/ Jsp / -less uri действительно является частью JSTL 1.0 десятилетней давности. Не используйте это. - person BalusC; 03.02.2010

Вам нужно будет использовать веб-фреймворк. Или хоть какой-нибудь удобный таглиб. Или инструмент для создания шаблонов, например FreeMarker.

Рекламные рамки:

Если вам нравится способ кодирования JSP, я бы посоветовал Распорки 2.

<s:if test="%{false}">
    <div>Will Not Be Executed</div>
</s:if>
<s:elseif test="%{true}">
    <div>Will Be Executed</div>
</s:elseif>
<s:else>
    <div>Will Not Be Executed</div>
</s:else>

Затем есть компонентно-ориентированный JSF.

Если вам нравится ООП и все кодируется на Java, попробуйте Apache Wicket (мой любимый ) или Google Web Toolkit.

person Ondra Žižka    schedule 03.02.2010
comment
Я использую struts2, если это помогает. - person Chris; 03.02.2010
comment
Теперь объедините его с библиотеками тегов, такими как JSTL, предложенными Винсентом, и вы избавитесь от скриптлетов. См. Здесь: struts.apache.org/2.1.8.1/docs/tag -reference.html, и там вы найдете, среди прочего, struts.apache.org/2.1.8.1/docs/text.html - person Ondra Žižka; 03.02.2010