一 拦截器
定义拦截器,实现HandlerInterceptor接口
package com.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author:Yang
* @date:2018/5/29
*/
public class Interceptor implements HandlerInterceptor {
/**
*进入Handler方法之前执行
* 用于身份认证,身份授权
* 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
/**
* return false 表示拦截,不再向下执行
* return true 表示放行
*/
return false;
}
/**
*进入Handler方法之后,返回ModelAndView之前执行
* 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
/**
*执行Handler之后执行
* 统一异常处理,统一日志处理
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}
二 springMVC 拦截器配置
1 针对HandlerMapping配置(不推荐使用)
springmvc拦截器针对HandlerMapping进行拦截设置,如果在某个HandlerMapping中配置拦截,经过该HandlerMapping映射成功的handler最终使用该拦截器。
2 类似全局的拦截器
springmvc配置类似全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中。
三 多拦截器测试
1 拦截器定义
- 拦截器一(Interceptor1)
package com.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author:Yang
* @date:2018/5/29
*/
public class Interceptor1 implements HandlerInterceptor {
/**
*进入Handler方法之前执行
* 用于身份认证,身份授权
* 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
/**
* return false 表示拦截,不再向下执行
* return true 表示放行
*/
System.out.println("拦截器1.........preHandle");
return false;
}
/**
*进入Handler方法之后,返回ModelAndView之前执行
* 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器1.........postHandle");
}
/**
*执行Handler之后执行
* 统一异常处理,统一日志处理
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("拦截器1.........afterCompletion");
}
}
- 拦截器二(Interceptor2)
package com.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author:Yang
* @date:2018/5/29
*/
public class Interceptor2 implements HandlerInterceptor {
/**
*进入Handler方法之前执行
* 用于身份认证,身份授权
* 比如身份认证,如果认证未通过表示当前用户没有登录,需要此方法拦截不再向下执行
*/
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
/**
* return false 表示拦截,不再向下执行
* return true 表示放行
*/
System.out.println("拦截器2.........preHandle");
return false;
}
/**
*进入Handler方法之后,返回ModelAndView之前执行
* 应用场景从modelAndView出发:将公用的模型数据在这里传到视图,也可以统一的指定视图
*/
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器2.........postHandle");
}
/**
*执行Handler之后执行
* 统一异常处理,统一日志处理
*/
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("拦截器2.........afterCompletion");
}
}
2 两个拦截器的preHandle都返回true
.......................省略..............
拦截器1.........preHandle
拦截器2.........preHandle
DEBUG [http-apr-8080-exec-3] - Fetching JDBC Connection from DataSource
DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 1
DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 2
DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 3
DEBUG [http-apr-8080-exec-3] - incremented pending_acquires: 4
.......................省略..............
拦截器2.........postHandle
拦截器1.........postHandle
.......................省略..............
DEBUG [http-apr-8080-exec-3] - Added model object 'items' of type [java.util.ArrayList] to request in view with name 'index'
DEBUG [http-apr-8080-exec-3] - Forwarding to resource [/index.jsp] in InternalResourceView 'index'
拦截器2.........afterCompletion
拦截器1.........afterCompletion
.......................省略..............
小结:preHandle按照顺序执行,postHandle、afterCompletion按照逆向顺序执行
3 拦截器一放行,拦截器二不放行
DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'environment'
DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'environment'
DEBUG [http-apr-8080-exec-3] - DispatcherServlet with name 'springmvc_result' processing GET request for [/items/queryItems]
DEBUG [http-apr-8080-exec-3] - Looking up handler method for path /items/queryItems
DEBUG [http-apr-8080-exec-3] - Returning handler method [public java.lang.String com.controller.ItemsController.queryItems(org.springframework.ui.Model,com.entity.ItemsQueryVo) throws java.lang.Exception]
DEBUG [http-apr-8080-exec-3] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-3] - Last-Modified value for [/items/queryItems] is: -1
拦截器1.........preHandle
拦截器2.........preHandle
拦截器1.........afterCompletion
DEBUG [http-apr-8080-exec-3] - Successfully completed request
小结:拦截器1放行,拦截器2 preHandle才会执行。
拦截器2 preHandle不放行,拦截器2 postHandle和afterCompletion不会执行。
只要有一个拦截器不放行,postHandle不会执行。
4 拦截器一不放行,拦截器二放行
.......................省略..............
DEBUG [http-apr-8080-exec-8] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-8] - Last-Modified value for [/items/queryItems] is: -1
拦截器1.........preHandle
DEBUG [http-apr-8080-exec-8] - Successfully completed request
小结:拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。
拦截器1 preHandle不放行,拦截器2不执行。
5 拦截器一不放行,拦截器二不放行
.......................省略..............
DEBUG [http-apr-8080-exec-2] - Returning cached instance of singleton bean 'itemsController'
DEBUG [http-apr-8080-exec-2] - Last-Modified value for [/items/queryItems] is: -1
拦截器1.........preHandle
DEBUG [http-apr-8080-exec-2] - Successfully completed request
小结:同上
*总结
拦截器1 preHandle不放行,postHandle和afterCompletion不会执行。
拦截器1 preHandle不放行,拦截器2不执行。
四 登录拦截器
1 思路
(1) 用户请求url
(2) 拦截器进行拦截效验
- 如果请求的url是公开地址(无需登录即可访问的url)放行
- 如果用户session不存在跳转到登录页面
- 如果用户session存在放行,继续操作
2 LoginInterceptor
package com.Interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
/**
* 登录认证拦截器
* @author:Yang
* @date:2018/5/29
*/
public class LoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest Request, HttpServletResponse Response, Object o) throws Exception {
//获取url
String url = Request.getRequestURI();
//判断url是否公开地址(实际使用时将公开地址配置在配置文件中)
//这里公开地址是登录提交的地址
if(url.indexOf("login")>=0){
//如果进行登录提交,放行
return true;
}
//判断session
HttpSession session = Request.getSession();
String username = (String) session.getAttribute("username");
if(username != "" && username != null){
//身份存在放行
return true;
}
//执行到这里,说明用户身份需要认真,跳转登录页面
Request.getRequestDispatcher("/login.jsp").forward(Request,Response);
return false;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println("拦截器1.........postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
System.out.println("拦截器1.........afterCompletion");
}
}
3 拦截器配置
4 controller
package com.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.servlet.http.HttpSession;
/**
* @author:Yang
* @date:2018/5/29
*/
@Controller
public class LoginController {
@RequestMapping("/login")
public String login(HttpSession session, String username, String password)throws Exception{
//调用service进行用户身份验证
//...
session.setAttribute("username",username);
return "redirect:/items/queryItems";
}
@RequestMapping("/logout")
public String logout(HttpSession session)throws Exception{
session.invalidate();
return "redirect:login";
}
}
五 存在问题
在登陆案例拦截器中,有两次if判断。当第一次判断是否进行登陆提交,当我们提交后会放行,执行LoginController类中的方法,多次调试发现进入LoginController类中,对应的方法会执行完,后续的postHandle和afterCompletion也会依次执行,根据多次调试发现,我们的第二次if判断是在执行完afterCompletion之后在执行,于是,想着是不是拦截器执行是在一个流程完成之后(preHandle,postHandle和afterCompletion),返回再执行,然后又去掉第二次if判断,测试就会有问题,无法登陆。preHandle按学习资料讲是在Handler执行之前执行,但案例测试实在想不明白。待解决