拦截器(Interceptor)介绍
拦截器,在AOP(Aspect-Oriented Programming)中用于在某个方法或字段被访问之前,进行拦截,然后在之前或之后加入某些操作。拦截是AOP的一种实现策略。
在WebWork的中文文档的解释为—拦截器是动态拦截Action调用的对象。它提供了一种机制可以使开发者可以定义在一个Action执行的前后执行的代码,也可以在一个Action执行前阻止其执行。同时也提供了一种可以提取Action中可重用的部分的方式。
作用域:动态拦截Action调用的对象(也就是我们的controller层)
我们日常开发中,经常会遇到这个场景:在访问系统功能前,需要用户登录,不登陆的话无法使用我们的系统,那么如果在每个方法前都加上登录代码,常见的可以使用以下几种方式:
- 使用AOP切面功能来实现
- 使用Spring的拦截器相关接口来自定义拦截器
- 实现WebMvcConfigurer接口,重写addCorsMappings()方法和addInterceptors()方法【配置拦截器】
- 实现HandlerInterceptor接口或者继承HandlerInterceptorAdapter,重写preHandle()方法【自定义拦截器】
拦截器将Action共用的行为独立出来,在Action执行前后执行。这也就是我们所说的AOP,它是分散关注的编程方法,它将通用需求功能从不相关类之中分离出来;同时,能够共享一个行为,一旦行为发生变化,不必修改很多类,只要修改这个行为就可以。
拦截器将很多功能从我们的Action中独立出来,大量减少了我们Action的代码,独立出来的行为就有很好的重用性。
当你提交对Action(默认是.action结尾的url)的请求时,ServletDispatcher会根据你的请求,去调度并执行相应的Action。在Action执行之前,调用被Interceptor截取,Interceptor在Action执行前后执行。
创建Interceptor必须实现com.opensymphony.xwork2.interceptor.Interceptor接口,该接口定义了如下三个方法。
-
void init():在该拦截器被实例化之后,在该拦截器执行拦截之前,系统将回调该方法。对于每个拦截器而言,其init()方法只执行一次。因此,该方法的方法体主要用于初始化资源。
-
void destory():该方法与init()方法对应。在拦截器实例被销毁之前,系统将回调该拦截器的destory方法,该方法用于销毁在init方法里打开的资源。
-
String intercept(ActionInvocation invocation):该方法是用户需要实现的拦截动作。就像Action的execute方法一样。intercept方法会返回一个字符串作为逻辑视图。如果该方法直接返回了一个字符串,系统会将跳转到该逻辑视图对应的实际视图资源,不会调用被拦截的Action。该方法的ActionInvocation参数包含了被拦截的Action的引用,可以通过调用该参数的invoke方法,将控制权转给下一个拦截器,或者转给Action的execute方法(如果该拦截器后没有其他拦截器,则直接执行Action的execute方法)
拦截器实现
配置类
/** * 拦截器的属性配置 */ @Configuration//标识这是一个配置类 public class InterceptorConfig implements WebMvcConfigurer { /** * 重写addCorsMappings()解决跨域问题 * 配置:允许http请求进行跨域访问 */ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**")//指哪些接口URL需要增加跨域设置 .allowedOrigins("*")//指的是前端哪些域名被允许跨域 .allowCredentials(true)//需要带cookie等凭证时,设置为true,就会把cookie的相关信息带上 .allowedMethods("GET", "HEAD", "POST", "PUT", "DELETE", "OPTIONS")//指的是允许哪些方法 .maxAge(3600);//cookie的失效时间,单位为秒(s),若设置为-1,则关闭浏览器就失效 } /** * 重写addInterceptors()实现拦截器 * 配置:要拦截的路径以及不拦截的路径 */ @Override public void addInterceptors(InterceptorRegistry registry) { //注册Interceptor拦截器(Interceptor这个类是我们自己写的拦截器类) InterceptorRegistration registration = registry.addInterceptor(new Interceptor1());//添加自定义的拦截器 //addPathPatterns()方法添加需要拦截的路径 registration.addPathPatterns("/getbotlist"); //“/**”所有路径都被拦截 //excludePathPatterns()方法添加不拦截的路径 registration.excludePathPatterns( //添加不拦截路径 "/demo/loginPage", //登录页面的地址【不拦截】 "/**/*.html", //html静态资源 "/**/*.js", //js静态资源 "/**/*.css" //css静态资源 ); } }
自定义拦截器
实现HandlerInterceptor这个接口,这个接口包括三个方法,preHandle是请求执行前执行的,postHandler是请求结束执行的,但只有preHandle方法返回true的时候才会执行,afterCompletion是视图渲染完成后才执行,同样需要preHandle返回true,该方法通常用于清理资源等工作。
/*
*自定义拦截器
*/
public class Interceptor1 implements HandlerInterceptor { /** * 在请求处理之前进行调用(Controller方法调用之前) */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) { System.out.println("-----------------------进入拦截器-------------------------"); return true; } @Override public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception { System.out.println("-----------------------controller执行完成-----------------------"); System.out.println(modelAndView);//ModelAndView是controller的返回值.这里要让controller返回值是ModelAndView类型 } @Override public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception { System.out.println("-----------------------视图渲染完成---------------------------");//对view的处理结束 } }