Много страниц или даже очень много страниц

Struts наверно был самым первым фреймворком, с которым я стал знакомиться при погружении в мир Web для Java. Если честно, то мне это доставило немало неприятных минут (даже часов/дней). Причина в том, что к тому моменту я сам слабо представлял себе все, что связано с Web-программированием на Java (подозреваю, что те, кто добрался до этой статьи понимают уже гораздо больше). Да и документация Struts до сих пор не блещет. Сейчас уже появилось немало книг, но тогда, в 2002 году это была проблема. Ну да ладно — в итоге я все-таки разобрался и теперь могу свои знания оформить в виде статьи.
Начиная разговор о Struts версии 1.х — в данной статье я буду рассматривать версию 1.3 — надо четко понять, для чего он был создан и до сих пор используется.
На тот момент КАЖДЫЙ запрос к серверу сопровождался перегрузкой страницы, т.к. технология AJAX не появилась. В случае большого приложения разработчик получал большое количество страниц и еще большее количество параметров. И эти параметры надо было проверить, собрать в некоторый объект, вызвать обработчик этого запроса, получить данные и показать пользователю какую-то новую страницу. А может и ту же самую. Через две недели придет предложение все-таки на новую. Или другую.
Думаю те, кто полагает, что с появление AJAX актуальность подобных задач ушла в прошлое, заблуждаются. Да, многие современные мобильники поддерживают JavaScript. И их будет все больше и больше. Но, во-первых, есть еще много мобильных устройств, которые не поддерживают JavaScript. Во-вторых — не будем думать, что не появятся новые устройства, которые будут иметь гораздо меньшие возможности, чем нынешние мобильные телефоны. Но им может вполне потребовать услуги удаленного сервера. В-третьих — кто вам сказал. что пользовательский интерфейс будет выглядеть лучше и проще на JavaScript ? Ну и наконец в-четвертых — это то, что вам могут рассказать разработчики, которые вынуждены тестировать свое творение на нескольких версиях тогое же IE. А если мы добавим к нему Firefox, Opera, Google Chrome, Safari и еще много чего, то этим ребятам не позавидуешь. Теперь представьте, что появится еще несколько десятков, а то и сотен версий иных клиентов ? То-то. И мы сразу задумаемся — а может рисовать на клиенте что-то очень простое ? И пусть сервер решает, какая страничка подходит данному клиенту. В конце концов кто сказал, что HTML у нас единственный и неповторимый ? Есть еще WML, PDF, HDML да и просто текст. И заметим, что реализовать переключение на сервере на разные варианты отображения гораздо удобнее. Сформировать предварительный документ в XML, а потом пиши XSL, который подходит для очередного броузера. Проблем в разы меньше.
Думаю, что этого достаточно для размышлений. Надеюсь, что мое несколько затянувшееся отступление Вам не помешает читать дальше.

Прежде чем углубиться непосредственно в сам Struts я бы хотел, чтобы вы попробовали «увидеть» архитектуру Web-приложения.
Представьте обычное GUI-приложение. Оно состоит из большого (или не очень) набора форм, ан которых вы можете отображать и вводить какие-то данные. После всяких действий вы нажимаете какую-то заветную кнопку, выбираете пункт меню или совершаете еще какое-то действие и … переноситесь в другую форму. Данные в этой форме могут быть как совсем новые, так и из предыдущей формы. На вашей форме есть списки, поля для ввода, таблицы и много чего еще. События от элементов обрабатываются какими-то функциями. Представили ?
А теперь замените формы на HTML-страницы. И вы увидите, что основная сложность — это иметь удобный механизм «улавливания» HTTP-запросов со страницы, удобный разбор пришедших данных и система перехода на другую форму, э-э-э-э пардон, страницу. Увидели ? Постарайтесь. Это существенно облегчит вам понимание многих аспектов web-програмирования. Во всяком случае мне это сильно помогает.
Давайте еще раз посмотрим на наше приложение. Мы оказываемся на странице, набираем какие-то данные, нажимаем кнопку. Наш HTTP-запрос (чудес тут не будет — все основывается на HTTP) приходит на Web-Server (тот же Tomcat) с каким-то набором параметров. Причем еще раз обращаю ваше внимание — это HTTP. Т.е. параметры приходят в самом привычном для HTTP виде — после URL стоит знак «?» и дальше через разделитель «&» идут пары «имя=значение». Т.е. что-то вроде такого

/MyApp/MyCommand?param1=value1&param2=value2

