Как избежать использования скриптлетов на моей странице JSP? - PullRequest
32 голосов
/ 03 февраля 2010

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

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

Этот JSP на самом деле является моей главной страницей декоратора. В основном мой веб-дизайн имеет полосу вкладок и подменю, и я хочу как-то выделить текущую вкладку и показать правильное подменю, посмотрев текущий 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>

Спасибо всем

Ответы [ 7 ]

42 голосов
/ 03 февраля 2010

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

Вот перезапись 1 на 1 с помощью, среди прочего, JSTL (просто сбросьте jstl-1.2.jar в /WEB-INF/lib) core и functions 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 веб-приложения.Это может помочь обнаружить закулисные скриптлеты.

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

9 голосов
/ 03 февраля 2010

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

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

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

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

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

и

${fn:contains(pageContext.request.requestURI, '/events/') 
6 голосов
/ 03 февраля 2010

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

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

6 голосов
/ 03 февраля 2010

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

Может кто-нибудь с немного большим количеством Java / JSP опыт, пожалуйста, дайте мне немного указатели относительно того, как изменить этот код так что это больше «лучшая практика», что угодно это может быть ?

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

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

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

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

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

3 голосов
/ 03 февраля 2010

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

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

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

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

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

3 голосов
/ 03 февраля 2010

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

, например

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

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

2 голосов
/ 03 февраля 2010

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

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

Если вам нравится JSP-способ кодирования, я бы предложил Struts 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 .

...