上一期咱们聊透了 SpringBoot 和 Spring MVC 的关系------SpringBoot 帮我们自动配好了 MVC 的核心组件,但实际开发中,光用默认配置肯定不够:
比如想改静态资源路径、加自定义拦截器、换消息转换器、调整请求参数解析规则......这些都需要我们自定义 Spring MVC 配置。
今天就教你 3 种自定义 Spring MVC 配置的方法,从简单到复杂,新手也能一步步跟着做,再也不用对着默认配置束手无策。
先搞懂SpringBoot 里自定义 MVC 配置的"规矩"
SpringBoot 为了不让我们乱改配置,定了一个核心规则:
想要自定义 MVC 配置,必须实现 WebMvcConfigurer 接口(或继承 WebMvcConfigurerAdapter,但 3.x 已废弃),并加上 @Configuration 注解。
这个接口里全是默认方法(不用全部实现,按需重写),覆盖了 MVC 配置的所有场景:静态资源、拦截器、消息转换器、视图解析器......
先给个基础模板,所有自定义配置都基于这个结构:
go
1importorg.springframework.context.annotation.Configuration;
2importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
3
4// 标记这是配置类,SpringBoot 启动时会扫描并加载
5@Configuration
6publicclassCustomWebMvcConfigimplementsWebMvcConfigurer{
7
8// 下面重写需要自定义的方法即可
9// 自定义静态资源路径、添加拦截器、配置消息转换器......
10}
⚠️ 踩坑提醒:千万别加 @EnableWebMvc 注解!
加了这个注解,SpringBoot 会完全关闭默认的 MVC 自动配置,所有配置都要你自己写(包括 DispatcherServlet、参数解析器这些核心组件),新手大概率会配崩。
最简单的自定义------修改静态资源访问路径
SpringBoot 默认的静态资源路径是 classpath:/static/、classpath:/public/、classpath:/resources/,比如你在 static 下放个 test.jpg,访问地址是 http://localhost:8080/test.jpg。
如果想加自定义路径(比如 classpath:/images/),或者改默认优先级,重写 addResourceHandlers 方法就行:
go
1importorg.springframework.context.annotation.Configuration;
2importorg.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
3importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
4
5@Configuration
6publicclassCustomWebMvcConfigimplementsWebMvcConfigurer{
7
8// 自定义静态资源配置
9@Override
10publicvoidaddResourceHandlers(ResourceHandlerRegistry registry){
11// 1. 添加自定义静态资源路径:classpath:/images/
12// addResourceHandler:前端访问路径前缀
13// addResourceLocations:本地资源实际路径
14 registry.addResourceHandler("/images/**")// 前端访问 http://localhost:8080/images/xxx.jpg
15.addResourceLocations("classpath:/images/");// 对应项目里的 src/main/resources/images/
16
17// 2. 覆盖默认静态资源路径(可选,不推荐,保留默认更灵活)
18// registry.addResourceHandler("/**")
19// .addResourceLocations("classpath:/my-static/");
20}
21}
测试:在 src/main/resources/images/ 下放 logo.png,访问 http://localhost:8080/images/logo.png 就能看到图片。
最常用的自定义------添加全局拦截器
开发中经常需要用拦截器做登录校验、接口限流、日志记录,这是自定义 MVC 最核心的场景。
步骤分两步:先写拦截器类,再在 MVC 配置里注册。
第一步:写自定义拦截器
go
1importjakarta.servlet.http.HttpServletRequest;
2importjakarta.servlet.http.HttpServletResponse;
3importorg.springframework.web.servlet.HandlerInterceptor;
4importorg.springframework.web.servlet.ModelAndView;
5
6// 自定义登录拦截器
7publicclassLoginInterceptorimplementsHandlerInterceptor{
8
9// 请求处理前执行(核心逻辑写这里)
10@Override
11publicbooleanpreHandle(HttpServletRequest request,HttpServletResponse response,Object handler)throwsException{
12// 模拟:从请求头获取 token,判断是否登录
13String token = request.getHeader("token");
14if(token ==null||!"admin123".equals(token)){
15// 未登录,返回 401 状态码
16 response.setStatus(401);
17 response.getWriter().write("未登录,请先登录!");
18returnfalse;// 拦截请求,不往下走
19}
20returntrue;// 放行请求
21}
22
23// 请求处理后执行(可选)
24@Override
25publicvoidpostHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)throwsException{
26HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
27}
28
29// 整个请求完成后执行(可选,比如清理资源)
30@Override
31publicvoidafterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex)throwsException{
32HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
33}
34}
第二步:在 MVC 配置里注册拦截器
go
1importorg.springframework.context.annotation.Bean;
2importorg.springframework.context.annotation.Configuration;
3importorg.springframework.web.servlet.config.annotation.InterceptorRegistry;
4importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
5
6@Configuration
7publicclassCustomWebMvcConfigimplementsWebMvcConfigurer{
8
9// 把拦截器注册为 Bean,Spring 才能管理
10@Bean
11publicLoginInterceptorloginInterceptor(){
12returnnewLoginInterceptor();
13}
14
15// 注册拦截器,并配置拦截规则
16@Override
17publicvoidaddInterceptors(InterceptorRegistry registry){
18 registry.addInterceptor(loginInterceptor())
19.addPathPatterns("/**")// 拦截所有请求
20.excludePathPatterns("/login","/hello");// 排除登录、hello 接口(不拦截)
21}
22}
测试:
-
访问
http://localhost:8080/hello:不用 token,正常返回(排除拦截); -
访问
http://localhost:8080/user/info:不加 token 会返回 401,加token: admin123请求头才放行。
进阶自定义------替换/新增消息转换器
Spring MVC 默认用 MappingJackson2HttpMessageConverter 处理 JSON 序列化/反序列化,但有时我们想自定义规则(比如日期格式、空值处理),或者换用 FastJSON 作为转换器。
以"自定义 Jackson 日期格式"为例:
go
1importcom.fasterxml.jackson.databind.ObjectMapper;
2importcom.fasterxml.jackson.databind.SerializationFeature;
3importcom.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
4importcom.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
5importorg.springframework.context.annotation.Bean;
6importorg.springframework.context.annotation.Configuration;
7importorg.springframework.http.converter.HttpMessageConverter;
8importorg.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
9importorg.springframework.web.servlet.config.annotation.WebMvcConfigurer;
10
11importjava.time.LocalDateTime;
12importjava.time.format.DateTimeFormatter;
13importjava.util.List;
14
15@Configuration
16publicclassCustomWebMvcConfigimplementsWebMvcConfigurer{
17
18// 自定义 JSON 消息转换器
19@Override
20publicvoidconfigureMessageConverters(List<HttpMessageConverter<?>> converters){
21// 1. 创建 Jackson 对象映射器,自定义序列化规则
22ObjectMapper objectMapper =newObjectMapper();
23// 处理 LocalDateTime 日期格式
24JavaTimeModule javaTimeModule =newJavaTimeModule();
25 javaTimeModule.addSerializer(LocalDateTime.class,
26newLocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
27 objectMapper.registerModule(javaTimeModule);
28// 关闭默认的日期序列化(避免转成时间戳)
29 objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);
30
31// 2. 创建自定义的消息转换器
32MappingJackson2HttpMessageConverter converter =newMappingJackson2HttpMessageConverter();
33 converter.setObjectMapper(objectMapper);
34
35// 3. 把自定义转换器加到列表最前面(优先级最高)
36 converters.add(0, converter);
37}
38}
测试:返回包含 LocalDateTime 类型的对象时,日期会按 yyyy-MM-dd HH:mm:ss 格式显示,而不是默认的时间戳或 ISO 格式。
新手常见问题(避坑清单)
- 自定义配置不生效?
-
检查
@Configuration注解有没有加; -
检查配置类是否在主启动类的扫描包下;
-
别加
@EnableWebMvc(除非你想完全自定义)。
-
拦截器里注入 Service 为 null?
-
-
原因:拦截器不是 Spring 管理的 Bean,直接 new 会导致依赖注入失败;
-
解决:像上面那样,用
@Bean注解把拦截器注册为 Spring Bean,再通过方法引用获取。
-
-
静态资源访问 404?
-
-
检查
addResourceHandlers里的路径是否写对(classpath:/别漏,/**通配符别少); -
别覆盖默认静态资源路径,优先用添加(
add)而非替换。
最后总结
SpringBoot 里自定义 Spring MVC 配置,核心就 3 点:
-
实现
WebMvcConfigurer接口 + 加@Configuration; -
按需重写接口里的方法(静态资源、拦截器、消息转换器等);
-
别加
@EnableWebMvc,保留 SpringBoot 自动配置的基础。
-