实验代码
https://github.com/yangsuperxiaolong/TestInterceptor
SpringMVC组件流程
在Spring MVC的框架流程中,有一个拦截器组件,拦截器组件可以在SpringMVC流程处理中的三个流程点插入拦截器进行处理。拦截器插入的流程点如上图所示,拦截器可以在业务控制器Controller执行之前拦截,也可以在Controller执行之后拦截,还可以在视图组件解析之后拦截。
拦截器的作用
拦截器的作用从总体上来说就是在特定的位置插入逻辑处理和逻辑调用,具体作用可用于日志处理、编码转换、权限检查等功能的实现。
拦截器规范
- 编写规范
必须实现HandlerInterceptor接口
提供preHandle,postHandle,afterCompletion3个方法 - 配置规范
<!-- 添加拦截器组件 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="拦截器拦截的请求"/>
<mvc:execlude-mapping path="拦截器不拦截的请求"/>
<bean class="...拦截器组件"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器的使用
- 编写一个拦截器组件,实现HandlerInterceptor接口
package com.hnust.springmvc.interceptor;
import java.awt.print.Printable;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
public class SimpleInterceptor implements HandlerInterceptor{
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// TODO Auto-generated method stub
System.out.println("------preHandle--------");
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
System.out.println("------postHandle--------");
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
System.out.println("------afterHandle--------");
}
}
由以上代码可知,编写的拦截器组件中有三个方法,代表可以在SpringMVC流程处理中的三个流程点插入该拦截器进行相应处理。
其中,preHandle方法返回一个boolean值,如果返回false,表明拦截器终止后续流程的执行,如果返回true,会执行后续组件。
在拦截器组件这三个方法都添加向控制台输出提示信息的代码,后续可以看到这三个方法的执行顺序。
2.添加拦截器配置
<!-- 添加拦截器组件 -->
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/hello.form"/>
<bean class="com.hnust.springmvc.interceptor.SimpleInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
这里定义了拦截器可拦截的请求,就是客户端浏览器如果发出hello.form请求,这个请求就会被SimpleInterceptor拦截器拦截进行相应处理。
实验结果分析
处理hello.form请求的HelloController业务组件控制器代码
package com.hnust.springmvc.controller;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class HelloController {
@RequestMapping("/hello.form")
public String excute(){
//调用相应的数据模型进行数据处理
System.out.println("-----HelloController-excute----");
return "ok";//返回视图组件名
}
}
当SimpleInterceptor拦截器中的preHandle方法返回值为true时,浏览器发出hello.form请求,实验结果如下:
控制台的输出结果:
由控制台的输出结果可以知道SpringMVC中各组件执行的顺序以及拦截器在框架流程中插入的位置。
如果将preHandle方法设定返回false值,那么拦截器会终止程序后续对该请求的处理。
运行时,浏览器没有接收任何返回信息
控制台只输出preHandle方法中的输出信息。
使用拦截器实现登录时的拦截验证
为了系统的安全性,一般都需要填写登录信息或者完成账号注册之后才能访问系统的内容,所以在没有账号登录的情况下,一些其他的客户端请求都需要被拦截。
下面使用一个验证登录的拦截器,在系统没有登录的情况下,拦截其他的请求,并将请求重定向到登录界面。
根据程序逻辑,拦截器组件代码如下:
package com.hnust.springmvc.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class CheckLoginInterceptor implements HandlerInterceptor{
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
//执行登录检查:检测用户Session是否含有登录添加信息
HttpSession session= request.getSession();
Object user=session.getAttribute("user");
if(user==null){//没有登录信息
response.sendRedirect("/springmvc-module1/login.jsp");//重定向到登录界面
return false;//阻止controller调用
}else{
return true;//合法,通过检测,执行controller
}
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
在applicationContext.xml文件中配置该拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/*"/>
<mvc:exclude-mapping path="/login.form"/>
<mvc:exclude-mapping path="/regist.form"/>
<bean class="com.hnust.springmvc.interceptor.CheckLoginInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
需要使用mvc:exclude-mapping排除掉登录和注册请求,否则登录或注册成功后发出登录请求会失败,因为登录或注册的请求也会被重定向到登录界面,这样陷入死循环,永远无法登录。
登录验证重要的是前台输入验证信息,如常用的账号和密码和后台数据库中用户信息表中的数据是否一致,如果一致,允许登录系统,如果不一致,就提醒用户不存在或者登录密码错误,这个业务逻辑需要在处理登录请求的业务控制器中添加。具体实现方法涉及数据库操作,后续会再写一篇。