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