Соглашения в коде JavaServer Pages


Соглашения в коде JavaServer Pages


Окончание. Начало в КГ №11.

JSP-объявления

Как и соглашения, принятые в Java-коде, каждое объявление переменной в JSP, пусть даже одного и того же типа, необходимо размещать на разных строках:

Не рекомендуется Рекомендуется
<%! private int x, y; %> <%! private int x; %>

<%! private int y; %>
JavaBean'ы не должны декларироваться или устанавливаться при помощи JSP-объявлений, поскольку для этой цели предназначен тэг <jsp:useBean>.

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

JSP-скриптлеты

По возможности следует избегать использования JSP-скриптлетов, в особенности когда библиотеки тэгов предоставляют эквивалентные функции. Такой подход делает страницы более читабельными и помогает отделить бизнес-логику от презентационной части/логики. Помимо этого ваши страницы будет очень просто переписать в стиле JSP версии 2.0 (хотя в JSP 2.0 есть поддержка скриптлетов, но их использование в этой спецификации всячески не приветствуется). В следующих примерах для каждого типа данных, которым представляется набор заказчиков, необходимо писать отдельный скриптлет:

customers как массив объектов Customer

<table>

<% for (int i=0; i<customers.length; i++) { %>

<tr>

<td><%= customers[i].getLastName() %></td>

<td><%= customers[i].getFirstName() %></td>

</tr>

<% } %>

</table>

customers как экземпляр класса Enumeration

<table>

<% for (Enumeration e = customers.elements();

e.hasMoreElements();) {

Customer customer = (Customer)e.nextElement();

%>

<tr>

<td><%= customer.getLastName() %></td>

<td><%= customer.getFirstName() %></td>

</tr>

<% } %>

</table>

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

<table>

<c:forEach var="customer" items="${customers}">

<tr>

<td><c:out value="${customer.lastName}"/></td>

<td><c:out value="${customer.firstName}"/></td>

</tr>

</c:forEach>

</table>

Это в духе применения шаблона проектирования MVC (model-view-controller) для послабления связи между презентационным ярусом и бизнес-логикой, поскольку JSP-скриптлеты вообще не должны использоваться для описания бизнес-логики. JSP-скриптлеты предпочтительнее использовать, если необходимо, для трансформирования данных (также иногда эти данные называют "объектами значений"), возвращаемых от обработанных клиентских запросов в подходящий, удобный формат. Но даже здесь лучше всего воспользоваться библиотекой тэгов или же отдельным сервлетом-контроллером. Например, следующий код получает имена заказчиков (customers) напрямую из базы данных и отображает их клиенту:

<%

// ЭТО НЕ РЕКОМЕНДУЕТСЯ ДЕЛАТЬ В ВИДЕ СКРИПТЛЕТА

Connection conn = null;

try {

// Получаем объект Connection

InitialContext ctx = new InitialContext();

DataSource ds = (DataSource)ctx.lookup("customerDS");

conn = ds.getConnection();

// Получаем имена заказчиков

Statement stmt = conn.createStatement();

ResultSet rs = stmt.executeQuery("SELECT name FROM customer");

// Выводим имена

while (rs.next()) {

out.println(rs.getString("name") + "<br>");

}

} catch (SQLException e) {

out.println("Невозможно получить имена заказчиков из базы данных:" + e);

} finally {

if (conn!= null)

conn.close();

}

%>

Следующий сегмент JSP-кода будет намного лучше, если он делегирует функцию работы с базой данных custom-тэгу myTags:dataSource, который инкапсулирует и прячет все детали работы с базой данных в своей реализации:

<myTags:dataSource

name="customerDS"

table="customer"

columns="name"

var="result" />

<c:forEach var="row" items="${result.rows}">

<c:out value="${row.name}" />

<br />

</c:forEach>

result — это скриптовая переменная, введенная custom-тэгом myTags:dataSource для того, чтобы хранить полученные данные об именах заказчиков из базы данных. JSP-код также может быть более эффективным при условии поддержки сразу нескольких различных выходных форматов данных (HTML, XML, WML), которые определяются динамически в зависимости от потребностей клиента, без всяких угроз в сторону backend-кода (для тэга dataSource). Однако лучше всего было бы делегировать эту функцию на отдельный сервлет, который обрабатывал бы полученные данные и представлял результат для JSP-страницы посредством параметров-атрибутов.

