1、定义
SpringwebMVC的处理器拦截器类似于Servlet开发中的过滤器Filter,用于对处理器进行预处理和后处理
2、拦截器的定义
定义拦截器,实现HandlerInterceptor接口,如下:
拦截器1:
package com.sky.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 测试拦截器1
* @author sk
*
*/
public class HandlerInterceptor1 implements HandlerInterceptor{
//执行Handler完成后执行此方法
//应用场景:统一的异常处理,统一的日志处理
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object handler, Exception arg3)
throws Exception {
System.out.println("HandlerInterceptor1......afterCompletion");
}
//进入Handler方法之后,在返回ModelAndView之前执行
//应用场景从modelAndView对象出发:将公用的模型数据(比如菜单的导航)在这里传到视图,也可以在这里面来统一指定视图
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor1......postHandle");
}
//在进入Handler方法之前执行
//用于身份认证、身份授权、
//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler) throws Exception {
System.out.println("HandlerInterceptor1......preHandle");
//return false表示拦截住,不向下执行
//return true 表示放行
return true;
}:
}
拦截器2:
package com.sky.ssm.interceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 测试拦截器1
* @author sk
*
*/
public class HandlerInterceptor2 implements HandlerInterceptor{
//执行Handler完成后执行此方法
//应用场景:统一的异常处理,统一的日志处理
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object handler, Exception arg3)
throws Exception {
System.out.println("HandlerInterceptor2......afterCompletion");
}
//进入Handler方法之后,在返回ModelAndView之前执行
//应用场景从modelAndView对象出发:将公用的模型数据(比如菜单的导航)在这里传到视图,也可以在这里面来统一指定视图
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor2......postHandle");
}
//在进入Handler方法之前执行
//用于身份认证、身份授权、
//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest arg0, HttpServletResponse arg1,
Object handler) throws Exception {
System.out.println("HandlerInterceptor2......preHandle");
//return false表示拦截住,不向下执行
//return true 表示放行
return true;
}
}
3、拦截器的配置,在springmvc.xml中进行配置
3.1、 针对HandlerMapping配置。
如果在某个HandlerMapping中配置拦截器,经过改HandlerMapping映射成功的Handler最终才能使用该拦截器
<bean class="org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping">
<property name="interceptors">
<list>
<ref bean="handlerInterceptor1"/>
<ref bean="handlerInterceptor2"/>
</list>
</property>
</bean>
<bean name="handlerInterceptor1" class="com.sky.ssm.interceptor.HandlerInterceptor1"/>
<bean name="handlerInterceptor2" class="com.sky.ssm.interceptor.HandlerInterceptor2"/>
</beans>
这种方式一般不推荐使用
3.2 、类似全局的拦截器
Springmvc可以配置类似于全局的拦截器,springmvc框架将配置的类似全局的拦截器注入到每个HandlerMapping中
<!-- 类似于全局的拦截器的配置 -->
<mvc:interceptors>
<!-- 多个拦截器,顺序执行 -->
<mvc:interceptor>
<!-- /**:表示拦截所有的url包括子url路径 -->
<!-- /*:表示只拦截最根上的url,不包括子url -->
<mvc:mapping path="/**"/>
<bean class="com.sky.ssm.interceptor.HandlerInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sky.ssm.interceptor.HandlerInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
4、拦截器的测试
测试需求:
测试多个拦截器各个方法执行的时机。
测试一:烂机器1放行,拦截器2放行
HandlerInterceptor1......preHandle
HandlerInterceptor2......preHandle
HandlerInterceptor2......postHandle
HandlerInterceptor1......postHandle
HandlerInterceptor2......afterCompletion
HandlerInterceptor1......afterCompletion
总结:
preHandle方法按顺序执行
postHandle和afterCompletion按拦截器配置的逆向顺序执行。
测试二:拦截器1放行,拦截器2不放行
HandlerInterceptor1......preHandle
HandlerInterceptor2......preHandle
HandlerInterceptor1......afterCompletion
总结:拦截器1放行,拦截器2的preHandle才会执行
拦截器2 preHandle不放行,拦截器2的postHandle和afterCompletion不会执行
只要有一个拦截器不放行,postHandle不会执行
测试三: 拦截器1不放行,拦截器2不放行
HandlerInterceptor1......preHandle
总结:拦截器1不放行,postHandle和afterCompletion不会执行
拦截器1不放行,拦截器2不执行
5、小结
根据测试结果,对拦截器的应用。
比如:统一日志处理拦截器,需要该拦截器preHandle一定放行,且将它放在拦截器链接中第一个位置
比如:登录认证拦截器,放在拦截器链接中第一个位置。权限校验拦截器,放在登录认证拦截器之后(因为登录通过后才校验权限)。
6、拦截器应用(实现登录认证)
6.1、需求
1、用户请求url
2、拦截器进行拦截校验
如果请求的url是公开地址(无需登录,即可访问的url),则放行
如果用户session不存在,跳转到登录页面
如果用户session存在,则放行,继续操作。
6.2、登录认证拦截器的实现
1、登录的controller方法
LoginController.java
package com.sky.ssm.controller;
import javax.servlet.http.HttpSession;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
public class LoginController {
//登录
@RequestMapping("/login")
public String login(HttpSession session,String username,String password) throws Exception{
//调用service进行用户身份验证
//在session中报错用户身份信息
session.setAttribute("username", username);
//重定向商品列表页面
return "redirect:/items/queryItems.action";
}
//退出
@RequestMapping("/logout")
public String logout(HttpSession session) throws Exception{
//清除session
session.invalidate();
//重定向商品列表页面
return "redirect:/items/queryItems.action";
}
}
2、interceptor代码实现
LoginInterceptor.java
package com.sky.ssm.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;
/**
* 登录认证的拦截器
* @author sk
*
*/
public class LoginInterceptor implements HandlerInterceptor{
//执行Handler完成后执行此方法
//应用场景:统一的异常处理,统一的日志处理
@Override
public void afterCompletion(HttpServletRequest arg0,
HttpServletResponse arg1, Object handler, Exception arg3)
throws Exception {
System.out.println("HandlerInterceptor1......afterCompletion");
}
//进入Handler方法之后,在返回ModelAndView之前执行
//应用场景从modelAndView对象出发:将公用的模型数据(比如菜单的导航)在这里传到视图,也可以在这里面来统一指定视图
@Override
public void postHandle(HttpServletRequest arg0, HttpServletResponse response,
Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("HandlerInterceptor1......postHandle");
}
//在进入Handler方法之前执行
//用于身份认证、身份授权、
//比如身份认证,如果认证不通过表示当前用户没有登录,需要此方法拦截不再向下执行
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response,
Object handler) throws Exception {
//首先获取请求的url
String url = request.getRequestURI();
//判断url是否是公开地址(实际使用时要将公开地址配置到配置到文件中)
//这里公开地址是登录提交的地址
if(url.indexOf("login.action") >= 0){
//如果进行登录提交,则放行
return true;
}
//判断session
HttpSession session = request.getSession();
//从session中取得用户的身份信息
String username = (String) session.getAttribute("username");
if(username != null){
//身份信息存在,放行
return true;
}
//执行到这里表示用户身份需要认真,跳转到登录页面
request.getRequestDispatcher("/WEB-INF/jsp/login.jsp").forward(request, response);
//return false表示拦截住,不向下执行
//return true 表示放行
return false;
}
}
3、配置拦截器
<!-- 类似于全局的拦截器的配置 -->
<mvc:interceptors>
<!-- 多个拦截器,顺序执行 -->
<!-- 登录认证拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sky.ssm.interceptor.LoginInterceptor"/>
</mvc:interceptor>
<mvc:interceptor>
<!-- /**:表示拦截所有的url包括子url路径 -->
<!-- /*:表示只拦截最根上的url,不包括子url -->
<mvc:mapping path="/**"/>
<bean class="com.sky.ssm.interceptor.HandlerInterceptor1"/>
</mvc:interceptor>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="com.sky.ssm.interceptor.HandlerInterceptor2"/>
</mvc:interceptor>
</mvc:interceptors>
4、登录页面的编写
login.jsp
<%@ page language="java" contentType="text/html; charset=utf-8"
pageEncoding="utf-8"%>
<%@ taglib uri="http://java.sun.com/jsp/jstl/core" prefix="c" %>
<%@ taglib uri="http://java.sun.com/jsp/jstl/fmt" prefix="fmt" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
<title>用户登录</title>
</head>
<body>
<form action="${pageContext.request.contextPath }/login.action" method="post">
用户账号:<input type="text" name="username"/>
用户密码:<input type="password" name="password"/><br />
<input type="submit" value="登录"/>
</form>
</body>
</html>
项目结构
至此:springmvc的架构入门基本完成,源码可以在我的资源中下载: SpringmvcAddMybatisProjects