`
Adan-Chiu
  • 浏览: 21684 次
社区版块
存档分类
最新评论

Spring MVC组件开发-拦截器

 
阅读更多

 

拦截器

        拦截器是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/**");
        }

 

对其进行测试,可以看到结果是这样的 (责任链模式)
preHandle1
preHandle2
preHandle3
......控制器逻辑日志打印.....
postHadle3
postHadle2
postHadle1

...........
afterCompletion3
afterCompletion2
afterCompletion1

 有些时候前置方法可能返回false,我们将RoleInterceptor2中的前置方法给为false进行测试后得到的结果:

preHandle1
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));  
        }          
    }  
}  
 

 

  • 描述: 单个拦截器执行流程
  • 大小: 15.6 KB
分享到:
评论

相关推荐

    拦截器与冲突解决

    在开发过程中,为了调试和定位问题,可以开启Spring MVC的日志,查看请求处理的详细过程,以找出拦截器未被调用的原因。此外,阅读Spring MVC的相关文档和源码也能帮助我们更深入地理解问题所在。 最后,对于提供的...

    spring MVC快速入门-深入分析.pdf

    - **拦截器**:Spring MVC 支持拦截器机制,可以在请求处理前后执行特定的操作,如权限验证、日志记录等。 - **异常处理**:通过配置 `@ExceptionHandler` 或 `@ControllerAdvice` 注解的方法来处理全局异常。 ####...

    Spring MVC--------我在创智软件的面试

    在面试中,深入理解Spring MVC可以帮助你展示对Web开发的深入理解和技术实力。 1. **核心组件**: Spring MVC的核心组件包括DispatcherServlet、Controller、Model、View和ViewResolver。DispatcherServlet作为...

    spring-webmvc-struts.jar

    而Spring MVC作为Spring框架的一部分,是构建Web应用程序的重要组件。Struts作为早期的MVC框架,也曾经是Java Web开发的主流选择。当Spring与Struts结合时,可以实现更高效、更灵活的应用架构。本文将深入探讨`...

    spring mvc-mybatis-lib

    Spring MVC还支持数据绑定、拦截器、异常处理和国际化等功能,极大地提高了开发效率。 MyBatis,是一个轻量级的持久层框架,它将SQL语句与Java代码解耦,使得开发者可以直接编写SQL来操作数据库,同时保持代码的...

    SSM基础框架(整合Spring、Spring MVC 、MyBatis-plus)(全注解版)

    6. 配置Spring MVC的servlet-context.xml或使用Java配置类,设置视图解析器、拦截器等。 7. 编写Controller层的代码,使用`@RequestMapping`等注解处理请求。 8. 使用MyBatis-Plus的API编写业务逻辑,通过`@Mapper`...

    spring-mvc-step-by-step.pdf

    - **拦截器与AOP**:探索Spring的拦截器机制以及面向切面编程(AOP)在Spring MVC中的应用。 - **异常处理**:如何优雅地处理应用运行时可能出现的异常。 - **国际化与本地化**:支持多语言环境的实现方法。 - **...

    Spring-MVC-step-by-step2.rar

    在源码层面,Spring MVC 的实现基于 AOP(面向切面编程),这使得我们可以轻松地添加拦截器(Interceptor)来实现日志记录、权限控制等功能。同时,Spring MVC 还支持自定义消息转换器(MessageConverter),方便...

    spring-spring mvc-mybaties整合dome

    2. **配置Spring MVC**:定义DispatcherServlet配置,包括视图解析器、拦截器、模型AndView的处理器映射器和处理器适配器。 3. **配置MyBatis**:在MyBatis的配置文件中,设置数据源、事务管理器以及Mapper配置,...

    spring mvc step by step,例子

    2. **配置Spring MVC**:在`web.xml`中配置`DispatcherServlet`,并添加Spring MVC的配置文件,如`spring-mvc.xml`,在这里定义视图解析器、拦截器、bean等。 3. **编写Controller**:创建一个控制器类,使用`@...

    spring-mvc-documentation-linesh-translation

    根据提供的文件信息,我们可以将其中的关键知识点归纳如下: ### Spring MVC 框架简介 ...通过对上述知识点的学习和理解,可以更好地掌握 Spring MVC 的使用方法,进而开发出更加优秀的 Web 应用程序。

    Spring MVC 学习记录总结1

    通过以上介绍,我们可以看出Spring MVC提供了一个结构清晰、组件丰富的框架,使开发者能够专注于业务逻辑,同时利用Spring的强大功能来简化Web应用的开发。在实际开发中,我们只需要关注Controller的实现和视图的...

    spring mvc jar包

    `org.springframework.web-3.0.2.RELEASE.jar`:这个库包含了一些 Web 相关的支持类,如 Web 应用上下文(WebApplicationContext)、HTTP 拦截器(HandlerInterceptor)和请求映射(RequestMapping)等,它们与 MVC ...

    Spring3MVC-REST-HelloWorld 实例简单代码

    Spring3MVC-REST-HelloWorld 是一个基础的示例,用于展示如何在Spring框架的...这只是一个起点,Spring MVC还支持许多高级特性,如拦截器、异常处理、数据验证和AOP(面向切面编程),可以应对各种复杂Web应用的需求。

    spring-webmvc-portlet.rar

    5. **拦截器**:允许在请求处理前后插入自定义逻辑,如权限检查、日志记录等。 二、Portlet框架 Portlet框架是为portlet容器(如Liferay、WebSphere Portal)提供的一套标准,它定义了portlet的生命周期、渲染机制...

    SPRING MVC3.2案例讲解---配置

    总的来说,Spring MVC 3.2的配置涉及多个方面,包括组件扫描、视图解析、注解驱动、拦截器、异常处理以及数据绑定等。通过合理的配置,我们可以构建出一个高效、灵活的Web应用框架。在实际项目中,应根据具体需求...

    一个改进版的spring-mvc-showcase

    总的来说,"一个改进版的spring-mvc-showcase"项目展示了如何利用Spring MVC构建一个现代Web应用,并且可能涵盖了许多高级特性,如AOP(面向切面编程)、RESTful API设计、拦截器、数据校验、异常处理等。...

    spring mvc xml配置拦截器

    XML配置是Spring MVC早期版本中常见的配置方式,它允许开发者通过XML文件来定义组件、映射URL和设置拦截器等。在本篇文章中,我们将深入探讨如何在Spring MVC中使用XML配置来实现拦截器。 拦截器(Interceptor)在...

    Spring MVC 教程快速入门 深入分析

    九、Spring MVC中的拦截器:拦截器是Spring MVC提供的一个可插入的组件,可以用来实现请求预处理和后处理。拦截器可以在请求到达控制器之前进行拦截,并对请求或响应进行一些预处理工作。 十、Spring MVC如何使用...

    spring-webmvc-3.1.1.RELEASE.jar.zip

    Spring Web MVC 3.1引入了自动配置的概念,使得开发者可以通过注解来声明式地配置MVC组件,如`@Controller`、`@RequestMapping`等。这极大地减少了XML配置文件的使用,简化了项目配置。 2. **ModelAndView与...

Global site tag (gtag.js) - Google Analytics