• 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 接口:

    1. @Component
    2. public class ProjectInterceptor implements HandlerInterceptor {
    3. @Override
    4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    5. System.out.println("preHandle");
    6. return true;
    7. }
    8. @Override
    9. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    10. System.out.println("postHandle");;
    11. }
    12. @Override
    13. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    14. System.out.println("afterCompletion");
    15. }
    16. }

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

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

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

    访问 localhost:81/books:

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

    1. @Override
    2. protected void addInterceptors(InterceptorRegistry registry) {
    3. registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    4. }

    1.2.2、简化开发

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

    1. @Configuration
    2. @ComponentScan("com.lyh.controller")
    3. @EnableWebMvc
    4. public class SpringMvcConfig implements WebMvcConfigurer {
    5. @Autowired
    6. private ProjectInterceptor projectInterceptor;
    7. @Override
    8. public void addInterceptors(InterceptorRegistry registry) {
    9. registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    10. }
    11. @Override
    12. public void addResourceHandlers(ResourceHandlerRegistry registry) {
    13. registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
    14. registry.addResourceHandler("/css/**").addResourceLocations("/css/");
    15. registry.addResourceHandler("/js/**").addResourceLocations("/js/");
    16. registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    17. }
    18. }

            因为我们已经把 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 包下再创建一个拦截器类:

    1. @Component
    2. public class ProjectInterceptor2 implements HandlerInterceptor {
    3. @Override
    4. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    5. System.out.println("preHandle2");
    6. return true;
    7. }
    8. @Override
    9. public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    10. System.out.println("postHandle2");;
    11. }
    12. @Override
    13. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
    14. System.out.println("afterCompletion2");
    15. }
    16. }

    配置拦截器: 

    访问 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 ,这是我们大数据开发中正儿八经会用到的东西,完了做个项目巩固巩固。

  • 相关阅读:
    Linux-安装tomcat以及开启防火墙
    CountDownLatch翻车后,我建议用CompletableFuture改造下
    【多目标进化优化】多目标进化群体的分布性
    一文读懂Elephant Swap,为何为ePLATO带来如此高的溢价?
    Anaconda Prompt中的指令集
    虚拟机访问共享文件夹需要输入主机用户名与密码
    【websocket】小白快速上手flask-socketio
    版本管理的使用
    10张流程图+部署图,讲透单点登录原理与简单实现
    知识图谱问答研究进展
  • 原文地址:https://blog.csdn.net/m0_64261982/article/details/137924065