(495) 925-0049, ITShop интернет-магазин 229-0436, Учебный Центр 925-0049
  Главная страница Карта сайта Контакты
Поиск
Вход
Регистрация
Рассылки сайта
 
 
 
 
 

Сервлеты в чистом виде: смена парадигмы (исходники)

Джейсон Ван Клив, 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 на "чистые" сервлеты, я смог сократить размер кода на две трети.

Например, возьмем эту сложную конструкцию для вывода ссылки в зависимости от прав доступа пользователя:

<c:if test="${user.permission[ sessionScope.ConstantMap[ EDIT_WIDGET ] ] != 0}">
  <c:url var="editUrl" value="/EditWidget.jsp"/>
  <div class="navigation"><a href="<c:out value="${editUrl}"/>">Edit
        this widget</a></div>
</c:if>

Она становится значительно понятнее при использовании синтаксиса Java:

if (user.getPermission(Constants.EDIT_WIDGET) != 0)
  out.printNavlinkDIV("/EditWidget.jsp", "Edit this widget");

Учтите также количество вспомогательного кода, сэкономленного за счет извлечения и вывода бизнес-объектов в одном и том же месте, вместо передачи их через запрос. Краткость - сестра таланта.

Работа с JSP и другими технологиями отображения- возможно, один из самых ненадежных аспектов Web-разработки. JSP страницы - это не HTML, не XML, не Java-код и не код JavaServer Pages Standard Tag Library (JSTL), не язык выражений (EL), а беспорядочная смесь этих и других технологий. Однако не только это нелепая смесь, но и каждый уровень абстракции создает новые препятствия для разработки. Отладка JSP страниц, к примеру, крайне напоминает поиск источника с помощью лозы. Вы знаете, что где-то там под поверхностью есть ошибка, но не можете её обнаружить на основании загадочного сообщения об ошибке, в котором указан номер строки, не соответствующий вашему коду.

Также JSP-технология не позволяет наследовать базовому классу, так что повторное использование сводится к bean-компонентам, include-файлам и специфическим taglib'ам. Taglib'ы также слишком сложны, чтобы быть эффективным средством повторного использования. Поддержка XML-файла для каждого сделанного изменения в API крайне утомительна, несмотря на то что "проектирование тегов это проектирование языка". Результат всего этого - еще один уровень в и без того многоуровневом интерфейсе.

 
Соответствие стандартам HTML и XHTML
Инкапсулирование HTML в Java-методах приносит единообразие за счет повторного использования и помогает минимизировать число опечаток. В свою очередь, это способствует достижению достойной цели - создания HTML- или XHTML-кода, соответствующего стандартам. Я реализовал сайт March Madness в соответствии с XHTML 1.0 Strict. После завершения функциональности потребовалось всего около полудюжины изменений, чтобы он прошел проверку в службе валидации W3C.
 

Сейчас мы встречаем новый World Wide Web. Вне зависимости от того, сможет ли AJAX перевернуть Web-разработку, Web-сайты будут становиться все более и более интеллектуальными. И хотя HTML сам по себе всегда декларативен, код, который он генерирует, определенно не декларативный. Технология JSP и другие системы шаблонов неминуемо оказываются слишком сложными, так как они пытаются выразить декларативно то, что на самом деле является динамическим выводом. Именно по этой причине разработчики вынуждены добавлять scriplet'ы в исходный код JSP, так как то, что они пытаются выразить это в такой же степени логика , как и форма.

Инкапсулируя HTML как Java-код, можно выразить логику вывода более сжато. Конструкции if и циклы for принимают свою хорошо известную естественную форму. А элементы страниц могут быть разложены по легко поддерживаемым и понимаемым методам. Поддержка JSP-страниц, которые редко хорошо документируются, в лучшем случае достаточно тяжела и подвержена ошибкам. Используя "чистые" сервлеты, можно максимизировать повторное использование кода, так как не нужно писать новый класс для каждой конструируемой страницы.

Безумный дизайн

 
March Madness (Мартовское безумие)

