(1)SpringMVC运行流程

在介绍SpringMVC拦截器之前,我们先介绍一下SpringMVC的运行流程:

(1)用户发送请求,经过 前端控制器Dispacherservlet(Controller的核心)将url交给处理器映射器HandlerMapping处理

(2)处理器映射器HandlerMapping处理url,返回HandlerExecutionChain(可能包含拦截器,一定包含自定义的Controller(Handler))

(3)前端控制器Controller交给处理器适配器HandlerAdapter 处理,处理完成后,返回MV对象(ModelAndView)

(4)前端控制器将MV 交给视图控制器ViewResolver ,处理过程:将MV 拆分成Model和View 两个对象,并且将model渲染到View视图上,并且将View返回给前端控制器

(5)最后,前端控制器将视图响应给用户。

(2)SpringMVC拦截器:

Spring MVC 的处理器拦截器类似于 Servlet 开发中的过滤器 Filter,用于对处理器进行预处理和后处理。

作用:用户可以自己定义一些拦截器来实现特定的功能。例:访问特定页面前验证用户是否登陆等

拦截器链:

谈到拦截器,还要向大家提一个词——拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段时,拦截器链中的拦截器就会按其之前定义的顺序被调用。

拦截器与过滤器的区别:

它和过滤器是有几分相似,但是也有区别,接下来我们就来说说他们的区别:

1)、过滤器是 servlet 规范中的一部分, 任何 java web 工程都可以使用。

拦截器是 SpringMVC 框架自己的,只有使用了 SpringMVC 框架的工程才能用。

