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:
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);
}
}
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", функциональный вариант, отделяет конфигурацию маршрутизации от фактической обработки запросов, как показано в следующем примере:
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();
}
}
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)
}
}
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();
}
}
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, как показано в следующем листинге:
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);
}
}
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 создаст его для вас.