写点什么

[SpringMVC] 拦截器①(概述、入门案例)

作者:fake smile by
  • 2022 年 9 月 18 日
    黑龙江
  • 本文字数:4820 字

    阅读完需:约 16 分钟

什么是拦截器

讲解拦截器的概念之前,我们先看一张图:



(1)浏览器发送一个请求会先到 Tomcat 的 web 服务器


(2)Tomcat 服务器接收到请求以后,会去判断请求的是静态资源还是动态资源


(3)如果是静态资源,会直接到 Tomcat 的项目部署目录下去直接访问


(4)如果是动态资源,就需要交给项目的后台代码进行处理


(5)在找到具体的方法之前,我们可以去配置过滤器(可以配置多个),按照顺序进行执行


(6)然后进入到到中央处理器(SpringMVC 中的内容),SpringMVC 会根据配置的规则进行拦截


(7)如果满足规则,则进行处理,找到其对应的 controller 类中的方法进行执行,完成后返回结果


(8)如果不满足规则,则不进行处理


(9)这个时候,如果我们需要在每个 Controller 方法执行的前后添加业务,具体该如何来实现?


这个就是拦截器要做的事。


  • 拦截器(Interceptor)是一种动态拦截方法调用的机制,在 SpringMVC 中动态拦截控制器方法的执行

  • 作用:

  • 在指定的方法调用前后执行预先设定的代码

  • 阻止原始方法的执行

  • 总结:拦截器就是用来做增强


看完以后,大家会发现


  • 拦截器和过滤器在作用和执行顺序上也很相似


所以这个时候,就有一个问题需要思考:拦截器和过滤器之间的区别是什么?


  • 归属不同:Filter(过滤器)属于 Servlet 技术,Interceptor(拦截器)属于 SpringMVC 技术

  • 拦截内容不同:Filter 对所有访问进行增强,Interceptor 仅针对 SpringMVC 的访问进行增强


拦截器入门案例

环境准备

  • 创建一个 Web 的 Maven 项目

  • pom.xml 添加 SSM 整合所需 jar 包


  <?xml version="1.0" encoding="UTF-8"?>    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">    <modelVersion>4.0.0</modelVersion>      <groupId>com.nefu</groupId>    <artifactId>springmvc_try</artifactId>    <version>1.0-SNAPSHOT</version>    <packaging>war</packaging>      <dependencies>      <dependency>        <groupId>javax.servlet</groupId>        <artifactId>javax.servlet-api</artifactId>        <version>3.1.0</version>        <scope>provided</scope>      </dependency>      <dependency>        <groupId>org.springframework</groupId>        <artifactId>spring-webmvc</artifactId>        <version>5.2.10.RELEASE</version>      </dependency>      <dependency>        <groupId>com.fasterxml.jackson.core</groupId>        <artifactId>jackson-databind</artifactId>        <version>2.9.0</version>      </dependency>    </dependencies>      <build>      <plugins>        <plugin>          <groupId>org.apache.tomcat.maven</groupId>          <artifactId>tomcat7-maven-plugin</artifactId>          <version>2.1</version>          <configuration>            <port>80</port>            <path>/</path>          </configuration>        </plugin>          <plugin>              <groupId>org.apache.maven.plugins</groupId>              <artifactId>maven-compiler-plugin</artifactId>              <configuration>                  <source>8</source>                  <target>8</target>              </configuration>          </plugin>      </plugins>    </build>  </project>
