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

Мне сказали, что использование скриптлетов (<% =...%>) на моих страницах 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 ответов

Решение

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

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

As to your actual question, you can disable scriptlets (and get runtime errors about using it) by adding the following entry in webapp's web.xml, It may help to spot overseen scriptlets.

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

To learn more about EL, check the Java EE tutorial part II chapter 5. Implicit EL objects, such as ${pageContext} are described here. To learn more about JSTL, check the Java EE tutorial part II chapter 7. Note that JSTL and EL are two separate things. JSTL is a standard taglib and EL just enables to access backend data programmatically. Although it is normally used in taglibs like JSTL, it can also be used standalone in template text.

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

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

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

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

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

а также

${fn:contains(pageContext.request.requestURI, '/events/') 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

например

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

заменит ваши заявления if.

Вам нужно будет использовать некоторые веб-рамки. Или хотя бы какой-нибудь удобный 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.

Другие вопросы по тегам