SPRING-SOURCE.RU
Исходный код:
Авиадиспетчер 1 этап
Авиадиспетчер 2 этап
Авиадиспетчер 3 этап
Последнее обновление 02.07.2010

Программа авиадиспетчер. 1 часть

В этой статье будет создано первое SpringMVC приложение. В качестве сервера можно использовать Tomcat 6, среда разработки Eclipse.
Приложение создается в несколько этапов и будет расписано в нескольких статьях. Базы данных в этой статье мы использовать не будем, а введем все данные сами.
Давайте опишем нашу программу не UML диаграммами, а словами. Начало нашей программы будет состоять из пакетов, первый пакет будет использоваться в первой части нашего урока, а второй во второй части. Разделение упростит понимание принципов работы SpringMVC.

Доменная модель. 1 пакет

Airport класс.

SpecialDeal класс (переводится как специальное предложение).

Свойства похожи на FlightLeg и FlightSearchCriteria (их 5).

Конструктор здесь устанавливает все эти свойства
Методы getter-ы и две проверки даты.

Доменная модель. 2 пакет

Flight класс.

Маршрут между двумя городами с остановками от нуля и более

В этом классе много getter-ов:

FlightLeg класс.

Остановки в маршруте.

Cодержит свойства:

В конструкторе устанавливаются все четыре свойства, а методы возвращают эти свойства

FlightSearchCriteria класс.

Свойства:

Методы здесь устанавливают и выводят эти значения за счет getter-ов и setter-ов.

Сервис

Создаем интерфейс FlightService.

DummyFlightSerice класс. Реализация интерфейса FlightService.

Реализация первого метода getSpecialDeals():

После выполнения этого метода у нас будет список специальных предложений.

Реализация второго метода findFlights (поиск маршрутов). Этот метод на данный момент не используется. Возвращает маршрут:

Описание

Сервис интерфейс - interface FlightService

                        
public interface FlightService {
    List<SpecialDeal> getSpecialDeals();
    List<Flight> findFlights(FlightSearchCriteria search);

}
		

Он помогает получить более легкий доступ к частям нашей доменной модели. Реализуется это при помощи шаблона фасад.

ApplicationContext

                        
<beans>
  <bean id="flightService"
    class="com.airport.service.DummyFlightService" />
</beans>
		

Здесь мы определяем реализацию flightService - обычный бин. Позже в web компоненты приложения будет вводиться этот сервис. Мы целенаправленно разделили бины приложения от любых web компонентов.

Web компоненты
Controller, View и ModelAndView классы.
Spring MVC делегирует ответственность за обработку HTTP запросов контроллерам. Контроллеры как сервлеты, соединены с одним или более URI и работают с HttpServletRequest и HttpServletResponse объектами.
View. Ответ от контроллера визуализируется экземпляром View класса.
ModelAndView. Когда процесс завершился, контроллер берет на себя ответственность за построение коллекции объектов, которые составляют ответ (модель), а также выбор страницы, которую увидит пользователь.
Модель это тип Map произвольных объектов, а View обычно задается логическим именем.

В нашем случае
Мы создали контроллер, который делегирует сервисному слою загружать специальные предложения, так чтобы View мог выводить это в XHTML.
В нашем приложении мы создали HomeController для обработки главной страницы. Метод handleRequestInternal(request, response) отвечает за обработку запроса. На выходе он выдает ModelAndView, это класс содержащий информацию об отображении (View) и данные для нее (Model). В данном случае View это страница home, но на самом деле страница определяется в viewResolver в spring-servlet.xml. А Model в данном случа хранит наши цифры, ну и в общем-то можно положить любые объекты, которые надо обработать в JSP. В обработчике можно не возвращать объект ModelAndView, можно вернуть null, и сделать всю работу по выдаче данных самому, через response.getOutputStream() и т.д., что тоже иногда полезно.
Нужно упомянуть, что по-умолчанию используется InternalResourceViewResolver. Это преобразователь (resolver) рассматривает имя представления (view) как путь к ресурсу web-приложения. То есть путь к приложению у нас home.

Метод service()
Метод service() является сердцем сервлета. Каждый запрос от клиента приводит к одному вызову метода service(). Этот метод читает запрос и формирует ответное сообщение при помощи своих двух аргументов ServletRequest и ServletResponse : Объект ServletRequest содержит данные от клиента. Данные состоят из пар имя/значение и InputStream. Существует несколько методов, возвращающих информацию о параметрах клиента. InputStream может быть получен при помощи метода getInputStream(). Этот метод возвращает объект ServletInputStream, который можно использовать для получения дополнительных данных от клиента. Если необходима выполнить обработку символьных данных, а не двоичных, то можно получить объект BufferedReader при помощи метода getReader().
Объект ServletResponse содержит ответ сервлета клиенту. Во время подготовки ответа прежде всего вызывается метод setContentType() для установки типа MIME ответа. Затем могут быть использованы методы getOutputStream() или getWriter() для получения объектов и ServletOutputStream или PrintWriter соответственно для передачи данных обратно клиенту.
Таким образом, существуют два способа передачи информации от клиента к сервлету. Первый – через передачу значений в параметрах запроса. Значения параметров могут быть вставлены в URL. Второй способ передачи информации от клиента к сервлету осуществляется через InputStream (или Reader).
Работа метода service() по существу проста – он создает ответ на каждый клиентский запрос, переданный ему с сервера. Однако необходимо помнить, что могут существовать несколько параллельных запросов, обрабатываемых в одно и то же время. Если метод service() требует каких-либо внешних ресурсов, таких как файлы, базы данных, то необходимо гарантировать, чтобы доступ к ресурсам являлся потокозащищенным.