Теперь наша задача состоит в том, чтобы из этого запроса получить данные и поместить их в удобную структуру. Здорово бы сразу в класс с таким набором полей, который напоминает набор пришедших параметров. Вторым совершенно логичным шагом будет проверить наши данные — может они содержат какие-то ошибки или просто опасны для обработки. Т.к. наше приложение смотрит в большой мир, желающих прислать не то будет гораздо больше. Учтите это обстоятельство. Далее следует вызов обработчика данных. Определение класса, который будет обрабатывать наш запрос обычно происходит путем анализа URL — в нем муогут быть например специальные слова. Если вспомните Spring, то там использовался UrlHandlerMapping. Наш класс все обработал (при этом он может обратиться к нашему Business Layer — у нас же там есть все необходимые функции), получил какие-то данные и теперь нам предстоит заключительный шаг — надо решить куда мы направляемся или другими словами — на какую JSP страницу нам идти и как удобно данные поместит на нее.
Таким образом можно выделить следующие задачи Web-layer:

  1. Преобразование данных из HTTP в класс
  2. Проверка (валидация) данных
  3. Определение обработчика запроса
  4. Интеграция с объектами на Business Layer
  5. Система навигации
  6. Удобные возможности отображения данных

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

 

Где скачать и библиотеки

Скачать Struts можно на сайте Struts. Распакуйте ZIP-файл в какой-нибудь каталог. Что касается библитек, то можно просто скопировать все, что находится в подкаталоге lib. Разве что jstl-1.0.2.jar можно не брать. Мой каталог с библиотеками включает больше, чем надо для нашего примера. Здесь вы видите и Hibernate, и Spring, но так уж сложилось и оптимизировать список я не вижу смысла. antlr-2.7.6.jar
asm.jar
aspectjweaver.jar
bsf-2.3.0.jar
cglib-2.1.jar
commons-beanutils-1.8.0.jar
commons-chain-1.2.jar
commons-collections-3.1.jar
commons-digester-1.8.jar
commons-fileupload-1.1.1.jar
commons-io-1.1.jar
commons-logging.jar
commons-validator-1.3.1.jar
dom4j-1.6.1.jar
ejb3-persistence.jar
hibernate-annotations.jar
hibernate-commons-annotations.jar
hibernate-entitymanager.jar
hibernate3.jar
javaee.jar
javassist-3.4.GA.jar
jstl.jar
jta-1.1.jar
junit-4.4.jar
log4j-1.2.15.jar
oro-2.0.8.jar
slf4j-api-1.5.3.jar
slf4j-log4j12-1.5.3.jar
spring-test.jar
spring-webmvc-struts.jar
spring-webmvc.jar
spring.jar
standard.jar
struts-core-1.3.10.jar
struts-el-1.3.10.jar
struts-extras-1.3.10.jar
struts-faces-1.3.10.jar
struts-mailreader-dao-1.3.10.jar
struts-scripting-1.3.10.jar
struts-taglib-1.3.10.jar
struts-tiles-1.3.10.jar

Алгоритм работы и составные части Struts

Как я уже отмечал, Struts решает проблему организации запросов от пользователя, получения данных и отображения. По сути — это уже известный нам шаблон MVC (Model, View, Controller). В качестве контроллера выступает ActionServlet, который по заданной конфигурации (чуть позже мы ее разберем) обрабатывает данные от клиента, помещает их в объект определенного класса (а точнее в наследника от Action Form) и вызывает подходящий обработчик этого события — наследника от класса Action. Обработчик должен выполнить какие-то действия, заполнить данные и вернуть некоторый статус, характеризующий насколько удачно все выполнилось. По данному статусу происходит поиск той JSP-страницы, которая будет показана пользователю. И данные, которые возможно будут собраны обработчиком, будут отображены на этой странице. Дальше цикл повторяется — ActionServlet получит и предварительно соберет данные в контейнер-наследник от ActionForm, вызовет обработчик (наследник Action), получит от него статус, по статусу вызовет нужную JSP. Вуаля.

В этой части мы напишем очень простое приложение, которое запросит у пользователя ID специальности и по этому ID найдет название. В базу данных мы ходить не будем, поэтому поиск будет достаточно формальным — мы просто пропишем его в нашем классе. В случае неудачного поиска попросим пользователя снова ввести данные.

Итак, давайте еще раз подробнее рассмотрим составные части Struts. Я выделил 5 основные частей:

  1. Описание контроллера — ActionServlet в web.xml
  2. Конфигурационный файл(файлы)
  3. Классы, наследуемые от Action и ActionForm
  4. JSP-страницы для отображения и ввода информации
  5. Тэги Struts

Начнем по порядку. Прописывание ActionServlet в web.xml не представляет каких-либо проблем. Это просто сервлет (специальный класс Struts), который будет получать все URL, которые надо обрабатывать. Выглядит это так:

 

Думаю, что что-то сверхудивительное вы не увидели. Отметим только параметр config в описании ActionServlet. Он указывает на файл конфигурации, который нам надо рассмотреть более подробно. Также отметим, что сервлет обрабатывает запросы, которые оканчиваются на .do

