SpringMVC(五)【拦截器】

前言

今天来把 SpringMVC 最后一部分学完,虽然课时很短,但是学起来还是很慢的,不过确收获很大。不得不感慨学大数据确实有必要把 SSM、SpringBoot 等各种 JavaEE 技术好好学一学,收获很大,尽管我们到现在 Java 代码写了应该20 W 行差不多,但是关于框架的代码我写的还是比较少的,主要是通过算法和 JavaFX 来练习 Java 基础语法。

1、拦截器

1.1、概念

  • 拦截器是一种动态拦截方法调用的机制,在 SpringMVC 中动态拦截控制器方法的执行
  • 作用
    • 在指定方法调用前后执行预先设定的代码
    • 阻止原始方法的执行(权限判断)

拦截器和过滤器的区别

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

1.2、入门案例

1.2.1、拦截器功能类

在 controller 包下新建一个包 interceptor ,毕竟拦截器是 SpringMVC 的内容,创建自定义拦截器类(记得添加注解 @Component 让 SpringMVC 来对它进行管理)只需要实现 HandlerInterceptor 接口:

java 复制代码
@Component
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");
    }
}

这里需要注意的是 preHandle 方法的返回值,如果返回值为 false 代表直接截断请求,所以后面的控制器方法不会被执行,后面的 postHandle 和 afterCompletion 方法也不会执行。

如果返回 true 则代表不拦截,所以它会执行控制器方法以及 postHandle 和 afterCompletion 方法。

在之前的 SpringMvcSupport 类中添加拦截器,需要配置两个参数:拦截器对象(因为拦截器已经被 SpringMVC 所管理了,所以我们直接通过自动装配获得),拦截哪个请求。

访问 localhost:81/books:

上面我们配置的拦截器只能拦截 /books 这一个请求,如果我们想要拦截 /books/2 后者 /books/100 呢,只需要添加一个参数 "/books/*" 即可:

java 复制代码
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }

1.2.2、简化开发

现在我们的 SpringMvcConfig 是空的,只是带有一堆注解,我们可以把 SpringMvcSupport 和 SpringMvcConfig 进行合并,其实就是让 SpringMvcConfig 实现 WebMvcConfigurer 接口(和 SpringMvcSupport 很像,后者实现的是 WebMvcConfigurationSupport 接口):

java 复制代码
@Configuration
@ComponentScan("com.lyh.controller")
@EnableWebMvc
public class SpringMvcConfig implements WebMvcConfigurer {

    @Autowired
    private ProjectInterceptor projectInterceptor;
    
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }

}

因为我们已经把 SpringMvcSupport 和 SpringMvcConfig 合并了,所以现在我们就不需要让 SpringMvcConfig 扫描 "com.lyh.config" 包了 。

有无拦截器的区别

可以看到,单个拦截器的时候,如果在 preHandle 方法返回 false,将直接终止执行(afterCompletion 方法也不会执行,但是这种情况在多个拦截器的情况下有所不同)。

1.3、拦截器参数

我们说拦截器可以帮我们做一些判断,来决定是否允许这个请求进一步进入 controller 方法,那它必然有一些上下文参数

1.3.1、preHandle 方法

  1. HttpServletRequest request
  2. HttpServletResponse response,
  3. Object handler

对于 request 和 response 这两个对象,我们很容易想到可以拿它们来干什么,比如 request.getHeader("Content-type") 来获得请求头中的 Content-type 属性值。

而这里的 handler 其实是 HandlerMethod 类,它对反射技术中的 Method 对象进行了封装。我们可以通过它来获得原始执行的方法,具体可以干什么以后用到再学。

1.3.2、postHandle 方法

postHandle 方法没有 handler 对象,但是它有一个 ModelAndView 对象,如果我们页面跳转的话,可以通过它来设置一些属性,但是我们到目前为止都是返回 json 并不返回页面,所以这里不做学习。

1.3.3、afterCompletion 方法

afterCompletion 方法同样除了 request 和 response 对象之外,它有一个 Exception 类型的对象,也就是说如果我们的表现层抛出异常的话,我们可以在这里拿到它,但是我们上一篇已经用了 SpringMVC 统一的异常处理器,所以这里也没啥用。

总之,这三个方法实用性最强的就是 preHandle 方法,它可以决定是否放行请求的下一步执行。

1.4、拦截器链配置

  • 当配置多个拦截器时,形成拦截器链
  • 拦截器的拦截顺序取决于我们 addIterceptors 方法中注册拦截器的顺序

1.4.2、创建拦截器类

我们在 interceptor 包下再创建一个拦截器类:

java 复制代码
@Component
public class ProjectInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2");
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2");;
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2");
    }
}

配置拦截器:

访问 localhost:85/books

可以看到,拦截器的拦截顺序取决于我们 addIterceptors 方法中注册拦截器的顺序: pre1 -> pre2 -> controller -> post2 -> post1 -> after2 -> after1。

注意:多个的拦截器情况下,比如下图:

  • 如果 pre3 返回 flase(pre1 和 pre2都返回 true),那么程序并不是直接终止,而是依然会执行 after2 和 after1;
  • 如果 pre2 返回 flase(pre1返回 true),那么程序并不是直接终止,而是依然会执行 after1;
  • 如果 pre1 返回 flase,那么程序直接终止。

总结

至此,SpringMVC 的学习结束,SSM 现在已经是一个程序员必知必会的东西了,可以说是一个应届生校招的基本技能,而不是亮点。接下来再学学 SpringBoot ,这是我们大数据开发中正儿八经会用到的东西,完了做个项目巩固巩固。

相关推荐
西猫雷婶12 分钟前
python学opencv|读取图像(二十一)使用cv2.circle()绘制圆形进阶
开发语言·python·opencv
kiiila13 分钟前
【Qt】对象树(生命周期管理)和字符集(cout打印乱码问题)
开发语言·qt
初晴~13 分钟前
【Redis分布式锁】高并发场景下秒杀业务的实现思路(集群模式)
java·数据库·redis·分布式·后端·spring·
小_太_阳38 分钟前
Scala_【2】变量和数据类型
开发语言·后端·scala·intellij-idea
直裾41 分钟前
scala借阅图书保存记录(三)
开发语言·后端·scala
黑胡子大叔的小屋1 小时前
基于springboot的海洋知识服务平台的设计与实现
java·spring boot·毕业设计
ThisIsClark1 小时前
【后端面试总结】深入解析进程和线程的区别
java·jvm·面试
唐 城1 小时前
curl 放弃对 Hyper Rust HTTP 后端的支持
开发语言·http·rust
雷神乐乐2 小时前
Spring学习(一)——Sping-XML
java·学习·spring
小林coding2 小时前
阿里云 Java 后端一面,什么难度?
java·后端·mysql·spring·阿里云