1. Введение
В этой статье мы сосредоточимся на основной концепции Spring MVC — контроллерах.
2. Обзор
Давайте начнем с того, что сделаем шаг назад и посмотрим на концепцию Front Controller
в типичной архитектуре Spring Model View Controller
.
На очень высоком уровне, вот основные обязанности, которые мы рассматриваем:
- Перехватывает входящие запросы
- Преобразует полезную нагрузку запроса во внутреннюю структуру данных
- Отправляет данные в
модель
для дальнейшей обработки - Получает обработанные данные из
модели
и передает эти данные впредставление
для рендеринга .
Вот краткая диаграмма потока высокого уровня в Spring MVC
:
Как видите, DispatcherServlet
играет роль Front Controller
в архитектуре.
Диаграмма применима как к типичным контроллерам MVC, так и к контроллерам RESTful — с некоторыми небольшими отличиями (описанными ниже).
В традиционном подходе приложения MVC
не ориентированы на сервисы, поэтому существует View Resolver
, который отображает окончательные представления на основе данных, полученных от контроллера
.
Приложения RESTful
спроектированы так, чтобы быть сервис-ориентированными и возвращать необработанные данные (обычно JSON/XML). Поскольку эти приложения не выполняют никакого рендеринга представлений, нет никаких преобразователей
представлений — обычно ожидается, что контроллер будет отправлять данные напрямую через HTTP-ответ.
Начнем с контроллеров в стиле MVC0.
3. Зависимости Maven
Чтобы иметь возможность работать с Spring MVC
, давайте сначала разберемся с зависимостями Maven:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.6.RELEASE</version>
<dependency>
Чтобы получить последнюю версию библиотеки, взгляните на spring-webmvc на Maven Central .
4. Веб-конфигурация проекта
Теперь, прежде чем рассматривать сами контроллеры, нам сначала нужно настроить простой веб-проект и выполнить быструю настройку сервлета .
Давайте сначала посмотрим, как можно настроить DispatcherServlet без использования
web.xml
, а вместо этого с помощью инициализатора:
public class StudentControllerConfig implements WebApplicationInitializer {
@Override
public void onStartup(ServletContext sc) throws ServletException {
AnnotationConfigWebApplicationContext root =
new AnnotationConfigWebApplicationContext();
root.register(WebConfig.class);
root.refresh();
root.setServletContext(sc);
sc.addListener(new ContextLoaderListener(root));
DispatcherServlet dv =
new DispatcherServlet(new GenericWebApplicationContext());
ServletRegistration.Dynamic appServlet = sc.addServlet("test-mvc", dv);
appServlet.setLoadOnStartup(1);
appServlet.addMapping("/test/*");
}
}
Чтобы настроить без XML, убедитесь, что в вашем пути к классам есть servlet-api
3.1.0.
Вот как будет выглядеть файл web.xml :
<servlet>
<servlet-name>test-mvc</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<load-on-startup>1</load-on-startup>
<init-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/test-mvc.xml</param-value>
</init-param>
</servlet>
Здесь мы устанавливаем свойство contextConfigLocation
, указывающее на файл XML
, используемый для загрузки контекста Spring. Если свойства нет, Spring будет искать файл с именем {servlet_name}-servlet.xml
.
В нашем случае servlet_name
— это test-mvc
, поэтому в этом примере DispatcherServlet
будет искать файл с именем test-mvc-servlet.xml
.
Наконец, давайте настроим DispatcherServlet
и сопоставим его с определенным URL
-адресом — чтобы закончить нашу систему на основе Front Controller
:
<servlet-mapping>
<servlet-name>test-mvc</servlet-name>
<url-pattern>/test/*</url-pattern>
</servlet-mapping>
Таким образом, в этом случае DispatcherServlet
будет перехватывать все запросы в шаблоне /test/*
.
5. Веб-конфигурация Spring MVC
Давайте теперь посмотрим, как можно настроить Dispatcher Servlet с помощью
Spring Config
:
@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {
"com.foreach.controller.controller",
"com.foreach.controller.config" })
public class WebConfig implements WebMvcConfigurer {
@Override
public void configureDefaultServletHandling(
DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
@Bean
public ViewResolver viewResolver() {
InternalResourceViewResolver bean =
new InternalResourceViewResolver();
bean.setPrefix("/WEB-INF/");
bean.setSuffix(".jsp");
return bean;
}
}
Теперь давайте рассмотрим настройку Dispatcher Servlet
с помощью XML
. Снимок XML-файла DispatcherServlet
— XML
- файл, который DispatcherServlet
использует для загрузки пользовательских контроллеров
и других объектов
Spring
, показан ниже: ``
<context:component-scan base-package="com.baledung.controller" />
<mvc:annotation-driven />
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix">
<value>/WEB-INF/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
Основываясь на этой простой конфигурации, фреймворк, конечно же, инициализирует любой bean-компонент контроллера, который он найдет в пути к классам.
Обратите внимание, что мы также определяем View Resolver, отвечающий за визуализацию представлений — здесь мы будем использовать Spring InternalResourceViewResolver
. Это предполагает, что имя представления
будет разрешено, что означает поиск соответствующей страницы с использованием префикса и суффикса (оба определены в конфигурации XML ).
Так, например, если контроллер
возвращает представление
с именем « welcome» ,
распознаватель
представлений попытается разрешить страницу с именем «welcome.jsp»
в
папке WEB -INF .
``
6. Контроллер MVC
Теперь давайте, наконец, реализуем контроллер в стиле MVC.
Обратите внимание, как мы возвращаем объект ModelAndView
, который содержит карту модели
и объект представления
; оба будут использоваться View Resolver
для рендеринга данных:
@Controller
@RequestMapping(value = "/test")
public class TestController {
@GetMapping
public ModelAndView getTestData() {
ModelAndView mv = new ModelAndView();
mv.setViewName("welcome");
mv.getModel().put("data", "Welcome home man");
return mv;
}
}
Итак, что именно мы здесь установили.
Во-первых, мы создали контроллер с именем TestController
и сопоставили его с путем «/test»
. В классе мы создали метод, который возвращает объект ModelAndView
и сопоставляется с запросом GET
, поэтому любой вызов URL, заканчивающийся на « test
», будет перенаправлен DispatcherServlet
в метод getTestData
в TestController
.
И, конечно же, мы возвращаем объект ModelAndView
с некоторыми данными модели.
Объект представления имеет имя, установленное на « добро пожаловать
». Как обсуждалось выше, View Resolver
будет искать страницу в папке WEB-INF с именем «
welcome.jsp
».
Ниже вы можете увидеть результат примера операции GET :
Обратите внимание, что URL
-адрес заканчивается на «test»
. Шаблон URL
— «/test/test
».
Первый «/test»
исходит от сервлета, а второй — от сопоставления контроллера.
7. Дополнительные зависимости Spring для REST
Теперь давайте рассмотрим контроллер RESTful. Конечно, неплохо бы начать с дополнительных зависимостей Maven, которые нам нужны для этого:
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>5.0.6.RELEASE</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.5</version>
</dependency>
</dependencies>
Пожалуйста, обратитесь к ссылкам jackson -core , spring-webmvc и spring-web для получения новейших версий этих зависимостей.
Джексон
, конечно, здесь не обязателен, но это, безусловно, хороший способ включить поддержку JSON. Если вы хотите глубже изучить эту поддержку, ознакомьтесь со статьей о конвертерах сообщений здесь .
8. Контроллер REST
Настройка для приложения Spring RESTful
такая же, как и для приложения MVC
, с той лишь разницей, что в нем нет View Resolvers
и карты модели.
Обычно API просто возвращает необработанные данные обратно клиенту — обычно представления XML
и JSON
— поэтому DispatcherServlet
обходит преобразователи представлений
и возвращает данные прямо в теле ответа HTTP .
Давайте посмотрим на простую реализацию контроллера RESTful:
@Controller
public class RestController {
@GetMapping(value = "/student/{studentId}")
public @ResponseBody Student getTestData(@PathVariable Integer studentId) {
Student student = new Student();
student.setName("Peter");
student.setId(studentId);
return student;
}
}
Обратите внимание на аннотацию @ResponseBody
к методу, которая указывает Spring обойти преобразователь представления
и , по сути, записать вывод непосредственно в тело HTTP-ответа .
Быстрый снимок вывода показан ниже:
Приведенный выше вывод является результатом отправки запроса GET
в API с идентификатором
студента 1
.
Одно небольшое замечание: аннотация @RequestMapping
— это `` одна из тех центральных аннотаций, которые вам действительно придется изучить, чтобы использовать их потенциал в полной мере.
9. Spring Boot и аннотация @RestController
Аннотация @RestController
из Spring Boot — это, по сути, быстрый ярлык, который избавляет нас от необходимости всегда определять @ResponseBody
.
Вот предыдущий пример контроллера, использующий эту новую аннотацию:
@RestController
public class RestAnnotatedController {
@GetMapping(value = "/annotated/student/{studentId}")
public Student getData(@PathVariable Integer studentId) {
Student student = new Student();
student.setName("Peter");
student.setId(studentId);
return student;
}
}
10. Заключение
В этом руководстве мы рассмотрим основы использования контроллеров в Spring как с точки зрения типичного приложения MVC, так и с точки зрения RESTful API.
Конечно, весь код в статье доступен на GitHub .