Сервлеты в чистом виде: смена парадигмы (исходники)Источник: IBM developerWorks Россия Джейсон Ван Клив, web-разработчик, Else For If
Считается, что для Web-страниц с динамическим содержимым технология JavaServer Pages (JSP) позволяет отделить задачи разработчика от задач дизайнера пользовательского интерфейса. К несчастью, технология JSP слишком сложна для многих дизайнеров, так что Java-программистам приходится лично заниматься обработкой JSP-страниц, часто с неудовлетворительными результатами. В этой статье демонстрируются преимущества нестандартного подхода: использование простых объектов-помощников (helper) для построения Web-интерфейса, основанного только на сервлетах. От редактора: Этот прием не рекомендуется для команд, в которых участвуют HTML-кодеры. Он предназначен для Java Web-разработчиков, которые пишут и поддерживают свой собственный HTML-код в несложных Web-приложениях. Технология JSP спроектирована так, чтобы отделить задачи Web-разработчика от персонала, который занимается проектированием динамических GUI страниц. К несчастью, технология JSP слишком сложна для многих дизайнеров пользовательских интерфейсов, так как добавляет несколько слоев для решения различных проблем при генерации динамического содержимого. К примеру, для интернационализации приложений необходимо хранить текст в определенном месте, отдельно от страниц пользовательского интерфейса, и обращаться к нему с помощью специальных ключей. Так что Java-разработчикам приходится работать c JSP-страницами в одиночку, зачастую переделывая работу дизайнеров пользовательского интерфейса, добавляя taglib'ы и другие элементы, чтобы избежать усложнения страницы из-за добавления Java-кода. Вопреки устоявшейся точке зрения, можно построить простой и симпатичный Web-интерфейс приложения, основанный на обычных сервлетах, с помощью простых объектов-помощников. Эта статья призывает рассмотреть генерацию представления для динамических Web-страниц с помощью стандартных средств Java. Я объясню преимущества этого подхода и продемонстрирую его на примере приложения для подсчета очков, которое я разработал для чемпионата NCAA March Madness. Замечание. Подход, продемонстрированный в этой статье, предназначен для Java Web-разработчиков, которые пишут и поддерживают собственный HTML код, а не для команд, в состав которых входят HTML кодеры. Динамический HTMLПодход, основанный на чистых сервлетах , позволяет упростить архитектуру. Он включает базовый класс-сервлет и специализированные объекты-генераторы, которые подклассы сервлета используют для производства выходных данных. Кода в данном случае получается немного, так как большая часть HTML инкапсулирована в методах объектов-помощников, которые могут быть переопределены при необходимости. Повторное использование кода всегда приветствуется, и большинство Web-сайтов совместно используют так много HTML между различными страницами, что повторное использование является крайне важным. Методы генерации HTML приводят к прямолинейному и компактному коду сервлетов, а, следовательно, и удобному для поддержки, так как стоимость поддержки кода более или менее пропорциональна размеру кода. Переписав UI интерфейс с JSP на "чистые" сервлеты, я смог сократить размер кода на две трети. Например, возьмем эту сложную конструкцию для вывода ссылки в зависимости от прав доступа пользователя:
Она становится значительно понятнее при использовании синтаксиса Java:
Учтите также количество вспомогательного кода, сэкономленного за счет извлечения и вывода бизнес-объектов в одном и том же месте, вместо передачи их через запрос. Краткость - сестра таланта. Работа с JSP и другими технологиями отображения- возможно, один из самых ненадежных аспектов Web-разработки. JSP страницы - это не HTML, не XML, не Java-код и не код JavaServer Pages Standard Tag Library (JSTL), не язык выражений (EL), а беспорядочная смесь этих и других технологий. Однако не только это нелепая смесь, но и каждый уровень абстракции создает новые препятствия для разработки. Отладка JSP страниц, к примеру, крайне напоминает поиск источника с помощью лозы. Вы знаете, что где-то там под поверхностью есть ошибка, но не можете её обнаружить на основании загадочного сообщения об ошибке, в котором указан номер строки, не соответствующий вашему коду. Также JSP-технология не позволяет наследовать базовому классу, так что повторное использование сводится к bean-компонентам,
Сейчас мы встречаем новый World Wide Web. Вне зависимости от того, сможет ли AJAX перевернуть Web-разработку, Web-сайты будут становиться все более и более интеллектуальными. И хотя HTML сам по себе всегда декларативен, код, который он генерирует, определенно не декларативный. Технология JSP и другие системы шаблонов неминуемо оказываются слишком сложными, так как они пытаются выразить декларативно то, что на самом деле является динамическим выводом. Именно по этой причине разработчики вынуждены добавлять scriplet'ы в исходный код JSP, так как то, что они пытаются выразить это в такой же степени логика , как и форма. Инкапсулируя HTML как Java-код, можно выразить логику вывода более сжато. Конструкции Безумный дизайн
Чтобы проиллюстрировать концепцию "чистых" сервлетов, я построю интерфейс для просмотра очков для чемпионата NCAA March Madness (см. врезку March Madness и материалы для скачивания). Пользователь может войти в систему, выбрать из 64-х команд чемпионата те 20 команд, которые, по его мнению, являются фаворитами, и присвоить каждой команде весовой коэффициент. После начала игр данные, введенные пользователями, можно только просматривать, и администратор сообщает победителей игр, как только они становятся известны. В зависимости от команд, выбранных пользователем, его очки аккумулируются, соотносятся с очками других пользователей и выводятся по порядку. Этот проект занял около трех недель моего свободного времени, большую часть которого я посвятил возне со стилями и графикой, так как я не художник. Кроме одного HTML-файла и других статических ресурсов, уровень GUI состоит из 21 Java класса, общим размером в 1334 Java-выражения, по измерениям JavaNCSS. Отход от Model - View - Controller (MVC)Архитектура, основанная только на сервлетах, которую я здесь продемонстрирую, включает только один уровень представления между клиентом и бизнес-логикой. Шаблон Модель - Вид - Контроллер (MVC), известный как Model 2, на самом деле не является панацеей, так как страдает серьезными ограничениями, и Web-среды для разработки приложений, поддерживающие его, имеют тенденцию к чрезмерному усложнению. Spring MVC и JavaServer Faces (MVC) слишком многословны, как и Struts, конфигурационные файлы которого являются крайне сложными и объемными и должны корректироваться каждый раз, чтобы следовать логике управления приложениями. Например, разработчики часто неверно понимают назначение модулей Для данного проекта использовалось несколько классов из моей собственной elseforif-servlet библиотеки. Именно эта библиотека является ключом к архитектуре проекта , так как она предоставляет удобный интерфейс для генерации HTML. Но мы не будем фокусироваться на библиотеке, просто проверим концепцию, чтобы доказать жизненность моего подхода. На рисунке 1 приведена частичная диаграмма классов, элементы библиотеки elseforif-servlet выделены зеленым. Рисунок 1. Фрагмент диаграммы классов Вверху дерева находится интерфейс, содержащий строковые HTML константы, используемые и объектами, генерирующими HTML, и сервлетами. Позже вы увидите, как они работают. Затем идут классы
Класс Этот базовый класс отвечает за обработку основной управляющей логики сервлета, так что конкретные подклассы могут сфокусироваться на своих специфических задачах. После установки стандартных заголовков HTTP и выполнения определенной проверки безопасности на уровне страницы, он передает объект
Класс
Говоря языком MVC, сервлеты - в данном случае базовые компоненты пользовательского интерфейса - сочетают уровни представления и управления. Для протокола, подобного HTTP, не поддерживающего сеанс взаимодействия с пользователем, это разумно. Запросы на отображение и запросы на обновление данных принимают одну и туже простую форму, и между ними нет четкого разделения. Я предпочитаю ради модульности реализовывать страницу с формой в одном сервлете, а обработчик этой формы в другом. Но как бы вы их ни разделяли, логика для генерации HTML, логика для обработки параметров сервлета и логика навигации по страницам тесно связаны между собой. Благое намерение MVC отделить их друг от друга порождает большие проблемы. Реализация бизнес-уровня должна иметь мало значения для уровня представления. Главное - иметь разумный бизнес-интерфейс, чтобы код пользовательского интерфейса занимался только своим делом. Для бизнес-уровня данного проекта я построил довольно простой CRUD (create-read-update-delete) интерфейс для работы с данными при помощи Apache Derby. Запуск приложенияЭто Web-приложение является практически самодостаточным, но может потребоваться изменить некоторые переменные для настроек среды в файле Форма и её обработкаТеперь можно погрузиться в код. Пользователи попадают на страницу Picks (cм. рисунок 2), чтобы выбрать свои любимые команды, прежде чем начнется первый раунд чемпионата. После этого они могут только просматривать подборку команд, отмеченных ими или другими пользователями. Рисунок 2. Страница Picks (отбор команд) Первым делом сервлет
Этим гарантируется, что обычные пользователи просматривают или редактируют подборки команд согласно бизнес-правилам, и также готовятся несколько локальных переменных, которые будут определять поведение страницы, особенно переменная
С этого момента начинается генерация HTML:
Этот метод печатает первую часть страницы, включая тег На следующей строке выполняется вызов метода для вывода меню:
Передавая URL для отображаемой страницы, я заставляю объект
Этот код открывает несколько тегов, специфичных для содержимого, которое будет находиться в этом контейнере, Дальше я закрою эти теги с помощью вызова похожего метода. Заметьте, что метод На следующих строках выводятся два
Аргументы За
Метод После заполнения формы нужно вывести список команд на правой части страницы. Массив команд сортируется по региону и рейтингу в NCAA. Для каждого региона есть небольшой заголовок, и список отображается в две колонки. Для данной задачи требуется выполнить определенные вычисления, так что она вынесена в отдельный метод, представленный в листинге 1. Листинг 1. Вынос генерации HTML в отдельный метод.
Константа Теперь можно завершить генерацию страницы:
Первая строка закрывает контейнер, который был начат ранее, и метод Сервлет-обработчик ( Другие аспекты подобного подходаХотя среды для разработки Web-приложений склонны усложнять общее положение вещей, они решают множество мелких проблем. Архитектура, основанная на сервлетах, приносит с собой гибкость для решения этих проблем, как и положено, не навязывая конкретных решений. БезопасностьВ промышленном приложении безопасность на уровне страницы, скорее всего, будет обрабатываться декларативно на уровне конфигурационного файла XML. Однако, на мой взгляд, обычно требуется более динамический интерфейс на уровне кода для управления нестандартными задачами внутри страниц, такими как функциональность, зависящая от даты в сервлете Picks. Это может делаться встроенными методами безопасности Servlet API, такими как метод
ИнтернационализацияХотя большинство сред поддерживают интернационализацию текстовых значений через файлы свойств (properties), этого же результата можно добиться с минимальным кодированием в генераторе HTML. Можно добавить метод, например, Настройка представленияЭта возможность с легкостью реализуется архитектурой проекта March Madness. Если зайти на домашнюю страницу и войти в систему, то будет показано приветственное сообщение. Если нажать на запятую после "Welcome", то представление страницы изменится. Эта альтернативная оболочка сайта - больше чем просто дополнительный CSS-файл. Я расширил класс Использование отступовОдной из проблем данного подхода может оказаться то, что сгенерированный HTML код не будет иметь отступов или будет плохо читаемым. Хотя ужасные отступы часто создаваемые кодом на базе шаблонов, использующим смесь HTML и scriptlet'ов, ничем не лучше. Даже если в коде нет scriptlet'ов, вырезка и вставка текста через какое то время обычно приводят к кривому и несимметричному коду. Мне удалось сделать HTML, генерируемый проектом March Madness более читабельным, добавив в генерируемый HTML несколько символов конца строки. Хотя аккуратно отформатированный HTML не является крайне необходимым для данного подхода, так можно найти большинство ошибок в разметке страницы, просматривая Java код, а не сгенерированный HTML-код. Разнесение элементов и конструкций по модулям сильно помогает сохранять ясность и удобство поддержки. ЗаключениеЭта статья является приглашением подумать о разработке за рамками сред для разработки Web-приложений, и представить Web-интерфейс приложения, построенный непосредственно на Java Servlet API. Поразительное число сред и систем шаблонов, доступных Java Web-разработчикам, заставляет считать себя незаменимыми, хотя они часто удивительно сложны и трудны в использовании. Размышляя о том, какая из них больше подходит к определенному типу Web-приложения, можно заодно подумать, чего можно достичь с помощью встроенных возможностей языка, таких как расширение и инкапсуляция. Как говорит Брюс Тейт (Bruce Tate): "Обычно лучше решать проблемы с помощью простоты и ловкости, а не грубой силы". У Web-сред действительно есть определенная сила, и JSP и шаблоны отлично работают, когда в проекте есть HTML-дизайнеры, создающие и поддерживающие их. Но для некоторых проектов простота "чистых" сервлетов является правильной альтернативой со своими особыми преимуществами, так как обеспечивает контроль и гибкость, не требуя упаковки всего динамического содержимого в объекты запроса. Unit-тестирование "чистых" сервлетов возможно без каких-либо дополнительных ухищрений. И повторно использовать сгенерированный HTML так же просто, как добавлять или переопределять методы. Так что дайте шанс этому подходу, и вы можете быть удивлены полученным результатом. |