济南企业建站哪家做的好,淘宝客 网站 备案,外发加工网app,如何免费建立个人网站1. Spring MVC 中的拦截器的使用“拦截器基本配置” 和 “拦截器高级配置” 文章目录 1. Spring MVC 中的拦截器的使用“拦截器基本配置” 和 “拦截器高级配置”2. 拦截器3. Spring MVC 中的拦截器的创建和基本配置3.1 定义拦截3.2 拦截器基本配置3.3 拦截器的高级配置 4. Spr…1. Spring MVC 中的拦截器的使用“拦截器基本配置” 和 “拦截器高级配置” 文章目录 1. Spring MVC 中的拦截器的使用“拦截器基本配置” 和 “拦截器高级配置”2. 拦截器3. Spring MVC 中的拦截器的创建和基本配置3.1 定义拦截3.2 拦截器基本配置3.3 拦截器的高级配置 4. Spring MVC中多个拦截器的执行顺序4.1 如果所有拦截器 preHandle( ) 方法 都返回 true时多个拦截器的的执行顺序4.2 如果其中一个拦截器 preHandle ( ) 方法返回 false多个拦截器的的执行顺序 5. 补充源码分析5.1 方法执行顺序的源码分析5.2 拦截与放行的源码分析5.3 DispatcherServlet 和 HandlerExecutionChain 的部分源码 6. 总结7. 最后 2. 拦截器
拦截器(Interceptor) 类似于过滤器(Filter)
Spring MVC 的拦截器作用是在请求到达控制器之前或之后进行拦截可以对请求和响应进行一些特定的处理。
拦截器可以用于很多场景下
登录验证对于需要登录才能访问的地址使用拦截器可以判断用户是否已登录如果未登录则跳转到登录页面。权限校验根据用户权限对部分网址进行访问控制拒绝未经授权的用户访问。请求日志记录请求信息例如请求地址请求参数请求时间等用于排查问题和性能优化。更改响应可以对响应的内容进行修改例如添加头信息调整响应内容格式等。
拦截器和过滤器的区别在于它们的作用层面不同 过滤器更注重在请求和响应的流程中进行处理可以修改请求和响应的内容例如设置编码和字符集请求头状态码等。拦截器则更加侧重于对控制器进行前置或后置处理在请求到达控制器之前或之后进行特定的操作例如打印日志权限验证等。 Filter、Servlet、Interceptor、Controller的执行顺序 3. Spring MVC 中的拦截器的创建和基本配置
3.1 定义拦截
实现org.springframework.web.servlet.HandlerInterceptor 接口共有三个方法可以进行选择性的实现 preHandle( )处理器方法调用之前执行。只有该方法有返回值返回值是布尔类型true 表示放行false 表示拦截 。postHandle( )处理器方法调用之后执行。afterCompletion( )渲染完成后执行。 3.2 拦截器基本配置
第一步编写拦截器该拦截器要实现org.springframework.web.servlet.HandlerInterceptor 接口 。 package com.rainbowsea.springmvc.interceptors;import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;public class Interceptor1 implements HandlerInterceptor {Overridepublic boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {System.out.println(Interceptor1s preHandle!);return true;}Overridepublic void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {System.out.println(Interceptor1s postHandle!);}Overridepublic void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {System.out.println(Interceptor1s afterCompletion!);}
} 在 Spring MVC 中拦截器的基本配置有两种方式 第一种方式是通过 xml 进行配置第二种方式是通过 Component 注解 xml 文件进行配置 第一种方式通过 xml 进行配置
需要注意的是这个基本配置默认情况下是拦截所有请求的。
在 springmvc.xml 文件中进行如下配置
mvc:interceptorsbean classcom.powernode.springmvc.interceptors.Interceptor1/
/mvc:interceptors?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:mvchttp://www.springframework.org/schema/mvcxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd!-- 组件扫描--context:component-scanbase-packagecom.rainbowsea.springmvc.controller,com.rainbowsea.springmvc.interceptors/context:component-scan!-- 视图解析器--bean idthymeleafViewResolver classorg.thymeleaf.spring6.view.ThymeleafViewResolver!--作用于视图渲染的过程中可以设置视图渲染后输出时采用的编码字符集--property namecharacterEncoding valueUTF-8/!--如果配置多个视图解析器它来决定优先使用哪个视图解析器它的值越小优先级越高--property nameorder value1/!--当 ThymeleafViewResolver 渲染模板时会使用该模板引擎来解析、编译和渲染模板--property nametemplateEnginebean classorg.thymeleaf.spring6.SpringTemplateEngine!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息加载模板并对其进行解析--property nametemplateResolverbean classorg.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver!--设置模板文件的位置前缀--property nameprefix value/WEB-INF/templates//!--设置模板文件后缀后缀Thymeleaf文件扩展名不一定是html也可以是其他例如txt大部分都是html--property namesuffix value.html/!--设置模板类型例如HTML,TEXT,JAVASCRIPT,CSS等--property nametemplateMode valueHTML/!--用于模板文件在读取和解析过程中采用的编码字符集--property namecharacterEncoding valueUTF-8//bean/property/bean/property/bean!-- 配置拦截器--mvc:interceptors!-- 基本配置第一种方式注意基本配置默认情况下是拦截所有请求的--bean classcom.rainbowsea.springmvc.interceptors.Interceptor1/bean/mvc:interceptors
/beans编写对应的 Controller 控制器进行测试 package com.rainbowsea.springmvc.controller;import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;Controller // 交给 Spring IOC 容器管理
public class IndexController {RequestMapping(/index)public String toIndex() {System.out.println(IndexController#toIndex() --- 处理器方法执行了);return index;}RequestMapping(ok)public String toOK() {System.out.println(IndexController#OK() --- 处理器方法执行了);return ok;}
}
运行测试 第二种方式是通过 Component 注解 xml 文件进行配置
注意同样的对于这种基本配置来说拦截器是拦截所有请求的。 第二种方式的前提 前提1包扫描在 spring mvc 中配置组件扫描 前提2使用 Component 注解进行对 编写的拦截器类进行标注即可。 两个前提都搞定了就可以在 spring mvc.xml 文件中进行配置了。 mvc:interceptorsref beaninterceptor1/
/mvc:interceptors运行测试 3.3 拦截器的高级配置
采用以上基本配置方式拦截器是拦截所有请求路径的。如果要针对某些路径进行拦截某些路径不拦截某些路径拦截可以采用高级配置在 spring mvc.xml 文件当中进行配置 以上的配置表示除 /ok 请求路径之外剩下的路径全部拦截。
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:mvchttp://www.springframework.org/schema/mvcxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd!-- 组件扫描--context:component-scanbase-packagecom.rainbowsea.springmvc.controller,com.rainbowsea.springmvc.interceptors/context:component-scan!-- 视图解析器--bean idthymeleafViewResolver classorg.thymeleaf.spring6.view.ThymeleafViewResolver!--作用于视图渲染的过程中可以设置视图渲染后输出时采用的编码字符集--property namecharacterEncoding valueUTF-8/!--如果配置多个视图解析器它来决定优先使用哪个视图解析器它的值越小优先级越高--property nameorder value1/!--当 ThymeleafViewResolver 渲染模板时会使用该模板引擎来解析、编译和渲染模板--property nametemplateEnginebean classorg.thymeleaf.spring6.SpringTemplateEngine!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息加载模板并对其进行解析--property nametemplateResolverbean classorg.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver!--设置模板文件的位置前缀--property nameprefix value/WEB-INF/templates//!--设置模板文件后缀后缀Thymeleaf文件扩展名不一定是html也可以是其他例如txt大部分都是html--property namesuffix value.html/!--设置模板类型例如HTML,TEXT,JAVASCRIPT,CSS等--property nametemplateMode valueHTML/!--用于模板文件在读取和解析过程中采用的编码字符集--property namecharacterEncoding valueUTF-8//bean/property/bean/property/bean!-- 高级配置指定一些路径被拦截一些路径不拦截--mvc:interceptorsmvc:interceptor!-- /** 表示拦截所有路径--mvc:mapping path/**/!-- /ok 请求路径不拦截--mvc:exclude-mapping path/ok/!-- /index 请求路径拦截--!-- mvc:mapping path/index/--!-- 设置对应的那个拦截器--ref beaninterceptor1/ref/mvc:interceptor/mvc:interceptors
/beans运行测试 4. Spring MVC中多个拦截器的执行顺序
这里我们为了探究多个拦截器存在的时候的执行顺序我们创建 3 个 拦截器。如下
4.1 如果所有拦截器 preHandle( ) 方法 都返回 true时多个拦截器的的执行顺序 配置多个拦截器 mvc:interceptors!-- 配置多个拦截器这个是基本配置默认是所有请求都会进行拦截处理--ref beaninterceptor1/refref beaninterceptor2/refref beaninterceptor3/ref/mvc:interceptors?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contexthttp://www.springframework.org/schema/contextxmlns:mvchttp://www.springframework.org/schema/mvcxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/cache http://www.springframework.org/schema/cache/spring-cache.xsd http://www.springframework.org/schema/mvc https://www.springframework.org/schema/mvc/spring-mvc.xsd!-- 组件扫描--context:component-scanbase-packagecom.rainbowsea.springmvc.controller,com.rainbowsea.springmvc.interceptors/context:component-scan!-- 视图解析器--bean idthymeleafViewResolver classorg.thymeleaf.spring6.view.ThymeleafViewResolver!--作用于视图渲染的过程中可以设置视图渲染后输出时采用的编码字符集--property namecharacterEncoding valueUTF-8/!--如果配置多个视图解析器它来决定优先使用哪个视图解析器它的值越小优先级越高--property nameorder value1/!--当 ThymeleafViewResolver 渲染模板时会使用该模板引擎来解析、编译和渲染模板--property nametemplateEnginebean classorg.thymeleaf.spring6.SpringTemplateEngine!--用于指定 Thymeleaf 模板引擎使用的模板解析器。模板解析器负责根据模板位置、模板资源名称、文件编码等信息加载模板并对其进行解析--property nametemplateResolverbean classorg.thymeleaf.spring6.templateresolver.SpringResourceTemplateResolver!--设置模板文件的位置前缀--property nameprefix value/WEB-INF/templates//!--设置模板文件后缀后缀Thymeleaf文件扩展名不一定是html也可以是其他例如txt大部分都是html--property namesuffix value.html/!--设置模板类型例如HTML,TEXT,JAVASCRIPT,CSS等--property nametemplateMode valueHTML/!--用于模板文件在读取和解析过程中采用的编码字符集--property namecharacterEncoding valueUTF-8//bean/property/bean/property/beanmvc:interceptors!-- 配置多个拦截器这个是基本配置默认是所有请求都会进行拦截处理--ref beaninterceptor1/refref beaninterceptor2/refref beaninterceptor3/ref/mvc:interceptors
/beans如果所有拦截器 preHandle 都返回 true 按照 springmvc.xml文件中配置的顺序自上而下调用 preHandle 4.2 如果其中一个拦截器 preHandle ( ) 方法返回 false多个拦截器的的执行顺序
Interceptor3 拦截器中的 preHandle()方法返回 false。其他两个拦截器返回 true. 规则只要有一个拦截器preHandle返回false任何postHandle都不执行。但返回false的拦截器的前面的拦截器按照逆序执行afterCompletion。 只要有一个拦截器preHandle方法返回false则任何拦截器的 postHandle()方法都不执行。但返回 false 的拦截器的前面的拦截器按照逆序执行afterCompletion。 返回 false 拦截器拦截住了则其中的 Controllor控制器不执行了其中的 postHandle 一个也不会执行。而对应的 afterCompletion()方法的执行是按照配置拦截器(自上而下)的倒序执行但其中返回 false 的拦截器中的 afterCompletion()方法不会被执行 只要有一个拦截器preHandle返回false任何postHandle都不执行。但返回false的拦截器的前面的拦截器按照逆序执行afterCompletion。只要有一个拦截器preHandle返回false任何postHandle都不执行。但返回false的拦截器的前面的拦截器按照逆序执行afterCompletion。 5. 补充源码分析
5.1 方法执行顺序的源码分析
public class DispatcherServlet extends FrameworkServlet {protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 调用所有拦截器的 preHandle 方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 调用处理器方法mv ha.handle(processedRequest, response, mappedHandler.getHandler());// 调用所有拦截器的 postHandle 方法mappedHandler.applyPostHandle(processedRequest, response, mv);// 处理视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,Nullable HandlerExecutionChain mappedHandler, Nullable ModelAndView mv,Nullable Exception exception) throws Exception {// 渲染页面render(mv, request, response);// 调用所有拦截器的 afterCompletion 方法mappedHandler.triggerAfterCompletion(request, response, null);}
}5.2 拦截与放行的源码分析
public class DispatcherServlet extends FrameworkServlet {protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 调用所有拦截器的 preHandle 方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {// 如果 mappedHandler.applyPreHandle(processedRequest, response) 返回false以下的return语句就会执行return;}}
}public class HandlerExecutionChain {boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i 0; i this.interceptorList.size(); i) {HandlerInterceptor interceptor this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {triggerAfterCompletion(request, response, null);// 如果 interceptor.preHandle(request, response, this.handler) 返回 false以下的 return false;就会执行。return false;}this.interceptorIndex i;}return true;}
}5.3 DispatcherServlet 和 HandlerExecutionChain 的部分源码
public class DispatcherServlet extends FrameworkServlet {protected void doDispatch(HttpServletRequest request, HttpServletResponse response) throws Exception {// 按照顺序执行所有拦截器的preHandle方法if (!mappedHandler.applyPreHandle(processedRequest, response)) {return;}// 执行处理器方法mv ha.handle(processedRequest, response, mappedHandler.getHandler());// 按照逆序执行所有拦截器的 postHanle 方法mappedHandler.applyPostHandle(processedRequest, response, mv);// 处理视图processDispatchResult(processedRequest, response, mappedHandler, mv, dispatchException);}private void processDispatchResult(HttpServletRequest request, HttpServletResponse response,Nullable HandlerExecutionChain mappedHandler, Nullable ModelAndView mv,Nullable Exception exception) throws Exception {// 渲染视图render(mv, request, response);// 按照逆序执行所有拦截器的 afterCompletion 方法mappedHandler.triggerAfterCompletion(request, response, null);}
}public class HandlerExecutionChain {// 顺序执行 preHandleboolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {for (int i 0; i this.interceptorList.size(); i) {HandlerInterceptor interceptor this.interceptorList.get(i);if (!interceptor.preHandle(request, response, this.handler)) {// 如果其中一个拦截器preHandle返回false// 将该拦截器前面的拦截器按照逆序执行所有的afterCompletiontriggerAfterCompletion(request, response, null);return false;}this.interceptorIndex i;}return true;}// 逆序执行 postHanlevoid applyPostHandle(HttpServletRequest request, HttpServletResponse response, Nullable ModelAndView mv) throws Exception {for (int i this.interceptorList.size() - 1; i 0; i--) {HandlerInterceptor interceptor this.interceptorList.get(i);interceptor.postHandle(request, response, this.handler, mv);}}// 逆序执行 afterCompletionvoid triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, Nullable Exception ex) {for (int i this.interceptorIndex; i 0; i--) {HandlerInterceptor interceptor this.interceptorList.get(i);try {interceptor.afterCompletion(request, response, this.handler, ex);}catch (Throwable ex2) {logger.error(HandlerInterceptor.afterCompletion threw exception, ex2);}}}
}6. 总结 实现org.springframework.web.servlet.HandlerInterceptor 接口共有三个方法可以进行选择性的实现 preHandle( )处理器方法调用之前执行。只有该方法有返回值返回值是布尔类型true 表示放行false 表示拦截 。postHandle( )处理器方法调用之后执行。afterCompletion( )渲染完成后执行。 在 Spring MVC 中拦截器的基本配置有两种方式 第一种方式是通过 xml 进行配置第二种方式是通过 Component 注解 xml 文件进行配置对于这种基本配置来说拦截器是拦截所有请求的。 拦截器的高级配置采用以上基本配置方式拦截器是拦截所有请求路径的。如果要针对某些路径进行拦截某些路径不拦截某些路径拦截可以采用高级配置在 spring mvc.xml 文件当中进行配置 Spring MVC中多个拦截器的执行顺序 如果所有拦截器 preHandle( ) 方法 都返回 true时多个拦截器的的执行顺序 按照 springmvc.xml文件中配置的顺序自上而下调用 preHandle 如果其中一个拦截器 preHandle ( ) 方法返回 false多个拦截器的的执行顺序 只要有一个拦截器preHandle方法返回false则任何拦截器的 postHandle()方法都不执行。但返回 false 的拦截器的前面的拦截器按照逆序执行afterCompletion。 拦截器源码分析。 7. 最后 “在这个最后的篇章中我要表达我对每一位读者的感激之情。你们的关注和回复是我创作的动力源泉我从你们身上吸取了无尽的灵感与勇气。我会将你们的鼓励留在心底继续在其他的领域奋斗。感谢你们我们总会在某个时刻再次相遇。”