2)、过滤器在 url-pattern 中配置了/*之后,可以对所有要访问的资源拦截。

拦截器它是只会拦截访问的控制器方法,如果访问的是 jsp, html,css,image 或者 js 是不会进行拦截的。

拦截器链执行流程图:

SpringMVC自定义拦截器使用步骤:

(1)自定义拦截器:

SpringMVC为我们提供了拦截器规范的接口,创建一个类实现HandlerInterceptor ,重写接口中的抽象方法;

抽象方法介绍:

1)、preHandle方法:在调用处理器之前调用该方法,如果该方法返回true则请求继续向下进行,否则请求不会继续向下进行,处理器也不会调用;

2)、postHandle方法:在调用完处理器后调用该方法;

3)、afterCompletion方法:只要该拦截器中的preHandle方法返回true,该方法就会被调用;

(2)在SpringMVC核心配置文件中注册自定义拦截器:

<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**" /><!-- 用于指定对拦截的 url --><mvc:exclude-mapping path=""/><!-- 用于排除指定的 url--><!-- 使用指定的拦截器进行对指定的url进行拦截--><bean  id="handlerInterceptorDemo1"  class="拦截器所对应的全限定类名"></bean></mvc:interceptor></mvc:interceptors>

三.拦截器的实现方式:

SpringMVC拦截器的实现一般有两种实现方式:

第一种是:要定义的 Interceptor 类要实现了Spring的HandlerInterceptor 接口

第二种是:继承实现了HandlerInterceptor 接口的类,比如Spring已经提供的实现了 HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter

注意上图的步骤三,HandlerMapping接口,返回一个HandlerExecutionChain类、

HandlerExecutionChain是通过HandlerMapping的getHandler方法返回的。

继承该接口的类是来实现请求和handler对象的映射关系的。

这个接口中只有这样一个方法

HandlerExecutionChain getHandler(HttpServletRequest request) throws Exception;

根据函数名,参数及返回值我们不难猜出这个接口的作用,就是根据request返回HandlerExecutionChain。至于HandlerMapping在springMVC中有多种实现,我们此处就不深究了。

对于getHandler最后的调度部分便是springMVC的最外层DispatcherServlet类(Controller的核心)了。

HandlerExecutionChain类由HandlerInterceptor构成

HandlerExecutionChain类:由一个handler和若干的HandlerInterceptor构成。那么这个类的作用就显而易见了,就是将拦截器和handle组合*起来执行。就是对handle进行了包装。

这个类中有几个主要的方法:

1.applyPreHandle()看起,我们发现这个方法就是做的这样一个工作,按照列表中interceptor的顺序来执行它们的preHandle方法,直到有一个返回false。再看一下返回false后这个方法所做的工作,这时会调用triggerAfterCompletion方法,此时this.interceptorIndex指向上一个返回true的interceptor的位置,所以它会按逆序执行所有返回true的interceptor的afterCompletion方法。

2.applyPostHandle(),这个方法较为简单,就是按照逆序执行所有interceptor的postHandle方法。

3.triggerAfterCompletion()也是一样,就是从最后一次preHandle成功的interceptor处逆序执行afterCompletion方法。

举例:

那么整个拦截器的处理过程我们便可以很清晰的分为两种情况:

一种是所有拦截器preHandle都返回true情况,另一种是有拦截器preHandle 返回false 的情况:

对于第一种情况:

那么在DispatcherServlet中分别依次调用HandlerExecutionChain类中applyPreHandle、applyPostHandle和triggerAfterCompletion方法,

那么所有方法的执行顺序为

A.pre -> B.pre -> C.pre -> D.pre-> D.post -> C.post -> B.post -> A.post-> D.after -> C.after -> B.after -> A.after

对于第二种情况:

我们不妨设C拦截器的preHandle返回为false。

这时DispatcherServlet类调用HandlerExecutionChain类中applyPreHandle方法,然后由applyPreHandle调用triggerAfterCompletion方法

那么执行情况如下:

A.pre -> B.pre -> C.pre ->
B.after -> A.after

也就是,指向上一个返回true的interceptor的位置(B位置),所以它会按逆序执行所有返回true的interceptor的afterCompletion方法。(也就是跳过了他们的postHandle方法)

四.案例:

1.继承自HandlerInterceptorAdapter

编写自定义的拦截器

public class LoginInterceptor extends HandlerInterceptorAdapter {@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response,Object handler) throws Exception { // 获得请求路径的uriString uri = request.getRequestURI();// 判断路径是登出还是登录验证,是这两者之一的话执行Controller中定义的方法if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {return true;}// 进入登录页面,判断session中是否有key,有的话重定向到首页,否则进入登录界面if(uri.endsWith("/login/") || uri.endsWith("/login")) {if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {response.sendRedirect(request.getContextPath() + "/index");} else {return true;}}// 其他情况判断session中是否有key,有的话继续用户的操作if(request.getSession() != null && request.getSession().getAttribute("loginUser") != null) {return true;}// 最后的情况就是进入登录页面response.sendRedirect(request.getContextPath() + "/login");return false;}}

登录Controller:

@Controller
@RequestMapping(value = "/login")
public class LoginController {@RequestMapping(value = {"/", ""})public String index() {return "login";}@RequestMapping("/auth")public String auth(@RequestParam String username, HttpServletRequest req) {req.getSession().setAttribute("loginUser", username);return "redirect:/index";}@RequestMapping("/out")public String out(HttpServletRequest req) {req.getSession().removeAttribute("loginUser");return "redirect:/login";}}

配置:

<mvc:interceptors><mvc:interceptor><mvc:mapping path="/**"/><bean class="org.format.demo.interceptor.LoginInterceptor"/></mvc:interceptor>
</mvc:interceptors>

我们看到LoginInterceptor里的preHandle方法对于地址“/login/auth”和"/login/out"不处理。

因此,可以写点配置,少写带java代码。在拦截器配置中添加2个exclude-mapping,并且去掉LoginInterceptor里的

if(uri.endsWith("/login/auth") || uri.endsWith("/login/out")) {return true;
}

配置新增:

<mvc:exclude-mapping path="/login/out"/>
<mvc:exclude-mapping path="/login/auth"/>

2.实现接口HandlerInterceptor

它的主要作用是拦截用户的请求并进行相应的处理。比如通过它来进行权限验证,或者是来判断用户是否登陆。
Spring MVC 的拦截器类似于Servlet中的拦截器!需要先定义一个类实现HandlerInterceptor接口。添加未实现的方法,在springmvc配置中配置,具体实现步骤如下:乱码过滤

package com.lx.controller;import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {/*** 该方法在目标方法之前被调用* 若返回值为true,则继续调用后去的拦截器和目标方法* 若返回值为false,则不会再调用后续的拦截器和方法* 可以考虑做权限.日志,事务,等.*/@Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {request.setCharacterEncoding("utf-8");response.setCharacterEncoding("text/htm;charset=utf-8");System.out.println("ddddd");return true;}/*** 调用目标方法之后,但渲染视图之前.* 有modelAndView对象,可以对请求域中的属性或视图做出修改.*/@Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {}* 渲染视图之后调用,释放资源.*/@Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {}
}

-boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler):在请求到达Handler之前,先执行这个前置处理方法.当该方法返回false时,请求直接返回,不会传递到链中的下一个拦截器,更不会传递到链尾的Handler,只有返回true时,请求才会向链中的下一个处理节点传递!

  • void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView); 在相应已经被渲染后,执行该方法.

  • void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex); 在响应已经被渲染后,执行该方法!

配置:

  <mvc:interceptors><mvc:interceptor><mvc:mapping path="/**" /><bean class="com.lx.controller.MyInterceptor" /></mvc:interceptor></mvc:interceptors>

