Spring MVC-拦截器
一、拦截器概述
1、 什么是拦截器?
Spring MVC中的拦截器(Interceptor)类似于Servlet中的过滤器(Filter),它主要用于拦截用户请求并作相应的处理。例如通过拦截器可以进行权限验证、记录请求信息的日志、判断用户是否登录等。
2、拦截器和过滤器的区别
①相似之处
a、都有优先处理请求的权利,都可以决定是否将请求转移到请求的实际处理的控制器处。
b、都可以对请求或者会话当中的数据进行加工。
②不同之处
a、 拦截器可以做前置处理也可以做后置处理,还可以进行完成处理,控制的 更加细致,而过滤器只负责前面的过滤行为而已。
b、 过滤器优先执行,还是拦截器优先呢?----------过滤器优先。
c、过滤器是servlet规范里面的组件。
d、 拦截器都是框架自己而外添加的组件。
3、通常拦截器类的定义方式:
#要使用Spring MVC中的拦截器,就需要对拦截器类进行定义和配置。
①通过实现HandlerInterceptor接口,或继承HandlerInterceptor接口的实现类(如HandlerInterceptorAdapter)来定义。
②通过实现WebRequestInterceptor接口,或继承WebRequestInterceptor接口的实现类来定义。
③以继承HandlerInterceptorAdapter接口方式为例:(3个方法)
a、preHandle() 方法:该方法会在控制器方法前执行,其返回值表示是否中断后续操作。当其返回值为true时,表示继续向下执行;当其返回值为false时,会中断后续的所有操作(包括调用下一个拦截器和控制器类中的方法执行等)
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println("preHandle");
return true;
}
b、postHandle()方法:该方法会在控制器方法调用之后,且解析视图之前执行。可以通过此方法对请求域中的模型和视图做出进一步的修改。
/**
* 只有指定了对应Handler中的方法之后 才执行!
* @param modelAndView
* @throws Exception
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println("postHandle");
}
c、afterCompletion()方法:该方法会在整个请求完成,即视图渲染结束之后执行,可以通过此方法实现一些资源清理、记录日志信息等工作。
/**
* 只要当前拦截器中的preHandle返回true则此方法必须执行!
* @param handler
* @param ex
* @throws Exception
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println("afterCompletion");
}
二、拦截器的配置
1、配置项
开发拦截器就像开发servlet或者filter一样,都需要在配置文件进行配置,配置代码如下:
<!--配置自定义的拦截器-->
<mvc:interceptors>
<!-- 拦截器1 -->
<mvc:interceptor>
<!--配置拦截器的作用路径-->
<mvc:mapping path="/shopadmin/**" />
<!--拦截实现类-->
<bean id="ShopInterceptor"
class="com.imooc.o2o.interceptor.shopadmin.ShopLoginInterceptor" />
</mvc:interceptor>
<!-- 拦截器2 -->
<mvc:interceptor>
<mvc:mapping path="/shopadmin/**" />
<!-- 不拦截页面-->
<mvc:exclude-mapping path="/shopadmin/shoplist" />
<mvc:exclude-mapping path="/shopadmin/getshoplist" />
<bean id="ShopPermissionInterceptor"
class="com.imooc.o2o.interceptor.shopadmin.ShopPermissionInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
上面的代码中,mvc:interceptors元素用于配置一组拦截器,基子元素中定义的是全局拦截器,它会拦截所有的请求;而mvc:interceptor元素中定义的是指定路径的拦截器,它会对指定路径下的请求生效。mvc:interceptor元素的子元素mvc:mapping用于配置拦截器作用的路径,该路径在其属性path 中定义。如上述代码中 path 的属性值“/**” 表示拦截所有路径,“/hello” 表示拦截所有以 “/hello” 结尾的路径。如果在请求路径中包含不需要拦截的内容,还可以通过mvc:exclude-mapping元素进行配置。
【注意】:mvc:interceptor中的子元素必须按照上述代码中的配置顺序进行编写,即mvc:mapping mvc:exclude-mapping ,否则文件会报错。
2. 拦截器的执行流程
a、程序先执行preHandle()方法,如果该方法的返回值为true,则程序会继续向下执行处理器中的方法,否则将不再向下执行。
b、在业务处理器(即控制器Controller类)处理完请求后,会执行postHandle()方法,然后会通过DispatcherServlet向客户端返回响应。
c、在DispatcherServlet处理完请求后,才会执行afterCompletion()方法。
三、用户拦截及操作权限拦截-实例
1、配置添加在spring-web.xml(5权限拦截)
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/mvc
http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd">
<!-- 配置SpringMVC -->
<!-- 1.开启SpringMVC注解模式 -->
<mvc:annotation-driven />
<!-- 2.静态资源默认servlet配置 (1)加入对静态资源的处理:js,gif,png (2)允许使用"/"做整体映射 -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<mvc:default-servlet-handler />
<!-- 3.定义视图解析器 -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/html/"></property>
<property name="suffix" value=".html"></property>
</bean>
<!-- 文件上传解析器 -->
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="defaultEncoding" value="utf-8"></property>
<!-- 1024 * 1024 * 20 = 20M -->
<property name="maxUploadSize" value="20971520"></property>
<property name="maxInMemorySize" value="20971520"></property>
</bean>
<!-- 4.扫描web相关的bean -->
<context:component-scan base-package="com.imooc.o2o.web" />
<!-- 5.权限拦截器 -->
<mvc:interceptors>
<!-- 校验是否已登录了店家管理系统的拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/shopadmin/**" />
<bean id="ShopInterceptor"
class="com.imooc.o2o.interceptor.shopadmin.ShopLoginInterceptor" />
</mvc:interceptor>
<!-- 校验是否对该店铺有操作权限的拦截器 -->
<mvc:interceptor>
<mvc:mapping path="/shopadmin/**" />
<!-- shoplist page -->
<mvc:exclude-mapping path="/shopadmin/shoplist" />
<mvc:exclude-mapping path="/shopadmin/getshoplist" />
<!-- shopregister page -->
<mvc:exclude-mapping path="/shopadmin/getshopinitinfo" />
<mvc:exclude-mapping path="/shopadmin/registershop" />
<mvc:exclude-mapping path="/shopadmin/shopoperation" />
<!-- shopmanage page -->
<mvc:exclude-mapping path="/shopadmin/shopmanagement" />
<mvc:exclude-mapping path="/shopadmin/getshopmanagementinfo" />
<bean id="ShopPermissionInterceptor"
class="com.imooc.o2o.interceptor.shopadmin.ShopPermissionInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
</beans>
2、实现类
①用户
package com.imooc.o2o.interceptor.shopadmin;
import java.io.PrintWriter;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.imooc.o2o.entity.PersonInfo;
/**
* 店家管理系统登录验证拦截器
*
* @author xiangze
*
*/
public class ShopLoginInterceptor extends HandlerInterceptorAdapter {
/**
* 主要做事前拦截,即用户操作发生前,改写preHandle里的逻辑,进行拦截
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 从session中取出用户信息来
Object userObj = request.getSession().getAttribute("user");
if (userObj != null) {
// 若用户信息不为空则将session里的用户信息转换成PersonInfo实体类对象
PersonInfo user = (PersonInfo) userObj;
// 做空值判断,确保userId不为空并且该帐号的可用状态为1,并且用户类型为店家
if (user != null && user.getUserId() != null && user.getUserId() > 0 && user.getEnableStatus() == 1)
// 若通过验证则返回true,拦截器返回true之后,用户接下来的操作得以正常执行
return true;
}
// 若不满足登录验证,则直接跳转到帐号登录页面
PrintWriter out = response.getWriter();
out.println("<html>");
out.println("<script>");
out.println("window.open ('" + request.getContextPath() + "/local/login?usertype=2','_self')");
out.println("</script>");
out.println("</html>");
return false;
}
}
②操作权限
package com.imooc.o2o.interceptor.shopadmin;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
import com.imooc.o2o.entity.Shop;
/**
* 店家管理系统操作验证拦截器
*
* @author xiangze
*
*/
public class ShopPermissionInterceptor extends HandlerInterceptorAdapter {
/**
* 主要做事前拦截,即用户操作发生前,改写preHandle里的逻辑,进行用户操作权限的拦截
*
* @author xiangze
*
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// 从session中获取当前选择的店铺
Shop currentShop = (Shop) request.getSession().getAttribute("currentShop");
@SuppressWarnings("unchecked")
// 从session中获取当前用户可操作的店铺列表
List<Shop> shopList = (List<Shop>) request.getSession().getAttribute("shopList");
// 非空判断
if (currentShop != null && shopList != null) {
// 遍历可操作的店铺列表
for (Shop shop : shopList) {
// 如果当前店铺在可操作的列表里则返回true,进行接下来的用户操作
if (shop.getShopId() == currentShop.getShopId()) {
return true;
}
}
}
// 若不满足拦截器的验证则返回false,终止用户操作的执行
return false;
}
}