当前位置: 首页 > 图灵资讯 > 技术篇> SpringMVC-2-Spring MVC拦截器详解:从入门到精通

SpringMVC-2-Spring MVC拦截器详解:从入门到精通

来源:图灵教育
时间:2023-08-21 17:22:28

SpringMVC-2-Spring MVC拦截器详解:从入门到精通今天的目标

能够编写拦截器并配置拦截器

1.拦截器[理解]1 1.1拦截器介绍 拦截器的概念和功能

  • 拦截器(Interceptor)在SpringMVC中,动态拦截控制器方法的执行是一种调用动态拦截方法的机制
  • 作用:
    1. 在调用指定方法前后执行预设代码
    2. 阻止原始方法的实施
    3. 总结:增强
  • 核心原理:AOP思想
1.2 拦截器和过滤器的区别
  • 属性不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术
  • 拦截内容不同:Filter增强所有访问,Interceptor只增强SpringMVC访问
1.3 拦截器应用场景

拦截器本质上是面向截面编程的(AOP),拦截器中可以实现符合横切关注点的功能,主要应用场景包括:

  • 登录验证,判断用户是否登录。
  • 验证权限,判断用户是否有访问资源的权限,如验证token
  • 记录日志,记录请求操作日志(用户IP、访问时间等)。),以统计请求访问量。
  • 处理cookie、本地化、国际化、主题等。
  • 性能监控、监控请求处理时间等。
2 入门案例2.1 实现步骤
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的功能

  1. 将adddinterceptors方法重写在上面添加静态资源的配置类中
  2. 添加拦截器和多个拦截路径:/book和/book/**
  3. 注入拦截器对象
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简化开发(注:侵入性强)

  1. WebMvcconfigurer接口在SpringMvcconfig主配置类中实现,接口中充满默认方法
  2. 注入拦截器对象,重写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;}
  • 参数

    1. request:请求对象
    2. response:响应对象
    3. handler:被调用的处理器对象本质上是一个方法对象,在反射技术中重新包装Method对象
  • 返回值为false,被拦截的处理器将不执行。

3.2 后置处理
/////调用原始方法后执行的内容@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()排除某些地址不被拦截

  • 执行效果

4.2 多个连接器的工作流程分析
  • 当配置多个拦截器时,形成拦截器链
  • 拦截器链的运行顺序以拦截器添加顺序为准
  • 当拦截器中拦截原始处理器时,后拦截器终止运行
  • 当拦截器运行中断时,aftercompletion操作仅在前面的拦截器中运行