注意其中的mvc:interceptor标签,子标签下有<mvc:mapping path="" />,<mvc:exclude-mapping path=""/>,分别是作用路径和不作用路径。

Spring = Spring拦截器之实现原理?相关推荐

  1. java面试 拦截器问题_面试必问:给我说一下Spring MVC拦截器的原理?

    拦截器是每个Web框架必备的功能,也是个老生常谈的主题了.本文将分析SpringMVC的拦截器功能是如何设计的,让读者了解该功能设计的原理. 重要接口及类介绍1. HandlerExecutionCh ...

  2. 面试:给我说一下Spring MVC拦截器的原理?

    点击上方蓝色"程序猿DD",选择"设为星标" 回复"资源"获取独家整理的学习资料! 来源 | https://urlify.cn/namaQ ...

  3. 面试官:给我说一下 Spring MVC 拦截器的原理?

    前言 SpringMVC是目前主流的Web MVC框架之一. 拦截器是每个Web框架必备的功能,也是个老生常谈的主题了. 本文将分析SpringMVC的拦截器功能是如何设计的,让读者了解该功能设计的原 ...

  4. Spring异步调用原理及SpringAop拦截器链原理

    一.Spring异步调用底层原理 开启异步调用只需一个注解@EnableAsync @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTI ...

  5. Spring Security入门到实践(一)HTTP Basic在Spring Security中的应用原理浅析

    一.Spring Security简介 打开Spring Security的官网,从其首页的预览上就可以看见如下文字: Spring Security is a powerful and highly ...

  6. Spring Boot spring mvc 拦截器

    2019独角兽企业重金招聘Python工程师标准>>> 上一篇对过滤器的定义做了说明,也比较简单.过滤器属于Servlet范畴的API,与Spring 没什么关系.  Web开发中, ...

  7. Ribbon 的替代品 Spring Cloud Loadbalancer 使用与原理分析

    目录 一. 使用方法 二. @LoadBalancerClients 与 @LoadBalancerClient 三. 自定义负载均衡 四. 重试机制 五. 原理分析 六. 执行流程分析 系列文章: ...

  8. Spring Security技术栈学习笔记(八)Spring Security的基本运行原理与个性化登录实现

    正如你可能知道的两个应用程序的两个主要区域是"认证"和"授权"(或者访问控制).这两个主要区域是Spring Security的两个目标."认证&qu ...

  9. Spring MVC拦截器

    1.如何实现登录权限检查 使用session进行约定值的检查 实现方法: (1)使用Filter (2)使用Spring的拦截器 拦截器组件简介:Spring MVC特有组件,可以在调用Control ...

最新文章

  1. 如何做研究与写论文?周志华大佬教您方法论!
  2. 对顶层生存空间的考虑---及蜷缩在内层的EJB
  3. VScode Python插件
  4. Spring注入日期到bean属性-CustomDateEditor
  5. 【报告分享】2020中国时尚跨境电商发展报告.pdf(附下载链接)
  6. 刘强东解读京东AI战略布局,沈南鹏高文杨强助阵谈AI机遇
  7. Spring的注解@Autowired和@Resource的区别
  8. xps转jpeg图片
  9. 勇敢猿猿不怕困难!为去大厂我把这个Java大厂面试真题刷了几十遍!(2021最新版)
  10. 如何下载react依赖包
  11. 穷人python入门教程视频_穷的解释|穷的意思|汉典“穷”字的基本解释
  12. MySQL数据库的锁 --- 六种分类 - 14种锁详细介绍
  13. 传统呼叫中心与云呼叫中心哪个好
  14. okgroup考试题:2019
  15. 数据结构的在C语言中的类型定义
  16. Mendix开发介绍实用篇(一)
  17. 关于IntelliJ IDEA有时候快捷键无效的说明
  18. 小优机器人系统恢复_解决一键还原ghost
  19. i5 11320h怎么样 相当于什么水平
  20. python语言是一个优秀的面向对象语言_Python语言是面向对象的

热门文章

  1. 微信小程序获取地理位置失败原因及解决方案
  2. Ins的Stories、小红书的视频笔记,短视频成就内容社区商业化变现?
  3. hadoop java move_Hadoop上Data Locality的详解
  4. 故障分析 | 一条du命令引发的内存不足报警
  5. jQuery面试题汇总
  6. 自媒体人应该拥有怎样的素质
  7. 如何保护个人隐私和敏感信息不被黑客窃取?
  8. linux需要关注的日志文件,如何更好地使用Linux日志
  9. mathtype中如何在双箭头上弄一个划掉的符号
  10. python——5行代码采集3000+上市公司信息