范文健康探索娱乐情感热点
投稿投诉
热点动态
科技财经
情感日志
励志美文
娱乐时尚
游戏搞笑
探索旅游
历史星座
健康养生
美丽育儿
范文作文
教案论文
国学影视

HandlerInterceptor处理器拦截器机制全解

  1 拦截器与过滤器处理器拦截器HandlerInterceptor是Spring MVC提供的特性,依赖于Spring MVC框架,而不依赖Servlet容器,Filter则是Servlet的特性,属于Servlet的规范,并且依赖Servlet容器。应用中可以存在多个拦截器形成拦截器链,也可以存在多个过滤器形成过滤器链!拦截器链和过滤器链的预处理和后处理的调用顺序都是相反的,即预处理调用时按照链从前向后调用,而后处理调用时则按照链从后向前调用。过滤器可用于对所有到达该应用的请求进行拦截,而拦截器则只能对通过DispatcherServlet进行处理的请求进行拦截。在Request请求到达Servlet之前执行过滤器的预处理逻辑,在请求到达DispatcherServlet之后、执行Handler之前执行拦截器的预处理逻辑,并在成功执行Handler之后执行拦截器的后处理逻辑,在DispatcherServlet返回之后最后执行过滤器的后处理逻辑。Filter在doFilter一个方法中定义预处理和后处理逻辑,在方法中通过filterChain.doFilter进行分隔,而HandlerInterceptor将预处理和后处理逻辑拆分成两个方法,即preHandle、postHandle方法。Filter有该类本身的初始化和销毁的回调方法,即init和destroy,而HandlerInterceptor则没有,但是HandlerInterceptor拥有afterCompletion处理方法,无论有没有抛出异常,在DispatcherServlet请求处理的最后都会执行!
  所以说,很多功能其实Filter和HandlerInterceptor都能做,具体看你怎么选了,如果使用Spring MVC框架,那么建议使用HandlerInterceptor吧,它可以类似于普通bean直接注册到Spring容器中被管理。
  关于Filter过滤器,我们在此前讲Java Web的时候就讲过了,在此不再赘述,我们主要讲Spring MVC的HandlerInterceptor。2 HandlerInterceptor拦截器的原理
  HandlerMapping在根据request查找Handler时,最终会返回一个HandlerExecutionChain对象,字面翻译就是处理器执行链对象,其内部包含了一个Handler和可以应用于该Handler的HandlerInterceptor执行链。
  所有的HandlerMapping实现都支持查找HandlerInterceptor链,想要自定义Handler的拦截器,必须实现org.springframework.web.servlet.HandlerInterceptor接口,此接口中有三个抽象方法,用于灵活的实现拦截器的功能:preHandle:在执行Handler之前(执行业务逻辑之前),根据拦截器链顺序执行;postHandle:在执行Handler成功(执行业务逻辑成功)之后,根据拦截器链倒序执行,如果前面的流程中抛出异常或者请求被拦截则不会执行!afterCompletion:在请求处理完毕之后执行,无论是否有响应视图,无论有没有通过preHandle,无论有没有抛出异常。只会对此前放行成功(preHandle返回true)的拦截器进行倒序调用。
  preHandle方法返回boolean类型的值,可以使用此方法中断或继续处理执行链。当当前此方法返回true时,拦截器链将继续先后执行,即继续执行后续拦截器的preHandle方法。当当前某个拦截器的preHandle方法返回false 时,DispatcherServlet 会假定拦截器本身已处理完毕请求(例如,已经渲染了合适的视图),此时将尝试直接倒序执行此前已放行的拦截器链的afterCompletion 方法,随后retrun结束处理,不会继续执行执行链中的后续其他拦截器和Handler实际处理程序(业务逻辑)以及后续其他流程。
  对于采用了@ResponseBody注解或者返回ResponseEntity的方法,postHandle后处理不太有效,因为在Handler执行成功时响应的数据(比如JSON数据)已经被写入response并且已被提交,并且是在postHandle方法被执行之前进行的!此时对于response的任何修改(比如添加额外的头部信息)都为时已晚。对于这种情况,我们可以实现ResponseBodyAdvice接口并且声明为ControllerAdvice,或者直接在RequestMappingHandlerAdapter中配置。3 配置拦截器3.1 编写实现类
  我们需要编写一个实现了拦截器接口HandlerInterceptor的类/**  1. 自定义拦截器  2.  3. @author lx  */ @Component public class MyInterceptor1 implements HandlerInterceptor {     /**      * 预处理,controller方法执行前      *      * @return true表示, 执行下一个拦截器, 没有拦截器了就执行controller中的方法;false表示不放行      */     @Override     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {         System.out.println("MyInterceptor1 preHandle invoke ,true");         return true;     }      /**      * 后处理      */     @Override     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {         System.out.println("MyInterceptor1 postHandle invoke");     }      /**      * 请求处理完毕调用      */     @Override     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {         System.out.println("MyInterceptor1 afterCompletion invoke");     } }3.2 配置拦截器3.2.1 配置拦截规则
  我们可以为某个拦截器设置拦截或者不拦截的路径,拦截器的路径也可以使用通配符,如下:? 表示匹配任何单个字符。* 表示匹配0或者任意数量的字符。** 表示匹配后续的任何0或者更多级的目录。
  路径
  解析
  /**
  表示拦截全部路径的请求
  /**/*.jsp
  表示拦截以.jsp结尾的全部请求
  /a/*.jsp
  表示拦截a路径下的以.jsp结尾的全部请求
  /b/jp.
  表示拦截b路径下的以j开头和p结尾的具有任何后缀的请求
  /?/?.xx
  表示拦截单个字符路径下一个字符名的xx后缀请求3.2.2 基于JavaCOnfig配置拦截器
  基于Java的配置很简单。编写配置类并继承WebMvcConfigurer类,重写其中的方法 addInterceptors,并且将这个配置类交给Spring管理!@Configuration @EnableWebMvc  //支持MVC配置 public class WebConfig implements WebMvcConfigurer {      /**      * 添加拦截器,默认执行顺序为添加顺序      */     @Override     public void addInterceptors(InterceptorRegistry registry) {         registry.addInterceptor(new LocaleChangeInterceptor());         registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");         /*          * 添加拦截器          * 通过addPathPatterns配置拦截器的拦截路径,可以多次调用该方法          * 通过excludePathPatterns配置拦截器的不拦截路径,可以多次调用该方法          */         registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/a/**");     } }3.2.3 基于XML配置拦截器
  基于XML的配置如下!                                                                                                                  3.3 测试
  有一个Controller:/**  * @author lx  */ @Controller public class InterceptorController {      public InterceptorController() {         System.out.println("InterceptorController create");     }      @RequestMapping(path = "/a/b/c")     public String interceptor1() {         System.out.println("---interceptor1 Controller invoke---");         return "/index.jsp";     }       @RequestMapping(path = "/a/bbb/c")     public String interceptor2() {         System.out.println("---interceptor2 Controller invoke---");         return "/index.jsp";      }       @RequestMapping(path = "/b")     public String interceptor3() {         System.out.println("---interceptor3 Controller invoke---");         return "/index.jsp";     } }
  我们测试访问/a/bbb/c和/a/b/c,发现请求都会被拦截:
  而访问/b则不会!4 拦截器的细节4.1 多个拦截器
  我们可以配置多个拦截器并应用到一个请求中!
  多个拦截器默认情况下是按照在XML或者JavaConfig中的定义的顺序执行的,如果想要指定Order排序,那么需要自己创建InterceptorRegistration。
  我们将MyInterceptor1类复制一份并改为MyInterceptor2配置到拦截器链中:@Configuration   //配置类 @EnableWebMvc  //支持Spring MVC注解配置 public class WebConfig implements WebMvcConfigurer {      /**      * 添加拦截器,默认执行顺序为添加顺序      */     @Override     public void addInterceptors(InterceptorRegistry registry) {         registry.addInterceptor(new LocaleChangeInterceptor());         registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");         /*          * 添加拦截器          * 通过addPathPatterns配置拦截器的拦截路径,可以多次调用该方法          * 通过excludePathPatterns配置拦截器的不拦截路径,可以多次调用该方法          */         registry.addInterceptor(new MyInterceptor1()).addPathPatterns("/a/**");         registry.addInterceptor(new MyInterceptor2()).addPathPatterns("/a/**");     } }
  我们测试访问/a/bbb/c,结果如下:
  正常情况下,preHandle方法在拦截器链中会顺序执行,而postHandle和afterCompletion方法则会倒序执行。4.2 拦截测试
  如果我们在第二个拦截器中preHandle返回false,也就是不放行,对请求进行拦截,那么访问/a/bbb/c结果如下:
  可以看到,Controller方法并没有被执行,拦截器链的postHandle方法也不会被执行,并且只执行了MyInterceptor1的afterCompletion方法。
  实际上,如果某个拦截器不放行,那么后续的拦截器的preHandle预处理方法、Handler处理器、所有的postHandle后处理方法都不会被执行,并且在最后只会对此前放行成功的拦截器倒序执行afterCompletion方法。4.3 拦截器跳转
  拦截器的preHandle、postHandle、afterCompletion方法均支持forward、include、redirect转发到其他路径或者动态资源!但是要注意在跳转前如果响应已提交,那么可能会造成异常(比如response写了数据并且执行了PrintWriter或者OutputStream的flush或者close方法,比如调用了sendError、sendRedirect方法,那么将会抛出一个IllegalStateException,并且操作不会完成)!
  基于这个特性,我们可以校验用户是否登陆,如果没有登陆,那么直接跳转到登录页面即可!/**  * 预处理,controller方法执行前      *      * @return true表示, 执行下一个拦截器, 没有拦截器了就执行controller中的方法;false表示不放行      */     @Override     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {         System.out.println("MyInterceptor2 preHandle invoke ,true");          //支持转发 //        RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.jsp"); //        requestDispatcher.forward(request, response);          //支持包含         RequestDispatcher requestDispatcher = request.getRequestDispatcher("/index.jsp");         requestDispatcher.include(request, response);          //支持重定向 //        response.sendRedirect("/mvc/index.jsp");         return false;     }
  再次访问/a/bbb/c,结果如下,确实转发到了index.jsp中

前申花队员一家四口住进了方舱接他们去方舱的车到达时,陶金一家五口人正在吃午饭。几天时间里,这名前申花球员以及他的母亲太太和女儿都被确认为新冠阳性感染者,只有他父亲暂时还阴着。陶金母亲是最早好转的,这天她为全家历史唯一!辽篮大外莫兰德即将成就NBA和CBA双料冠军的壮举很少关注CBA的球迷看到标题可能会问,莫兰德是谁?打过NBA吗?确定不是世纪腰王莫兰特或者死神杜兰特?确定不是!NBA打过,而且还拿过NBA总冠军!同时,我敢肯定,能提出这样的问题苏炳添透露接班人?陈冠锋10秒30夺冠,中国最快00后来了近日,中国田径队展开了一系列选拔比赛,在广东进行的队内测试比赛中,00后小将陈冠锋以10秒30的成绩取得了冠军,第二名汤星强是10秒34,接着是第三名陈佳鹏10秒38。而这些年轻小蕾哈娜露着9个月的孕肚出街,穿针织蓝裙像美人鱼,终于穿平底鞋富婆蕾哈娜首次荣登富豪排行榜,成了最富有的女歌手,身价17亿美元。而如今怀孕有9个月的蕾哈娜,天天演绎着高调的孕妇装穿搭,开辟了孕妇穿搭的新时尚了。当地时间周三晚上,蕾哈娜和黑人男隋文静再演绎配音技能,美人鱼里的张雨绮,网友太赞了北京冬奥会花样滑冰冠军隋文静,最近开启了炫技时刻,连续发出几段自己的配音视频,每一段都演绎得非常精彩,不论是周迅,还是动漫人物,都非常的惟妙惟肖。隋文静又晒出一段演绎,配音的对象是奥斯卡红毯甜茶帅回来了,美人鱼大胆粗暴,穿着放飞的不少一年一度的国际盛宴奥斯卡颁奖典礼终于拉开了帷幕,不得不说好久都没有看到那么多欧美大咖了,真想说一句,好多人啊!话不多说,先来看看群星璀璨的红毯吧!今年来的人多,穿出个性的也挺多,奇北京怀柔感染者曾到访三地,22日人员和环境检测均为阴性据山水怀柔公众号,4月22日12时,怀柔区疾控中心接报,朝阳区一新冠阳性检出病例分别于4月11日和4月19日到怀柔区百泉山景区青龙峡景区朝瑜山庄旅游。接报后,怀柔区疾控中心公安属地北京西山40亩牡丹盛开,将持续至5月中旬谷雨三朝看牡丹。北京西山国家森林公园的牡丹园花团锦簇,这里有202个品种的牡丹,花期将持续20到30天。牡丹有数千年的自然生长和两千多年的人工栽培历史,被称为百花之王。北京西山国家北京环球影视城,游客过山车后意外死亡4月22日晚,本周有一名游客在北京环球度假区霸天虎过山车区域,突然紧急状况,园区救助人员使用紧急复苏,AED等措施,送医后不治身亡。同时,暂时关闭该项目,相关部门也进行核查,符合要北京总体经济保持稳步恢复态势原标题北京总体经济保持稳步恢复态势北京市统计局国家统计局北京调查总队4月20日发布了今年一季度北京经济数据。根据地区生产总值统一核算结果,全市实现地区生产总值9413。4亿元,按不玉兔二号月球车工作状态良好,月背行驶超1142米日月安属?列星安陈?两千多年前,面对遥不可及的浩瀚宇宙,诗人屈原带着对未知的求索发出了天问。而今天,中国的航天人在用一次次飞跃,不断刷新着中国航天的新高度。今天是第七个中国航天日,
京西小故宫万寿寺重张,五大陈列展唤起很多旧时记忆北京晚报记者徐英波十一假期,有京西小故宫之称的万寿寺迎来修缮五年重新开放后的首个长假,多样体验吸引市民参观游览。步入殿内,券顶上经过修复亮出的彩绘图中,形态各异的红色蝙蝠飞翔于青天从一棵松到万亩林海从一棵百年松树,到4。8亿棵松树林!从一片荒原到115万亩森林!用10年时光植树造林10。2万亩松树林!如果以一米种一棵树排成一排,可以绕地球12圈!60年没有发生过一起火灾!36花都新八景是哪些?由你来推荐大洋网讯广州之北,有座魅力之城。历史人文与现代时尚在这里交汇自然生态与城市新貌在这里相融。作为广州的北大门和后花园,花都历史上曾诞生花县八景和花都新八景。进入新时代,花都经济社会快历经磨难的钢铁丝稠之路泛亚铁路东盟通道历经磨难的钢铁丝绸之路泛亚铁路东盟通道,推进到什么地步了?泛亚铁路的范围太广,断断续续规划了半个世纪,本质上是一个贯通欧亚大陆的货运铁路网络。它共有北路南路南北走廊和东盟通道四条线景德镇瑶里超好看的民俗巡游,和漂亮汉服小姐姐同船国庆假期第四天风和日丽天气晴朗又是适合来景德镇瑶里古镇的一天呢!沉浸式古镇体验踏入古镇的第一刻起便被古镇吸引小桥流水青砖瓦黛到来的游客朋友们都会在古镇口与瑶里二字合影留念而夜晚的古短途游受欢迎热门旅游地热度不减央视网消息这个国庆假期,本地休闲和短途旅游受到欢迎,热门旅游目的地热度依然不减。各地在做好疫情防控的基础上,为市民游客提供丰富的文化和旅游体验。湖北参观先烈故居感悟家国情怀国庆假期后来啊,书没有读好,喜欢的人也没有在一起无意看到这句话,心头不由一颤,随后伤感弥漫天际。活着总会遇到很多遗憾,有人说,人生不是过错,就是错过。小时候不知道奶奶在星空下讲的故事原来如此好听,也不知道赌气扔了家里攒钱买的不满远离身边负能量的人,即便是父母你能干成什么事?不好好上班,我们不都是这么过来的吗?就你特殊!就你?不可能,我告诉你,你这辈子也不会挣到钱,我吃的咸盐也比你多!每每听到这些话是不是很耳熟?是不是像似发生在每一个对比亚迪9月销量首次突破20万辆,元系列成出口主力车型来源爱集微集微网消息,10月3日晚,比亚迪发布9月产销数据称,该月销售新车201259辆,同比增长151。2,其中乘用车销售200973辆(含出口7736辆),同比增长154。3。不奋斗,世界那么大,你靠什么去看看每个人心里都有一片海,自己不扬帆,没人帮你启航。世界那么大,想出去看看但是,如果不奋斗,你凭什么去看一看。不奋斗,你的才华如何配得上你的任性不奋斗,你的脚步,如何赶得上父母老去的速相信奇迹,最重要的是相信某种程度上来说,周亦安和叶芯很像。都怀抱着某种天真的明艳的理想主义,在一件件个案中与真相较真与公义较真,也与自己较真。不同的是,生活并不总是理想乐园,周亦安比最高法下来的叶芯多了现