JavaRush /Курсы /Модуль 5. Spring /Spring Boot и Web MVC

Spring Boot и Web MVC

Модуль 5. Spring
16 уровень , 0 лекция
Открыта

Spring Boot отлично подходит для разработки веб-приложений. Вы можете создать автономный HTTP-сервер, используя встроенный Tomcat, Jetty, Undertow или Netty. Большинство веб-приложений используют модуль spring-boot-starter-web для быстрого выполнения. Вы также можете компилировать реактивные веб-приложения с помощью модуля spring-boot-starter-webflux.

Если вы хотите создавать веб-приложения на основе сервлетов, то можете воспользоваться возможностями автоконфигурации Spring Boot для Spring MVC или Jersey.

Фреймворк "Spring Web MVC"

Фреймворк Spring Web MVC (часто упоминается как "Spring MVC") – это полноценный веб-фреймворк по схеме "модель-представление-контроллер". Spring MVC позволяет создавать специальные бины с аннотациями @Controller или @RestController для обработки входящих HTTP-запросов. Методы в контроллере отображаются на протокол HTTP с помощью аннотаций @RequestMapping.

В следующем коде показана типичная аннотация @RestController, которая работает с данными в формате JSON:

Java
import java.util.List; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; @RestController @RequestMapping("/users") public class MyRestController { private final UserRepository userRepository; private final CustomerRepository customerRepository; public MyRestController(UserRepository userRepository, CustomerRepository customerRepository) { this.userRepository = userRepository; this.customerRepository = customerRepository; } @GetMapping("/{userId}") public User getUser(@PathVariable Long userId) { return this.userRepository.findById(userId).get(); } @GetMapping("/{userId}/customers") public List<Customer> getUserCustomers(@PathVariable Long userId) { return this.userRepository.findById(userId).map(this.customerRepository::findByUser).get(); } @DeleteMapping("/{userId}") public void deleteUser(@PathVariable Long userId) { this.userRepository.deleteById(userId); } } 
Kotlin
import org.springframework.web.bind.annotation.DeleteMapping import org.springframework.web.bind.annotation.GetMapping import org.springframework.web.bind.annotation.PathVariable import org.springframework.web.bind.annotation.RequestMapping import org.springframework.web.bind.annotation.RestController @RestController @RequestMapping("/users") class MyRestController(private val userRepository: UserRepository, private val customerRepository: CustomerRepository) { @GetMapping("/{userId}") fun getUser(@PathVariable userId: Long): User { return userRepository.findById(userId).get() } @GetMapping("/{userId}/customers") fun getUserCustomers(@PathVariable userId: Long): List<Customer> { return userRepository.findById(userId).map(customerRepository::findByUser).get() } @DeleteMapping("/{userId}") fun deleteUser(@PathVariable userId: Long) { userRepository.deleteById(userId) } } 

"WebMvc.fn", функциональный вариант, отделяет конфигурацию маршрутизации от фактической обработки запросов, как показано в следующем примере:

Java
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.MediaType; import org.springframework.web.servlet.function.RequestPredicate; import org.springframework.web.servlet.function.RouterFunction; import org.springframework.web.servlet.function.ServerResponse; import static org.springframework.web.servlet.function.RequestPredicates.accept; import static org.springframework.web.servlet.function.RouterFunctions.route; @Configuration(proxyBeanMethods = false) public class MyRoutingConfiguration { private static final RequestPredicate ACCEPT_JSON = accept(MediaType.APPLICATION_JSON); @Bean public RouterFunction<ServerResponse> routerFunction(MyUserHandler userHandler) { return route() .GET("/{user}", ACCEPT_JSON, userHandler::getUser) .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers) .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser) .build(); } } 
Kotlin
import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.MediaType import org.springframework.web.servlet.function.RequestPredicates.accept import org.springframework.web.servlet.function.RouterFunction import org.springframework.web.servlet.function.RouterFunctions import org.springframework.web.servlet.function.ServerResponse @Configuration(proxyBeanMethods = false) class MyRoutingConfiguration { @Bean fun routerFunction(userHandler: MyUserHandler): RouterFunction<ServerResponse> { return RouterFunctions.route() .GET("/{user}", ACCEPT_JSON, userHandler::getUser) .GET("/{user}/customers", ACCEPT_JSON, userHandler::getUserCustomers) .DELETE("/{user}", ACCEPT_JSON, userHandler::deleteUser) .build() } companion object { private val ACCEPT_JSON = accept(MediaType.APPLICATION_JSON) } } 
Java
import org.springframework.stereotype.Component; import org.springframework.web.servlet.function.ServerRequest; import org.springframework.web.servlet.function.ServerResponse; @Component public class MyUserHandler { public ServerResponse getUser(ServerRequest request) { ... return ServerResponse.ok().build(); } public ServerResponse getUserCustomers(ServerRequest request) { ... return ServerResponse.ok().build(); } public ServerResponse deleteUser(ServerRequest request) { ... return ServerResponse.ok().build(); } } 
Kotlin
import org.springframework.stereotype.Component import org.springframework.web.servlet.function.ServerRequest import org.springframework.web.servlet.function.ServerResponse @Component class MyUserHandler { fun getUser(request: ServerRequest?): ServerResponse { return ServerResponse.ok().build() } fun getUserCustomers(request: ServerRequest?): ServerResponse { return ServerResponse.ok().build() } fun deleteUser(request: ServerRequest?): ServerResponse { return ServerResponse.ok().build() } } 
Чтобы модулировать определение маршрутизатора, можно определять столько бинов RouterFunction, сколько пожелаете. Бины можно упорядочить, если требуется применять очередность выполнения.

