Конфигурация MVC на Java и пространство имен MVC на XML предусматривают конфигурацию по умолчанию, подходящую для большинства приложений, и конфигурационный API для ее настройки.

Вам не потребуется разбираться в базовых бинах, создаваемых Java-конфигурацией MVC и пространством имен MVC.

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

В Java-конфигурации можно использовать аннотацию @EnableWebMvc для активации конфигурации MVC, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig {
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig

В XML-конфигурации можно использовать элемент <mvc:annotation-driven> для активации конфигурации MVC, как показано в следующем примере:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven/>
</beans>

В следующем примере регистрируется ряд инфраструктурных бинов Spring MVC и подстраивается под зависимости, доступные в classpath (например, преобразователи полезных данных для JSON, XML и др.).

API конфигурации MVC

В Java-конфигурации можно реализовать интерфейс WebMvcConfigurer, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    // Реализовываем методы конфигурации...
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    // Реализовываем методы конфигурации...
}

В XML можно проверять атрибуты и подэлементы <mvc:annotation-driven/>. Можно просмотреть XML-схему Spring MVC или использовать функцию автодополнения кода в вашей IDE, чтобы узнать, какие атрибуты и подэлементы доступны.

Преобразование типа

По умолчанию установлены форматировщики для различных типов чисел и дат наряду со средствами поддержки настройки через @NumberFormat и @DateTimeFormat для полей.

Чтобы зарегистрировать кастомные форматировщики и преобразователи в конфигурации Java, используйте следующее:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        // ...
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addFormatters(registry: FormatterRegistry) {
        // ...
    }
}

Чтобы сделать то же самое в XML-конфигурации, используйте следующее:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven conversion-service="conversionService"/>
    <bean id="conversionService"
            class="org.springframework.format.support.FormattingConversionServiceFactoryBean">
        <property name="converters">
            <set>
                <bean class="org.example.MyConverter"/>
            </set>
        </property>
        <property name="formatters">
            <set>
                <bean class="org.example.MyFormatter"/>
                <bean class="org.example.MyAnnotationFormatterFactory"/>
            </set>
        </property>
        <property name="formatterRegistrars">
            <set>
                <bean class="org.example.MyFormatterRegistrar"/>
            </set>
        </property>
    </bean>
</beans>

По умолчанию Spring MVC учитывает региональные настройки запроса при парсинге и форматировании значений даты. Это справедливо для форм, где даты представлены в виде строк с полями формы "input". Однако для полей формы "date" и "time" браузеры используют фиксированный формат, определенный в спецификации HTML. Для таких случаев форматирование даты и времени можно настроить следующим образом:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addFormatters(FormatterRegistry registry) {
        DateTimeFormatterRegistrar registrar = new DateTimeFormatterRegistrar();
        registrar.setUseIsoFormat(true);
        registrar.registerFormatters(registry);
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addFormatters(registry: FormatterRegistry) {
        val registrar = DateTimeFormatterRegistrar()
        registrar.setUseIsoFormat(true)
        registrar.registerFormatters(registry)
    }
}

Валидация

По умолчанию, если в classpath присутствует Bean Validation (например, Hibernate Validator), LocalValidatorFactoryBean регистрируется как глобальный валидатор для использования с аннотацией @Valid и свойства Validated на аргументах методов контроллера.

