一、自定义拦截器实现类
在Springmvc中想要定义拦截器,则自定义一个类要实现HandlerInterceptor接口,HandlerInterceptor接口中有三个抽象方法,若不想使用全部,则可以或者是这个类继承HandlerInterceptor接口的实现类,比如Spring已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter ;
在此之前,先回顾下springmvc整个访问的流程:
HandlerInterceptor接口的定义如下:
public interface HandlerInterceptor {
boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception;
void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception;
void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception;
}
HandlerInterceptor接口中定义了三个抽象方法:
**preHandle方法:**Springmvc中可以存在多个自定义拦截器。每个拦截器的调用会依据他的声明顺序依次执行,preHandle()为最先执行的方法,返回值为boolean类型。当返回true时,会继续调用下一个拦截器的preHandle方法,直至最后一个拦截器的preHandle运行结束并返回true时,才调用Controller中的方法。当某个拦截器的preHandle()返回值为false时,后续的拦截器和Controller都不会再执行;这个方法作用在上图中2的位置。
postHandle方法:执行完Controller后调用的方法。也就意味着在此之前全部拦截器的preHandle()返回值均为true,否则无法执行Controller。进而总结出此方法的一个特点:postHandle()方法是只有在preHandle()方法的返回值为true 时才能被调用的方法。它的执行时间是在处理器适配器进行处理之后,在上图中10的位置执行,也就是说在这个方法中你可以对ModelAndView进行操作。这个方法的链式结构跟正常访问的方向是相反的,也就是说先声明的Interceptor拦截器该方法反而会后调用。
afterCompletion方法:次方法同样为当前对应的拦截器 的preHandle方法的返回值为true 时才能被调用的方法。该方法将在整个请求完成之后,也就是在上图13位置执行,这个方法的主要作用是用于清理资源的。
二、拦截器应用简单示例
1.创建自定义Class实现HandlerInterceptor接口:
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
System.out.println("preHandle....");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle....");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion....");
}
}
2.在springmvc.xml中配置自定义的Interceptor
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 多个拦截器,顺序执行 -->
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<!-- <bean class="com.asjy.util.MyInterceptor"></bean> -->
<mvc:interceptor>
<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
<mvc:mapping path="/user/**" />
<bean class="com.asjy.util.MyInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
3.测试,访问登录页login.jsp,点击登录后会向Controller发送一个请求(jsp页和Controller页不为本次重点,略)
三、多个拦截器应用示例
1.新增两个测试拦截器MyInterceptor2, MyInterceptor3,增加一个登录验证拦截器LoginInterceptor,对于未进行登录的用户禁止访问login.jsp以外的页面
public class MyInterceptor2 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
System.out.println("preHandle....2");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle....2");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion....2");
}
}
public class MyInterceptor3 implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
System.out.println("preHandle....3");
return true;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("postHandle....3");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("afterCompletion....3");
}
}
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request,
HttpServletResponse response, Object handler) throws Exception {
// TODO Auto-generated method stub
System.out.println("Login....preHandle.... 4");
//获取请求的URL
String url = request.getRequestURI();
//URL:login.jsp是公开的;这个demo是除了login.jsp是可以公开访问的,其它的URL都进行拦截控制
if(url.indexOf("doLogin.do")>=0){
return true;
}
//获取Session
HttpSession session = request.getSession();
String username = (String)session.getAttribute("username");
if(username != null){
return true;
}
//不符合条件的,跳转到登录界面
request.getRequestDispatcher("../login.jsp").forward(request, response);
return false;
}
@Override
public void postHandle(HttpServletRequest request,
HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("login...postHandle....4");
}
@Override
public void afterCompletion(HttpServletRequest request,
HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("login...afterCompletion....4");
}
}
2.在springmvc.xml中配置自定义的Interceptor
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 多个拦截器,顺序执行 -->
<!-- 使用bean定义一个Interceptor,直接定义在mvc:interceptors根下面的Interceptor将拦截所有的请求 -->
<bean class="com.asjy.util.MyInterceptor"></bean>
<bean class="com.asjy.util.MyInterceptor2"></bean>
<bean class="com.asjy.util.MyInterceptor3"></bean>
<mvc:interceptor>
<!-- 定义在mvc:interceptor下面的表示是对特定的请求才进行拦截的 -->
<mvc:mapping path="/user/**" />
<bean class="com.asjy.util.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
点击登录后,拦截器放行,跳转至doLogin.do,保存信息至session中。代码为:
@RequestMapping("doLogin")
public String doLogin(String username,HttpServletRequest request){
HttpSession session = request.getSession();
session.setAttribute("username", username);
return "redirect:/user/list.do"; //重至用户列表主页面
}
@RequestMapping("list")
public String doAdd(UserExt userExt,Model model){
List<User> list = new ArrayList<User>();
User u1 = new User();
u1.setId(1);
u1.setUsername("tom");
User u2 = new User();
u2.setId(2);
u2.setUsername("jerry");
User u3 = new User();
u3.setId(3);
u3.setUsername("lucy");
list.add(u1);
list.add(u2);
list.add(u3);
model.addAttribute("list",list);
return "list";
}
3.测试
(1)未进行登录状态下直接访问list.do
可见程序执行至LoginInterceptor时,未检测到session中username的值,则返回false,并跳转至登录页,程序无法进入Controller
(2).先登录
登录成功:
打开新窗口,再次直接访问list.do
访问成功!看看控制台打印的什么: