摘要:本文不仅详细展示了Springboot整合SpringbootMVC中组件的几种方式,还把Springmvc中易混淆的点和难点复习,在理解整合的过程中,自己也能达到整合各个组件的套路模版
一、WebMvcConfigurer的直接应用
要想整合SpringMVC ,关键就是理解WebMvcConfigurer。WebMvcConfigurer是一个接口,我们的WebMvcAutoConfiguration(自动装配类)中的WebMvcAutoConfigurationAdapter就实现了这个类,此类用于自定义 Spring MVC 的核心行为,无需替换默认的 Spring MVC 组件,只需重写对应方法即可实现定制化,这也是 Spring Boot 整合 Spring MVC 的推荐配置方式,不会破坏自动配置的特性。
(1)addInterceptors 注册拦截器(最常用)
步骤一、定义一个类实现HandlerInterceptor接口
java
public class LoginInterceptor implements HandlerInterceptor {
/**
* 请求到达controller之前
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
String token = request.getHeader("Authorization");
if((token != null && token.equals( "")) || token == null ){
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
response.getWriter().write("请先登录");
return false;
}
return true;
}
/**
* 响应完全完成,报错渲染视图等等
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("响应完成");
}
/**
* 请求处理之后,视图渲染之前
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
System.out.println("请求处理之后,视图渲染之前执行");
}
}
步骤二,配置类实现WebMvcConfigurer接口,并实现里面的addInterceptors方法。
java
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
/**
* 注册登录拦截器
* @param registry
*/
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new LoginInterceptor())
.addPathPatterns("/**")
.excludePathPatterns("/login/**","/index/**","/error/**","/*.png","/mvc/hello");
}
}
(2)配置静态资源映射
直接编写配置类,实现addResourceHandlers接口
java
@Configuration
public class SpringMvcConfig implements WebMvcConfigurer {
public void addResourceHandlers(ResourceHandlerRegistry registry) {
// 配置静态资源映射规则
// 第一个参数:前端访问的URL路径前缀(必须以 /** 结尾)
// 第二个参数:静态资源在项目中的实际存储路径(classpath: 表示项目资源目录 src/main/resources/)
registry.addResourceHandler("/img/**")
.addResourceLocations("classpath:/images/");
registry.addResourceHandler("/js/**")
.addResourceLocations("classpath:/static/js/");
registry.addResourceHandler("/css/**")
.addResourceLocations("classpath:/static/css/");
// 若需要访问本地磁盘的静态资源(如 D:/uploads/ 下的图片),使用 file: 前缀
registry.addResourceHandler("/upload/**")
.addResourceLocations("file:D:/uploads/");
}
}
(3)配置跨域请求,实现addCorsMappings接口
java
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**") // 对 /api/ 开头的所有接口配置跨域
.allowedOriginPatterns("*") // 允许所有来源(生产环境建议指定具体域名,如 "http://localhost:8081")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP请求方法
.allowCredentials(true) // 是否允许携带Cookie(前后端认证时需要)
.maxAge(3600) // 跨域请求的有效期(秒),默认30分钟
.allowedHeaders("*"); // 允许所有请求头(如 Token、Content-Type 等)
}
(4)简化视图跳转,实现addViewControllers
java
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/")
.setViewName("forward:index.html");
registry.addViewController("/login")
.setViewName("loginView");
registry.addViewController("/manager")
.setViewName("error/404");
}
(5)配置内容协商,支持返回数据为JSON,XML,YML形式
步骤一,开启 请求参数指定返回结果 配置文件写入
java
mvc:
contentnegotiation:
favor-parameter: true
写了这个方法以后,在前段给后端传参数时,拼接format=yml或者yaml或者json或者xml,然后返回指定的内容。
或者通过指定Accept,包括application/yaml 或者application/yml或者application/json,application/xml形式
步骤二、
java
/**
* 配置内容协商
* @param
*/
@Override
public void configureContentNegotiation(ContentNegotiationConfigurer configurer) {
// 1. 定义媒体类型映射:key 是参数值,value 是对应的 HTTP 媒体类型
Map<String, MediaType> mediaTypeMap = new HashMap<>();
mediaTypeMap.put("json", MediaType.APPLICATION_JSON);
mediaTypeMap.put("xml", MediaType.APPLICATION_XML);
mediaTypeMap.put("yaml", MediaType.parseMediaType("application/yaml")); // 新增 YAML 映射
mediaTypeMap.put("yml", MediaType.parseMediaType("application/yml")); // 兼容 yml 后缀参数
// 2. 配置内容协商规则
configurer.favorParameter(true) // 启用请求参数协商
.parameterName("format") // 请求参数名(?format=yaml)
.mediaTypes(mediaTypeMap) // 加载所有媒体类型映射
.ignoreAcceptHeader(false) // 不忽略 Accept 头,支持混合协商(参数优先级 > 请求头)
.defaultContentType(MediaType.APPLICATION_JSON); // 默认返回 JSON
}
(6)格式化器 ,实现addFormatters接口
专门处理「字符串和 Java 类型」的互转,支持注解配置(如@DateTimeFormat),更适合前端传递的字符串参数
与configureMessageConverters()的区别:
addFormatters():主要处理请求参数(URL 参数、表单参数)的类型转换 / 格式化,聚焦于「字符串与 Java 类型」的绑定。configureMessageConverters():主要处理JSON 数据(请求体、响应体)的转换 / 格式化,聚焦于「Java 对象与 JSON 字符串」的序列化 / 反序列化。- 简单区分:URL 参数用
addFormatters(),JSON 参数用configureMessageConverters()。
二、springboot配置过滤器与监听器
过滤器与监听器不属于springMVC,属于JavaEE,本文在这里说即为了帮大家区分,同时扩展。
(1)过滤器
2.1.1 来源
来自Servlet 规范,是 Web 容器(Tomcat)级别的拦截,作用于所有请求(包括静态资源、Servlet 请求等),早于 Spring MVC 的处理流程。
2.1.2 核心功能
核心是 「对请求 / 响应进行统一的预处理和后处理」,具备拦截请求的能力,但侧重点是「统一处理」,不关注请求最终的处理器(Controller)。
- 预处理请求 :在请求到达
DispatcherServlet之前执行,比如:编码格式统一设置(解决中文乱码)、请求参数过滤(防 XSS 注入)、用户登录状态校验(未登录拦截跳转到登录页)、记录请求日志。 - 后处理响应:在 Controller 处理完成、响应返回给客户端之前执行,比如:统一添加响应头、对响应数据进行加密 / 格式化、清理资源。
- 链式调用:支持多个 Filter 组成过滤器链,按配置顺序依次执行(先配置的先执行预处理,后执行后处理,类似 "先进后出")。
- 拦截范围广 :能拦截所有进入 Web 应用的请求,包括
@Controller接口、静态资源(JS、CSS、图片)、JSP 等,只要是 Tomcat 接收的请求,都会经过 Filter。
2.2.3 配置过滤器
步骤 1:自定义 Filter(无需添加@WebFilter注解)
java
import jakarta.servlet.*;
import java.io.IOException;
public class MyCustomFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
System.out.println("MyCustomFilter 初始化完成");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("MyCustomFilter 执行预处理逻辑");
request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");
chain.doFilter(request, response); // 放行
System.out.println("MyCustomFilter 执行后处理逻辑");
}
@Override
public void destroy() {
System.out.println("MyCustomFilter 销毁完成");
}
}
步骤 2:创建配置类,注册 Filter 到 Spring 容器
java
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration // 标记为Spring配置类
public class FilterConfig {
// 注册自定义Filter
@Bean
public FilterRegistrationBean<MyCustomFilter> myCustomFilterRegistration() {
FilterRegistrationBean<MyCustomFilter> registrationBean = new FilterRegistrationBean<>();
// 设置要注册的Filter实例
registrationBean.setFilter(new MyCustomFilter());
// 设置拦截路径(/* 拦截所有请求)
registrationBean.addUrlPatterns("/*");
// 设置Filter名称
registrationBean.setName("myCustomFilter");
// 设置执行顺序(值越小,执行优先级越高,默认值为Integer.MAX_VALUE)
registrationBean.setOrder(1);
// 可选:排除拦截路径(如静态资源)
registrationBean.addExcludeUrlPatterns("/static/*", "/favicon.ico");
return registrationBean;
}
}
(2)监听器
2.2.1 来源
同样来自Java EEt 规范 ,核心是一系列事件监听接口(如ServletContextListener、HttpSessionListener、ServletRequestListener),由 Web 容器(如 Tomcat)负责触发,不属于 Spring 生态。
2.2.2 核心功能
<1>监听 Web 应用的「启动」和「关闭」事件,是最常用的监听器,应用启动时(Tomcat 启动、Spring Boot 内嵌 Tomcat 启动):执行初始化逻辑,如加载全局配置文件、初始化全局缓存、连接第三方服务。应用关闭时:执行清理逻辑,如关闭数据库连接、释放缓存资源、记录应用关闭日志。
<2>HttpSessionListener(会话监听器):监听用户 Session 的「创建」和「销毁」事件,比如统计当前在线用户数量。
<3>ServletRequestListener(请求监听器):监听每个 HTTP 请求的「创建」和「销毁」事件,比如统计每个请求的处理时长。
<4>属性监听器 (如ServletContextAttributeListener):监听全局上下文、Session、Request 中的属性(添加、修改、删除)事件,使用较少。
2.2.3 配置监听器
步骤 1:自定义 Listener(无需添加@WebListener注解)
java
import jakarta.servlet.ServletContextEvent;
import jakarta.servlet.ServletContextListener;
public class MyCustomListener implements ServletContextListener {
@Override
public void contextInitialized(ServletContextEvent sce) {
System.out.println("===== 应用启动成功,执行全局初始化逻辑 =====");
}
@Override
public void contextDestroyed(ServletContextEvent sce) {
System.out.println("===== 应用即将关闭,执行全局清理逻辑 =====");
}
}
步骤 2:创建配置类,注册 Listener 到 Spring 容器
java
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@Configuration
public class ListenerConfig {
@Bean
public ServletListenerRegistrationBean<MyCustomListener> myCustomListenerRegistration() {
ServletListenerRegistrationBean<MyCustomListener> registrationBean = new ServletListenerRegistrationBean<>();
registrationBean.setListener(new MyCustomListener());
return registrationBean;
}
}