Ярые американские баскетбольные фанаты достигают полного безумия каждый март, когда 64 лучшие мужские команды из Национальной Атлетической Ассоциации Университетов (National Collegiate Athletic Association - NCAA) сходятся в чемпионате с играми на выбывание и единственным победителем, длящемся несколько недель. Множество болельщиков наслаждаются, записывая свои предсоревновательные прогнозы и результаты игр в общую схему, по мере того как ситуация в чемпионате меняется и число участников уменьшается. Также многие обожают соревноваться друг с другом в неофициальных или специальных соревнованиях, где награждают тех, чьи прогнозы оказались более точными.

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

Например, разработчики часто неверно понимают назначение модулей Action в Struts. Бизнес-логика имеет тенденцию накапливаться и застревать в них (а то и на всем протяжении пути от них до JSP). Реализация представления и контроллера как сервлетов побуждает хранить бизнес-логику там, где она должна быть, так как сервлеты явно сфокусированы на взаимодействии с браузером.

Для данного проекта использовалось несколько классов из моей собственной elseforif-servlet библиотеки. Именно эта библиотека является ключом к архитектуре проекта , так как она предоставляет удобный интерфейс для генерации HTML. Но мы не будем фокусироваться на библиотеке, просто проверим концепцию, чтобы доказать жизненность моего подхода.

На рисунке 1 приведена частичная диаграмма классов, элементы библиотеки elseforif-servlet выделены зеленым.

Рисунок 1. Фрагмент диаграммы классов
Фрагмент диаграммы классов

Вверху дерева находится интерфейс, содержащий строковые HTML константы, используемые и объектами, генерирующими HTML, и сервлетами. Позже вы увидите, как они работают. Затем идут классы HTMLWriter и HTMLFlexiWriter, реализующие базовые низкоуровневые HTML методы, которые могут потребоваться любому Web-сайту. Разница между ними в том, что HTMLWriter печатает информацию напрямую в поток вывода, тогда как HTMLFlexiWriter также может возвращать выводимую информацию в виде строк. Часто оказывается удобным передать результат работы одного метода-генератора HTML параметром в другой метод-генератор HTML, как в этом примере.

out.printA(URL_ELSEFORIF, out.IMG("/img/elseforif.gif", 88, 31));
 

Класс MadnessWriter затем добавляет высокоуровневую функциональность для вывода HTML, необходимую для данного Web-сайта - общие элементы, такие как верхний и нижний колонтитулы и меню, все, что специфично для данного сайта и неоднократно встречается на нем. Это легкий, не приспособленный к многопоточному использованию объект, создаваемый для каждого запроса абстрактным базовым классом-сервлетом MadnessServlet с помощью метода-фабрики.

Этот базовый класс отвечает за обработку основной управляющей логики сервлета, так что конкретные подклассы могут сфокусироваться на своих специфических задачах. После установки стандартных заголовков HTTP и выполнения определенной проверки безопасности на уровне страницы, он передает объект MadnessWriter в защищенный метод doBoth():

protected void doBoth(HttpServletRequest request, HttpServletResponse response,
      HttpSession session, MadnessWriter out) throws ServletException, IOException

Класс MadnessServlet также реализует интерфейс MadnessConstants, предоставляя подклассам удобный доступ к статическим значениям, определенным в HTMLConstants. Таким образом, применение объекта MadnessWriter вместе с этими константами позволяет создать для сервлетов компактный Java-подобный синтаксис.

 
Параметры и валидация
Можно эффективно обрабатывать параметры, не прибегая к сложным системам. Библиотека elseforif-servlet включает несколько классов-помощников, которые сервлеты могут использовать напрямую, с помощью шаблона декоратора, объявив их параметры в методе init(). Это придает сервлетам удобную форму, превращая init() в своего рода сигнатуру, так что можно сразу определить, какие параметры ожидаются. Специальная реализация Map инкапсулирует аргументы и результаты проверки, которые могут передаваться в сессии и распространяться между сервлетами при необходимости.
 

Говоря языком MVC, сервлеты - в данном случае базовые компоненты пользовательского интерфейса - сочетают уровни представления и управления. Для протокола, подобного HTTP, не поддерживающего сеанс взаимодействия с пользователем, это разумно. Запросы на отображение и запросы на обновление данных принимают одну и туже простую форму, и между ними нет четкого разделения. Я предпочитаю ради модульности реализовывать страницу с формой в одном сервлете, а обработчик этой формы в другом. Но как бы вы их ни разделяли, логика для генерации HTML, логика для обработки параметров сервлета и логика навигации по страницам тесно связаны между собой. Благое намерение MVC отделить их друг от друга порождает большие проблемы.

