Разработка веб-приложений на Spring. Часть 2 (Конфигурация)

Posted Wednesday, February 6, 2008 under J2EE, Java, Spring, Фреймворки.

В предыдущей статье мы занимались проектированием будущего приложения на Spring. Определили его цели, структуру, а также рассмотрели основные компоненты. В качестве примера используем всё тот же AllOfRss.com.

В данной статье я рассмотрю конфигурацию нашего приложения. В процессе будут созданы все необходимые конфигурационные файлы для его полноценного функционирования.
Для начала откроем Eclipse и создадим новый проект (File->New->Web Project), также рекомендую установить плагин для более комфортной работы с фреймворком Spring – Spring IDE Plugin. В процессе создания проекта, Eclipse попросит указать название вашей “Web root folder” (по умолчанию стоит – WebRoot), я обычно указываю – web, а также J2EE Specification Level, отметьте – Java EE 5.0 (если, конечно, вы используете Java 5). Остальное пусть будет без изменений.

Веб дескриптор

Как и в любом другом веб-приложении на Java всё начинается с конфигурации web.xml (web(WebRoot)/WEB-INF/web.xml).

Для начала установим путь к осноному конфигу Spring.

web.xml

<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/allofrss-servlet.xml</param-value>
</context-param>

<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>

Сравнительно с другими веб-приложениям на Java, приложение на Spring не отличается особой оригинальностью поскольку здесь тоже всё работает через сервлеты, правда сервлет здесь будет всего один. DispatcherServlet главный сервлет в приложении на Spring. Он выполняет роль “гейтвея” входящих запросов, перенаправляя вызовы “внутрь” системы (в науке это называется паттерном Front Controller).

web.xml

<servlet>
<servlet-name>allofrss</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>

Следует, также, установить маппинг на DispatcherServlet. Конструкция, приведенная ниже, означает, что все запросы, которые начинаются с “/c” будут направлены на DispatcherServlet.

web.xml

