Mastering Spring MVC Configuration: In‑Depth Guide to WebMvcConfigurer

This guide explains how the WebMvcConfigurer callback interface lets developers extend Spring MVC behavior without disabling Spring Boot’s auto‑configuration, covering the full request lifecycle, common customizations such as interceptors, CORS, message converters, static resources, async support, and production‑grade pitfalls.

Cloud Architecture
Cloud Architecture
Cloud Architecture
Mastering Spring MVC Configuration: In‑Depth Guide to WebMvcConfigurer

Introduction

In Spring MVC development, configuration is essential. WebMvcConfigurer is a Java‑based callback interface that allows developers to customize MVC behavior while preserving Spring Boot’s automatic configuration.

Quick Start

@Configuration
public class WebConfig implements WebMvcConfigurer {

}

Spring Boot automatically scans and applies this configuration.

Spring MVC Request Processing Flow

The request passes through the following components:

DispatcherServlet – core dispatcher

HandlerMapping – maps URL to a controller

HandlerInterceptor.preHandle

Controller

HandlerInterceptor.postHandle

ViewResolver / HttpMessageConverter – renders the response

HandlerInterceptor.afterCompletion

Where WebMvcConfigurer Fits

WebMvcConfigurer

is the extension entry for MVC components. Key methods and the components they affect include:

addInterceptors → HandlerInterceptor

addResourceHandlers → ResourceHttpRequestHandler

addFormatters → DataBinder

extendMessageConverters → HttpMessageConverter

configurePathMatch → HandlerMapping

configureAsyncSupport → AsyncRequest

Common Configurations

1. Interceptor

Used for login validation, permission checks, request logging, rate limiting, etc.

@Override
public void addInterceptors(InterceptorRegistry registry) {
    registry.addInterceptor(new LoginInterceptor())
            .addPathPatterns("/**")
            .excludePathPatterns("/login", "/css/**", "/js/**");
}

public class LoginInterceptor implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
        System.out.println("before controller");
        return true;
    }
}

2. View Controllers

Map URLs directly to views without a controller.

@Override
public void addViewControllers(ViewControllerRegistry registry) {
    registry.addViewController("/").setViewName("home");
    registry.addViewController("/login").setViewName("login");
}

3. Static Resource Handling

@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
    registry.addResourceHandler("/static/**")
            .addResourceLocations("classpath:/static/", "file:/data/static/")
            .setCachePeriod(3600)
            .resourceChain(true);
}

4. CORS Configuration

@Override
public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/api/**")
            .allowedOrigins("http://localhost:3000")
            .allowedMethods("GET", "POST", "PUT", "DELETE")
            .allowedHeaders("*")
            .allowCredentials(true)
            .maxAge(3600);
}

// Or use the annotation
@CrossOrigin

5. HttpMessageConverter

Converts between Java objects and HTTP bodies (JSON, XML, String). To add a custom converter without losing defaults:

@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
    converters.add(0, new MyCustomConverter());
}

Do not use configureMessageConverters because it replaces the default converters.

6. Content Negotiation

@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
    configurer.favorParameter(true)
            .parameterName("format")
            .defaultContentType(MediaType.APPLICATION_JSON)
            .mediaType("json", MediaType.APPLICATION_JSON)
            .mediaType("xml", MediaType.APPLICATION_XML);
}

// Request example: /api/user?format=json

7. Formatter & Converter

@Override
public void addFormatters(FormatterRegistry registry) {
    registry.addConverter(new StringToEnumConverter());
    registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
}

// Example conversions: String → Date, String → Enum

8. Path Matching

@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
    configurer.setUseTrailingSlashMatch(true);
    configurer.setUseSuffixPatternMatch(false);
}

9. Async Request Support

@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
    configurer.setDefaultTimeout(5000);
    configurer.setTaskExecutor(mvcExecutor());
}

Spring Boot Auto‑Configuration Mechanism

Spring Boot registers WebMvcAutoConfiguration, which delegates to DelegatingWebMvcConfiguration. That class collects all WebMvcConfigurer beans via WebMvcConfigurerComposite and applies them in order.

Interceptor vs Filter vs AOP

Filter – Servlet layer, used for encoding, CORS.

Interceptor – Spring MVC layer, used for login checks.

AOP – Spring layer, used for logging, transactions.

Execution order: Filter → Interceptor.preHandle → Controller → Interceptor.postHandle → Interceptor.afterCompletion → Filter.

Spring Boot 2.6 PathPattern Change

From Spring Boot 2.6 the default path matcher switches from AntPathMatcher to PathPatternParser, offering higher performance. To keep the old behavior set spring.mvc.pathmatch.matching-strategy=ant_path_matcher.

Production‑Grade Template

@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(authInterceptor())
                .addPathPatterns("/api/**")
                .excludePathPatterns("/login", "/error", "/static/**", "/swagger/**");
    }

    @Bean
    public HandlerInterceptor authInterceptor() {
        return new AuthInterceptor();
    }

    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/api/**")
                .allowedOrigins("*")
                .allowedMethods("*")
                .maxAge(3600);
    }

    @Override
    public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
        for (HttpMessageConverter<?> converter : converters) {
            if (converter instanceof MappingJackson2HttpMessageConverter) {
                ObjectMapper mapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
                mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL);
            }
        }
    }

    @Override
    public void addFormatters(FormatterRegistry registry) {
        registry.addFormatter(new DateFormatter("yyyy-MM-dd"));
    }
}

Common Pitfalls

1. Using @EnableWebMvc

Disables Spring Boot’s MVC auto‑configuration, causing static resources to return 404. Solution: avoid @EnableWebMvc.

2. Overriding Message Converters

Implementing configureMessageConverters removes the default converters. Use extendMessageConverters instead.

3. Interceptor Capturing Static Resources

Static assets may fail to load. Exclude them with excludePathPatterns("/static/**").

Spring MVC vs WebFlux

Model: Servlet (MVC) vs Reactive (WebFlux)

IO: Blocking vs Non‑blocking

Server: Tomcat vs Netty

Concurrency: Thread pool vs EventLoop

Conclusion

WebMvcConfigurer

is one of the core extension points of Spring MVC. It enables developers to customize MVC behavior—interceptors, CORS, message converters, static resources, path matching, content negotiation, formatters, async handling—without breaking Spring Boot’s auto‑configuration, and helps solve common production issues.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

spring-bootInterceptorCORSspring-mvcWebMvcConfigurerAsyncSupportMessageConverter
Cloud Architecture
Written by

Cloud Architecture

Focuses on cloud‑native and distributed architecture engineering, sharing practical solutions and lessons learned. Covers microservice governance, Kubernetes, observability, and stability engineering to help your systems run stable, fast, and cost‑effectively.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.