Реализация бизнес-уровня должна иметь мало значения для уровня представления. Главное - иметь разумный бизнес-интерфейс, чтобы код пользовательского интерфейса занимался только своим делом. Для бизнес-уровня данного проекта я построил довольно простой CRUD (create-read-update-delete) интерфейс для работы с данными при помощи Apache Derby.

Запуск приложения

Это Web-приложение является практически самодостаточным, но может потребоваться изменить некоторые переменные для настроек среды в файле web.xml, прежде чем помещать его в каталог webapps. По крайней мере, встроенному экземпляру СУБД Derby требуется место, чтобы создать и хранить файлы с данными. По умолчанию в UNIX используется каталог /var/derby/, так что если используется Linux, то нужно создать такой каталог и обеспечить сервлет-контейнер правом на запись туда. В приложение можно войти, используя имя пользователя admin и пароль password . Дополнительную информацию можно найти в файле README загруженного пакета.

Форма и её обработка

Теперь можно погрузиться в код. Пользователи попадают на страницу Picks (cм. рисунок 2), чтобы выбрать свои любимые команды, прежде чем начнется первый раунд чемпионата. После этого они могут только просматривать подборку команд, отмеченных ими или другими пользователями.

Рисунок 2. Страница Picks (отбор команд)
Страница Picks (отбор команд)

Первым делом сервлет Picks для генерации страницы извлекает объект с информацией о пользователе, Player в данной системе, из бизнес-уровня и выполняет проверку безопасности:

