拦截器
拦截器是spring MVC中强大的控件,它可以在进入处理器之前做一些操作,或者在处理器完成后进行操作,甚至是在渲染视图后进行操作。spring mvc会在启动期间就通过@RequestMapping的注解解析URI和处理器的对应关系,在运行的时候通过请求找到对应的HandlerMapping,然后构建HandlerExecutionChain对象,它是一个执行的责任链对象。
对于拦截器所需要关注的有两点,一个是它有哪些方法,方法的含义是什么;第二个是它各个方法在流程中执行的顺序是如何。
拦截器的定义
spring要求处理器的拦截器都要实现org.springframework.web.servlet.HandlerInterceptor接口,这个接口定义了三个方法:
public interface HandlerInterceptor { default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { return true; } default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception { } default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception { } }
这三个方法的意义:
- preHandler方法:在处理器之前执行的前置方法,这样spring mvc可以在进入处理器前处理一些方法了。它返回一个boolean值,会影响到后面的流程。
- postHandler方法:在处理器之后执行的后置方法,处理器的逻辑完成后运行它。
- afterCompletion方法:无论是否产生异常都会在渲染视图后执行的方法。
在新版本中,这三个方法被定义成了默认方法,因为有时候我们可能只需要实现三个回调方法中的某一个,在老版本中要想
需要的回调方法拦截器的执行流程的话。spring提供了一个HandlerInterceptorAdapter适配器(一种适配器设计模式的实现)。
拦截器的执行流程
拦截器可能有多个,后面再来看多个拦截器的执行流程,这里先看一个拦截器的流程:
在进入处理器之前或者之后处理一些逻辑,或者是在渲染视图后处理一些逻辑,都是允许的。有时需要自己实现一些拦截器,以加强请求的功能。注意:当前置方法返回false时,就不会再执行后面的逻辑了。在拦截器中可以完成前置方法、后置方法和完成方法的相关逻辑。
开发拦截器
开发一个角色拦截器,它只是一个简单的测试,我们可以实现HandlerInterceptor接口,也可以继承HandlerInterceptorAdapter方法,因为在我们使用的版本中,HandlerInterceptor里的方法被定义为默认方法,根据需要覆盖掉特定方法即可。
public class RoleInterceptor implements HandlerInterceptor { /** * 拦截器处理器处理之前会先经过该方法:前置方法 * @return 如果返回true,会进入(放行)下一个拦截器(链) */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("前置方法,返回true,进入后面的处理流程,返回false,完成处理,请求结束"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("后置方法,处理器完成处理,视图渲染之前调用"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("完成方法:视图渲染完成"); } }
配置拦截器
<mvc:interceptors> <mvc:interceptor> <mvc:mapping path="/controll/**"/> <bean class="com.wise.bbs.interceptor.RoleInterceptor"/> </mvc:interceptor> </mvc:interceptors>在xml配置中,用元素<mvc:interceptors>配置拦截器,在里面可以配置多个拦截器,path属性告诉拦截器拦截什么请求,它使用一个正则式的匹配。下面介绍下用java代码 配置:
package com.wise.tiger.config; //*************************import******************************// @Configuration @ComponentScan(basePackages = "com.wise.tiger.web") @EnableWebMvc public class WebConfig implements WebMvcConfigurer { // 视图解析器 @Bean public InternalResourceViewResolver viewResolver() { var viewResolver = new InternalResourceViewResolver(); viewResolver.setPrefix("/WEB-INF/pages/"); viewResolver.setSuffix(".jsp"); return viewResolver; } @Override // 静态资源不被前端控制器拦截 public void addResourceHandlers(ResourceHandlerRegistry registry) { registry.addResourceHandler("/static/**")// 添加静态资源的url-pattern .addResourceLocations("/static/"); } @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RoleInterceptor()).addPathPatterns("/control/**"); } }
多个拦截器的执行顺序
多个拦截器会以怎样的顺序执行呢,首先讨论preHandler方法返回为true的情况,先建三个角色拦截器
public class RoleInterceptor1 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle1"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle1"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion1"); } } public class RoleInterceptor2 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle2"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle2"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion2"); } } public class RoleInterceptor3 implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("preHandle3"); return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { System.out.println("postHandle3"); } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { System.out.println("afterCompletion3"); } }
配置多个拦截器
@Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RoleInterceptor1()).addPathPatterns("/control/**"); registry.addInterceptor(new RoleInterceptor2()).addPathPatterns("/control/**"); registry.addInterceptor(new RoleInterceptor3()).addPathPatterns("/control/**"); }
preHandle2
preHandle3
......控制器逻辑日志打印.....
postHadle3
postHadle2
postHadle1
...........
afterCompletion3
afterCompletion2
afterCompletion1
有些时候前置方法可能返回false,我们将RoleInterceptor2中的前置方法给为false进行测试后得到的结果:
preHandle2
afterCompletion1
注意:当其中一个preHandle方法返回false后,按配置顺序,后面的preHandle方法都不会执行了,而控制器和后面的postHandle也不会再运行。
应用
性能监控[引用自开涛博客内容]
如记录一下请求的处理时间,得到一些慢请求(如处理时间超过500毫秒),从而进行性能改进,一般的反向代理服务器如apache都具有这个功能,但此处我们演示一下使用拦截器怎么实现。
实现分析:
1、在进入处理器之前记录开始时间,即在拦截器的preHandle记录开始时间;
2、在结束请求处理之后记录结束时间,即在拦截器的afterCompletion记录结束实现,并用结束时间-开始时间得到这次请求的处理时间。
问题:
我们的拦截器是单例,因此不管用户请求多少次都只有一个拦截器实现,即线程不安全,那我们应该怎么记录时间呢?
解决方案是使用ThreadLocal,它是线程绑定的变量,提供线程局部变量(一个线程一个ThreadLocal,A线程的ThreadLocal只能看到A线程的ThreadLocal,不能看到B线程的ThreadLocal)。
public class StopWatchHandlerInterceptor implements HandlerInterceptor { //线程局部变量,拦截器是单例形式存在,所以每一个请求的开始时间应该绑定在当前线程上 private NamedThreadLocal<Long> startTimeThreadLocal = new NamedThreadLocal<Long>("StopWatch-StartTime"); @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { long beginTime = System.currentTimeMillis();//1、开始时间 startTimeThreadLocal.set(beginTime);//线程绑定变量(该数据只有当前请求的线程可见) return true;//继续流程 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { long endTime = System.currentTimeMillis();//2、结束时间 long beginTime = startTimeThreadLocal.get();//得到线程绑定的局部变量(开始时间) long consumeTime = endTime - beginTime;//3、消耗的时间 if(consumeTime > 500) {//此处认为处理时间超过500毫秒的请求为慢请求 //TODO 记录到日志文件 System.out.println( String.format("%s consume %d millis", request.getRequestURI(), consumeTime)); } } }
相关推荐
在开发过程中,为了调试和定位问题,可以开启Spring MVC的日志,查看请求处理的详细过程,以找出拦截器未被调用的原因。此外,阅读Spring MVC的相关文档和源码也能帮助我们更深入地理解问题所在。 最后,对于提供的...
- **拦截器**:Spring MVC 支持拦截器机制,可以在请求处理前后执行特定的操作,如权限验证、日志记录等。 - **异常处理**:通过配置 `@ExceptionHandler` 或 `@ControllerAdvice` 注解的方法来处理全局异常。 ####...
在面试中,深入理解Spring MVC可以帮助你展示对Web开发的深入理解和技术实力。 1. **核心组件**: Spring MVC的核心组件包括DispatcherServlet、Controller、Model、View和ViewResolver。DispatcherServlet作为...
而Spring MVC作为Spring框架的一部分,是构建Web应用程序的重要组件。Struts作为早期的MVC框架,也曾经是Java Web开发的主流选择。当Spring与Struts结合时,可以实现更高效、更灵活的应用架构。本文将深入探讨`...
Spring MVC还支持数据绑定、拦截器、异常处理和国际化等功能,极大地提高了开发效率。 MyBatis,是一个轻量级的持久层框架,它将SQL语句与Java代码解耦,使得开发者可以直接编写SQL来操作数据库,同时保持代码的...
6. 配置Spring MVC的servlet-context.xml或使用Java配置类,设置视图解析器、拦截器等。 7. 编写Controller层的代码,使用`@RequestMapping`等注解处理请求。 8. 使用MyBatis-Plus的API编写业务逻辑,通过`@Mapper`...
- **拦截器与AOP**:探索Spring的拦截器机制以及面向切面编程(AOP)在Spring MVC中的应用。 - **异常处理**:如何优雅地处理应用运行时可能出现的异常。 - **国际化与本地化**:支持多语言环境的实现方法。 - **...
在源码层面,Spring MVC 的实现基于 AOP(面向切面编程),这使得我们可以轻松地添加拦截器(Interceptor)来实现日志记录、权限控制等功能。同时,Spring MVC 还支持自定义消息转换器(MessageConverter),方便...
2. **配置Spring MVC**:定义DispatcherServlet配置,包括视图解析器、拦截器、模型AndView的处理器映射器和处理器适配器。 3. **配置MyBatis**:在MyBatis的配置文件中,设置数据源、事务管理器以及Mapper配置,...
2. **配置Spring MVC**:在`web.xml`中配置`DispatcherServlet`,并添加Spring MVC的配置文件,如`spring-mvc.xml`,在这里定义视图解析器、拦截器、bean等。 3. **编写Controller**:创建一个控制器类,使用`@...
根据提供的文件信息,我们可以将其中的关键知识点归纳如下: ### Spring MVC 框架简介 ...通过对上述知识点的学习和理解,可以更好地掌握 Spring MVC 的使用方法,进而开发出更加优秀的 Web 应用程序。
通过以上介绍,我们可以看出Spring MVC提供了一个结构清晰、组件丰富的框架,使开发者能够专注于业务逻辑,同时利用Spring的强大功能来简化Web应用的开发。在实际开发中,我们只需要关注Controller的实现和视图的...
`org.springframework.web-3.0.2.RELEASE.jar`:这个库包含了一些 Web 相关的支持类,如 Web 应用上下文(WebApplicationContext)、HTTP 拦截器(HandlerInterceptor)和请求映射(RequestMapping)等,它们与 MVC ...
Spring3MVC-REST-HelloWorld 是一个基础的示例,用于展示如何在Spring框架的...这只是一个起点,Spring MVC还支持许多高级特性,如拦截器、异常处理、数据验证和AOP(面向切面编程),可以应对各种复杂Web应用的需求。
5. **拦截器**:允许在请求处理前后插入自定义逻辑,如权限检查、日志记录等。 二、Portlet框架 Portlet框架是为portlet容器(如Liferay、WebSphere Portal)提供的一套标准,它定义了portlet的生命周期、渲染机制...
总的来说,Spring MVC 3.2的配置涉及多个方面,包括组件扫描、视图解析、注解驱动、拦截器、异常处理以及数据绑定等。通过合理的配置,我们可以构建出一个高效、灵活的Web应用框架。在实际项目中,应根据具体需求...
总的来说,"一个改进版的spring-mvc-showcase"项目展示了如何利用Spring MVC构建一个现代Web应用,并且可能涵盖了许多高级特性,如AOP(面向切面编程)、RESTful API设计、拦截器、数据校验、异常处理等。...
XML配置是Spring MVC早期版本中常见的配置方式,它允许开发者通过XML文件来定义组件、映射URL和设置拦截器等。在本篇文章中,我们将深入探讨如何在Spring MVC中使用XML配置来实现拦截器。 拦截器(Interceptor)在...
九、Spring MVC中的拦截器:拦截器是Spring MVC提供的一个可插入的组件,可以用来实现请求预处理和后处理。拦截器可以在请求到达控制器之前进行拦截,并对请求或响应进行一些预处理工作。 十、Spring MVC如何使用...
Spring Web MVC 3.1引入了自动配置的概念,使得开发者可以通过注解来声明式地配置MVC组件,如`@Controller`、`@RequestMapping`等。这极大地减少了XML配置文件的使用,简化了项目配置。 2. **ModelAndView与...