В предыдущей статье мы занимались проектированием будущего приложения на 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>
Вот теперь действительно всё. В этой статье я планировал перейти уже непосредственно к реализации нашего приложения, однако в процессе написания всё же решил разделить статью на две части. Ожидайте следующую завершающую часть уже совсем скоро.
Читайте также:
Я к сожалению ещё не научился красиво оформлять код в статье, так что заранее прошу прощения за корявость. Буду благодарен за различные советы в этой области.
М-даа, почитал и подумал, насколько же проще такие веб-приложения делать на Django
Впрочем, в джаве в struts-2 если конфигурацию стараться разруливать аннотациями – тоже не страшно
До аннотаций мы ещё доберёмся
по поводу Джанго, согласен, есть свои плюсы. Но с другой стороны, в джаве есть много готовых удобных решений, хотя бы взять тот же Spring Web Flow. Сложно переоценить удобство этой библиотеки. Просто нужно четко представлять себе задачу и подбирать под её реализацию наиболее удобный инструмент.
Помнится, ты как-то приводил пример распределённой архитектуры, когда кэш у тебя хранился в MySql, а все основные данные в PostgreSql. Как бы ты решил эту задачу в Джанго? Насколько я знаю, он не позволяет работать с нексколькими датасорсами (или я ошибаюсь?)…
Конечно, вот я потому и говорю, что это для такого проекта как твой AllOfRSS
Django приходится патчить, чтобы кеш хранить в одной базе, а сами данные приложения – в другой. И сейчас работает только с одиним датасорсом, что реально один из основных минусов системы. Но для проектов не очень больших это и не надо, а проекты под многомилионные нагрузки, как оказалось на собственном опыте, совсем не обязательно должны быть разбиты по нескольким СУБД (я имею в виду модель, а не модель-сессии-статистика-кеш).
Я все еще считаю джаву лучшим на сегодня решением для enterprise-проектов, где у нас много интеграции со сторонними разработками, много унаследованного кода и.т.п. Но для мелких и средних веб-проектов ее бы сейчас ни за что не стал использовать, для крупных самостоятельных веб-проектов — надо смотреть по ситуации.
п.с. кеш в mysql, данные в postgres, через пару месяцев на джанго будем решать этот вопрос как раз.
Жду продолжения, спасибо за статью.
Продолжение уже написано и в данный момент вносятся последние правки. так что совсем скоро опубликую
Убедительная просьба:
1) добавлять screenshots к работе с приложениями типа Eclipse -> сильнА помогает чайникам
2) хорошая практика аттачить код проекта к статье
Автору в любом случае огромное спасибо! И, как говориться, пешы исчо!