这篇主讲拦截器,在讲拦截器之前,顺便提两句监听器和过滤器。
拦截器、监听器、过滤器
过滤器(Filter):当你有一堆东西的时候,你只希望选择符合你要求的某一些东西。定义这些要求的工具,就是过滤器。
举例:在web.xml中会有很多过滤器,比如字符过滤器;比如对请求方法进行过滤的过滤器等。
拦截器(Interceptor):在一个流程正在进行的时候,你希望干预它的进展,甚至终止它进行,这是拦截器做的事情。
举例:本文下面的代码示例就是一个典型的拦截器例子。
监听器(Listener):当一个事件发生的时候,你希望获得这个事件发生的详细信息,而并不想干预这个事件本身的进程,这就要用到监听器。
举例:在web.xml中有时候会配置这一项 ↓
<listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>classpath:spring/applicationContext.xml</param-value>
</context-param>
诸如此类的监听器。
当然我这么解释肯定无法准确的理解它们之间的区别,所以请移步知乎大神的回答(第一个)。
接下来看我的关于拦截器的小demo吧。
代码
Github地址
先看一下项目结构
主要讲一下LoginInterceptor类以及SomeUtils类,其他内容去Github上看吧。
首先看SomeUtils.java
@Service
public class SomeUtils {
public void setCookies(HttpServletResponse response, User user) throws ServletException,IOException{
System.out.println("Enter setCookie()");
try{
String username = user.getName();
String password = user.getPassword();
String token = username + "," + password;
Cookie cookie = new Cookie("user", token);
cookie.setMaxAge(60 * 2);
cookie.setPath("/");
response.addCookie(cookie);
}catch (Exception e){
e.printStackTrace();
}
}
public boolean checkCookie(HttpServletRequest request) throws ServletException,IOException{
System.out.println("Enter checkCookie()");
boolean flag = false;
Cookie[] cookies = request.getCookies();
if(cookies != null){
for (int i=0; i<cookies.length; i++){
if(cookies[i].getName().equals("user")){
try{
String token = cookies[i].getValue();
String[] elements = token.split(",");
String username = elements[0];
String password = elements[1];
if(username.equals("admin") && password.equals("key")){
flag = true;
}
}catch (Exception e){
e.printStackTrace();
}
}
}
}
return flag;
}
}
里面实现了两个方法,一个是设置缓存,一个是检查缓存中的值是否正确,这里还是简化了操作,逻辑上可能会有瑕疵。
另一个就是拦截器类LoginInterceptor.java
public class LoginInterceptor implements HandlerInterceptor {
@Autowired
private SomeUtils utils;
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception{
boolean flag = utils.checkCookie(request);
if(!flag) {
response.sendRedirect("/login");
return false;
}
return true;
}
@Override
public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
}
}
在我们自己实现拦截器的时候,我们需要实现接口HandlerInterceptor
,然后其中的三个方法分别是:
preHandle
,在调用Controller相关方法之前执行,我们看到这个方法有个返回值,因为Interceptor可能有多个,是链式处理,所以如果其中有返回值为false
的时候,整个请求就此中断,进入到相应的处理页面。
postHandle
,在当前Interceptor中的preHandle
返回值为true
时才会执行,它的执行时间时Controller方法调用后,视图渲染之前。
afterCompletion
,该方法也是需要preHandle
方法返回值为true
时才会执行,执行时间在视图渲染之后,一般用来清理资源。
拦截器我们定义好了,但是如何使用呢?我们看一下,我们在spring-web.xml
中进行了如下对于拦截器的配置:
<!--配置拦截器-->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/a/**"/>
<bean class="com.yubotao.interceptor.LoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
简单解释一下:<mvc:mapping path="/a/**"/>
定义了拦截规则,即所有/a
开头的url都需要经过拦截器进行处理;然后下面的标签<bean class="com.yubotao.interceptor.LoginInterceptor"/>
则定义了该拦截规则使用的拦截器类。
最后运行的结果就是,当第一次直接访问/a/Pass
时,会重定向到/login
,这时就是拦截器在起作用;然后当登陆的帐密完全正确的时候,才会进入成功界面,这个时候结合cookie的存在,在cookie时限内,可不用再次登陆即可进入/a/Pass
的相关页面。
最后补充一句,因为之前有段时间没写java了,导致在进行字符串比较的时候使用了运算符==
,这个比较的是两个字符串地址,所以永远不会相等;这时候使用equals()
方法,可以避免这个问题,这是因为String
类重写了equals()
方法,否则和使用==
是一样的,这里千万要注意,可能一不小心就会犯这种低级错误。