1.拦载器介绍
SpringMVC拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似与servlet中的Filter。
SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor来实现的。
所有HandlerMapping实现都支持处理程序拦截器,当您希望将特定功能应用于特定请求时,这些拦截器非常有用——例如,校验检查会话,记录日志等。拦截器必须实现org.springframework.web的HandlerInterceptor接口。该接品有三种方法,可以提供足够的灵活性来进行各种预处理和后处理:
-
preHandle(..)
: 在实际的处理程序执行之前 -
postHandle(..)
: 在执行处理程序之后 -
afterCompletion(..)
: 完成后(..):完整的请求完成后
preHandle(..)方法返回一个布尔值。我们可以使用此方法中断或继续执行链的处理。当此方法返回true时,处理程序执行链将继续。当它返回false时,DispatcherServlet假设拦截器本身已经处理了请求(例如,呈现了一个适当的视图),并且不再继续执行执行链中的其他拦截器和实际的处理程序。
注意,postHandle在@ResponseBody和ResponseEntity方法中不太有用,因为响应是在HandlerAdapter中写入并提交的,而且是在postHandle之前。这意味着对响应进行任何更改都太晚了,比如添加额外的消息头。对于这样的场景,您可以实现ResponseBodyAdvice,或者将它声明为控制器通知bean,或者直接在RequestMappingHandlerAdapter上配置它
在SpringMVC中定义一个Interceptor非常简单,主要有两步操作;
1、HandlerInterceptor接口
2、注册拦截器
2.拦截器的工作原理
当收到请求时,DispatcherServlet将请求交给处理器映射(HandlerMapping),让它找出对应该请求的HandlerExecutionChain对象。
HandlerExecutionChain顾名思义就是一个执行链,它包含一个处理该请求的处理器(Handler),同时包括若干个对该请求实施拦截的拦截器(HandlerInterceptor).当HanderMapping返回HanderExceutionChain后,DispatcherServlet将请求交给定义在HandlerExcecutionChain中的拦截器和处理器一并处理。
HandlerExecutionChain是负责处理请求并返回ModelAndView的处理执行链,其结构如下;
想要开发一个拦截器,需要实现接口
public class SpringMvcInterceptor implements HandlerInterceptor{ /** * 在请求到达Handler之前,先执行这个前置处理方法。当该方法返回false时,请求直接返回,不会传递到 * 链中下一个拦截器,更不会调用处理器链末端的Handler中,只有返回true时请求才向链中的下一个处理节 * 点传递。 * SpringMvc中的拦截器是链式的,可以同时存在多个interceptor,springmvc会根据声明的前后顺序一个 * 接一个的执行,且所有的interceptor中的preHandle方法都会在。 */ @Override public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2) throws Exception { // TODO Auto-generated method stub return true; } /** * 在业务处理器处理请求执行完成后,生成视图之前执行的动作 * 可在modelAndView中加入数据,比如当前时间 */ @Override public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, ModelAndView arg3) throws Exception { // TODO Auto-generated method stub } /** * 在DispatcherServlet完全处理完请求后被调用,可用于清理资源、可记录操作日志等 * 当有拦截器抛出异常时,会从当前拦截器往回执行所有的拦截器的afterCompletion() */ @Override public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3) throws Exception { // TODO Auto-generated method stub } }
位于处理器链末端的是一个Handler,DispactherServlet通过HandlerAdapter适配器对Handler进行封装,并按统一的适配器接口对Handler处理方法进行调用。
3开发示例
1.创建 拦截器
自定义拦截器
public class TimeInterceptor implements HandlerInterceptor {
//前置调用
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle 被调用:"+request.getRequestURL());
System.out.println("当前时间是:"+new Date());
request.setAttribute("startTime", System.currentTimeMillis());
System.out.println(request.getRequestURI());
if(request.getRequestURI().startsWith("/mvc329/user")) {
System.out.println("user请求");
response.sendRedirect(request.getContextPath()+"/index.jsp");
return false;
}else {
return true;
}
}
//后置调用
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle 被调用:"+request.getRequestURL());
System.out.println("当前时间是:"+new Date());
Long end=System.currentTimeMillis();
Long start=(Long) request.getAttribute("startTime");
System.out.println(handler+"调用 ,花费时间为:"+(end-start));
if(modelAndView!=null) {
System.out.println(handler+" viewName:"+(modelAndView.getViewName()));
}
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion 被调用:"+request.getRequestURL());
System.out.println("当前时间是:"+new Date());
Long end=System.currentTimeMillis();
Long start=(Long) request.getAttribute("startTime");
System.out.println(handler+"显示调用 ,花费时间为:"+(end-start));
}
}
2注册拦截器
可以在SpringMVC.xml中配置多个拦截器,每个拦截器都可以指定一个匹配的映射路径,以限制拦截器的作用范围
<!-- springmvc.xml配置MVC拦截器 --> <mvc:interceptors> <!-- 使用bean定义一个interceptor,直接定义在mvc:interceptors根下面interceptor 将拦截所有的请求--> <mvc:interceptor> <!-- 定义在mvc:interceptor下面的表示对特定的请求才进行拦截 --> <mvc:mapping path="/**"/> <mvc:exclude-mapping path="/book/**"/> <bean id="timerInterceptor" class="com.oracle.interceptor.TimeInterceptor"> </bean> </mvc:interceptor> </mvc:interceptors>