<servlet-mapping>
<servlet-name>allofrss</servlet-name>
<url-pattern>/c/*</url-pattern>
</servlet-mapping>

И последенее, что следует внести в наш web.xml:

<welcome-file-list>
<welcome-file>index.jsp</welcome-file>
</welcome-file-list>

Закончив с конфигурацией web.xml, можно перейти к настройке Spring приложения. Я предлагаю разделить конфигурацию на 3 конфигурационных файла:

  • /WEB-INF/context/common.xml – основной конфиг, содержащий информацию о маппингах и слое отображения
  • /WEB-INF/context/allofrss-context.xml – конфиг, содержащий информацию о контроллерах приложения
  • /WEB-INF/context/allofrss-data.xml – содержит информацию о классах доступа к БД

Настройка маппинга и слоя отображения

Создайте файл /WEB-INF/context/common.xml следующего содержания.

common.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=”http://www.springframework.org/schema/aop”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd”>

<!– This config contains main info about application mappings and view resolvers–>

</beans>

Далее, следует добавить информацию о классе, который будет заниматься маппингом реквестов в приложении. Как я упоминал в предыдущей статье, для этих целей будем использовать SimpleUrlHandlerMapping.

common.xml

<bean id=”simpleUrlMapping” class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>

</bean>

В терминах Spring любой класс, конфигурируемый с его помощью называется бином(<bean…), не путать с JavaBeans. В связи с этим, поначалу вас может одолевать вопрос, типа, причём тут бин если я подключаю обычный класс. Извините, не ко мне вопрос, просто смиритесь :)

Запись id=”simpleUrlMapping” определяет уникальный идентификатор для подключаемого класса для возможности ссылаться на этот класс в пределах конфигов по короткому имени.

Определив класс, добавим ему параметры маппинга.

common.xml

<bean id=”simpleUrlMapping” class=”org.springframework.web.servlet.handler.SimpleUrlHandlerMapping”>
<property name=”order”><value>0</value></property>
<property name=”mappings”>
<props>
<prop key=”/welcome”>inviteController</prop>
<prop key=”/about”>aboutController</prop>
</props>
</property>
</bean>

Записи <prop key=”/welcome”>inviteController</prop>, <prop key=”/about”>aboutController</prop> означают, что запросы /welcome и /about должны обработать классы с id inviteController и aboutController соотвественно.

Осталось подключить класс, который будет заниматься отображением.

common.xml

<bean id=”viewResolver” class=”org.springframework.web.servlet.view.InternalResourceViewResolver”>
<property name=”cache” value=”false”/> <!– Запрещаем кэширование –>
<property name=”viewClass”><value>org.springframework.web.servlet.view.JstlView</value></property> <!– Используем JSTL –>
<property name=”prefix”><value>/WEB-INF/templates/jsp/</value></property> <!– Путь, где будут храниться JSP –>
<property name=”suffix”><value>.jsp</value></property> <!– Расширение для файлов шаблонов –>
</bean>

Конфигурация контроллеров

Создайте файлик /WEB-INF/context/allofrss-context.xml с базовым содержанием, аналогичным предыдущему common.xml.

Добавим информацию о классах контроллерах.

allofrss-context.xml

<bean id=”inviteController” class=”com.allofrss.controllers.action.InviteActionController”>
<property name=”commandName” value=”invite”/> <!– Название формы–>
<property name=”commandClass” value=”com.allofrss.beans.form.InviteFormBean”/> <!– Бин формы –>
<property name=”formView” value=”invite”/> <!– Название JSP с формой –>
<property name=”successView” value=”invite”/> <!– Название JSP, которая будет показана после успешной обработки формы –>
<property name=”validator”> <!– Класс валидатора формы –>
<bean class=”com.allofrss.validators.InviteFormValidator”/>
</property>
</bean>

<bean id=”aboutController” class=”com.allofrss.controllers.lookup.AboutController”/>

Конфигурация доступа к БД

Аналогично, создаём файл /WEB-INF/context/allofrss-data.xml следующего содержания.

allofrss-data.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=”http://www.springframework.org/schema/aop”
xmlns:tx=”http://www.springframework.org/schema/tx”
xsi:schemaLocation=”
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd”>

</beans>

Для начала следует определить источник данных, в качестве параметров класса передать данные о драйвере базы данных, логине и пароле.

allofrss-data.xml

<bean id=”dataSource” class=”org.apache.commons.dbcp.BasicDataSource” destroy-method=”close”>
<property name=”driverClassName” value=”com.mysql.jdbc.Driver”/>
<property name=”url” value=”jdbc:mysql://localhost:3306/database_name?useUnicode=true”/>
<property name=”username” value=”username”/>
<property name=”password” value=”password”/>
</bean>

Как я упоминал в предыдущей статье, в качестве ORM будет использоваться фреймворк Hibernate. В Spring присутствуют классы, облегчающие процесс интеграции Hibernate в ваше приложение. Прежде всего следует определить класс поддержки сессий БД.

allofrss-data.xml

<bean id=”sessionFactory” class=”org.springframework.orm.hibernate3.LocalSessionFactoryBean”>
<property name=”dataSource” ref=”dataSource”/> <!– В качестве параметра передается ссылка на определенный выше класс источника данных –>
<property name=”mappingResources”/>
<property name=”hibernateProperties”> <!– Некоторые параметры Hibernate –>
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.show_sql=true
hibernate.format_sql=false
hibernate.use_sql_comments=true
hibernate.connection.charSet=utf8
</value>
</property>
</bean>

На данном этапе можно сказать, что конфигурация доступа к БД закончена, однако мы на этом не остановимся и добавим ещё один очень важный компонент – поддержку транзакций.

Воспользуемся встроенным в Spring менеджером транзакций DataSourceTransactionManager, а также поддержкой AOP. Для этого добавим несколько простых строчек.

allofrss-data.xml

<tx:annotation-driven transaction-manager=”txManager”/>

<bean id=”txManager” class=”org.springframework.jdbc.datasource.DataSourceTransactionManager”>
<property name=”dataSource” ref=”dataSource”/> <!– В качестве параметра всё тот же источник данных –>
</bean>

Ну и на последок, объединим все созданные конфигурационные файлы, создав файл /WEB-INF/allofrss-servlet.xml с таким содержанием.

allofrss-servlet.xml

<?xml version=”1.0″ encoding=”UTF-8″?>
<beans xmlns=”http://www.springframework.org/schema/beans”
xmlns:xsi=”http://www.w3.org/2001/XMLSchema-instance”
xmlns:aop=”http://www.springframework.org/schema/aop”
xsi:schemaLocation=”http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd”>

<import resource=”context/allofrss-data.xml” />
<import resource=”context/allofrss-context.xml” />
<import resource=”context/common.xml” />
</beans>

Вот теперь действительно всё. В этой статье я планировал перейти уже непосредственно к реализации нашего приложения, однако в процессе написания всё же решил разделить статью на две части. Ожидайте следующую завершающую часть уже совсем скоро.

Читайте также:

7 comments

  1. Андрей Ясинецкий says:

    Я к сожалению ещё не научился красиво оформлять код в статье, так что заранее прошу прощения за корявость. Буду благодарен за различные советы в этой области.

    Ответить
  2. М-даа, почитал и подумал, насколько же проще такие веб-приложения делать на Django :) Впрочем, в джаве в struts-2 если конфигурацию стараться разруливать аннотациями – тоже не страшно :)

    Ответить
  3. Андрей Ясинецкий says:

    До аннотаций мы ещё доберёмся ;)

    по поводу Джанго, согласен, есть свои плюсы. Но с другой стороны, в джаве есть много готовых удобных решений, хотя бы взять тот же Spring Web Flow. Сложно переоценить удобство этой библиотеки. Просто нужно четко представлять себе задачу и подбирать под её реализацию наиболее удобный инструмент.

    Помнится, ты как-то приводил пример распределённой архитектуры, когда кэш у тебя хранился в MySql, а все основные данные в PostgreSql. Как бы ты решил эту задачу в Джанго? Насколько я знаю, он не позволяет работать с нексколькими датасорсами (или я ошибаюсь?)…

    Ответить
  4. Конечно, вот я потому и говорю, что это для такого проекта как твой AllOfRSS :) Django приходится патчить, чтобы кеш хранить в одной базе, а сами данные приложения – в другой. И сейчас работает только с одиним датасорсом, что реально один из основных минусов системы. Но для проектов не очень больших это и не надо, а проекты под многомилионные нагрузки, как оказалось на собственном опыте, совсем не обязательно должны быть разбиты по нескольким СУБД (я имею в виду модель, а не модель-сессии-статистика-кеш).

    Я все еще считаю джаву лучшим на сегодня решением для enterprise-проектов, где у нас много интеграции со сторонними разработками, много унаследованного кода и.т.п. Но для мелких и средних веб-проектов ее бы сейчас ни за что не стал использовать, для крупных самостоятельных веб-проектов — надо смотреть по ситуации.

    п.с. кеш в mysql, данные в postgres, через пару месяцев на джанго будем решать этот вопрос как раз. :)

    Ответить
  5. Сергей Попов says:

    Жду продолжения, спасибо за статью.

    Ответить
  6. Андрей Ясинецкий says:

    Продолжение уже написано и в данный момент вносятся последние правки. так что совсем скоро опубликую ;)

    Ответить
  7. Убедительная просьба:
    1) добавлять screenshots к работе с приложениями типа Eclipse -> сильнА помогает чайникам
    2) хорошая практика аттачить код проекта к статье

    Автору в любом случае огромное спасибо! И, как говориться, пешы исчо!

    Ответить

Leave a Reply

Распечатать
Поделиться
Twitter It!

Статья относится к