«1. Введение

В этой статье мы сосредоточимся на основной концепции Spring MVC — контроллерах.

2. Обзор

Давайте начнем с того, что сделаем шаг назад и посмотрим на концепцию Front Controller в типичной архитектуре Spring Model View Controller.

На очень высоком уровне, вот основные обязанности, которые мы рассматриваем:

    Перехватывает входящие запросы Преобразовывает полезную нагрузку запроса во внутреннюю структуру данных Отправляет данные в Модель для дальнейшей обработки Получает обработанные данные из модели и передает эти данные в представление для рендеринга

Вот краткая диаграмма высокоуровневого потока в Spring MVC:

SpringMVC

Как видите, DispatcherServlet играет роль переднего контроллера в архитектуре.

Схема применима как к типичным контроллерам MVC, так и к контроллерам RESTful — с некоторыми небольшими отличиями (описанными ниже).

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

Приложения 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 Web Config

Давайте теперь посмотрим, как можно настроить Dispatcher Servlet с помощью Spring Config:

@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {
  "com.baeldung.controller.controller",
  "com.baeldung.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>

На основе этой простой конфигурации фреймворк, конечно же, инициализирует любой компонент контроллера. который он найдет в пути к классам.

Обратите внимание, что мы также определяем 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:

result_final

Обратите внимание, что 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, с той лишь разницей, что нет никаких преобразователей представления и карты модели.

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-ответ.

Быстрый снимок вывода показан ниже:

16th_july

Приведенный выше вывод является результатом отправки запроса 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.