我们可以通过实现 WebMvcConfigurer
接口来自定义 Spring MVC (尤其是在 Spring Boot 环境中) 的配置。
以下是通过实现 WebMvcConfigurer
接口的配置方法:
核心:创建一个 @Configuration
类并实现 WebMvcConfigurer
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.validation.MessageCodesResolver;
import org.springframework.validation.Validator;
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
import org.springframework.web.method.support.HandlerMethodReturnValueHandler;
import org.springframework.web.servlet.HandlerExceptionResolver;
import org.springframework.web.servlet.config.annotation.*; // 关键导入
import java.util.List;
@Configuration
// 在Spring Boot中不需要 @EnableWebMvc,除非你想完全禁用Spring Boot的MVC自动配置
public class MyCustomWebMvcConfigurer implements WebMvcConfigurer {
// 具体配置方法如下:
}
可以定制的方面:
拦截器 (Interceptors):
addInterceptors(InterceptorRegistry registry)
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyAuthInterceptor())
.addPathPatterns("/secure/**") // 拦截以 /secure/ 开头的路径
.excludePathPatterns("/secure/login", "/secure/public/**"); // 排除某些路径
}
格式化器和转换器 (Formatters and Converters):
addFormatters(FormatterRegistry registry)
Formatter
(用于特定类型的格式化,如日期) 和 Converter
(用于类型之间的转换),这些在数据绑定时非常有用。@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StringToMyCustomObjectConverter());
registry.addFormatter(new MyCustomDateFormatter());
}
HTTP 消息转换器 (HttpMessageConverters):
configureMessageConverters(List> converters)
: 完全替换默认的转换器列表。extendMessageConverters(List> converters)
: 在默认转换器列表的基础上添加或修改。推荐使用这个,因为它保留了Spring Boot的自动配置转换器。extendMessageConverters
):@Override
public void extendMessageConverters(List<HttpMessageConverter<?>> converters) {
// 添加一个自定义的 Protobuf 消息转换器
// converters.add(0, new ProtobufHttpMessageConverter()); // 添加到列表开头
// 或者移除/修改已有的转换器,例如配置Jackson
// for (HttpMessageConverter> converter : converters) {
// if (converter instanceof MappingJackson2HttpMessageConverter) {
// ObjectMapper objectMapper = ((MappingJackson2HttpMessageConverter) converter).getObjectMapper();
// // 自定义 Jackson ObjectMapper 的配置
// objectMapper.disable(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES);
// }
// }
}
静态资源处理 (Static Resource Handling):
addResourceHandlers(ResourceHandlerRegistry registry)
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/my-assets/**") // 对外暴露的URL模式
.addResourceLocations("classpath:/custom-static/", "file:/var/www/my-app-assets/") // 实际资源位置
.setCachePeriod(3600 * 24); // 缓存周期 (秒)
}
跨域资源共享 (CORS) 配置:
addCorsMappings(CorsRegistry registry)
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 对 /api/ 下的所有路径生效
.allowedOrigins("http://example.com", "https://trusted.client.com") // 允许的源
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的方法
.allowedHeaders("*") // 允许所有请求头
.allowCredentials(true) // 是否允许发送Cookie
.maxAge(3600); // 预检请求的缓存时间 (秒)
}
视图控制器 (View Controllers):
addViewControllers(ViewControllerRegistry registry)
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("home"); // 访问根路径时显示 home 视图
registry.addViewController("/about").setViewName("aboutPage");
registry.addRedirectViewController("/old-path", "/new-path"); // 重定向
}
内容协商 (Content Negotiation) 策略:
configureContentNegotiation(ContentNegotiationConfigurer configurer)
Accept
头、URL参数、路径扩展名)来决定响应的内容类型(如JSON, XML)。@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
configurer.favorParameter(true) // 启用基于URL参数的协商 (如 ?format=json)
.parameterName("mediaType") // 自定义参数名,默认为 "format"
.ignoreAcceptHeader(false) // 是否忽略 Accept 请求头 (默认为 false)
.defaultContentType(MediaType.APPLICATION_JSON) // 默认返回JSON
.mediaType("xml", MediaType.APPLICATION_XML) // 将 "xml" 映射到 application/xml
.mediaType("json", MediaType.APPLICATION_JSON); // 将 "json" 映射到 application/json
}
自定义参数解析器 (Argument Resolvers):
addArgumentResolvers(List resolvers)
// @Override
// public void addArgumentResolvers(List resolvers) {
// resolvers.add(new CurrentUserArgumentResolver()); // 假设有一个解析当前用户的解析器
// }
自定义返回值处理器 (Return Value Handlers):
addReturnValueHandlers(List handlers)
// @Override
// public void addReturnValueHandlers(List handlers) {
// handlers.add(new MyCustomReturnValueHandler());
// }
路径匹配配置 (Path Matching):
configurePathMatch(PathMatchConfigurer configurer)
.json
, .xml
),是否匹配URL末尾的斜杠。@Override
public void configurePathMatch(PathMatchConfigurer configurer) {
configurer.setUseSuffixPatternMatch(false); // 推荐禁用后缀匹配
configurer.setUseTrailingSlashMatch(true); // 路径末尾的 / 是否视为与没有 / 相同
}
异步请求处理配置 (Async Support):
configureAsyncSupport(AsyncSupportConfigurer configurer)
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(60 * 1000L); // 设置默认超时时间为60秒
// configurer.setTaskExecutor(myAsyncTaskExecutor()); // 配置自定义的异步任务执行器
}
视图解析器 (View Resolvers):
configureViewResolvers(ViewResolverRegistry registry)
// @Override
// public void configureViewResolvers(ViewResolverRegistry registry) {
// InternalResourceViewResolver resolver = new InternalResourceViewResolver();
// resolver.setPrefix("/WEB-INF/jsp/");
// resolver.setSuffix(".jsp");
// registry.viewResolver(resolver);
// }
异常处理器 (Exception Resolvers):
configureHandlerExceptionResolvers(List resolvers)
或 extendHandlerExceptionResolvers(List resolvers)
HandlerExceptionResolver
。extendHandlerExceptionResolvers
):// @Override
// public void extendHandlerExceptionResolvers(List resolvers) {
// resolvers.add(0, new MyCustomGlobalExceptionResolver());
// }
获取Validator实例 (Validator):
getValidator()
Validator
实例。你可以覆盖此方法以提供自定义的 Validator
。// @Override
// public Validator getValidator() {
// // return new MyCustomValidator(); // 返回你自定义的Validator
// return WebMvcConfigurer.super.getValidator(); // 或调用父类方法获取默认
// }
获取消息代码解析器 (MessageCodesResolver):
getMessageCodesResolver()
MessageCodesResolver
。// @Override
// public MessageCodesResolver getMessageCodesResolver() {
// // return new MyCustomMessageCodesResolver();
// return WebMvcConfigurer.super.getMessageCodesResolver();
// }
通过实现 WebMvcConfigurer
并覆盖这些方法,可以灵活的定制Spring MVC的行为,同时还能充分利用Spring Boot的自动配置带来的便利。