Наш конфигурационный файл состоит из нескольких частей. Первая описана тэгом form-beans. Она включает в себя описание всех классов, которые наследуются от ActionForm. Как я уже говорил, задача этих классов служить контейнерами для хранения данных пришедших со страниц. В описании мы указываем имя lookupForm под которым к этом классу можно будет обратиться и название класса. Кроме этого можно указать несколько атрибутов, но для понимания сути это пока несущественно.
Следующая часть — action-mappings. Она описывает во-первых класс, который будет являться обработчиком и во-вторых, связь с классом отActionForm. Здесь вы можете видеть следующие атрибуты для тэга action:

  • path — описывает URL. По сути это реализация идеи, которую я описывал. Для понимания кто что обрабатывает используются разные URL
  • type — класс для наследника ActionForm
  • name — имя ActionForm. В нашем случае это lookupForm, его мы видим в тэге form-bean
  • validate — атрибут, указывающий на необходимость вызова проверки данных
  • input — указывает на страницу, на которую возвращается приложение в случае ошибки

Также надо обратить внимание на часть с тэгом forward. Это раздел навигации. Формируя какое-либо ключевое слово мы будем переходить на нужную нам страницу.
Ну и наконец тэг message-resources. Он служит для описания файла, в котором находятся строковые константы. Это удобный механизм интернационализации и упрощения использавония строк. Вопросы связанные с этим файлов мы рассмотрим в свое время.

 

Рассмотрев вкратце вопросы конфигурации обратим наше внимание на «сладкую парочку» — Action/ActionForms. Сначала рассмотримLookupForm. Как уже говорилось этот класс служит контейнером для параметров. Но кроме этого он может иметь функцию проверки (для этого он реализует метод validate. И функцию инициализации данных — reset.

В классе указано всего лишь два свойства — professionId и professionName. Надо обратить внимание, что для каждого свойства есть пара методов set/get.
Также обратите внимание на метод validate. Он возвращает объект класса ActionErrors. Это список ошибок обнаруженных при проверке. Если список не пустой — значит ошибки есть. Если пустой — значит все в порядке.
Посмотрите на то, как мы создаем запись об ошибке. При добавлении мы указываем два параметра:
— имя свойства, на котором произошла ошибка
— строка-ключ. Она указывает на значение из файла ApplicationResource
Больше каких-либо замечаний по этому классу на данный момент нет.

Теперь давайте рассмотрим файл LookupAction.java. В нем сосредоточена логика обработки нашего выдающегося запроса. Ключевым методом является execute. Именно в нем происходит вся логика.

Код в методе execute достаточно прозрачный — мы приводим переданный объект типа ActionForm к нашему типу, потом ищем профессию по указанному ID (у нас их немного) и потом формируем ответ — куда идти. Надеюсь, что основная концепция Struts уже более менее понятна.

Нам осталось немного — посмотреть на тэги Struts, которые облегчают нам жизнь. У нас всего две страницы — index.jsp и result.jsp. Давайте посмотрим на них. Итак, index.jsp

Как видите, здесь мы используем тэги Struts — они помечены префиксом html. На полном и подробном описании мы пока не будем останавливаться, но очень советую вам почитать о них — описание есть на официальном сайте. И достаточно неплохое.
Сосредоточим наше внимание на тэгах, которые указаны в файле.

  • html:errors — этот тэг позволяет выводить те ошибки, которые мы с вами создавали. Также обратите внимание на свойстваerrors.header, errors.footer в файле ApplicationResource. Именно эти свойства «обрамляют» сообщение об ошибках сверху и снизу.
  • html:form — это аналого тэга FORM для HTML. Но тэг от Struts позволяет не думать об окончании «.do»
  • html:text — текстовое поле для ввода у которого я советую обратить внимание на имя — professionId. Именно по имени будет найдено свойство в нашем классе LookupForm.
  • html:submit — кнопка для отправки нашей формы на сервер по указаному атрибуту action в тэге html:form

 

Файл result.jsp еще проще.

Здесь мы используем тэг bean:write, который позволяет нам вывести свойство определенного класса. На класс указывает атрибут name а атрибутproperty указывает на свойство класса.

На этом наше первое и очень поверхностное знакомство с пакетом Struts 1.x будем считать состоявшимся. Впереди нас ждут еще некоторые возможности этого заслуженного пакета.

Архив с исходными кодами: Исходный код

4 comments to Struts 1.x. Первое знакомство

  • oleg  says:

    Добрый день. А продолжения не будет? Не совсем понятно в какой класс теперь передавать значения чтобы получить данные из бизнес уровня…

    • admin  says:

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

      • oleg  says:

        Еще не понятно зачем вы привели пример MVC-Struts если приводите аналог в статье «Spring. Переходим на Web». Каким из этих 2-х MVC пользоваться для написания серьезных систем? Или нужно как-то использовать оба вариант?

        • admin  says:

          Это два разных пакета, но у них просто очень похожая идея. Использовать их вместе наверно вряд ли надо.
          Оба используются для написания — Struts до сих пор используется для администраторской консоли IBM WebSphere. Spring я тоже использовал — хотя проект был не очень большой.
          Еще раз повторюсь — это старые статьи и на сегодня некоторые их идеи и реализации можно считать устаревшими. Хотя в определенных ситуациях они еще очень неплохо работают.

Leave a reply

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code class="" title="" data-url=""> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong> <pre class="" title="" data-url=""> <span class="" title="" data-url="">

Лимит времени истёк. Пожалуйста, перезагрузите CAPTCHA.