LXF98:Java EE
Maximax (обсуждение | вклад) (Новая: {{Цикл/Java EE}}) |
Dionysius (обсуждение | вклад) (→<font color=darkred>Struts</font>, великий и ужасный) |
||
(не показаны 7 промежуточных версий 4 участников) | |||
Строка 1: | Строка 1: | ||
{{Цикл/Java EE}} | {{Цикл/Java EE}} | ||
+ | ==<font color=darkred>Struts</font>, великий и ужасный== | ||
+ | |||
+ | [[Media:JavaEE_LXF98.tar.gz|Скачать исходный код примера]] | ||
+ | |||
+ | ''<font color=darkred>'''ЧАСТЬ 10'''</font> Компьютеры были придуманы, чтобы избавить человечество от рутины – так зачем делать вручную то, что можно сгенерировать автоматически? '''Александр Бабаев''' покажет, как Struts позволяет избежать монотонного кодирования приложений J2EE.'' | ||
+ | |||
+ | Вручную делать простые вещи хорошо: быстро, просто, понятно. Но что делать, если нужно так же быстро и просто создать нечто большое? Сайт-портал, например? Не тот портал, который Яндекс, а корпоративный – где интегрирована система хранения документов, информационная система, наша адресная книга? | ||
+ | |||
+ | В PHP в этом случае приходит на помощь ''CMS''. Сладкие слова, которые обещают «в два клика» сделать вам все что угодно. Маркетинг, конечно, страшная сила, но почему так много ''CMS'' на PHP, и нет на ''Java''? | ||
+ | |||
+ | Возможно, просто потому что не нужно. Место ''CMS'' в ''Java'' занимают разнообразные инструментарии разработчика, которые помогают обходить сложные и рутинные работы. В результате можно небольшими силами сделать систему, по сложности намного превосходящую то, что можно сделать «вручную». | ||
+ | |||
+ | ===Что включается в Struts?=== | ||
+ | |||
+ | ''Struts'' не изобретает велосипедов. В его основе лежит шаблон «MODEl-View-Controller», который мы рассматривали в [[LXF92:Java EE|LXF92]], но с его помощью проще создать грамотное приложение, так как четко определены задачи по его созданию; проще разобраться, что необходимо написать для получения результата. | ||
+ | |||
+ | Итак, ''Struts'' (будем рассматривать более простую, первую версию) содержит: | ||
+ | |||
+ | *''API'' для создания обработчика запросов (менеджер, распределяющий запросы по действиям) и для создания самих действий (<font color=darkred>Actions</font>). | ||
+ | *''API'' для создания обработчиков форм. | ||
+ | *''API'' для работы с проверкой корректности заполнения (валидации) форм. | ||
+ | *''Tiles''. Расширение для создания модульных страниц (что-то «вроде SSI»). | ||
+ | *''JSP-taglib'', библиотека ''JPS''-тэгов для упрощения написания JSP-страниц. | ||
+ | *''XML''-конфигурационные файлы, для простой и быстрой настройки всего вышеперечисленного и связи его друг с другом. | ||
+ | |||
+ | Все это в предыдущих статьях мы делали вручную. Теперь настало время проделать то же самое более «технологично». | ||
+ | |||
+ | ===Как этим пользоваться?=== | ||
+ | |||
+ | Во-первых, библиотеку нужно скачать. Это можно сделать со странички http://struts.apache.org/download.cgi#struts138. После чего следует распаковать полученный файл и вытащить оттуда все JAR-архивы. | ||
+ | |||
+ | В качестве примера, создадим уже знакомую телефонную книгу. Сперва каталог; в нем, как всегда, организуем подкаталоги для исходных текстов, скомпилированного кода, библиотек и JSP-файлов. Получится что-то такое: | ||
+ | |||
+ | *'''libs''' | ||
+ | **''antlr-2.7.2.jar'' | ||
+ | **''bsf-2.3.0.jar'' | ||
+ | **''commons-beanutils-1.7.0.jar'' | ||
+ | **''commonschain-1.1.jar'' | ||
+ | **''commons-digester-1.8.jar'' | ||
+ | **''commons-fileipload-1.1.1.jar'' | ||
+ | **''commons-io-1.1.jar'' | ||
+ | **''commons-logging-1.0.4.jar'' | ||
+ | **''commons-validator-1.3.1.jar'' | ||
+ | **''jstl-1.0.2.jar'' | ||
+ | **''oro-2.0.8.jar'' | ||
+ | **''standart-1.0.2.jar'' | ||
+ | **''struts-core-1.3.8.jar'' | ||
+ | **''struts-el-1.3.8.jar'' | ||
+ | **''struts-extras-1.3.8.jar'' | ||
+ | **''struts-faces-1.3.8.jar'' | ||
+ | **''struts-mailreader-dao-1.3.8.jar'' | ||
+ | **''struts-scripting-1.3.8.jar'' | ||
+ | **''struts-taglib-1.3.8.jar'' | ||
+ | **''struts-tiles-1.3.8.jar'' | ||
+ | *'''out''' | ||
+ | *'''src''' | ||
+ | **''MessageResources_en.properties'' | ||
+ | **''MessageResources_ru.properties'' | ||
+ | **'''ru''' | ||
+ | *'''web''' | ||
+ | **''index.jsp'' | ||
+ | **'''pages''' | ||
+ | **'''WEB-INF''' | ||
+ | |||
+ | Затем в каталог библиотек нужно положить JAR-файлы ''Struts''. Готово? Тогда можно приступать к кодированию. | ||
+ | |||
+ | Когда запрос приходит в сервлет, он первым делом попадает в ''Struts'', который перенаправляет его в менеджер запросов (<font color=darkred>ActionServet</font>) и далее в нужное действие (<font color=darkred>Action</font>). Это происходит примерно так: | ||
+ | |||
+ | Как видно, схема здорово напоминает примененную нами при создании адресной книги. Зачем тогда ''Struts''? А затем, чтобы не писать много-много однотипного кода, который повторяется из проекта в проект. | ||
+ | |||
+ | ===Конфигурационные файлы=== | ||
+ | |||
+ | Вначале научимся запускать ''Struts''. Для этого нужно перенаправить все запросы сервлету-обработчику и написать файл конфигурации. Вот | ||
+ | простой дескриптор для простого ''Struts''-приложения: | ||
+ | <source lang="xml"> | ||
+ | <?xml version="1.0" encoding="UTF-8"?> | ||
+ | <web-app> | ||
+ | <servlet> | ||
+ | <servlet-name>action</servlet-name> | ||
+ | <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> | ||
+ | <init-param> | ||
+ | <param-name>config</param-name> | ||
+ | <param-value>/WEB-INF/struts-config.xml</param-value> | ||
+ | </init-param> | ||
+ | </servlet> | ||
+ | <servlet-mapping> | ||
+ | <servlet-name>action</servlet-name> | ||
+ | <url-pattern>*.do</url-pattern> | ||
+ | </servlet-mapping> | ||
+ | </web-app> | ||
+ | </source> | ||
+ | Видно, что все запросы <font color=darkred>*.do</font> передаются сервлету <font color=darkred>action</font>, обрабатываемому классом <font color=darkred>ActionServlet</font>. Это стандартный класс Struts, который перенаправляет запросы в действия. Ему передается конфигурационный файл '''struts-config.xml'''. Вот он: | ||
+ | <source lang="xml"> | ||
+ | <?xml version="1.0" encoding="UTF-8" ?> | ||
+ | <struts-config> | ||
+ | <form-beans> | ||
+ | <form-bean name="addForm" type="org.apache.struts.validator.DynaValidatorForm"> | ||
+ | <form-property name="name" type="java.lang.String" initial="Name"/> | ||
+ | <form-property name="phone" type="java.lang.String" initial="1234567"/> | ||
+ | <form-property name="age" type="java.lang.Integer" initial="20"/> | ||
+ | <form-property name="comment" type="java.lang.String" initial="NoComment"/> | ||
+ | </form-bean> | ||
+ | <action-mappings> | ||
+ | <action path="/add" name="addForm" validate="true" type="ru.linuxformat.actions.Add"> | ||
+ | <forward name="form" path="/pages/Add.jsp"/> | ||
+ | <forward name="done" path="/list.do"/> | ||
+ | </action> | ||
+ | <action path="/list" type="ru.linuxformat.actions.ShowAll"> | ||
+ | <forward name="ok" path="/pages/List.jsp"/> | ||
+ | </action> | ||
+ | </action-mappings> | ||
+ | <message-resources parameter="MessageResources"/> | ||
+ | <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> | ||
+ | <set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml,/WEB-INF/validation.xml"/> | ||
+ | </plug-in> | ||
+ | </struts-config> | ||
+ | </source> | ||
+ | В данном файле описана форма добавления контакта (<font color=darkred>form-bean</font>), с использованием стандартного класса формы с поддержкой автоматической проверки полей (<font color=darkred>DynaValidatorForm</font>). | ||
+ | |||
+ | После этого описано, какие запросы в какие классы перенаправляются. | ||
+ | <source lang="xml"> | ||
+ | <action path="/list" type="ru.linuxformat.actions.ShowAll"> | ||
+ | <forward name="ok" path="/pages/List.jsp"/> | ||
+ | </action> | ||
+ | </source> | ||
+ | В этом примере запрос <font color=darkred>/list.do</font> пойдет в класс <font color=darkred>ShowAll.Forward</font> используется внутри действия, чтобы упростить перенаправление вывода. Дальше будет понятно, как. | ||
+ | |||
+ | После описания действий все становится совсем просто.Описывается файл, откуда будут браться локализованные строки, и | ||
+ | подключается модуль, который обеспечивает простую и мощную валидацию (проверку) форм. | ||
+ | |||
+ | ===Действия=== | ||
+ | |||
+ | Перейдем к классам. Все они должны быть унаследованы от класса <font color=darkred>org.apache.struts.action.Action</font>. При этом в простейшем случае нужно переопределить только один метод, <font color=darkred>execute(…)</font>. Например, вот действие, которое показывает список контактов: | ||
+ | <source lang="java"> | ||
+ | public class ShowAll extends Action { | ||
+ | public ActionForward execute(ActionMapping aActionMapping, | ||
+ | ActionForm aActionForm, | ||
+ | HttpServletRequest aHttpServletRequest, | ||
+ | HttpServletResponse aHttpServletResponse) | ||
+ | throws Exception { | ||
+ | aHttpServletRequest.setAttribute("contacts", | ||
+ | Contacter.getInstance().getContactsSortedByName()); | ||
+ | return aActionMapping.findForward("ok"); | ||
+ | } | ||
+ | } | ||
+ | </source> | ||
+ | В этом действии в атрибут запроса кладется список всех контактов, после чего вызывается форвард <font color=darkred>"ok"</font> – именно он был описан чуть выше. | ||
+ | <source lang="xml"> | ||
+ | <action path="/list" type="ru.linuxformat.actions.ShowAll"> | ||
+ | <forward name="ok" path="/pages/List.jsp"/> | ||
+ | </action> | ||
+ | </source> | ||
+ | Из описания видно, что форвард перенаправляет обработку запроса в '''List.jsp''. Посмотрим, что в нем написано: | ||
+ | <source lang="xml"> | ||
+ | <%@ page pageEncoding="UTF-8" language="java" contentType="text/ | ||
+ | html; utf-8" %> | ||
+ | <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> | ||
+ | <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> | ||
+ | <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %> | ||
+ | <html:html> | ||
+ | <head> | ||
+ | … | ||
+ | </head> | ||
+ | <body> | ||
+ | … | ||
+ | <table border="1"> | ||
+ | <tr> | ||
+ | <td><bean:message key="AddressBook.list.name"/></td> | ||
+ | <td><bean:message key="AddressBook.list.phone"/></td> | ||
+ | <td><bean:message key="AddressBook.list.comment"/></td> | ||
+ | <td><bean:message key="AddressBook.list.age"/></td> | ||
+ | </tr> | ||
+ | <logic:iterate id="contact" type="ru.linuxformat.Contact" | ||
+ | name="contacts" scope="request"> | ||
+ | <tr> | ||
+ | <td><%=contact.getName()%></td> | ||
+ | <td><%=contact.getPhone()%></td> | ||
+ | <td><%=contact.getComment()%></td> | ||
+ | <td><%=contact.getAge()%></td> | ||
+ | </tr> | ||
+ | </logic:iterate> | ||
+ | </table> | ||
+ | </body> | ||
+ | </html:html> | ||
+ | </source> | ||
+ | На многоточия заменены неинтересные куски кода, а интересное – в самом начале листинга (<font color=darkred>taglib</font>). Это так называемые библиотеки тэгов. Примеры можно видеть здесь же. Скажем, <font color=darkred><bean:messagekey="AddressBook.list.name"/></font> вставляет локализованную строку, соответствующую данному ключу. А <font color=darkred><logic:iterate></font> умеет итерировать по коллекциям (списки, ассоциативные массивы и так далее). В данном случае мы итерируем по атрибуту запроса <font color=darkred>contacts</font>, который мы положили туда в действии. | ||
+ | |||
+ | ===Формы, проверка корректности форм=== | ||
+ | |||
+ | Другая интересная часть – формы. Второе действие, добавление контакта, выглядит следующим образом (приведен только код метода <font color=darkred>execute</font>): | ||
+ | <source lang="java"> | ||
+ | if (aHttpServletRequest.getParameter("name") == null) { | ||
+ | return aActionMapping.findForward("form"); | ||
+ | } else { | ||
+ | DynaActionForm form = (DynaActionForm) aActionForm; | ||
+ | Contacter.getInstance().addContact(form.getString("name"), form. | ||
+ | getString("phone"), form.getString("comment"), (Integer) form. | ||
+ | get("age")); | ||
+ | return aActionMapping.findForward("done"); | ||
+ | } | ||
+ | </source> | ||
+ | Логика очень похожа на ту, что была в предыдущих статьях. Если форма не заполнена, переходим по форварду <font color=darkred>form</font>, который показывает форму для ввода. Если она заполнена (и валидирована), то контакт добавляется в список, и мы переходим на форвард <font color=darkred>done</font>. Вот и сама форма (точнее, ее основная часть): | ||
+ | <source lang="xml"> | ||
+ | <html:form action="/add" method="post" onsubmit="return | ||
+ | validateAddForm(this);"> | ||
+ | <table> | ||
+ | <tr> | ||
+ | <td><bean:message key="AddressBook.add.name"/>:</td> | ||
+ | <td><html:text property="name"/></td> | ||
+ | </tr> | ||
+ | … | ||
+ | <tr> | ||
+ | <td colspan="2"><html:submit titleKey="AddressBook.add. | ||
+ | submit"/></td> | ||
+ | </tr> | ||
+ | </table> | ||
+ | </html:form> | ||
+ | <html:javascript formName="addForm"/> | ||
+ | </source> | ||
+ | Тут интересны два момента. Во-первых, используются тэги ''Struts'' (<font color=darkred>html:…</font>), упрощающие создание компонентов формы. Во-вторых, используется скрипт валидации (<font color=darkred>onsubmit="…"</font> и <font color=darkred><html:Javascript …></font>). Он обеспечивает валидацию прямо в браузере, не отсылая запрос на сервер. | ||
+ | |||
+ | Сами правила валидации задаются в файле '''validation.xml'''. Вот как это выглядит: | ||
+ | <source lang="xml"> | ||
+ | <form-validation> | ||
+ | <formset> | ||
+ | <form name="addForm"> | ||
+ | <field property="age" depends="required,integer,intRange"> | ||
+ | <arg key="AddressBook.add.age"/> | ||
+ | <arg position="1" name="intRange" key="10" | ||
+ | resource="false"/> | ||
+ | <arg position="2" name="intRange" key="20" | ||
+ | resource="false"/> | ||
+ | <var><var-name>min</var-name><var-value>10</var-value></ | ||
+ | var> | ||
+ | <var><var-name>max</var-name><var-value>20</var-value></ | ||
+ | var> | ||
+ | </field> | ||
+ | </form> | ||
+ | </formset> | ||
+ | </form-validation> | ||
+ | </source> | ||
+ | Форму я создал в '''struts-config'''. Называться она должна так же. Для поля <font color=darkred>age</font> задается три правила валидации: <font color=darkred>required</font>, <font color=darkred>integer</font>, <font color=darkred>intRange</font>. Первое говорит, что поле обязательно, второе – что значение должно быть целочисленным, третье правило сообщает, что значение должно лежать в пределах от 10 до 20. В качестве параметров задаются аргументы сообщений, которые будут выводиться при ошибочном заполнении формы (<font color=darkred>arg</font>), и параметры для правил валидации (<font color=darkred>var</font>). | ||
+ | |||
+ | ===Локализация=== | ||
+ | |||
+ | Последняя часть, пока не описанная – локализация. Сообщения хранятся в так называемых properties-файлах, причем если property-файл называется '''MessageResources''', то, например, файл русской локализации должен называться '''MessageResources_ru.properties''', а английской – '''MessageResources_en.properties'''. Если нужно уточнить – например, английский язык, Америка – то получается так: '''MessageResources_en_US.properties'''. | ||
+ | |||
+ | Структура файлов '''properties''' очень проста. Каждая строка (не пустая и не комментарий) состоит из двух частей, разделенных знаком равенства (<font color=darkred>=</font>). Слева – ключ, справа – значение этого ключа. | ||
+ | |||
+ | Эти файлы нужно положить в каталог '''src''', и проконтролировать, чтобы они переписались туда же, куда попадают class-файлы. Плюс, для неанглийских | ||
+ | файлов, их нужно преобразовать в ASCII-формат. Это делается утилитой ''native2ascii'' из поставки JDK. Инструкции по пользованию утилитой можно найти здесь: http://Java.sun.com/Javase/6/docs/technotes/tools/windows/native2ascii.html. | ||
+ | |||
+ | После этого можно использовать в JSP вставки вида <font color=darkred><bean:message key="AddressBook.add.name"/></font>, вместо которых будет вставлена локализованная строка, соответствующая данному ключу (в примере – <font color=darkred>AddressBook.add.name</font>). | ||
+ | |||
+ | ===Что дальше?=== | ||
+ | |||
+ | ''Struts'' – великолепная библиотека, позволяющая упростить разработку сложных приложений. Особенно хорошо такого рода библиотеки подходят для задач, в которых много монотонной работы: больших форм, большого количества простых действий, необходимость проверки данных, вводимых в форму, локализация. | ||
+ | |||
+ | Также полезно, что используются стандартные средства: ''JSP'', ''Servlets'', да и сам ''Struts'' – самая распространенная библиотека для такого рода работ. В результате при приеме на работу, например, знание именно ''Struts'' позволяет набрать несколько дополнительных баллов. | ||
+ | |||
+ | Правда, еще больше баллов дает знание ''EJB3''. Но об этом мы поговорим в следующей, заключительной статье. |
Текущая версия на 10:40, 1 января 2009
|
|
|
- Метамодернизм в позднем творчестве В.Г. Сорокина
- ЛитРПГ - последняя отрыжка постмодерна
- "Ричард III и семиотика"
- 3D-визуализация обложки Ridero создаем обложку книги при работе над самиздатом.
- Архитектура метамодерна - говоря о современном искусстве, невозможно не поговорить об архитектуре. В данной статье будет отмечено несколько интересных принципов, характерных для построек "новой волны", столь притягательных и скандальных.
- Литература
- Метамодерн
- Рокер-Прометей против изначального зла в «Песне про советскую милицию» Вени Дркина, Автор: Нина Ищенко, к.ф.н, член Союза Писателей ЛНР - перепубликация из журнала "Топос".
- Как избавиться от комаров? Лучшие типы ловушек.
- Что делать если роблокс вылетает на windows
- Что делать, если ребенок смотрит порно?
- Почему собака прыгает на людей при встрече?
- Какое масло лить в Задний дифференциал (мост) Visco diff 38434AA050
- О чем может рассказать хвост вашей кошки?
- Верветки
- Отчетность бюджетных учреждений при закупках по Закону № 223-ФЗ
- Срок исковой давности как правильно рассчитать
- Дмитрий Патрушев минсельхоз будет ли преемником Путина
- Кто такой Владислав Поздняков? Что такое "Мужское Государство" и почему его признали экстремистским в России?
- Как правильно выбрать машинное масло в Димитровграде?
- Как стать богатым и знаменитым в России?
- Почему фильм "Пипец" (Kick-Ass) стал популярен по всему миру?
- Как стать мудрецом?
- Как правильно установить FreeBSD
- Как стать таким как Путин?
- Где лучше жить - в Димитровграде или в Ульяновске?
- Почему город Димитровград так называется?
- Что такое метамодерн?
- ВАЖНО! Временное ограничение движения автотранспортных средств в Димитровграде
- Тарифы на электроэнергию для майнеров предложено повысить
Содержание |
[править] Struts, великий и ужасный
ЧАСТЬ 10 Компьютеры были придуманы, чтобы избавить человечество от рутины – так зачем делать вручную то, что можно сгенерировать автоматически? Александр Бабаев покажет, как Struts позволяет избежать монотонного кодирования приложений J2EE.
Вручную делать простые вещи хорошо: быстро, просто, понятно. Но что делать, если нужно так же быстро и просто создать нечто большое? Сайт-портал, например? Не тот портал, который Яндекс, а корпоративный – где интегрирована система хранения документов, информационная система, наша адресная книга?
В PHP в этом случае приходит на помощь CMS. Сладкие слова, которые обещают «в два клика» сделать вам все что угодно. Маркетинг, конечно, страшная сила, но почему так много CMS на PHP, и нет на Java?
Возможно, просто потому что не нужно. Место CMS в Java занимают разнообразные инструментарии разработчика, которые помогают обходить сложные и рутинные работы. В результате можно небольшими силами сделать систему, по сложности намного превосходящую то, что можно сделать «вручную».
[править] Что включается в Struts?
Struts не изобретает велосипедов. В его основе лежит шаблон «MODEl-View-Controller», который мы рассматривали в LXF92, но с его помощью проще создать грамотное приложение, так как четко определены задачи по его созданию; проще разобраться, что необходимо написать для получения результата.
Итак, Struts (будем рассматривать более простую, первую версию) содержит:
- API для создания обработчика запросов (менеджер, распределяющий запросы по действиям) и для создания самих действий (Actions).
- API для создания обработчиков форм.
- API для работы с проверкой корректности заполнения (валидации) форм.
- Tiles. Расширение для создания модульных страниц (что-то «вроде SSI»).
- JSP-taglib, библиотека JPS-тэгов для упрощения написания JSP-страниц.
- XML-конфигурационные файлы, для простой и быстрой настройки всего вышеперечисленного и связи его друг с другом.
Все это в предыдущих статьях мы делали вручную. Теперь настало время проделать то же самое более «технологично».
[править] Как этим пользоваться?
Во-первых, библиотеку нужно скачать. Это можно сделать со странички http://struts.apache.org/download.cgi#struts138. После чего следует распаковать полученный файл и вытащить оттуда все JAR-архивы.
В качестве примера, создадим уже знакомую телефонную книгу. Сперва каталог; в нем, как всегда, организуем подкаталоги для исходных текстов, скомпилированного кода, библиотек и JSP-файлов. Получится что-то такое:
- libs
- antlr-2.7.2.jar
- bsf-2.3.0.jar
- commons-beanutils-1.7.0.jar
- commonschain-1.1.jar
- commons-digester-1.8.jar
- commons-fileipload-1.1.1.jar
- commons-io-1.1.jar
- commons-logging-1.0.4.jar
- commons-validator-1.3.1.jar
- jstl-1.0.2.jar
- oro-2.0.8.jar
- standart-1.0.2.jar
- struts-core-1.3.8.jar
- struts-el-1.3.8.jar
- struts-extras-1.3.8.jar
- struts-faces-1.3.8.jar
- struts-mailreader-dao-1.3.8.jar
- struts-scripting-1.3.8.jar
- struts-taglib-1.3.8.jar
- struts-tiles-1.3.8.jar
- out
- src
- MessageResources_en.properties
- MessageResources_ru.properties
- ru
- web
- index.jsp
- pages
- WEB-INF
Затем в каталог библиотек нужно положить JAR-файлы Struts. Готово? Тогда можно приступать к кодированию.
Когда запрос приходит в сервлет, он первым делом попадает в Struts, который перенаправляет его в менеджер запросов (ActionServet) и далее в нужное действие (Action). Это происходит примерно так:
Как видно, схема здорово напоминает примененную нами при создании адресной книги. Зачем тогда Struts? А затем, чтобы не писать много-много однотипного кода, который повторяется из проекта в проект.
[править] Конфигурационные файлы
Вначале научимся запускать Struts. Для этого нужно перенаправить все запросы сервлету-обработчику и написать файл конфигурации. Вот простой дескриптор для простого Struts-приложения:
<?xml version="1.0" encoding="UTF-8"?> <web-app> <servlet> <servlet-name>action</servlet-name> <servlet-class>org.apache.struts.action.ActionServlet</servlet-class> <init-param> <param-name>config</param-name> <param-value>/WEB-INF/struts-config.xml</param-value> </init-param> </servlet> <servlet-mapping> <servlet-name>action</servlet-name> <url-pattern>*.do</url-pattern> </servlet-mapping> </web-app>
Видно, что все запросы *.do передаются сервлету action, обрабатываемому классом ActionServlet. Это стандартный класс Struts, который перенаправляет запросы в действия. Ему передается конфигурационный файл struts-config.xml. Вот он:
<?xml version="1.0" encoding="UTF-8" ?> <struts-config> <form-beans> <form-bean name="addForm" type="org.apache.struts.validator.DynaValidatorForm"> <form-property name="name" type="java.lang.String" initial="Name"/> <form-property name="phone" type="java.lang.String" initial="1234567"/> <form-property name="age" type="java.lang.Integer" initial="20"/> <form-property name="comment" type="java.lang.String" initial="NoComment"/> </form-bean> <action-mappings> <action path="/add" name="addForm" validate="true" type="ru.linuxformat.actions.Add"> <forward name="form" path="/pages/Add.jsp"/> <forward name="done" path="/list.do"/> </action> <action path="/list" type="ru.linuxformat.actions.ShowAll"> <forward name="ok" path="/pages/List.jsp"/> </action> </action-mappings> <message-resources parameter="MessageResources"/> <plug-in className="org.apache.struts.validator.ValidatorPlugIn"> <set-property property="pathnames" value="/org/apache/struts/validator/validator-rules.xml,/WEB-INF/validation.xml"/> </plug-in> </struts-config>
В данном файле описана форма добавления контакта (form-bean), с использованием стандартного класса формы с поддержкой автоматической проверки полей (DynaValidatorForm).
После этого описано, какие запросы в какие классы перенаправляются.
<action path="/list" type="ru.linuxformat.actions.ShowAll"> <forward name="ok" path="/pages/List.jsp"/> </action>
В этом примере запрос /list.do пойдет в класс ShowAll.Forward используется внутри действия, чтобы упростить перенаправление вывода. Дальше будет понятно, как.
После описания действий все становится совсем просто.Описывается файл, откуда будут браться локализованные строки, и подключается модуль, который обеспечивает простую и мощную валидацию (проверку) форм.
[править] Действия
Перейдем к классам. Все они должны быть унаследованы от класса org.apache.struts.action.Action. При этом в простейшем случае нужно переопределить только один метод, execute(…). Например, вот действие, которое показывает список контактов:
public class ShowAll extends Action { public ActionForward execute(ActionMapping aActionMapping, ActionForm aActionForm, HttpServletRequest aHttpServletRequest, HttpServletResponse aHttpServletResponse) throws Exception { aHttpServletRequest.setAttribute("contacts", Contacter.getInstance().getContactsSortedByName()); return aActionMapping.findForward("ok"); } }
В этом действии в атрибут запроса кладется список всех контактов, после чего вызывается форвард "ok" – именно он был описан чуть выше.
<action path="/list" type="ru.linuxformat.actions.ShowAll"> <forward name="ok" path="/pages/List.jsp"/> </action>
Из описания видно, что форвард перенаправляет обработку запроса в 'List.jsp. Посмотрим, что в нем написано:
<%@ page pageEncoding="UTF-8" language="java" contentType="text/ html; utf-8" %> <%@ taglib uri="http://struts.apache.org/tags-html" prefix="html" %> <%@ taglib uri="http://struts.apache.org/tags-bean" prefix="bean" %> <%@ taglib uri="http://struts.apache.org/tags-logic" prefix="logic" %> <html:html> <head> … </head> <body> … <table border="1"> <tr> <td><bean:message key="AddressBook.list.name"/></td> <td><bean:message key="AddressBook.list.phone"/></td> <td><bean:message key="AddressBook.list.comment"/></td> <td><bean:message key="AddressBook.list.age"/></td> </tr> <logic:iterate id="contact" type="ru.linuxformat.Contact" name="contacts" scope="request"> <tr> <td><%=contact.getName()%></td> <td><%=contact.getPhone()%></td> <td><%=contact.getComment()%></td> <td><%=contact.getAge()%></td> </tr> </logic:iterate> </table> </body> </html:html>
На многоточия заменены неинтересные куски кода, а интересное – в самом начале листинга (taglib). Это так называемые библиотеки тэгов. Примеры можно видеть здесь же. Скажем, <bean:messagekey="AddressBook.list.name"/> вставляет локализованную строку, соответствующую данному ключу. А <logic:iterate> умеет итерировать по коллекциям (списки, ассоциативные массивы и так далее). В данном случае мы итерируем по атрибуту запроса contacts, который мы положили туда в действии.
[править] Формы, проверка корректности форм
Другая интересная часть – формы. Второе действие, добавление контакта, выглядит следующим образом (приведен только код метода execute):
if (aHttpServletRequest.getParameter("name") == null) { return aActionMapping.findForward("form"); } else { DynaActionForm form = (DynaActionForm) aActionForm; Contacter.getInstance().addContact(form.getString("name"), form. getString("phone"), form.getString("comment"), (Integer) form. get("age")); return aActionMapping.findForward("done"); }
Логика очень похожа на ту, что была в предыдущих статьях. Если форма не заполнена, переходим по форварду form, который показывает форму для ввода. Если она заполнена (и валидирована), то контакт добавляется в список, и мы переходим на форвард done. Вот и сама форма (точнее, ее основная часть):
<html:form action="/add" method="post" onsubmit="return validateAddForm(this);"> <table> <tr> <td><bean:message key="AddressBook.add.name"/>:</td> <td><html:text property="name"/></td> </tr> … <tr> <td colspan="2"><html:submit titleKey="AddressBook.add. submit"/></td> </tr> </table> </html:form> <html:javascript formName="addForm"/>
Тут интересны два момента. Во-первых, используются тэги Struts (html:…), упрощающие создание компонентов формы. Во-вторых, используется скрипт валидации (onsubmit="…" и <html:Javascript …>). Он обеспечивает валидацию прямо в браузере, не отсылая запрос на сервер.
Сами правила валидации задаются в файле validation.xml. Вот как это выглядит:
<form-validation> <formset> <form name="addForm"> <field property="age" depends="required,integer,intRange"> <arg key="AddressBook.add.age"/> <arg position="1" name="intRange" key="10" resource="false"/> <arg position="2" name="intRange" key="20" resource="false"/> <var><var-name>min</var-name><var-value>10</var-value></ var> <var><var-name>max</var-name><var-value>20</var-value></ var> </field> </form> </formset> </form-validation>
Форму я создал в struts-config. Называться она должна так же. Для поля age задается три правила валидации: required, integer, intRange. Первое говорит, что поле обязательно, второе – что значение должно быть целочисленным, третье правило сообщает, что значение должно лежать в пределах от 10 до 20. В качестве параметров задаются аргументы сообщений, которые будут выводиться при ошибочном заполнении формы (arg), и параметры для правил валидации (var).
[править] Локализация
Последняя часть, пока не описанная – локализация. Сообщения хранятся в так называемых properties-файлах, причем если property-файл называется MessageResources, то, например, файл русской локализации должен называться MessageResources_ru.properties, а английской – MessageResources_en.properties. Если нужно уточнить – например, английский язык, Америка – то получается так: MessageResources_en_US.properties.
Структура файлов properties очень проста. Каждая строка (не пустая и не комментарий) состоит из двух частей, разделенных знаком равенства (=). Слева – ключ, справа – значение этого ключа.
Эти файлы нужно положить в каталог src, и проконтролировать, чтобы они переписались туда же, куда попадают class-файлы. Плюс, для неанглийских файлов, их нужно преобразовать в ASCII-формат. Это делается утилитой native2ascii из поставки JDK. Инструкции по пользованию утилитой можно найти здесь: http://Java.sun.com/Javase/6/docs/technotes/tools/windows/native2ascii.html.
После этого можно использовать в JSP вставки вида <bean:message key="AddressBook.add.name"/>, вместо которых будет вставлена локализованная строка, соответствующая данному ключу (в примере – AddressBook.add.name).
[править] Что дальше?
Struts – великолепная библиотека, позволяющая упростить разработку сложных приложений. Особенно хорошо такого рода библиотеки подходят для задач, в которых много монотонной работы: больших форм, большого количества простых действий, необходимость проверки данных, вводимых в форму, локализация.
Также полезно, что используются стандартные средства: JSP, Servlets, да и сам Struts – самая распространенная библиотека для такого рода работ. В результате при приеме на работу, например, знание именно Struts позволяет набрать несколько дополнительных баллов.
Правда, еще больше баллов дает знание EJB3. Но об этом мы поговорим в следующей, заключительной статье.