复制代码


  • 创建对应的配置类


  public class ServletContainersInitConfig extends AbstractAnnotationConfigDispatcherServletInitializer {      protected Class<?>[] getRootConfigClasses() {          return new Class[0];      }        protected Class<?>[] getServletConfigClasses() {          return new Class[]{SpringMvcConfig.class};      }        protected String[] getServletMappings() {          return new String[]{"/"};      }        //乱码处理      @Override      protected Filter[] getServletFilters() {          CharacterEncodingFilter filter = new CharacterEncodingFilter();          filter.setEncoding("UTF-8");          return new Filter[]{filter};      }  }    @Configuration  @ComponentScan({"com.nefu.controller"})  @EnableWebMvc  public class SpringMvcConfig{       }
复制代码


  • 创建模型类 Book


  public class Book {      private String name;      private double price;        public String getName() {          return name;      }        public void setName(String name) {          this.name = name;      }        public double getPrice() {          return price;      }        public void setPrice(double price) {          this.price = price;      }        @Override      public String toString() {          return "Book{" +                  "书名='" + name + '\'' +                  ", 价格=" + price +                  '}';      }  }
复制代码


  • 编写 Controller


  @RestController  @RequestMapping("/books")  public class BookController {        @PostMapping      public String save(@RequestBody Book book){          System.out.println("book save..." + book);          return "{'module':'book save'}";      }        @DeleteMapping("/{id}")      public String delete(@PathVariable Integer id){          System.out.println("book delete..." + id);          return "{'module':'book delete'}";      }        @PutMapping      public String update(@RequestBody Book book){          System.out.println("book update..."+book);          return "{'module':'book update'}";      }        @GetMapping("/{id}")      public String getById(@PathVariable Integer id){          System.out.println("book getById..."+id);          return "{'module':'book getById'}";      }        @GetMapping      public String getAll(){          System.out.println("book getAll...");          return "{'module':'book getAll'}";      }  }
复制代码

拦截器开发

步骤 1:创建拦截器类

我们可以创建一个拦截器文件夹,命名为 interceptor,这个文件夹我们可以把它放在 controller 文件夹中,因为拦截器本来就与表现层有关。然后我们再在拦截器文件夹中创建一个拦截器类 ProjectInterceptor:



让类实现 HandlerInterceptor 接口,重写接口中的三个方法。


@Component//定义拦截器类,实现HandlerInterceptor接口//注意当前类必须受Spring容器控制public class ProjectInterceptor implements HandlerInterceptor {    @Override    //原始方法调用前执行的内容    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {        System.out.println("preHandle...");        return true;    }
@Override //原始方法调用后执行的内容 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle..."); }
@Override //原始方法调用完成后执行的内容 public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion..."); }}
复制代码


注意:拦截器类要被 SpringMVC 容器扫描到。


拦截器中的preHandler方法,如果返回 true,则代表放行,会执行原始 Controller 类中要请求的方法,如果返回 false,则代表拦截,后面的就不会再执行了(你的原始方法也不会执行)。

步骤 2:配置拦截器类

也就是配置你执行什么样的请求的时候你的拦截器会生效


配置拦截器的地方与我们前面配置页面静态资源放行的地方是一样的。


在配置的时候我们要把拦截器给添加进去,这里我们使用自动装配进行注入。


@Configurationpublic class SpringMvcSupport extends WebMvcConfigurationSupport {    @Autowired    private ProjectInterceptor projectInterceptor;
@Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); }
@Override protected void addInterceptors(InterceptorRegistry registry) { //配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books" ); }}
复制代码


注意:


//配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books" );
复制代码


如果向上面这样配置拦截器,那么你访问:


localhost/books/100
复制代码


这样拦截器是不能生效的,你需要修改拦截器的配置:


//配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*" );
复制代码


也就是说他是从 localhost 后面那一级开始配置的


同时我们也可以配置多个:


//配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books/*" ,"/books" );
复制代码

步骤 3:SpringMVC 添加 SpringMvcSupport 包扫描

@Configuration@ComponentScan({"com.nefu.controller","com.nefu.config"})@EnableWebMvcpublic class SpringMvcConfig{   }
复制代码

步骤 4:运行程序测试

使用 PostMan 发送http://localhost/books



如果发送http://localhost/books/100会发现拦截器没有被执行,原因是拦截器的addPathPatterns方法配置的拦截路径是/books,我们现在发送的是/books/100,所以没有匹配上,因此没有拦截,拦截器就不会执行。

步骤 5:修改拦截器拦截规则

@Configurationpublic class SpringMvcSupport extends WebMvcConfigurationSupport {    @Autowired    private ProjectInterceptor projectInterceptor;
@Override protected void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/pages/**").addResourceLocations("/pages/"); }
@Override protected void addInterceptors(InterceptorRegistry registry) { //配置拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*" ); }}
复制代码


这个时候,如果再次访问http://localhost/books/100,拦截器就会被执行。


最后说一件事,就是拦截器中的preHandler方法,如果返回 true,则代表放行,会执行原始 Controller 类中要请求的方法,如果返回 false,则代表拦截,后面的就不会再执行了。

简化 SpringMvcSupport 的编写

@Configuration@ComponentScan({"com.nefu.controller"})@EnableWebMvc//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性public class SpringMvcConfig implements WebMvcConfigurer {    @Autowired    private ProjectInterceptor projectInterceptor;
@Override public void addInterceptors(InterceptorRegistry registry) { //配置多拦截器 registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*"); }}
复制代码


此后咱们就不用再写SpringMvcSupport类了。

总结

最后我们来看下拦截器的执行流程:



当有拦截器后,请求会先进入 preHandle 方法,


​ 如果方法返回 true,则放行继续执行后面的 handle[controller 的方法]和后面的方法


​ 如果返回 false,则直接跳过后面方法的执行。

发布于: 刚刚阅读数: 5
用户头像

fake smile by

关注

还未添加个人签名 2022.07.31 加入

还未添加个人简介

评论

发布
暂无评论
[SpringMVC]拦截器①(概述、入门案例)_springmvc_fake smile by_InfoQ写作社区