前言
SpringBoot 对 SpringMVC 做了大量自动化配置,让开发实现了 "开箱即用",但实际业务开发中,默认配置往往无法满足定制化需求。本文将从核心知识点 + 实操案例 出发,详解如何通过WebMvcConfigurer接口实现 SpringMVC 的四大核心扩展,同时梳理每个扩展的核心原理与关键注意事项,内容可直接复用到实际项目,适配新手学习与开发实战。
一、SpringMVC 扩展核心基础
核心知识点
WebMvcConfigurer是 SpringBoot 扩展 SpringMVC 的核心入口接口 ,提供多个默认空实现的扩展方法,按需实现即可完成定制化配置,不会破坏 SpringBoot 原有自动配置 ;自定义扩展配置类必须添加@Configuration注解,且需放在启动类同包 / 子包下,确保被 Spring 扫描加载。
基础配置类模板
所有扩展功能均基于此配置类实现,后续只需在类中重写对应扩展方法即可:
java
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* SpringMVC扩展核心配置类
* 注解+接口缺一不可,是所有扩展的基础载体
*/
@Configuration
public class MyMvcConfig implements WebMvcConfigurer {
// 各类扩展方法均写在此处
}
二、扩展 1:视图控制器配置(请求路径转发)
核心知识点
实现addViewControllers方法,无需编写空 Controller ,直接通过配置完成请求路径到页面的转发,简化简单路由开发;需严格区分路径规则:写forward:/xxx.html指向static目录纯静态页,直接写视图名指向templates目录模板页。
实操案例
实现访问/tx自动转发到static目录下的success.html静态页:
java
/**
* 视图控制器:请求路径转发配置
* 核心:forward:/ 前缀指定静态资源路径,无前缀则指向模板页
*/
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/tx").setViewName("forward:/success.html");
}
关键注意
若需转发到templates目录的动态模板页,直接写视图名即可,如registry.addView
Controller("/index").setViewName("index")(对应templates/index.html)。
三、扩展 2:自定义日期格式化器注册
核心知识点
实现addFormatters方法,向FormatterRegistry注册自定义Formatter<Date>,统一完成前后端日期类型的自动转换 :前端传入的日期字符串自动解析为后端Date类型,后端Date类型自动格式化为指定规则的字符串返回前端,替代手动解析,统一项目日期处理规范。
实操案例
实现yyyy-MM-dd格式的字符串与Date类型互转,适配前后端日期参数传递:
java
import org.springframework.format.Formatter;
import org.springframework.format.FormatterRegistry;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addFormatter(new Formatter<Date>() {
// 响应前端:Date → 字符串(格式化)
@Override
public String print(Date date, Locale locale) {
return new SimpleDateFormat("yyyy-MM-dd").format(date);
}
// 接收前端:字符串 → Date(解析)
@Override
public Date parse(String s, Locale locale) throws ParseException {
return new SimpleDateFormat("yyyy-MM-dd").parse(s);
}
});
}
测试验证
编写简单 Controller,可直接接收前端yyyy-MM-dd格式的日期参数,无需手动处理:
java
@RestController
public class TestController {
@GetMapping("/date")
public String testDate(Date date) {
return "接收并格式化后的日期:" + date;
}
}
四、扩展 3:FastJson 消息转换器扩展(替换 Jackson)
核心知识点
实现configureMessageConverters方法,通过FastJsonHttpMessageConverter替换 SpringMVC 默认的 Jackson JSON 处理器 ;可全局配置 JSON 格式化规则(如美化输出、全局日期格式),也可通过实体类@JSONField注解实现字段级自定义 JSON 规则,满足项目个性化的 JSON 序列化 / 反序列化需求。
实操案例
步骤 1:引入 FastJson 依赖
XML
<!-- pom.xml中添加依赖,指定稳定版本 -->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
步骤 2:配置 FastJson 消息转换器
java
import com.alibaba.fastjson.serializer.SerializerFeature;
import com.alibaba.fastjson.support.config.FastJsonConfig;
import com.alibaba.fastjson.support.spring.FastJsonHttpMessageConverter;
import org.springframework.http.converter.HttpMessageConverter;
import java.util.List;
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>> converters) {
// 1. 创建FastJson转换器实例
FastJsonHttpMessageConverter fastConverter = new FastJsonHttpMessageConverter();
// 2. 配置FastJson全局规则
FastJsonConfig fastJsonConfig = new FastJsonConfig();
fastJsonConfig.setSerializerFeatures(SerializerFeature.PrettyFormat); // 美化输出
fastJsonConfig.setDateFormat("yyyy-MM-dd HH:mm:ss"); // 全局日期格式化
fastConverter.setFastJsonConfig(fastJsonConfig);
// 3. 添加到转换器列表,替换默认Jackson
converters.add(fastConverter);
}
步骤 3:实体类字段级自定义(可选)
java
import com.alibaba.fastjson.annotation.JSONField;
import java.util.Date;
public class User {
private String username;
private Integer age;
// 单独指定该字段的日期格式,优先级高于全局配置
@JSONField(format = "yyyy-MM-dd")
private Date createTime;
// 省略get/set方法
}
测试验证
返回 User 对象时,将以 FastJson 规则格式化 JSON,字段级配置会覆盖全局配置:
java
@GetMapping("/user")
public User testUser() {
User user = new User();
user.setUsername("张三");
user.setAge(20);
user.setCreateTime(new Date());
return user;
}
五、扩展 4:自定义拦截器开发与注册
核心知识点
- 自定义类实现
HandlerInterceptor接口,重写三个核心方法实现拦截逻辑:preHandle(请求处理前执行,返回 true 放行)、postHandle(请求处理后、视图渲染前执行)、afterCompletion(视图渲染后执行,无论是否异常必执行); - 实现
addInterceptors方法注册自定义拦截器,通过addPathPatterns配置拦截路径 、excludePathPatterns配置排除路径,实现精准的请求拦截管控,常用于登录校验、接口日志、权限控制等场景。
实操案例
步骤 1:编写自定义拦截器
java
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 自定义拦截器:实现请求前置/后置/最终处理
*/
public class MyInterceptor implements HandlerInterceptor {
// 请求前置拦截:核心拦截逻辑(如登录校验)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("前置拦截:请求路径=" + request.getRequestURI());
return true; // 返回true放行,false直接拦截
}
// 请求后置处理:视图渲染前执行
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, org.springframework.web.servlet.ModelAndView modelAndView) throws Exception {
System.out.println("后置拦截");
}
// 最终处理:视图渲染后执行,可做资源释放
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("最终拦截");
}
}
步骤 2:注册拦截器并配置规则
java
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new MyInterceptor())
.addPathPatterns("/**") // 拦截所有请求
.excludePathPatterns("/**/*.html", "/**/*.css", "/**/*.js"); // 排除静态资源
}
六、扩展常见问题与解决方案
问题:拦截器重复触发(日志 / 逻辑执行多次)
核心原因
请求转发场景下,转发源路径(如/tx)和目标路径(如/success.html)会触发两次请求,拦截器会分别拦截两次请求,导致日志或业务逻辑重复执行。
解决方案(两种任选)
-
精准排除路径 :在
excludePathPatterns中排除转发目标路径、所有静态资源,从根源避免拦截重复请求:java.excludePathPatterns("/success.html", "/**/*.html", "/**/*.css", "/**/*.js"); -
判断内部转发请求 :在
preHandle方法中通过请求属性判断是否为内部转发请求,若是则直接放行不处理:java@Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { // 判定内部转发请求,直接放行 if (request.getAttribute("javax.servlet.forward.request_uri") != null) { return true; } System.out.println("前置拦截:请求路径=" + request.getRequestURI()); return true; }
七、全文核心知识点总结
- SpringMVC 扩展的核心入口是
WebMvcConfigurer接口,配合@Configuration注解实现无侵入式扩展,不破坏自动配置; - 视图控制器通过
addViewControllers实现无 Controller 的路径转发,需区分static和templates目录的路径规则; - 自定义日期格式化器通过
addFormatters注册,实现前后端日期类型的自动解析与格式化,统一项目日期处理; - 实现
configureMessageConverters可替换 FastJson 为 JSON 处理器,支持全局 + 字段级的 JSON 规则配置; - 自定义拦截器需实现
HandlerInterceptor并通过addInterceptors注册,配合拦截 / 排除规则实现精准请求管控; - 转发场景下拦截器重复触发的核心解决思路是排除重复路径 或跳过内部转发请求。
后记
本文讲解的WebMvcConfigurer接口扩展方式,是 SpringBoot 开发中最常用、最优雅的 SpringMVC 扩展方案,既保留了 SpringBoot 自动化配置的便捷性,又能完美适配业务的定制化需求。掌握这些扩展方法,能大幅提升日常开发效率,解决实际项目中的各类个性化配置问题。后续可在此基础上进一步学习跨域配置、自定义参数解析器等高级扩展场景,完善 SpringMVC 的定制化能力。