Автоконфигурация Spring MVC

Spring Boot предусматривает автоконфигурацию для Spring MVC, которая отлично работает с большинством приложений.

Автоконфигурация добавляет следующие функции вдобавок к настройкам Spring по умолчанию:

  • Добавление бинов ContentNegotiatingViewResolver и BeanNameViewResolver.

  • Поддержка обработки статических ресурсов, включая поддержку WebJars.

  • Автоматическая регистрация бинов Converter, GenericConverter и Formatter.

  • Поддержка HttpMessageConverters.

  • Автоматическая регистрация MessageCodesResolver.

  • Поддержка статического index.html.

  • Автоматическое использование бина ConfigurableWebBindingInitializer.

Если необходимо сохранить эти настройки Spring Boot MVC и внести дополнительные настройки MVC (перехватчики, форматировщики, контроллеры представления и другие функции), то можете добавить свой собственный класс, помеченный аннотацией @Configuration, типа WebMvcConfigurer, но без аннотации @EnableWebMvc.

Если необходимо передать кастомные экземпляры RequestMappingHandlerMapping, RequestMappingHandlerAdapter или ExceptionHandlerExceptionResolver и при этом сохранить настройки Spring Boot MVC, то можно объявить бин типа WebMvcRegistrations и использовать его для передачи кастомных экземпляров этих компонентов.

Если необходимо полностью контролировать работу Spring MVC, то можно добавить свою собственную @Configuration, помеченную аннотацией @EnableWebMvc, или же добавить свою собственный класс DelegatingWebMvcConfiguration, помеченный аннотацией @Configuration, как описано в Javadoc для аннотации @EnableWebMvc.

Spring MVC использует ConversionService, отличный от того, который используется для преобразования значений из вашего файла application.properties или application.yaml. Это значит, что преобразователи Period, Duration и DataSize будут недоступны и что аннотации @DurationUnit и @DataSizeUnit будут проигнорированы.

Если необходимо персонализировать настройки службы ConversionService, используемой Spring MVC, то можно предусмотреть бин WebMvcConfigurer с методом addFormatters. Из этого метода можно регистрировать любой предпочтительный преобразователь или делегировать полномочия статическим методам, доступным для ApplicationConversionService.

HttpMessageConverters

Spring MVC использует интерфейс HttpMessageConverter для преобразования HTTP-запросов и ответов. Адекватные настройки по умолчанию предусмотрены "из коробки". Например, объекты могут быть автоматически преобразованы в JSON (с помощью библиотеки Jackson) или в XML (с помощью расширения Jackson XML, если оно доступно, или с помощью JAXB, если расширение Jackson XML недоступно). По умолчанию строки кодируются в UTF-8.

Если необходимо добавить или настроить преобразователи, то можно использовать класс HttpMessageConverters для Spring Boot, как показано в следующем листинге:

Java
import org.springframework.boot.autoconfigure.http.HttpMessageConverters; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.http.converter.HttpMessageConverter; @Configuration(proxyBeanMethods = false) public class MyHttpMessageConvertersConfiguration { @Bean public HttpMessageConverters customConverters() { HttpMessageConverter<?> additional = new AdditionalHttpMessageConverter(); HttpMessageConverter<?> another = new AnotherHttpMessageConverter(); return new HttpMessageConverters(additional, another); } } 
Kotlin
import org.springframework.boot.autoconfigure.http.HttpMessageConverters import org.springframework.context.annotation.Bean import org.springframework.context.annotation.Configuration import org.springframework.http.converter.HttpMessageConverter @Configuration(proxyBeanMethods = false) class MyHttpMessageConvertersConfiguration { @Bean fun customConverters(): HttpMessageConverters { val additional: HttpMessageConverter<*> = AdditionalHttpMessageConverter() val another: HttpMessageConverter<*> = AnotherHttpMessageConverter() return HttpMessageConverters(additional, another) } } 

Любой бин HttpMessageConverter, присутствующий в контексте, добавляется в список преобразователей. Таким же образом можно переопределять преобразователи по умолчанию.

MessageCodesResolver

Spring MVC содержит стратегию генерации кодов ошибок для вывода сообщений об ошибках привязки: MessageCodesResolver. Если установлено свойство spring.mvc.message-codes-resolver-format PREFIX_ERROR_CODE или POSTFIX_ERROR_CODE, Spring Boot создаст его для вас.

Комментарии
ЧТОБЫ ПОСМОТРЕТЬ ВСЕ КОММЕНТАРИИ ИЛИ ОСТАВИТЬ КОММЕНТАРИЙ,
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