一、拦截器概述
拦截器是 Spring MVC 提供的一种AOP(面向切面编程)思想的具体实现,它允许你在处理器(Controller)方法执行前后插入自定义逻辑,实现请求的预处理和后处理。
1.1 拦截器的创建与基本配置
实现org.springframework.web.servlet.HandlerInterceptor 接口,共有三个方法可以进行选择性的实现:
- preHandle:处理器方法调用之前执行(只有该方法有返回值,返回值是布尔类型,true放行,false拦截。)
- postHandle:处理器方法调用之后执行
- afterCompletion:渲染完成后执行
在springmvc.xml文件中进行如下配置:
第一种方式:
<mvc:interceptors>
<bean class="com.powernode.springmvc.interceptors.Interceptor1"/>
</mvc:interceptors>
第二种方式:
<mvc:interceptors>
<ref bean="interceptor1"/>
</mvc:interceptors>
第二种方式的前提:拦截器需要使用 @Component 注解进行标注,且需要被spring包扫描到,加入bean管理。
注意:对于这种基本配置来说,拦截器是拦截所有请求的。
1.2 拦截器的高级配置
采用以上基本配置方式,拦截器是拦截所有请求路径的。如果要针对某些路径进行拦截,某些路径不拦截,可以采用高级配置:
<mvc:interceptors>
<mvc:interceptor>
<!–拦截所有路径–>
<mvc:mapping path="/**"/>
<!–除 /test 路径之外–>
<mvc:exclude-mapping path="/test"/>
<!–拦截器–>
<ref bean="interceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
1.3 拦截器的执行顺序
如果所有拦截器preHandle都返回true,按照springmvc.xml文件中配置的顺序,自上而下调用 preHandle:
<mvc:interceptors>
<ref bean="interceptor1"/>
<ref bean="interceptor2"/>
</mvc:interceptors>

