首页 > 图灵资讯 > 技术篇>正文
SpringMVC-2-Spring MVC拦截器详解:从入门到精通
2023-08-21 17:22:28
SpringMVC-2-Spring MVC拦截器详解:从入门到精通今天的目标
1.拦截器[理解]1 1.1拦截器介绍 拦截器的概念和功能能够编写拦截器并配置拦截器
- 拦截器(Interceptor)在SpringMVC中,动态拦截控制器方法的执行是一种调用动态拦截方法的机制
- 作用:
- 在调用指定方法前后执行预设代码
- 阻止原始方法的实施
- 总结:增强
- 核心原理:AOP思想
- 属性不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
- 拦截内容不同:Filter增强所有访问,Interceptor只增强SpringMVC访问
拦截器本质上是面向截面编程的(AOP),拦截器中可以实现符合横切关注点的功能,主要应用场景包括:
- 登录验证,判断用户是否登录。
- 验证权限,判断用户是否有访问资源的权限,如验证token
- 记录日志,记录请求操作日志(用户IP、访问时间等)。),以统计请求访问量。
- 处理cookie、本地化、国际化、主题等。
- 性能监控、监控请求处理时间等。
1 创建web项目(Maven web结构)2 导入坐标(SpringMVC+Servlet)3 SpringMVCConfig 配置类 配置前缀”/pages“与后缀”和后缀”.jsp”4 ServletConfig IOC容器和拦截请求路径的配置创建”/“5” 自定义控制器类(StudentController)6 开发视图页面/pages/success.jsp
2.2 代码实现[第一步]创建web工程(Maven结构)【第二步】导入坐标(SpringMVC+Servlet)<dependencies> <!--spring-webmvc--> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-webmvc</artifactId> <version>5.3.15</version> </dependency> <!--servlet--> <dependency> <groupId>javax.servlet</groupId> <artifactId>javax.servlet-api</artifactId> <version>4.0.1</version> <scope>provided</scope> </dependency> </dependencies>
【第三步】创建SpringMvc配置文件/*** SpringMVC配置*/@Configuration //1.目前标识的配置类别 指定此类为配置类,替代application.xml@ComponentScan("com.zbbmeta")/2.配置扫描web层包 代替<context:component-scan base-package="com.zbbmeta" />@EnableWebMvc //如果使用接口,这个注释需要添加到拦截器中。不建议使用这种方法,两种方法只能配置一种,否则会有冲突public class SpringMvcConfig {}
[第四步]创建Web容器初始配置类public class ServletConfig extends AbstractAnnotationConfigDispatcherServletInitializer { // 暂时不管,需要整合Spring @Override protected Class<?>[] getRootConfigClasses() { return new Class[0]; } ///在tomcat启动时调用IOC容器对象,用于创建springmvc框架 //加载springmvc配置类, Tomcat将利用此配置类创建IOC容器,生成springmvc容器(本质上是spring容器) @Override protected Class<?>[] getServletConfigClasses() { return new Class[] {SpringMvcConfig.class}; } // SpringMVC应该处理哪些要求? 表示SpringMVC处理项目中的所有要求, SpringMVC不应处理静态资源,而应放行 ///设置DispatcherServlet绑定处理请求的路径"/",除jsp的所有资源请求外,处理jsp的所有资源 @Override protected String[] getServletMappings() { return new String[] {"/"}; }}
【第五步】创建控制器package com.zbbmeta.controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RestController;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;@RestController@RequestMapping("/student")//Requestmaping可以在类或方法中添加public class StudentController { /** * 搜索Student */ @RequestMapping("/find") public String find(HttpServletRequest request, HttpServletResponse response) { System.out.println("搜索Student"); return "find success"; }}
2.3 拦截器代码实现了[第一步]做法:定义一个类,实现HandlerInterceptor接口
package com.zbbmeta.Iinterceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class StudentInterceptor implements HandlerInterceptor { /////调用原始方法前执行的内容 //可拦截控制执行返回值类型,true放行,false终止 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=================前置通知================="); return true; } /////调用原始方法后执行的内容 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("=================后置通知================="); } ////调用原始方法后执行的内容 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("=================最终通知================="); }}
【第二步】配置加载拦截器我们分别介绍了两种配置加载拦截器的方法:
加载拦截器方法1:注:@Componention注释已包含@Component的功能
- 将adddinterceptors方法重写在上面添加静态资源的配置类中
- 添加拦截器和多个拦截路径:/book和/book/**
- 注入拦截器对象
package com.zbbmeta.config;import com.zbbmeta.Iinterceptor.StudentInterceptor;import org.springframework.context.annotation.Configuration;import org.springframework.web.servlet.config.annotation.InterceptorRegistry;import org.springframework.web.servlet.config.annotation.WebMvcConfigurationSupport;@Configurationpublic class SpringMvcSupport extends WebMvcConfigurationSupport { @Override protected void addInterceptors(InterceptorRegistry registry) { ///注意拦截器和拦截地址 表示添加 StudentInterceptor 拦截路径是 /student/* 所有请求 registry.addInterceptor(new StudentInterceptor()).addPathPatterns("/student/*"); }}
加载拦截器方法2:使用标准界面WebMvcconfigurer简化开发(注:侵入性强)
- WebMvcconfigurer接口在SpringMvcconfig主配置类中实现,接口中充满默认方法
- 注入拦截器对象,重写addinterceptors方法
注:只能选择一两种方式,否则会有冲突。如果方式一起工作,第二种方式的拦截器将无法使用。
也就是说,如果一次出现在项目中 extends WebMvcConfigurationSupport ,其他的 extends WebMvcConfigurationSupport 和 implements WebMvcConfigurer 会失效 。
/** * SpringMVC配置类别 */@Configuration //1.目前标识的配置类别 指定此类为配置类,替代application.xml@ComponentScan("com.zbbmeta")/2.配置扫描web层包 代替<context:component-scan base-package="com.zbbmeta" />@EnableWebMvc //如果使用接口,这个注释需要添加到拦截器中。不建议使用这种方法,两种方法只能配置一种,否则会有冲突publicic class SpringMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { ///注意拦截器和拦截地址 表示添加 StudentInterceptor 拦截路径是 /student/* 所有请求 registry.addInterceptor(new StudentInterceptor()).addPathPatterns("/student/*"); }}
2.4 拦截器流程分析3 拦截器参数3.1 前置处理///原始方法调用前执行的内容//返回值类型可拦截控制执行,true放行,false终止@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=================前置通知================="); return true;}
参数
- request:请求对象
- response:响应对象
- handler:被调用的处理器对象本质上是一个方法对象,在反射技术中重新包装Method对象
返回值为false,被拦截的处理器将不执行。
/////调用原始方法后执行的内容@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("=================后置通知=================");}
- modelandview参数:如果处理器完成返回结果,可以读取相应的数据和页面信息并跳转
3.3 完成后处理注:如果处理器方法异常,则该方法不会执行
////调用原始方法后执行的内容@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("=================最终通知=================");}
- 参数ex:如果处理器执行过程中有异常对象,可以单独处理异常情况
注:无论处理器方法内部是否有异常,都将执行该方法。
**思考:postHandle()和aftercompletion()方法都是处理器方法执行后执行的。有什么区别?
4 4.1配置拦截器链 配置多个拦截器- 定义第二个拦截器
package com.zbbmeta.Iinterceptor;import org.springframework.web.servlet.HandlerInterceptor;import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;public class Studentinterceptor implements HandlerInterceptor { /////调用原始方法前执行的内容 //可拦截控制执行返回值类型,true放行,false终止 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("=================Student2前置通知================="); return true; } /////调用原始方法后执行的内容 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("=================Student2后置通知================="); } ////调用原始方法后执行的内容 @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("=================Student2最终通知================="); }}
- 配置加载第二个拦截器
/** * SpringMVC配置类别 */@Configuration //1.目前标识的配置类别 指定此类为配置类,替代application.xml@ComponentScan("com.zbbmeta")/2.配置扫描web层包 代替<context:component-scan base-package="com.zbbmeta" />@EnableWebMvc //如果使用接口,拦截器需要添加此注释。不建议使用这种方法,两种方法只能配置一种,否则会有冲突publicic class SpringMvcConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { ///注意拦截器和拦截地址 表示添加 StudentInterceptor 拦截路径是 /student/* 所有请求 registry.addInterceptor(new StudentInterceptor()).addPathPatterns("/student/*"); registry.addInterceptor(new Studentinterceptor2().addPathPatterns("/student/*"); }}
提示:可采用excludePathPatterns()排除某些地址不被拦截
- 执行效果
- 当配置多个拦截器时,形成拦截器链
- 拦截器链的运行顺序以拦截器添加顺序为准
- 当拦截器中拦截原始处理器时,后拦截器终止运行
- 当拦截器运行中断时,aftercompletion操作仅在前面的拦截器中运行