一、拦截器介绍和作用
SpringMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理。用户可以自己定义一些拦截器来实现特定的功能。谈到拦截器,还要向大家提一个词—拦截器链(Interceptor Chain)。拦截器链就是将拦截器按一定的顺序联结成一条链。在访问被拦截的方法或字段是时,拦截器链中拦截器就会按其之前定义的顺序被调用。
二、拦截器与过滤器的区别
过滤器是Servlet规范中的一部分,任何java web工程都可以使用。拦截器是 SpringMVC 框架自己的,只有使用了SpringMVC框架的工程才能用。过滤器在web.xml中的 url-pattern 标签中配置了 /* 之后,可以对所有要访问的资源拦截。
我们要想自定义拦截器, 要求必须实现:HandlerInterceptor 接口。
三、自定义拦截器的步骤
(一)实现HandlerInterceptor接口
public class MyIntercepter implements HandlerInterceptor {
/**
* 控制层执行器方法前的拦截器
* @param request
* @param response
* @param handler
* @return
* @throws Exception
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname!=null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
/**
* 控制层方法返回时拦截器
* @param request
* @param response
* @param handler
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
System.out.println("我是控制层执行器方法返回时拦截器");
}
/**
* 控制层方法结束后的拦截器
* @param request
* @param response
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponseresponse, Object handler, @Nullable Exception ex) throws Exception {
System.out.println("我是控制层执行器方法结束后的拦截器");
}
}
(二)配置拦截器
<!--springMVC配置文件中注册拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/><!--用于指定拦截的url-->
<mvc:exclude-mapping path="/file/login"/><!--用于指定排除的url-->
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>
</mvc:interceptors>
四、拦截器的注意事项
(一)拦截器的放行
拦截器中的放行指的是:如果有下一个拦截器就执行下一个,如果该拦截器处于拦截器链的最后一个,则执行控制器中的方法。
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
//方法返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法。
(二)拦截器中方法的说明
定义拦截器需要实现HandlerInterceptor接口,该接口中有三个方法:
-
preHandle()方法:
控制层执行器方法前的拦截器(该方法时在控制层执行器方法前调用,当该方法返回结果为true则继续调用下一个拦截器,如果已经是最后一个拦截器,则调用控制层中的执行器方法;当该方法返回结果为false,则不会继续执行控制层执行器中的方法)
-
postHandle()方法
控制层方法返回时拦截器(该方法是控制层执行器方法执行之后,由DispatcherServlet在将结果响应给浏览器前调用的方法)
-
afterCompletion()方法
控制层方法结束后的拦截器(该方法在请求业务处理执行完全结束之后由DispatcherServlet调用执行)
(三)多个拦截器的执行顺序
- 先来顺序执行 所有拦截器的 preHandle方法
- 如果任何一个拦截器返回false。直接跳出不执行目标方法
- 如果当前拦截器prehandler返回为true。则执行下一个拦截器的preHandle
- 如果当前拦截器返回为false。直接 倒序执行所有已经执行了的拦截器的 afterCompletion;
- 所有拦截器都返回True。执行目标方法
- 倒序执行所有拦截器的postHandle方法。
- 前面的步骤有任何异常都会直接倒序触发 afterCompletion
- 页面成功渲染完成以后,也会倒序触发 afterCompletion
五、拦截器的简单案例(验证用户是否登录)
(一)实现思路分析
1、定义登录页面,并定义请求映射。
2、判断用户名密码是否正确
3、如果正确 向 session 中写入用户信息
4、返回登录成功。
5、拦截用户请求,判断用户是否登录
6、如果用户已经登录。放行
7、如果用户未登录,跳转到登录页面
(二)案例代码
1、登录页面 login.jsp
<html>
<head>
<title>Title</title>
</head>
<body>
<form action="/file/login" method="post">
用户名:<input type="text" name="pname">
密码:<input type="text" name="password">
<input type="submit" value="登录">
</form>
</body>
</html>
2、控制器实现
@RequestMapping("login")
public String login(String pname, String password, HttpSession session){
System.out.println("登录校验成功");
//将登录成功的用户名存放到session中
session.setAttribute("pname",pname);
return "main";
}
3、拦截器实现
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("我是控制层执行器方法前的拦截器");
//校验用户是否登录
HttpSession session = request.getSession();
String pname=(String)session.getAttribute("pname");
if(pname!=null){
//当前用户已经登录,放行
return true;
}else{
//当前用户未登录,拦截跳转到登录页面
request.getRequestDispatcher("/login.jsp").forward(request,response);
return false;
}
//返回true表示继续执行控制层执行器方法,返回false表示方法结束,不会执行控制层执行器方法
}
4、注册拦截器
<mvc:interceptor>
<mvc:mapping path="/**"/><!--用于指定拦截的 url-->
<mvc:exclude-mapping path="/file/login"/><!--用于指定排除的 url-->
<bean class="com.offcn.util.MyIntercepter"></bean>
</mvc:interceptor>