只要有一个拦截器preHandle返回false,任何postHandle都不执行。但返回false的拦截器的前面的拦截器按照逆序执行afterCompletion。
源码分析:
public class DispatcherServlet extends FrameworkServlet {
protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 按照顺序执行所有拦截器的preHandle方法
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 执行处理器方法
mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
// 按照逆序执行所有拦截器的 postHanle 方法
mappedHandler.applyPostHandle(processedRequest, response, mv);
// 处理视图
processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);
}
private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,
@Nullable HandlerExecutionChain mappedHandler, @Nullable ModelAndView mv,
@Nullable Exception exception) throws Exception {
// 渲染视图
render(mv, request, response);
// 按照逆序执行所有拦截器的 afterCompletion 方法
mappedHandler.triggerAfterCompletion(request, response, null);
}
}
public class HandlerExecutionChain {
private final Object handler;
private final List<HandlerInterceptor> interceptorList;
/**
* 执行所有拦截器的 preHandle 方法(在 Controller 执行之前调用)
* 按配置顺序正向执行
* @return true: 所有拦截器都放行;false: 有拦截器拦截了请求
*/
boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
// 正向遍历拦截器列表(从第一个到最后一个)
for(int i = 0; i < this.interceptorList.size(); this.interceptorIndex = i++) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
// 调用当前拦截器的 preHandle 方法
if (!interceptor.preHandle(request, response, this.handler)) {
// 如果当前拦截器返回 false,说明它要拦截请求
// 触发所有已执行过 preHandle 的拦截器的 afterCompletion 方法进行清理
this.triggerAfterCompletion(request, response, (Exception)null);
return false; // 返回 false 表示请求被拦截
}
// interceptorIndex 记录最后一个成功执行 preHandle 的拦截器下标
// 方便后面 afterCompletion 知道哪些拦截器需要执行清理
}
return true; // 所有拦截器都放行
}
/**
* 执行所有拦截器的 postHandle 方法(在 Controller 执行之后,视图渲染之前调用)
* 逆向执行(从最后一个拦截器开始往前)
*/
void applyPostHandle(HttpServletRequest request, HttpServletResponse response, @Nullable ModelAndView mv) throws Exception {
// 从最后一个拦截器开始往前遍历(逆向)
for(int i = this.interceptorList.size() – 1; i >= 0; —i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
// 调用拦截器的 postHandle 方法
interceptor.postHandle(request, response, this.handler, mv);
}
}
/**
* 触发所有已执行过 preHandle 的拦截器的 afterCompletion 方法
* 用于请求完成后的清理工作(无论正常结束还是发生异常)
* 逆向执行(从最后一个成功执行的拦截器开始往前)
*/
void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
// interceptorIndex 记录的是最后一个成功执行 preHandle 的拦截器下标
// 从那个下标开始往前遍历(逆向)
for(int i = this.interceptorIndex; i >= 0; —i) {
HandlerInterceptor interceptor = (HandlerInterceptor)this.interceptorList.get(i);
try {
// 调用拦截器的 afterCompletion 方法进行清理
interceptor.afterCompletion(request, response, this.handler, ex);
} catch (Throwable ex2) {
// 如果清理过程本身也抛异常,记录日志但不影响其他拦截器的清理
logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
}
}
}
}
注:这里如果在interceptor.preHandle(request, response, this.handler)方法中就返回false,那么触发所有已执行过 preHandle 的拦截器的 afterCompletion 方法进行清理this.triggerAfterCompletion(request, response, (Exception)null);,并不通过业务代码。
二、SSM整合
1. 引入相关依赖
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>6.2.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>6.2.12</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.15</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>3.0.5</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.30</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.2.8</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.19.2</version>
</dependency>
<dependency>
<groupId>jakarta.servlet</groupId>
<artifactId>jakarta.servlet-api</artifactId>
<version>6.0.0</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.42</version>
</dependency>
<dependency>
<groupId>org.thymeleaf</groupId>
<artifactId>thymeleaf-spring6</artifactId>
<version>3.1.2.RELEASE</version>
</dependency>
</dependencies>
2. 创建包结构

