在之前学习JAVAWEB 的时候,我们学习了过滤器的知识。过滤器的作用是保护请求的服务器资源,在请求资源被执行之前,如果请求地址符合拦截范围,则会先执行过滤器。过滤器的执行时机,是在Servlet之前执行的。但是在使用了SpringMVC后,Servlet只有一个了,也就是DisptcherServlet。那么,如果我们仍然使用过滤器来完成请求的拦截,因为过滤器是在Servlet之前执行的,就会造成,过滤器会拦截DispatcherServlet所有的请求。那么,如果我们有部分请求不想被拦截,怎么办?
拦截器使用
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。通常拦截器类可以通过两种方式来定义。
1.通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
2.通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
拦截器和过滤器的区别
1拦截器SpringMVC的,而过滤器是servlet的。
2拦截器不依赖与servlet容器,由spring容器初始化,过滤器依赖与servlet容器,由servlet容器初始化。
3拦截器只能对action请求起作用,而过滤器则可以对几乎所有的请求起作用。
4拦截器可以访问action上下文、值栈里的对象,而过滤器不能访问。
5在action的生命周期中,拦截器可以多次被调用,而过滤器只能在容器初始化时被调用一次。
6拦截器可以获取IOC容器中的各个bean,而过滤器就不太方便,这点很重要,在拦截器里注入一个service,可以调用业务逻辑。
1.定义一个拦截器
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*在请求到达我们定义的handler之前工作的*/
System.out.println("MyInterceptor preHandle");
/*返回的是true,代表放行,可以继续到达handler*/
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor postHandle");
/*handler 处理单元返回ModelAndView 时候进行 拦截*/
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/*
页面渲染完毕,但是还没有给浏览器响应数据的时候
*/
System.out.println("MyInterceptor afterCompletion");
}
}
2.springmvc.xml中注册拦截器
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor" class="com.msb.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
拦截器内容详解
1、preHandle方法
- 执行时机: 再进入控制单元方法之前执行
- 如何调用: 按拦截器定义顺序调用
- 具体作用: 如果程序员决定该拦截器对请求进行拦截处理后还要调用其他的拦截器,或者是业务处理器去 进行处理,则返回 true。 如果程序员决定不需要再调用其他的组件去处理请求,则返回 false。
- 参数详解
- HttpServletRequest arg0,拦截的请求的request对象
- HttpServletResponse arg1, 拦截的请求的response对象
- Object arg2 封存了单元方法对象的HandleMethod对象
/**
*
* @param request 请求对象
* @param response 响应对象
* @param handler 目标要调用的Handler
* @return 返回true放行,返回false拦截
* @throws Exception
*/
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
/*在请求到达我们定义的handler之前工作的*/
System.out.println("MyInterceptor preHandle");
/*设置请求和响应的乱码 */
/* request.setCharacterEncoding("UTF-8");
response.setCharacterEncoding("UTF-8");*/
// 判断是否登录
/*User user =(User) request.getSession().getAttribute("user");
if(null == user)
response.sendRedirect("index.jsp");
return false;*/
// 用户权限控制
return true;
}
2、postHandle方法
- 执行时机: 在进行数据处理和做出响应之间进行这个方法的调用
- 如何调用 :在拦截器链内所有拦截器返成功调用
- 具体作用: 在业务处理器处理完请求后,但是 DispatcherServlet 向客户端返回响应前被调用,
- 在该方法中对用户请求 request域数据进行处理。
- 参数详解
- HttpServletRequest arg0, 拦截的请求的request对象
- HttpServletResponse arg1, 拦截的请求的response对象
- Object arg2, 封存了单元方法对象的HandleMethod对象
- ModelAndView arg3 封存了单元方法的返回值资源路径和请求转到的Map数据
/**
*
* @param request
* @param response
* @param handler
* @param modelAndView controller响应的结果,视图和数据
* @throws Exception
*/
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("MyInterceptor postHandle");
/*控制数据*/
/*Map<String, Object> map = modelAndView.getModel();
String msg = (String)map.get("msg");
String newMsg = msg.replaceAll("脏话", "**");
map.put("msg", newMsg);*/
/*控制视图*/
/*modelAndView.setViewName("/testDemo1.jsp");*/
}
3、afterCompletion方法
执行时机: 在进行页面渲染的时候执行
- 如何调用: 按拦截器定义逆序调用
- 具体作用: 在DispatcherServlet 完全处理完请求后被调用,可以在该方法中进行一些资源清理的操作。
- 参数详解
- HttpServletRequest arg0, 拦截的请求的request对象
- HttpServletResponsearg1, 拦截的请求的response对象
- Object arg2, 封存了单元方法对象的HandleMethod对象
- Exception arg3 存储了责任链的异常信息
/**
* 无论controller是否出现异常,都会执行的方法
* 一般来说都做一些资源释放工作
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
/*页面渲染完毕,但是还没有给浏览器响应数据的时候*/
System.out.println("MyInterceptor afterCompletion");
System.out.println(ex);
}
多个拦截器执行顺序
多个拦截器同时存在时,执行的顺序由配置顺序决定. 先配置谁, 谁就先执行.多个拦截器可以理解为拦截器栈, 先进后出(后进先出), 如图所示:
<!--注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor1" class="com.msb.interceptor.MyInterceptor"></bean>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/login.action"/>
<bean id="myInterceptor2" class="com.msb.interceptor.MyInterceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
执行结果:
MyInterceptor preHandle
MyInterceptor2 preHandle
login.action
MyInterceptor2 postHandle
MyInterceptor postHandle
success.jsp
MyInterceptor2 afterCompletion
MyInterceptor afterCompletion