Главный вывод из этого это то, что контроллеры не предназначены визуализировать ответ. Вместо этого он делегирует эту задачу другим компонентам SpringMVC. Специальное предложение переходит от FlightService напрямую в модель с именем specials. ModelAndView экземпляр конструируется с именем home, которое используется при визуализации этого контроллера.

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

Также как есть ApplicationContext для FlightService, web компоненты имеют свой ApplicationContext. HomeController определен и настраивается в spring-servlet.xml, чье имя имеет некую особенность. По умолчанию Spring ищет все бины сконфигурированные с именем, начинающимся с / (слеша) и использует это имя для URI связывания. Мы связываем HomeController к URI /home (это префикс), который будет добавлен к полному WebApplicationContext (как это происходит будет рассказано чуть позже URI mapping for Controllers).
После того как контроллер настроен и сконфигурирован, время построить и сконфигурировать View.
Если все нормально, HomeController создаст ModelAndView с View именем home. InternalResourceViewResolver позволяет просто связать View логическое имя с View экземпляром, только если логическое View имя равно имени файла (home = home.jsp). Дополнительное преимущество использования нашего ViewResolver заключается в том, что он уже по умолчанию поддерживает jsp страницы. В итоге получается следующее: имя home в контроллере + viewResolver = /WEB-INF/jsp/home.jsp

Вывод: Мы создали контроллер с именем HomeController и JSP файл для показа результатов работы.

HomeController делегирует FlightService найти «специальное предложение» и затем разместить результаты в ModelAndView. Этот ModelAndView объект возращается из контроллера включая имя View.
View имя ссылается на jsp файл при помощи InternalResourceViewResolver. Создается полный путь через соединение префикса, имя view и суффикса. InternalResourceViewResolver и HomeController определяются и конфигурируются в spring-servler.xml файле, который определяет все бины, которые нужны для web компонентов приложения.

Теперь переходим к web.xml. Web Application конфигурация.

Иницилизация Root ApplicationContext
SpringMVC обычно имеет два ApplicationContext настроенных как взаимосвязь родитель-потомок. Родитель или Root ApplicationContext содержит все не web бины, такие как сервисы, DAO и поддержку POJO. В нашем случае ApplicationContext содержит FlightService реализацию и его имя applicationContext.xml. ApplicationContext должен иницилизироваться перед web ресурсами, так как он предоставляет сервисы необходимые для web.
Для создания родителя ApplicationContext есть два выбора. Первое — использование ContextLoaderListener, в ответ на contextInitialized() callback ServletContainerListener. Этот класс рекомендуется для создания ApplicationContext, но он доступен только в контейнере Servlet 2.3 или выше.
Если вы используете контейнер Servlet 2.2, вы должны использовать ContextLoaderListener. В нашем примере мы именно его и используем.
Настраивается ContextLoaderListener в <listener> элементе в web.xml файле. В ходе иницилизации используется путь и файл по умолчанию /WEB-INF/applicationContext.xml для поиска файла для Root ApplicationContext. После того как ApplicationContext построен он располагается в поле видимости web приложения.
После того как Root сконфигурирован, остается последний кусочек мозайки: должен быть определен главный сервлет для приложения, который предоставит точку входа. DispatcherServlet — играет роль, координируя организацию процесса для каждого входящего web запроса.

DispatcherServlet

Сервлет DispatcherServlet требует определения контроллера и других конфигураций в файле "имя сервлета"-servlet.xml. DispatcherServlet — это Front Controller системы. Например, DispatcherServlet доставляет ModelAndView возвращенный контроллером к соответствующему viewResolver. DispatcherServlet также создает WebApplicationContext, который содержит web компоненты такие как контроллеры и viewResolver.

URI связывание для контроллера

Существует три компонента для связывания URI пути, webApplicationContext пути, Servlet связывание и Controller связывание. Как вы помните, мы определили HomeController с URL /home, который дополнительно связывается с сервлетом /app/*. Третий кусок головоломки WebApplicationContext путь. Связав все это, мы получим путь к нашему приложнию в web браузере.

Как все работает. Последовательность обработки запроса

Работа начинается, когда HTTP запрос вводиться в систему. Обратите внимание как DispatcherServlet управляет работой, взяв возвращенный контроллером ModelAndView и затем делегирует ViewResolver найти View. На этой диаграмме изображена лишь часть работы DispatcherServlet. Тем не менее, это точно отражает важные этапы жизненного цикла связанного с HomeController и FlightService объектами.

Spring Request Handling Sequence