3. Spring整合MyBatis
在resources下编写jdbc.properties
jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/test
jdbc.username=root
jdbc.password=662811
编写DataSourceConfig
public class DataSourceConfig {
@Value("${jdbc.driver}")
private String driver;
@Value("${jdbc.url}")
private String url;
@Value("${jdbc.username}")
private String username;
@Value("${jdbc.password}")
private String password;
// 配置 Druid 数据源
@Bean
public DataSource dataSource(){
DruidDataSource dataSource = new DruidDataSource();
dataSource.setDriverClassName(driver);
dataSource.setUrl(url);
dataSource.setUsername(username);
dataSource.setPassword(password);
return dataSource;
}
// 在DataSourceConfig中添加事务管理器对象
@Bean
public PlatformTransactionManager platformTransactionManager(DataSource dataSource){
DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
dataSourceTransactionManager.setDataSource(dataSource);
return dataSourceTransactionManager;
}
}
编写MyBatisConfig
@MapperScan("com.tant1an.ssm.mapper")
public class MyBatisConfig {
// 该方法用于创建 SqlSessionFactoryBean 实例,它是 Spring 与 MyBatis 整合的核心配置
@Bean
public SqlSessionFactoryBean sqlSessionFactory(DataSource dataSource){
SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
// 设置数据源
sqlSessionFactoryBean.setDataSource(dataSource);
// 设置别名
sqlSessionFactoryBean.setTypeAliasesPackage("com.tant1an.ssm.pojo");
return sqlSessionFactoryBean;
}
}
编写SpringConfig
// spring 框架的核心注解,用于标记一个类为配置类
@Configuration
// 组件扫描
@ComponentScan({"com.tant1an.ssm.service"})
// 从类路径下加载jdbc.properties
@PropertySource("classpath:jdbc.properties")
// 加载数据源和MyBatis配置
@Import({DataSourceConfig.class, MyBatisConfig.class})
// 在SpringConfig中开启事务管理器
@EnableTransactionManagement
public class SpringConfig {
}
4. Spring整合Spring MVC
编写WebAppInitializer(web.xml)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[]{SpringConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[]{SpringMvcConfig.class};
}
@Override
protected String[] getServletMappings() {
return new String[]{"/"};
}
@Override
protected Filter[] getServletFilters() {
// 配置字符编码过滤器
CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
characterEncodingFilter.setEncoding("UTF-8");
characterEncodingFilter.setForceResponseEncoding(true);
characterEncodingFilter.setForceRequestEncoding(true);
// 配置HiddenHttpMethodFilter
HiddenHttpMethodFilter hiddenHttpMethodFilter = new HiddenHttpMethodFilter();
return new Filter[]{characterEncodingFilter, hiddenHttpMethodFilter};
}
}
编写SpringMvcConfig
@Configuration
@ComponentScan("com.tant1an.ssm.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {
// 以下三个方法合并起来就是开启视图解析器
@Bean
public ThymeleafViewResolver getViewResolver(SpringTemplateEngine springTemplateEngine) {
ThymeleafViewResolver resolver = new ThymeleafViewResolver();
resolver.setTemplateEngine(springTemplateEngine);
resolver.setCharacterEncoding("UTF-8");
resolver.setOrder(1);
return resolver;
}
@Bean
public SpringTemplateEngine templateEngine(ITemplateResolver iTemplateResolver) {
SpringTemplateEngine templateEngine = new SpringTemplateEngine();
templateEngine.setTemplateResolver(iTemplateResolver);
return templateEngine;
}
@Bean
public ITemplateResolver templateResolver(ApplicationContext applicationContext) {
SpringResourceTemplateResolver resolver = new SpringResourceTemplateResolver();
resolver.setApplicationContext(applicationContext);
resolver.setPrefix("/WEB-INF/templates/");
resolver.setSuffix(".html");
resolver.setTemplateMode(TemplateMode.HTML);
resolver.setCharacterEncoding("UTF-8");
resolver.setCacheable(false);//开发时关闭缓存,改动即可生效
return resolver;
}
// 开启静态资源处理,开启默认的Servlet处理
@Override
public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
configurer.enable();
}
// 视图控制器
@Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addViewController("/").setViewName("index");
}
// 配置异常处理器
@Override
public void configureHandlerExceptionResolvers(List<HandlerExceptionResolver> resolvers) {}
// 配置拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {}
}
5. pojo类编写
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User {
private Long id;
private String name;
private String password;
private String email;
}
6. controller、service、mapper层代码的编写
mapper层:
@Mapper
public interface UserMapper {
@Select("select * from tbl_user where id = #{id}")
User selectById(Long id);
}
service层及实现类:
public interface UserService { User getById(Long id);}
// 实现类
@Transactional
@Service
public class UserServiceImpl implements UserService {
@Autowired
private UserMapper userMapper;
@Override
public User getById(Long id) {
return userMapper.selectById(id);
}
}
controller层:
@RestController
@RequestMapping("/user")
public class UserController {
@Autowired
private UserService userService;
@GetMapping("/{id}")
public User detail(@PathVariable("id") Long id){
User user = userService.getById(id);
System.out.println(user);
return user;
}
}
注:在配置Tomcat的时候,需要构建工件,我们可以在当前文件的项目结构中找到工件,添加Web应用程序:展开型。如果在启动程序时,显示工件无法加载,可以通过错误日志,也许是依赖在工件中未加载,可以重新添加工件。
最后感谢动力节点提供的优质学习资源,让我们在技术道路上能够站在巨人的肩膀上继续前行。本资料仅为学习过程的副产品,希望能帮助到更多同样在努力学习的开发者。






