1.1. Spring MVC拦截器概述
拦截器是SpringMVC中的一个核心应用组件,主要用于处理多个
Controller的共性问题.当我们的请求由DispatcherServlet派发
到具体Controller之前首先要执行拦截器中一些相关方法,在这些
方法中可以对请求进行相应预处理(例如权限检测,参数验证),这些方法可以决定对这个请求进行拦截还是放行。
通过spring mvc 架构图分析,拦截器在Spring MVC中处理流程中的一个位置

请求到达后端控制器之前有一堆拦截器,拦截器在请求到达后端控制器之前可以做一些预处理。从控制器返回的数据也可以在拦截器做预处理。拦截器有拦截器链,过滤器有过滤器链。通常把拦截器和Controller称为执行链中的一个对象。过滤器是请求到达前端控制器之前执行,拦截器是前端控制器到达后端控制器之前执行,他们两个所处的位置不同。所以在过滤器里取不到后端控制器。先执行的拦截器最后结束。后结束的拦截器最先结束。
1)假如对请求数据进行编码,是应在过滤器还是拦截器?
推荐使用过滤器。
2)拦截器有哪些有些应用场景呢?(处理后台控制业务的共性-对请求进行拦截不让其传入后端控制器)
a)进行身份认证(判定用户是否是合法用户)
b)进行系统监控
c)进行日志记录
1.2. Spring MVC拦截器编写及基本配置
拦截器如何编写?
我们自己编写Spring MVC拦截器需要实现HandlerInterceptor接口或者继承此接口的实现类 HandlerInterceptorAdapter(继承这个类时可根据需求重写必要的方法)
/spring-mvc-v2/src/main/resources/spring-configs.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:util="http://www.springframework.org/schema/util" xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.3.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-4.3.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx-4.3.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-4.3.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util-4.3.xsd
http://www.springframework.org/schema/data/jpa
http://www.springframework.org/schema/data/jpa/spring-jpa-1.3.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.3.xsd">
<!-- 配置spring中bean对象的扫描(包括后端控制器)
component-scan元素用于包以及包中的子类并且将使用了@Controller,@Service类似注解等修饰的类
交给Spring容器管理。 -->
<context:component-scan base-package="controller"/>
<!--配置和启用spring MVC默认配置(例如底层支持json)-->
<mvc:annotation-driven/>
<!--配置springMVC视图解析器(负责视图解析操作)-->
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<!--前缀-->
<property name="Prefix" value="/WEB-INF/pages/"></property>
</bean>
<!--配置拦截器对象-->
<mvc:interceptors>
<mvc:interceptor>
<!--要拦截的路径url-->
<mvc:mapping path="/**"/>
<!--要排除的拦截路径url-->
<mvc:exclude-mapping path="/doStudyInterceptor.do"/>
<!--拦截器对象-->
<bean class="controller.TimeInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
</beans>
/spring-mvc-v2/src/main/java/controller/InterceptorController.java
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/")
public class InterceptorController {
@RequestMapping("doSomeThing")
@ResponseBody
public String doSomeThing() {
System.out.println("InterceptorController.doSomeThing()");
// 获取方法执行时长
long startTime = System.nanoTime();
String result = "do some thing";
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
return result;
}
@RequestMapping("doStudyInterceptor")
@ResponseBody
public String doStudyInterceptor() {
System.out.println("InterceptorController.doStudyInterceptor()");
// 获取方法执行时长
long startTime = System.nanoTime();
String result = "do study Interceptor";
long endTime = System.nanoTime();
System.out.println(endTime - startTime);
return result;
}
}
/spring-mvc-v2/src/main/java/controller/TimeInterceptor.java
package controller;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器的编写:是实现HandlerInterceptor接口或继承HandlerInterceptorAdapter
* 继承适配器只需要实现一部分功能
* 拦截器的配置
* 1)xml方式(spring-config.xml)
* 2)基于annotation方式
*/
public class TimeInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("TimeInterceptor.preHandle()");
return true;//false表示拦截。true表示放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TimeInterceptor.postHandle()");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("TimeInterceptor.afterCompletion()");
}
}
http://localhost/spring-mvc-v2/doSomeThing.do
控制台输出
TimeInterceptor.preHandle()
InterceptorController.doSomeThing()
554
TimeInterceptor.postHandle()
TimeInterceptor.afterCompletion()
http://localhost/spring-mvc-v2/doStudyInterceptor.do
控制台输出
InterceptorController.doStudyInterceptor()
554
共性的方法提出
/spring-mvc-v2/src/main/java/controller/InterceptorController.java
package controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
@Controller
@RequestMapping("/")
public class InterceptorController {
@RequestMapping("doSomeThing")
@ResponseBody
public String doSomeThing() {
System.out.println("InterceptorController.doSomeThing()");
// 获取方法执行时长
String result = "do some thing";
try {
Thread.sleep(5000);
} catch (Exception e) {
}
return result;
}
@RequestMapping("doStudyInterceptor")
@ResponseBody
public String doStudyInterceptor() {
System.out.println("InterceptorController.doStudyInterceptor()");
// 获取方法执行时长
String result = "do study Interceptor";
try {
Thread.sleep(6000);
} catch (Exception e) {
}
return result;
}
}
/spring-mvc-v2/src/main/java/controller/TimeInterceptor.java
package controller;
import java.lang.reflect.Method;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 拦截器的编写:是实现HandlerInterceptor接口或继承HandlerInterceptorAdapter 继承适配器只需要实现一部分功能
* 拦截器的配置 1)xml方式(spring-config.xml) 2)基于annotation方式
*/
public class TimeInterceptor implements HandlerInterceptor {
public TimeInterceptor() {
System.out.println("TimeInterceptor.TimeInterceptor()");
}
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("TimeInterceptor.preHandle()");
long startTime = System.currentTimeMillis();
// 没有共享就没有伤害
request.setAttribute("startTime", startTime);
return true;// false表示拦截。true表示放行
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("TimeInterceptor.postHandle()");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("TimeInterceptor.afterCompletion()");
long endTime = System.currentTimeMillis();
long startTime = (Long) request.getAttribute("startTime");
long totalTime = endTime - startTime;
System.out.println(handler.getClass().getName());
//将handler向下转型(目的获取方法信息)
if (handler instanceof HandlerMethod) {
//将handler向下转型-获取方法相关信息
HandlerMethod hMethod = (HandlerMethod) handler;
//获取方法对象
Method method = hMethod.getMethod();
//获取执行方法所在的类的信息
String beanCls = hMethod.getBeanType().getName();
System.out.println(beanCls+"."+method.getName()+"()" + "总时长" + totalTime);
}
}
}
http://localhost/spring-mvc-v2/doSomeThing.do
TimeInterceptor.preHandle()
InterceptorController.doSomeThing()
TimeInterceptor.postHandle()
TimeInterceptor.afterCompletion()
org.springframework.web.method.HandlerMethod
controller.InterceptorController.doSomeThing()总时长5018
基于拦截器实现控制方法监控,计算控制层方法时长,判断哪些方法需要计算,哪些不需要