В конфигурации Java можно настроить глобальный экземпляр Validator, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public Validator getValidator() {
        // ...
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun getValidator(): Validator {
        // ...
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:mvc="http://www.springframework.org/schema/mvc"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="
        http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/mvc
        https://www.springframework.org/schema/mvc/spring-mvc.xsd">
    <mvc:annotation-driven validator="globalValidator"/>
</beans>

Обратите внимание, что также можно регистрировать реализации Validator локально, как показано в следующем примере:

Java
@Controller
public class MyController {
    @InitBinder
    protected void initBinder(WebDataBinder binder) {
        binder.addValidators(new FooValidator());
    }
}
Kotlin
@Controller
class MyController {
    @InitBinder
    protected fun initBinder(binder: WebDataBinder) {
        binder.addValidators(FooValidator())
    }
}
Если необходимо, чтобы LocalValidatorFactoryBean был куда-то внедрён, создайте бин и пометьте его аннотацией @Primary, чтобы избежать конфликта с тем, что был объявлен в конфигурации MVC.

Перехватчики

В конфигурации Java можно зарегистрировать перехватчики для применения к входящим запросам, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new LocaleChangeInterceptor());
        registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addInterceptors(registry: InterceptorRegistry) {
        registry.addInterceptor(LocaleChangeInterceptor())
        registry.addInterceptor(ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**")
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:interceptors>
    <bean class="org.springframework.web.servlet.i18n.LocaleChangeInterceptor"/>
    <mvc:interceptor>
        <mvc:mapping path="/**"/>
        <mvc:exclude-mapping path="/admin/**"/>
        <bean class="org.springframework.web.servlet.theme.ThemeChangeInterceptor"/>
    </mvc:interceptor>
</mvc:interceptors>
Сопоставленные перехватчики не идеально подходят для использования в качестве уровня безопасности из-за возможности возникновения несоответствия аннотированному контроллеру согласования путей, который также может прозрачно согласовывать косые черты и расширения путей, наряду с другими вариантами согласования путей. Многие из этих вариантов уже устарели, но вероятность несоответствия остается. Как правило, мы рекомендуем использовать Spring Security, который включает в себя специальный MvcRequestMatcher для согласования путей Spring MVC, а также имеет брандмауэр безопасности, который блокирует многие нежелательные символы в путях URL-адресов.

Типы содержимого

Можно сконфигурировать способ, которым Spring MVC определяет запрашиваемые типы среды передачи данных из запроса (например, заголовок Accept, расширение пути URL-адреса, параметр запроса и другие).

По умолчанию проверяемым является только заголовок Accept.

Если необходимо использовать разрешение типа содержимого на основе URL-адреса, рассмотрите возможность использования стратегии параметров запроса вместо расширений пути.

В Java-конфигурации можно настроить разрешение запрашиваемого типа содержимого, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
        configurer.mediaType("json", MediaType.APPLICATION_JSON);
        configurer.mediaType("xml", MediaType.APPLICATION_XML);
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureContentNegotiation(configurer: ContentNegotiationConfigurer) {
        configurer.mediaType("json", MediaType.APPLICATION_JSON)
        configurer.mediaType("xml", MediaType.APPLICATION_XML)
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"/>
<bean id="contentNegotiationManager" class="org.springframework.web.accept.ContentNegotiationManagerFactoryBean">
    <property name="mediaTypes">
        <value>
            json=application/json
            xml=application/xml
        </value>
    </property>
</bean>

Преобразователи сообщений

Вы можете настроить HttpMessageConverter в Java-конфигурации, переопределив configureMessageConverters() (чтобы заменить преобразователи по умолчанию, созданные Spring MVC) или переопределив extendMessageConverters() (чтобы настроить преобразователи по умолчанию или добавить дополнительные преобразователи к преобразователям по умолчанию).

В следующем примере добавлены преобразователи XML и Jackson JSON с настроенным ObjectMapper вместо стандартных:

Java
@Configuration
@EnableWebMvc
public class WebConfiguration implements WebMvcConfigurer {
    @Override
    public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
        Jackson2ObjectMapperBuilder builder = new Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(new SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(new ParameterNamesModule());
        converters.add(new MappingJackson2HttpMessageConverter(builder.build()));
        converters.add(new MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()));
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfiguration : WebMvcConfigurer {
    override fun configureMessageConverters(converters: MutableList<HttpMessageConverter<*>>) {
        val builder = Jackson2ObjectMapperBuilder()
                .indentOutput(true)
                .dateFormat(SimpleDateFormat("yyyy-MM-dd"))
                .modulesToInstall(ParameterNamesModule())
        converters.add(MappingJackson2HttpMessageConverter(builder.build()))
        converters.add(MappingJackson2XmlHttpMessageConverter(builder.createXmlMapper(true).build()))

В предыдущем примере Jackson2ObjectMapperBuilder используется для создания общей конфигурации для MappingJackson2HttpMessageConverter и MappingJackson2XmlHttpMessageConverter с включенным отступом, настроенным форматом даты и регистрацией модуля jackson-module-parameter-names, который добавляет поддержку доступа к именам параметров (функция, добавленная в Java 8).

Это средство сборки настраивает свойства Jackson по умолчанию следующим образом:

Оно также автоматически регистрирует следующие известные модули, если они обнаружены в classpath:

Включение отступов с поддержкой Jackson XML требует наличия зависимости woodstox-core-asl в дополнение к jackson-dataformat-xml.

Имеются и другие любопытные модули Jackson:

  • jackson-datatype-money: Поддержка типов javax.money (неофициальный модуль).

  • jackson-datatype-hibernate: Поддержка специфических для Hibernate типов и свойств (включая аспекты отложенной загрузки).

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:annotation-driven>
    <mvc:message-converters>
        <bean class="org.springframework.http.converter.json.MappingJackson2HttpMessageConverter">
            <property name="objectMapper" ref="objectMapper"/>
        </bean>
        <bean class="org.springframework.http.converter.xml.MappingJackson2XmlHttpMessageConverter">
            <property name="objectMapper" ref="xmlMapper"/>
        </bean>
    </mvc:message-converters>
</mvc:annotation-driven>
<bean id="objectMapper" class="org.springframework.http.converter.json.Jackson2ObjectMapperFactoryBean"
      p:indentOutput="true"
      p:simpleDateFormat="yyyy-MM-dd"
      p:modulesToInstall="com.fasterxml.jackson.module.paramnames.ParameterNamesModule"/>
<bean id="xmlMapper" parent="objectMapper" p:createXmlMapper="true"/>

Представление контроллеров

Это сокращение для определения ParameterizableViewController, который при вызове немедленно переходит к представлению. Можно использовать его в статических случаях, когда нет логики Java-контроллера, которую нужно выполнить до того, как представление сгенерирует ответ.

В следующем примере Java-конфигурации направлен запрос на / в представление под названием home:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addViewControllers(ViewControllerRegistry registry) {
        registry.addViewController("/").setViewName("home");
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addViewControllers(registry: ViewControllerRegistry) {
        registry.addViewController("/").setViewName("home")
    }
}

В следующем примере получается то же самое, что и в предыдущем, но при помощи XML, путем использования элемента <mvc:view-controller>:

<mvc:view-controller path="/" view-name="home"/>

Если метод с аннотацией @RequestMapping отображен на URL-адрес для любого HTTP-метода, то контроллер представления нельзя использовать для обработки того же URL-адреса. Это связано с тем, что совпадение по URL-адресу с аннотированным контроллером считается достаточно убедительным признаком принадлежности конечной точки, поэтому клиенту может быть отправлен ответ 405 (METHOD_NOT_ALLOWED), 415 (UNSUPPORTED_MEDIA_TYPE) или аналогичный ответ для помощи в отладке. По этой причине рекомендуется избегать разделения обработки URL-адреса на аннотированный контроллер и контроллер представления.

Распознаватели представлений

Конфигурация MVC упрощает регистрацию распознавателей представлений.

В следующем примере Java-конфигурации конфигурируется разрешение представления согласования контента с использованием JSP и Jackson в качестве View по умолчанию для визуализации в формате JSON:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.jsp();
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.enableContentNegotiation(MappingJackson2JsonView())
        registry.jsp()
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:jsp/>
</mvc:view-resolvers>

Обратите внимание, однако, что FreeMarker, Tiles, Groovy Markup и шаблоны скриптов также требуют конфигурирования технологии представления.

Пространство имен MVC предусматривает специальные элементы. Следующий пример работает с FreeMarker:

<mvc:view-resolvers>
    <mvc:content-negotiation>
        <mvc:default-views>
            <bean class="org.springframework.web.servlet.view.json.MappingJackson2JsonView"/>
        </mvc:default-views>
    </mvc:content-negotiation>
    <mvc:freemarker cache="false"/>
</mvc:view-resolvers>
<mvc:freemarker-configurer>
    <mvc:template-loader-path location="/freemarker"/>
</mvc:freemarker-configurer>

В Java-конфигурации можно добавить соответствующий бин Configurer, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureViewResolvers(ViewResolverRegistry registry) {
        registry.enableContentNegotiation(new MappingJackson2JsonView());
        registry.freeMarker().cache(false);
    }
    @Bean
    public FreeMarkerConfigurer freeMarkerConfigurer() {
        FreeMarkerConfigurer configurer = new FreeMarkerConfigurer();
        configurer.setTemplateLoaderPath("/freemarker");
        return configurer;
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureViewResolvers(registry: ViewResolverRegistry) {
        registry.enableContentNegotiation(MappingJackson2JsonView())
        registry.freeMarker().cache(false)
    }
    @Bean
    fun freeMarkerConfigurer() = FreeMarkerConfigurer().apply {
        setTemplateLoaderPath("/freemarker")
    }
}

Статические ресурсы

Эта опция обеспечивает удобный способ обработки статических ресурсов из списка местоположений на основе Resource.

В следующем примере, если запрос начинается с /resources, относительный путь используется для поиска и обработки статических ресурсов относительно /public в корне веб-приложения или в classpath в /static. Ресурсы предоставляются с истечением срока действия в один год, чтобы обеспечить максимальное использование кэша браузера и сокращение HTTP-запросов, сделанных браузером. Информация Last-Modified выводится из Resource#lastModified, чтобы предоставлять поддержку условных HTTP-запросов с заголовками "Last-Modified".

В следующем листинге показано, как это сделать с помощью Java-конфигурации:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)));
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public", "classpath:/static/")
                .setCacheControl(CacheControl.maxAge(Duration.ofDays(365)))
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:resources mapping="/resources/**"
    location="/public, classpath:/static/"
    cache-period="31556926" />

Обработчик ресурсов также поддерживает цепочку реализаций ResourceResolver и ResourceTransformer, которые можно использовать, чтобы создать набор инструментальных средств для работы с оптимизированными ресурсами.

Вы можете использовать VersionResourceResolver для версионированных URL-адресов ресурсов на основе хэша MD5, вычисленного из контента, фиксированной версии приложения или другого. ContentVersionStrategy (хэш MD5) является продуманным выбором – за некоторыми значительными исключениями, такими как ресурсы JavaScript, используемые с загрузчиком модулей.

В следующем примере показано, как использовать VersionResourceResolver в Java-конфигурации:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(new VersionResourceResolver().addContentVersionStrategy("/**"));
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun addResourceHandlers(registry: ResourceHandlerRegistry) {
        registry.addResourceHandler("/resources/**")
                .addResourceLocations("/public/")
                .resourceChain(true)
                .addResolver(VersionResourceResolver().addContentVersionStrategy("/**"))
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:resources mapping="/resources/**" location="/public/">
    <mvc:resource-chain resource-cache="true">
        <mvc:resolvers>
            <mvc:version-resolver>
                <mvc:content-version-strategy patterns="/**"/>
            </mvc:version-resolver>
        </mvc:resolvers>
    </mvc:resource-chain>
</mvc:resources>

Затем можно использовать ResourceUrlProvider для перезаписи URL-адресов и применения полной цепочки распознавателей и преобразователей – например, для вставки версий. Конфигурация MVC предусматривает бин ResourceUrlProvider, который можно внедрять в другие бины. Вы также можете сделать перезапись прозрачной с помощью ResourceUrlEncodingFilter для Thymeleaf, JSP, FreeMarker и других, используя URL-теги, которые полагаются на HttpServletResponse#encodeURL.

Обратите внимание, что при использовании EncodedResourceResolver (например, для обработки закодированных ресурсов с методами сжатия gzip или brotli) и VersionResourceResolver, необходимо зарегистрировать их именно в таком порядке. Это обеспечивает надежное вычисление версий, базирующихся на содержимом, на основе некодированного файла.

WebJars также поддерживаются при помощи WebJarsResourceResolver, который автоматически регистрируется при наличии библиотеки org.webjars:webjars-locator-core в classpath. Распознаватель может переписывать URL-адреса, чтобы включить в состав версию jar, а также сопоставлять входящие URL-адреса без версий – например, из /jquery/jquery.min.js в /jquery/1.2.0/jquery.min.js.

Java-конфигурация на основе ResourceHandlerRegistry предусматривает дополнительные возможности для тонкого контроля, например, логику работы при последнем изменении и оптимизированное разрешение ресурсов.

Сервлет по умолчанию

Фреймворк Spring MVC позволяет отображать DispatcherServlet на / (тем самым переопределяя отображение стандартного сервлета контейнера), при этом статические запросы к ресурсам будут обрабатываться стандартным сервлетом контейнера. Он конфигурирует DefaultServletHttpRequestHandler с URL-отображением /** и самым низким приоритетом по отношению к другим URL-отображениям.

Этот обработчик перенаправляет все запросы на сервлет по умолчанию. Поэтому он должен оставаться последним в порядке следования всех других HandlerMappings для URL. Это происходит в случае, если используется <mvc:annotation-driven>. Кроме того, если вы создаете свой собственный экземпляр HandlerMapping, не забудьте установить его свойство order в значение меньшее, чем у DefaultServletHttpRequestHandler, которое является Integer.MAX_VALUE.

В следующем примере показано, как активировать эту функцию, используя настройки по умолчанию:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
        configurer.enable()
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:default-servlet-handler/>

Оговорка при переопределении отображения / сервлета заключается в том, что RequestDispatcher для сервлета по умолчанию должен быть найден по имени, а не по пути. DefaultServletHttpRequestHandler пытается автоматически определить сервлет по умолчанию для контейнера во время запуска, используя список известных имен для большинства основных контейнеров сервлетов (включая Tomcat, Jetty, GlassFish, JBoss, Resin, WebLogic и WebSphere). Если сервлет по умолчанию был кастомно сконфигурирован с другим именем, или если используется другой контейнер сервлетов, где имя сервлета по умолчанию неизвестно, то нужно явно указать имя сервлета по умолчанию, как показано в следующем примере:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable("myCustomDefaultServlet");
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configureDefaultServletHandling(configurer: DefaultServletHandlerConfigurer) {
        configurer.enable("myCustomDefaultServlet")
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:default-servlet-handler default-servlet-name="myCustomDefaultServlet"/>

Сопоставление путей

Вы можете настроить параметры, связанные с сопоставлением путей и обработкой URL-адресов. Подробнее об отдельных опциях см. в javadoc по PathMatchConfigurer.

В следующем примере показано, как настроить согласование путей в Java-конфигурации:

Java
@Configuration
@EnableWebMvc
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void configurePathMatch(PathMatchConfigurer configurer) {
        configurer
            .setPatternParser(new PathPatternParser())
            .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController.class));
    }
    private PathPatternParser patternParser() {
        // ...
    }
}
Kotlin
@Configuration
@EnableWebMvc
class WebConfig : WebMvcConfigurer {
    override fun configurePathMatch(configurer: PathMatchConfigurer) {
        configurer
            .setPatternParser(patternParser)
            .addPathPrefix("/api", HandlerTypePredicate.forAnnotation(RestController::class.java))
    }
    fun patternParser(): PathPatternParser {
        //...
    }
}

В следующем примере показано, как получить такую же конфигурацию на XML:

<mvc:annotation-driven>
    <mvc:path-matching
        trailing-slash="false"
        path-helper="pathHelper"
        path-matcher="pathMatcher"/>
</mvc:annotation-driven>
<bean id="pathHelper" class="org.example.app.MyPathHelper"/>
<bean id="pathMatcher" class="org.example.app.MyPathMatcher"/>

Расширенная Java-конфигурация

@EnableWebMvc импортирует DelegatingWebMvcConfiguration, которая:

  • Передает конфигурацию Spring по умолчанию для приложений Spring MVC

  • Обнаруживает и делегирует реализации WebMvcConfigurer для настройки этой конфигурации.

В расширенном режиме вы можете удалить аннотацию @EnableWebMvc и производить расширение непосредственно из DelegatingWebMvcConfiguration вместо реализации WebMvcConfigurer, как показано в следующем примере:

Java
@Configuration
public class WebConfig extends DelegatingWebMvcConfiguration {
    // ...
}
Kotlin
@Configuration
class WebConfig : DelegatingWebMvcConfiguration() {
    // ...
}

Можно сохранять существующие методы в WebConfig, но теперь также есть возможность переопределять объявления бинов из базового класса, и все еще можно иметь любое количество других реализаций WebMvcConfigurer в classpath.

Расширенная XML-конфигурация

Пространство имен MVC не предусматривает расширенный режим. Если требуется настроить свойство бина, которое нельзя изменить другим способом, то можно использовать перехватчик жизненного цикла BeanPostProcessor в ApplicationContext для Spring, как показано в следующем примере:

Java
@Component
public class MyPostProcessor implements BeanPostProcessor {
    public Object postProcessBeforeInitialization(Object bean, String name) throws BeansException {
        // ...
    }
}
Kotlin
@Component
class MyPostProcessor : BeanPostProcessor {
    override fun postProcessBeforeInitialization(bean: Any, name: String): Any {
        // ...
    }
}