一、拦截器概述
SpringMVC的拦截器(Interceptor)与java Servlet的过滤器(Filter)类似,用于拦截用户的请求并且做出相应的处理。一般应用于权限认证、记录请求信息的日志、判断用户是否登陆等功能。
(一)拦截器的实现方式
一种是通过实现 Handlerlnterceptor 接口; 另一种是通过实现 WebRequestlnterceptor 接口。
以实现 Handlerlnterceptor 接口的定义方式为例,自定义拦截器类的代码如下所示。
public class TestInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle方法在控制器处理请求方法前执行");
/**
* 返回值为true表示继续向下执行,false表示中断后续操作
*/
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 方法在视图渲染结束之后执行,即最后执行");
}
}
• preHandler方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。
• postHandle方法:该方法会在控制器方法调用之后,且解析视图之前执行。 可以通过此 方法对请求域中的模型和视图做出进一步的修改。
• afterCompletion方法:方法会在整个请求完成,即视图渲染结束之后执行。 可以通过此方法实现一些资源清理、记录曰志信息等工作。
(二) 拦截器的配置
要使自定义的拦截器类生效,还需要在 Spring MVC 的配置文件中进行配置。配置代码如下:
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 配置一个全局拦截器,拦截所有的请求 -->
<bean class="interceptor.LoginInterceptor"></bean>
<mvc:interceptor>
<!-- 配置拦截器的作用路径 -->
<mvc:mapping path="/**"/>
<!-- 配置不需要拦截的路径 -->
<mvc:exclude-mapping path=""/>
<!-- 定义在<mvc:interceptor>下面的,表示对匹配路径的请求才进行拦截 -->
<bean class="interceptor.LoginInterceptor"></bean>
</mvc:interceptor>
</mvc:interceptors>
注意:
1、拦截器bean类所放的位置决定拦截器是全局拦截器还是局部拦截器
2、<mvc:mapping path="/gotoTest"/>表示拦截以/gotoTest结尾的路径
3、 mvc:interceptor 中的子元素必须严格按照 <:mvc:mapping … />、<mvc:exclude-mapping … />、<bean … />的顺序。
二、拦截器的执行流程
(一)单个拦截器的执行流程
1、控制器类InterceptorController
@Controller
public class InterceptorController {
@RequestMapping("/gotoTest")
public String gotoTest() {
System.out.println("Controller正在测试拦截器,执行控制器的处理请求方法!");
return "test";
}
}
2、拦截器类
public class TestInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("preHandle方法在控制器处理请求方法前执行");
/**
* 返回值为true表示继续向下执行,false表示中断后续操作
*/
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 方法在视图渲染结束之后执行,即最后执行");
}
}
3、Springmvc-servlet.xml
<!-- 使用扫描机制扫描控制器类 -->
<context:component-scan base-package="com.controller"></context:component-scan>
<!-- 配置视图解析器 -->
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver"
id="internalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/"></property>
<property name="suffix" value=".jsp"></property>
</bean>
<!-- 配置拦截器 -->
<mvc:interceptors>
<!-- 配置一个全局拦截器,拦截所有的请求 -->
<bean class="interceptor.LoginInterceptor"></bean>
</mvc:interceptors>
4、运行结果
(二)多个拦截器的执行流程
1、控制器和拦截器上同
2、Springmvc-servlet.xml文件的配置
<mvc:interceptors>
<mvc:interceptor>
<!-- 配置拦截器的作用路径 -->
<mvc:mapping path="/**"/>
<!-- 定义在<mvc:interceptor>下面的,表示对匹配路径的请求才进行拦截 -->
<bean class="interceptor.Interceptor1"></bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 配置拦截器的作用路径 -->
<mvc:mapping path="/gotoTest"/>
<bean class="interceptor.Interceptor2"></bean>
</mvc:interceptor>
</mvc:interceptors>
3、运行结果
多个拦截器在执行的过程中,preHandle方法按照配置文件中拦截器的配置顺序执行,而postHandle和afterCompletion方法则按照配置文件的反序执行。
三、应用案列——用户登录权限验证
1、创建POJO类
public class User {
private String uname;
private String upwd;
//省略getter和setter方法
}
2、创建控制器类
@Controller
public class UserController {
/**
* 登录页面初始化
*/
@RequestMapping("/tologin")
public String initLogin() {
return "login";
}
/**
* 处理登录功能
*/
@RequestMapping("/login")
public String login(User user,Model model,HttpSession session) {
System.out.println("用户名:"+user.getUname());
if("juhaijun".equals(user.getUname())
&&"123456".equals(user.getUpwd())) {
session.setAttribute("user", user);
return "redirect:main";
}
model.addAttribute("msg", "用户名或密码错误");
System.out.println("用户名或密码错误!");
return "login";
}
/**
* 跳转到主页面
*/
@RequestMapping("/main")
public String toMain() {
return "main";
}
/**
* 退出登录
*/
@RequestMapping("/logout")
public String logout(HttpSession session) {
// 清除session
session.invalidate();
return "login";
}
}
3、创建拦截器类
public class LoginInterceptor implements HandlerInterceptor{
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 获取登陆的url
String url= request.getRequestURI();
System.out.println("请求路径为:"+url);
// 登录界面不进行拦截
if(url.indexOf("/tologin")>=0 || url.indexOf("/login")>=0) {
return true;
}
// 获取session
HttpSession session = request.getSession();
Object obj = session.getAttribute("user");
if(obj != null) {
//处于登录状态
return true;
}
// 未登录状态
request.setAttribute("msg", "用户还未登陆,请先登录");
request.getRequestDispatcher("/WEB-INF/views/login.jsp").forward(request, response);
return false;
}
}
4、创建jsp页面——登录页面和主界面
<body>
${msg }
<form action="${pageContext.request.contextPath }/login" method="post">
用户名:<input type="text" name="uname"/>
密码:<input type="password" name="upwd"/>
<input type="submit" value="登录"/>
</form>
</body>
<body>
当前用户:${user.uname }<br>
<a href="${pageContext.request.contextPath }/logout">退出</a>
</body>
5、运行结果
四、拦截器小结
我们应当熟悉拦截器在单个执行和多个执行流程下的区别,着重掌握Springmvc配置文件的配置流程。深入理解拦截器在上述应用案列中的作用。如有不足,多谢各位斧正。