PlayerManager playerMan = PlayerManager.GetInstance();
Player player = playerMan.select(session.getAttribute(P_PLAYER_ID), true);
boolean readOnly = GetCutoffDateIsPassed() && !player.getAdmin();
String playerID = request.getParameter(P_PLAYER_ID);
if (playerID != null)
  if (readOnly // player.getAdmin())
    player = playerMan.select(playerID, true);
  else
    throw new ServletException("You may not view other players' picks"
          " until the cutoff date has passed:  " + CutoffDate + ".");

Этим гарантируется, что обычные пользователи просматривают или редактируют подборки команд согласно бизнес-правилам, и также готовятся несколько локальных переменных, которые будут определять поведение страницы, особенно переменная readOnly. Затем я получаю массив объектов Team, который содержит официальный список участников чемпионата. Потом я вызываю метод, чтобы получить из этого массива коллекцию типа Map, отсортированную по алфавиту, которая мне понадобится для выпадающих списков:

TeamManager teamMan = TeamManager.GetInstance();
Team[] teams = teamMan.selectAll();
Map selectTeams = getDropDownMap(teams);

С этого момента начинается генерация HTML:

out.printPreContent(null, out.SCRIPTFile("/js/picks.js"));

Этот метод печатает первую часть страницы, включая тег HEAD полностью, открывающий тег BODY и логотип вверху страницы. Отметим URL к JavaScript-файлу, который добавляется в тег HEAD. Можно подумать, что эта операция провалится после установки WAR файла, так как в этом случае ко всем URL автоматически добавится префикс контекста /madness. На самом деле префикс контекста передается динамически в конструктор MadnessWriter, который затем автоматически добавляет его ко всем URL, начинающимся со слэша - крайне полезная возможность, если вы не любите использовать контекст.

На следующей строке выполняется вызов метода для вывода меню:

out.printMenu(URL_PICKS);
 

Передавая URL для отображаемой страницы, я заставляю объект MadnessWriter пропустить ссылку на эту страницу или сделать её неактивной. Затем я вызываю метод для начала элемента TABLE с графической границей, который я называю box (контейнер):

out.printBeginBox();
 

Этот код открывает несколько тегов, специфичных для содержимого, которое будет находиться в этом контейнере, Дальше я закрою эти теги с помощью вызова похожего метода. Заметьте, что метод printMenu() выше также вызывает эти методы. Такой вид инкапсуляции может ускорить отладку. Например, если есть такая ошибка - некоторые граничные элементы TD контейнера имеют ширину в 1%, что может привести к слишком толстой границе при растягивании окна браузера, то я смогу исправить её в единственном месте и для всего приложения сразу. Этого можно достичь с помощью специальных taglib'ов, но не так просто.

На следующих строках выводятся два DIV-элемента, первый показывает, успешно ли бы отправлена форма:

if ("true".equals(request.getAttribute(P_SUCCESS)))
  out.printDIV("smallHeading", "Team picks were saved successfully.");
out.printDIV("reminder", "(Reminder:  \"Pick 20\" represents the team you"
      + " think likeliest to win.  \"Pick 1\" is the least likely.)");

Аргументы "smallHeading" и "reminder" указывают на классы каскадных таблиц стилей (Cascading Style Sheets - CSS), которые будут применены к открывающимся элементам DIV, после которых будут напечатаны вторые аргументы вместе с закрывающими тегами DIV. Если содержание DIV элемента reminder окажется слишком сложным, можно вызвать метод out.printBeginDIV("reminder"), который напечатает только открывающий тег DIV. Данное правило наименования методов присутствует в классах HTMLWriter и HTMLFlexiWriter. Однако строковые константы в интерфейсе HTMLConstants немного отличаются - например, для открывающих и закрывающих DIV тегов по умолчанию используются DIV и END_DIV соответственно.

За DIV-элементом reminder будет выведена форма с выпадающим списком для каждой из 20 команд, выбираемых пользователем. Или, если пользователь может только просматривать отобранные команды, печатаются только названия команд. С помощью синтаксиса Java эту логику можно выразить довольно естественно:

if (!readOnly)
  out.printSELECT(P_PICK + i, selectTeams, teamID);
else
  {
  String teamName = (String)(selectTeams.get(teamID));
  out.print((teamName != null) ? teamName : "(no pick)");
  }

Метод printSELECT() создает элемент OPTION для каждой пары ключ/значение в коллекции типа Map, сразу помечая один элемент, значение ключа которого совпадает с teamID, как выбранный.

После заполнения формы нужно вывести список команд на правой части страницы. Массив команд сортируется по региону и рейтингу в NCAA. Для каждого региона есть небольшой заголовок, и список отображается в две колонки. Для данной задачи требуется выполнить определенные вычисления, так что она вынесена в отдельный метод, представленный в листинге 1.

Листинг 1. Вынос генерации HTML в отдельный метод.

                
private void doRegionList(Team[] teams, MadnessWriter out) throws IOException
  {
  out.print(TABLE + TR);
  out.printBeginTD(null, "regionList");
  for (int i = 0; i < teams.length; i++)
    {
    if ((i & 15) == 0)
      {
      if (i == 32)
        {
        out.print(END_TD + NL);
        out.printBeginTD(null, "regionList");
        }
      out.print(NL + DIV);
      out.print(REGION_NAMES[i >> 4]);
      out.print(":" + END_DIV + OL);
      }
    out.print(NL + LI);
    out.printHTMLEscape(teams[i].getFullName());
    out.print(" (");
    out.print((teams[i].getRank() & 15) + 1);
    out.print(")");
    out.print(END_LI);
    if ((i % 16) == 15)
      out.print(END_OL);
    }
  out.print(END_TABLE_3);
  }

Константа END_TABLE_3 является сокращением для комбинации закрывающих тегов TD, TR, TABLE. Это очень удобно, после того как вы подключили эту константу, но краткость подобного синтаксиса полагается на хороший дизайн HTML, предполагающий использовать HTML только для разметки и хранить как можно больше информации о стиле отображения в таблице стилей.

Теперь можно завершить генерацию страницы:

out.printEndBox();
out.printPostContent();

Первая строка закрывает контейнер, который был начат ранее, и метод printPostContent() выводит оставшуюся часть страницы, включая нижний колонтитул. Вот и все! Страница Picks с формой готова.

Сервлет-обработчик (PicksAction) отвечает на подтверждение страницы Picks, собирая идентификаторы выбранных команд из объекта запроса и передавая их в бизнес-уровень для обновления соответствующего пользователю объекта Player, и после этого возвращаяется на страницу с формой Picks. Здесь также выполняется проверка безопасности, не позволяющая пользователям изменять список выбранных команд после начала игр. Так как и форма, и её обработчик - это просто сервлеты, то нет никакой явной причины, чтобы они были написаны с различными интерфейсами. Оба отвечают на параметризованные запросы от браузера, используя одинаковые бизнес-объекты, и вместе формируют цельный компонент пользовательского интерфейса. Среда на основе MVC в данном случае только мешала бы левой руке согласованно работать с правой.

Другие аспекты подобного подхода

Хотя среды для разработки Web-приложений склонны усложнять общее положение вещей, они решают множество мелких проблем. Архитектура, основанная на сервлетах, приносит с собой гибкость для решения этих проблем, как и положено, не навязывая конкретных решений.

Безопасность

В промышленном приложении безопасность на уровне страницы, скорее всего, будет обрабатываться декларативно на уровне конфигурационного файла XML. Однако, на мой взгляд, обычно требуется более динамический интерфейс на уровне кода для управления нестандартными задачами внутри страниц, такими как функциональность, зависящая от даты в сервлете Picks. Это может делаться встроенными методами безопасности Servlet API, такими как метод isUserInRole(), доступный через объект запроса или для этого может быть написан отдельный интерфейс. Кодирование c использованием Servlet API может использоваться с любым из этих подходов.

 
HotSwap и цикл разработки
Изменение и перекомпиляция обычных классов может оказаться более утомительным, чем изменение JSP, которые компилируются автоматически в запущенном приложении. Отладочный интерфейс Java HotSwap, добавленный в версии 1.4, решает эту проблему, позволяя перегружать измененные классы на лету без перезапуска Web-приложения или потери сеанса пользователя. Хорошая среда разработки умеет использовать эту возможность. Мой сервлет-контейнер Caucho Resin 3.0 даже может автоматически распознавать изменения в классах в каталоге WEB-INF/classes и проворно менять их на лету.
 

Интернационализация

Хотя большинство сред поддерживают интернационализацию текстовых значений через файлы свойств (properties), этого же результата можно добиться с минимальным кодированием в генераторе HTML. Можно добавить метод, например, printText(), который будет принимать ключ в качестве входного параметра и выводить переведенное текстовое значение, а метод text() будет просто возвращать это значение. Сгенерированный в сервлете код будет таким же лаконичным и быстрым, как и его JSP-аналог, если не лучше. Это также дает лучший контроль над обработкой непереведенных значений, например, позволяя выдать исключительную ситуацию или использовать значение из языка по умолчанию.

Настройка представления

Эта возможность с легкостью реализуется архитектурой проекта March Madness. Если зайти на домашнюю страницу и войти в систему, то будет показано приветственное сообщение. Если нажать на запятую после "Welcome", то представление страницы изменится. Эта альтернативная оболочка сайта - больше чем просто дополнительный CSS-файл. Я расширил класс MadnessWriter, и теперь, когда выбирается альтернативная оболочка, базовый класс-сервлет создает соответствующий объект-подкласс и передает его в зачищенный метод service(). Этот подкласс MadnessWriter может не только переопределить таблицу стилей по умолчанию, но и структуру генерируемого HTML тоже, например, показав другой логотип или более сложную границу вокруг контейнеров. Никакого специального кода внутри самих сервлетов для этого не требуется.

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

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

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

Ссылки по теме


 Распечатать »
 Правила публикации »
  Написать редактору 
 Рекомендовать » Дата публикации: 14.01.2008 
 

Магазин программного обеспечения   WWW.ITSHOP.RU
EMS SQL Management Studio for PostgreSQL (Business) + 1 Year Maintenance
Allround Automation PL/SQL Developer - 5 user license
GFI WebMonitor Plus Edition - подписка на 1 год
Microsoft 365 Business Basic (corporate)
VCL Subscription
 
Другие предложения...
 
Курсы обучения   WWW.ITSHOP.RU
 
Другие предложения...
 
Магазин сертификационных экзаменов   WWW.ITSHOP.RU
 
Другие предложения...
 
3D Принтеры | 3D Печать   WWW.ITSHOP.RU
 
Другие предложения...
 
Новости по теме
 
Рассылки Subscribe.ru
Информационные технологии: CASE, RAD, ERP, OLAP
Программирование на Microsoft Access
CASE-технологии
OS Linux для начинающих. Новости + статьи + обзоры + ссылки
СУБД Oracle "с нуля"
Мастерская программиста
Компьютерная библиотека: книги, статьи, полезные ссылки
 
Статьи по теме
 
Новинки каталога Download
 
Исходники
 
Документация
 
 



    
rambler's top100 Rambler's Top100