SpringMVC拦截器

拦截器

无拦截器-------------------------->controller------------------------------------>
有拦截器---->preHandle--|---true---controller--postHandle---afterCompletion--|------>
					   |---false--------------------------------------------|

拦截器(Interceptor)是一种动态拦截方法调用的机制,在SpringMVC中动态拦截控制器方法的执行;可以在指定的方法调用前后执行预先设定的代码,或者权限控制阻止原始方法的执行,总的来说拦截器就是用来做增强。

拦截器和过滤器之间的区别

归属不同:Filter属于Servlet技术,Interceptor属于SpringMVC技术

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

过滤器1--过滤器2--mvc核心--拦截器1--拦截器2--处理器--拦截器2--拦截器1--过滤器2--过滤器1-->

拦截器开发

ProjectInterceptor:重写HandlerInterceptor接口中的三个方法。

preHandler方法返回true代表放行,继续执行原始Controller类中要请求的方法;返回false代表拦截,终止原始操作

package com.lmcode.interceptor;

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    //原始方法调用前执行的内容
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle...");
        return true;
        /*返回false可以终止原始操作*/
    }
    //原始方法调用后执行的内容
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    //原始方法调用完成后执行的内容
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

添加拦截器:SpringMVCSupport

package com.lmcode.config;

@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    // 放行静态资源
    @Override
    protected void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/pages/**").addResourceLocations("/pages/");
        registry.addResourceHandler("/css/**").addResourceLocations("/css/");
        registry.addResourceHandler("/js/**").addResourceLocations("/js/");
        registry.addResourceHandler("/plugins/**").addResourceLocations("/plugins/");
    }

    // 添加拦截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

SpringMvcConfig:添加SpringMvcSupport包扫描

package com.lmcode.config;

@Configuration
@ComponentScan({
        "com.lmcode.controller",
        "com.lmcode.advice",
        "com.lmcode.config",
        "com.lmcode.interceptor"})
@EnableWebMvc
public class SpringMvcConfig {
}

添加拦截器方法二【侵入性强,和spring强绑定】

使用SpringMvcConfig实现WebMvcConfigurer方法,可以放行静态资源或添加拦截器

package com.lmcode.config;

@Configuration
@ComponentScan({"com.itheima.controller"})
@EnableWebMvc
//实现WebMvcConfigurer接口可以简化开发,但具有一定的侵入性
public class SpringMvcConfig implements WebMvcConfigurer {
    @Autowired
    private ProjectInterceptor projectInterceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //配置多拦截器
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
    }
}

拦截器方法

  • request:请求对象
  • response:响应对象
  • handler:被调用的处理器对象,本质上是一个方法对象,对反射中的Method对象进行了再包装
  • modelAndView:页面跳转相关数据
  • ex:如果处理器执行过程中出现异常对象,可以针对异常情况进行单独处理

现在大多是异步开发,而且有全局异常处理器,所以ModelAndView和ex使用率不高;最常用的是preHandle,在这个方法中可以通过返回值来决定是否要进行放行:把业务逻辑放在该方法中,如果满足业务则返回true放行,不满足则返回false拦截。

前置处理方法:preHandle
@Override
public boolean preHandle(HttpServletRequest request,HttpServletResponse response,Object handler) throws Exception {
    System.out.println("preHandle");
    return true;
}

使用request对象或response对象可以获取请求数据中的内容,如获取请求头的Content-Type

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    String contentType = request.getHeader("Content-Type");
    System.out.println("preHandle..."+contentType);
    return true;
}

使用handler参数,可以获取当前方法的相关信息

@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    System.out.println(handler); // com.lmcode.controller.BookController#save(Book)
    System.out.println(handler.getClass()); // class org.springframework.web.method.HandlerMethod
    HandlerMethod hm = (HandlerMethod)handler;
    String methodName = hm.getMethod().getName(); // 获取方法的名称
    return true;
}
后置处理方法:postHandle
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {
    System.out.println("postHandle");
}
完成处理方法:afterCompletion
@Override
public void afterCompletion(HttpServletRequest request,HttpServletResponse response,Object handler,Exception ex) throws Exception {
    // 通过ex可以拿到原始的程序执行过程中出现的异常
    System.out.println("afterCompletion");
}

拦截器链

配置多个拦截器形成拦截器链

preHandle与配置顺序相同,必定运行;postHandle与配置顺序相反,可能不运行;afterCompletion与配置顺序相反,可能不运行。

两个拦截器时,当拦截器1返回false时,流程终止,拦截器2的pre也不执行了

三个拦截器时,当1,2正常运行,但是3返回false,最后只会运行1,2的after

package com.lmcode.interceptor;

@Component
public class ProjectInterceptor implements HandlerInterceptor {
    //原始方法调用前执行的内容
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle1...");
        return false;
        /*返回false可以终止原始操作*/
    }
    //原始方法调用后执行的内容
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle1...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    //原始方法调用完成后执行的内容
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion1...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}
package com.lmcode.interceptor;

@Component
public class ProjectInterceptor2 implements HandlerInterceptor {
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println("preHandle2...");
        return false;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println("postHandle2...");
        HandlerInterceptor.super.postHandle(request, response, handler, modelAndView);
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println("afterCompletion2...");
        HandlerInterceptor.super.afterCompletion(request, response, handler, ex);
    }
}

按照配置拦截器的先后进行拦截

pre1--->pre2--代码--->post2--->post1--->after2--->after1

package com.lmcode.config;

@Configuration
public class SpringMVCSupport extends WebMvcConfigurationSupport {
    @Autowired
    private ProjectInterceptor projectInterceptor;
    private ProjectInterceptor2 projectInterceptor2;

    // 添加拦截器
    @Override
    protected void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(projectInterceptor).addPathPatterns("/books","/books/*");
        registry.addInterceptor(projectInterceptor2).addPathPatterns("/books","/books/*");
    }
}
posted @ 2024-04-07 00:09  燕子去了  阅读(23)  评论(0编辑  收藏  举报

Powered by .NET 8.0 on Kubernetes

我会翻山越岭,到每一个我想去的地方

...