Подведем некоторый итог касательно JSP-скриптлетов:

  • JSP-скриптлеты в идеале вообще не должны присутствовать на JSP-странице, поскольку JSP — это скриптовый язык, и реализация бизнес-логики средствами JSP просто недопустима.
  • Использование библиотеки custom-тэгов всегда приветствуется, когда возможна обработка данных на стороне сервера.
  • Используйте объекты значений (value objects) (JavaBeans) для получения или посылки данных на стороне сервера, а скриптлеты используйте для трансформации этих объектов в различные форматы вывода для клиента.
  • JSP-выражения

    JSP-выражения должны применяться так же аккуратно, как и JSP-скриптлеты. Чтобы понять, почему так, давайте рассмотрим три следующих примера, которые выполняют одинаковые функции:

    Пример 1 (Java-код):

    <%= myBean.getName() %>

    Пример 2 (JSP-тэг):

    <jsp:getProperty name="myBean" property="name" />

    Пример 3 (JSTL-тэг):

    <c:out value="${myBean.name}" />

    В первом примере предполагается, что переменная myBean уже определена. В остальных двух предполагается, что переменная myBean — это атрибут, который может быть найден с использованием метода PageContext.findAttribute(). Кроме того, второй пример также предполагает, что переменная myBean была введена на этой странице при помощи тэга <jsp:useBean>.

    Из трех этих примеров предпочтение следует отдать третьему. Во-первых, третий вариант достаточно короток, чтобы сойти за JSP-выражение, во-вторых, его проще понять, и, в-третьих, он имеет мало общего с JSP-скриптлетами (которые предполагают, что web-разработчик знаком с языком Java, а также с основными API-вызовами). Более того, это позволяет странице больше походить на стиль JSP 2.0, где, для того чтобы выполнить аналогичную функцию, достаточно следующего кода: "${myBean.name}" в тексте шаблона. Какой бы пример ни применялся, он должен быть одобрен и согласован всеми web-разработчиками и быть последовательным во всех создаваемых JSP-страницах одного проекта. Также следует отметить, что третий пример, с использованием JSTL, несколько отличается от остальных тем, что получает значение myBean из контекста страницы, а не из локальной Java-переменной.

    И, наконец, предпочтительнее использовать JSP-выражения вместо эквивалентных JSP-скриптлетов, которые основываются на своем скриптовом языке. Например:

    <%= x %>

    лучше, чем

    <% out.print(x); %>


    Пустые линии и пробелы

    Пробельные символы обычно используются для того, чтобы сделать JSP-код более красивым, а также упростить процесс поддержки и изучения этого кода. В частности, пустые линии и пробелы должны присутствовать на JSP-страницах в местах, где имеет смысл их вставлять.


    Пустые линии

    Пустые линии обычно используются для улучшения точности и разборчивости JSP-страниц. Важно также, что пустые строки не вызывают каких-либо побочных эффектов для выходного формата. Например, ниже приведены два JSP-выражения, которые разделены пустой строкой и заключены в HTML-тэг <PRE>. В этом случае между результатами данных выражений на странице в браузере пользователя будет вставлена дополнительная пустая строка, как это было на самой JSP-странице до ее обработки. Однако, если блок тегов <PRE> отсутствует, то эта дополнительная пустая строка никак не скажется на внешнем виде результативной HTML-страницы в браузере пользователя.


    JSP-выражения
    Вид в браузере пользователя
    <pre>

    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>

    </pre>
    Joe

    Block
    <pre>

    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>

    </pre>
    Joe

    Block

    <%= customer.getFirstName() %>

    <%= customer.getLastName() %>
    Joe Block


    Пробелы

    Символ пробела всегда должен присутствовать между самим JSP-тэгом и его содержимым. Например:

    <%= customer.getName() %>

    выглядит куда лучше, чем

    <%=customer.getName()%>

    Также присутствие пробельных символов желательно для разделения тэга комментария и самого комментария:

    <%—

    - многостроковый комментарий, который разбит

    - на две строки.

    —%>

    <%— короткий комментарий в одну строку —%>


    Именные соглашения

    Применяя именные соглашения, вы обеспечиваете элементам вашего web-компонента простоту идентификации, классифицирования и координации в проектах. В этой части статьи мы рассмотрим те именные соглашения, которые так или иначе касаются JSP.


    Имена JSP-файлов

    Имена JSP-файлов всегда должны начинаться с букв в нижнем регистре. Имя может состоять из нескольких слов. В таком случае каждое последующее слово (исключая начальное) следует начинать с заглавной буквы. Имя JSP-файла может быть как простым глаголом, так и небольшим предложением. Однако имен, состоящих только лишь из одного глагола, следует избегать, поскольку такие имена не несут в себе никакой информации для разработчиков. Например:

    perform.jsp

    не так понятно, как, скажем, вот это:

    performLogin.jsp

    В случае использования глагола как части имени JSP-файла по возможности лучше использовать этот глагол в настоящем времени, а не в виде герундия и прочих форм. Например:

    showAccountDetails.jsp

    предпочтительнее, чем

    showingAccountDetails.jsp

    Имена тэгов

    Ниже приведена таблица правил именования обработчиков JSP-тэгов и ассоциативных классов:


    Описание

    Имя класса
    Тэг XXX, дополнительная информация (потомок javax.servlet.jsp.tagext.TagExtraInfo) XXXTEI
    Тэг XXX, TLV (потомок javax.servlet.jsp.tagext.TagLibraryValidator) XXXTLV
    Тэг XXX, интерфейс обработчика (потомок javax.servlet.jsp.tagext.Tag/IterationTag/BodyTag) XXXTag
    Тэг XXX, реализация обработчика XXXTag
    Дополнительно: эти имена не должны нарушать соглашения, принятые для именования классов и интерфейсов в коде Java.

    Также для того, чтобы эти классы тэгов было проще отличать от других классов, полезно добавлять суффиксы пакетов, тэгов, а также библиотек тэгов в имя пакета класса, например:

    com.mycorp.myapp.tags.XXXTag


    Префикс имен тэгов

    Префикс имени тэга должен быть достаточно коротким, соответствовать функции, выполняемой этим тэгом, а также начинаться, как и имена JSP-файлов, с буквы нижнего регистра. Префикс имени тэга не должен содержать каких бы то ни было неалфавитных символов. Вот несколько примеров:


    Пример

    OK?
    mytaglib нет
    myTagLib да
    MyTagLib нет
    MyTagLib1 нет
    My_Tag_Lib нет
    My$Tag$Lib нет

    JSP-страницы в синтаксисе XML

    JSP предоставляет два разных синтаксиса: стандартный синтаксис для написания JSP-странц и XML-синтаксис для написания JSP-документов. В этой статье мы преимущественно рассматривали стандартный синтаксис JSP. Однако многие из рассмотренных нами концепций могут также применяться и для JSP-документов. Введение JSP-документов произошло во многом из-за преобладания XML и его повсеместного внедрения, а также в целях предоставления возможности спецификации JSP 2.0 обеспечить более дружественное взаимодействие с XML-синтаксисом.


    Структура JSP-документа

    Все JSP-документы должны иметь примерно следующую структуру:

    <? xml version="1.0"?>

    <!—

    - Author(s):

    - Date:

    - Copyright Notice:

    - @(#)

    - Description:

    —>

    <jsp:root xmlns:jsp="http://java.sun.com/JSP/Page"

    xmlns:prefix1="URI-for-taglib1"

    xmlns:prefix2="URI-for-taglib2"

    version="1.2">

    JSP Document...

    </jsp:root>

    Первая строчка — это опциальный XML-пролог, который, собственно, позволяет определить, что это есть некий XML-документ. После пролога идет комментарий к документу.

    Элемент <jsp:root> говорит о том, что это есть именно JSP-документ, а не какой-нибудь другой. Этот элемент должен быть корневым. Внутри этого тэга должны импортироваться все используемые именные пространства, а также библиотеки тэгов. Фактическое содержимое JSP-страницы — это все подэлементы корневого элемента <jsp:root>.

    Поскольку JSP-документы должны соответствовать всем правилам построения XML-документов, некоторые элементы, как, например, <% %> должны быть заменены их XML-эквивалентами (в этом случае — на <jsp:scriptlet />). За более подробной информацией обращайтесь к спецификации JSP.


    XML-комментарий

    В спецификации JSP ничего не сказано по поводу того, остаются ли XML-комментарии внутри документа после обработки его JSP-процессором, поэтому лучше всего воспользоваться обходным маневром, т.к. в этом случае клиент в любом случае получит желаемое вами. Например, вот так:

    ...

    <jsp:text><![CDATA[

    <!—

    - Многостроковый комментарий, который

    - будет послан клиенту.

    —>

    ]]></jsp:text>

    ...

    Java-код в JSP-документах

    При использовании Java-кода внутри объявлений, скриптлетов или выражений элемент CDATA должен использоваться лишь тогда, когда необходимо быть уверенным, что ваш код не вредит структуре документа:

    ...

    <jsp:scriptlet>

    for(int level = 0; level < 3; level++) {

    </jsp:scriptlet>

    <tr>

    <td>

    <jsp:expression><![CDATA[

    "<h" + level + ">Text</h" + level + ">"

    ]]></jsp:expression>

    </td>

    </tr>

    <jsp:scriptlet>

    }

    </jsp:scriptlet>

    ...

    А вообще написания Java-кода в ваших JSP-страницах следует избегать хотя бы по следующим причинам:

  • Синтаксические ошибки в Java-коде внутри JSP-страниц не выявляются на этапе разворачивания вашего компонента в контейнере. А синтаксические ошибки в библиотеках тэгов и сервлетах, напротив, выявляются еще до этого, на этапе компиляции.
  • Java-код в JSP-страницах гораздо сложнее отлаживать.
  • Java-код довольно сложно поддерживать, особенно если авторы страниц не сильны в Java.
  • Общепризнанная практика — не смешивать бизнес-логику с презентационной логикой. А JSP выполняет в первую очередь презентационную функцию.
  • Код, содержащий HTML-, Java-код и прочие языки, гораздо сложнее читать.
  • Таким образом, проще всего держаться ближе к JSP 2.0 — не использовать Java-код на своих JSP-страницах.
  • Инициализация JavaBean'ов

    JSP предоставляет подходящий элемент для инициализации всех свойств JavaBean'ов, например:

    <jsp:setProperty name="bankClient" property="*"/>

    Однако такой прием следует использовать с осторожностью. Во-первых, если бин содержит свойство, скажем, amount, и такого параметра (amount) не существует в текущем объекте ServletRequest или же его значение равно "", ничего не выйдет: JSP даже не присвоит null самым обыкновенным свойствам этого бина. Во-вторых, неэлементарные свойства, которые не имеют определенного заранее PropertyEditor'а, не обязательно будут проинициализированы строковым значением из объекта ServletRequest. В-третьих, злоумышленники могут указать дополнительные параметры в строке запроса, тем самым установив нежелательные свойства вашему бину в случае, если приложение спроектировано недостаточно тщательно.

    Если вы все равно не хотите отказываться от использования property="*" в тэге jsp:setProperty и таким образом хотите получать более чистый код, примите во внимание совет добавлять комментарий перед этим тэгом, в котором указывать, какие свойства вы предполагаете инициализировать у конкретного бина.

    Например, в следующем примере комментарий оповещает о том, что у бина bankClient должны быть проинициализированы два свойства: firstName и lastName.

    <%—

    - requires firstName and lastName from the ServletRequest

    —%>

    <jsp:setProperty name="bankClient" property="*" />


    Кавычки

    Вместо одинарных кавычек (') в большинстве случаев следует использовать двойные кавычки ("). Это общепринятое соглашение. Например:

    Одинарные кавычки (не рекомендуется) Двойные кавычки (предпочтительнее)
    <%@ page import='javabeans.*'%>

    <%@ page import="java.util.*" %>
    <%@ page import="javabeans.*" %>

    <%@ page import="java.util.*" %>
    Исключение составляет тот случай, когда в строке необходимо использовать двойные кавычки — тогда лучше воспользоваться апострофами:

    <jsp:include page='<%= getFoodMenuBar("Monday") %>' />


    Использование JavaScript

    Все ваши скрипты на JavaScript не должны зависеть от каких-либо особенностей конкретного браузера, чтобы правильно функционировать на всех существующих браузерах, которые поддерживают JavaScript. Также правилом хорошего тона в программировании считается выносить JavaScript-скрипты в отдельные файлы, отдельно от JSP-страниц. Для того, чтобы вставить файл со скриптом, можно воспользоваться следующим HTML-выражением:

    <script language=javascript src="/js/main.js">

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


    Каскадные таблицы стилей (CSS)

    Как известно, каскадные таблицы стилей (Cascading Style Sheets) используются для централизации контроля над основными свойствами и характеристиками различных тэгов (заголовков, таблиц, ссылок и т.д.). Они значительно упрощают процесс поддержки кода и значительно уменьшают его размер. Так, вместо того, чтобы встраивать информацию о стиле в каждый HTML-тэг, где это необходимо, например:

    <H1><FONT color="blue">Chapter 1</FONT></H1>

    ...

    <H1><FONT color="blue">Chapter 2</FONT></H1>

    ...

    Можно определить информацию о стилистике заголовка H1 в файле (например, myJspStyle.css) следующим образом:

    H1 { color: blue }

    А после применить его к JSP-странице:

    <link rel="stylesheet" href="css/myJspStyle.css" type="text/css">

    ...

    <H1>Chapter 1</H1>

    ...

    <H1>Chapter 2</H1>

    ...


    Прочие рекомендации

    В этой статье было представлено множество рекомендаций касательно соглашений в коде JSP и прочих артефактов при разработке web-компонентов с целью улучшить и тем самым упростить его дальнейшую поддержку, а также придать ему более профессиональный и стандартизированный вид. Однако, если вы углубитесь в этот процесс, то обнаружите множество других полезных и важных приемов. Например, в спецификации JSP 1.2 присутствует множество дополнительных рекомендаций, с которыми вы можете ознакомиться.

    Исходный код проекта, который использовался для написания этой статьи, а также уже собранный проект вы можете скачать отсюда: http://developer.java.sun.com/servlet/CodeConventionServlet/ . Вам понадобится скачать WAR-файл.

    По материалам Kam Hay Fung и Mark Roth
    Подготовил Алексей Литвинюк,
    http://www.litvinuke.hut.ru



    Компьютерная газета. Статья была опубликована в номере 12 за 2003 год в рубрике программирование :: разное

    ©1997-2024 Компьютерная газета