1.SpringMVC拦截器工作原理
如果要实现SpringMVC拦截器,就需要实现HandlerInterceptor接口:
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
//handle:被拦截的请求的目标对象
return true;
//这个返回值:表示我们是否需要将当前的请求拦截下来 false:请求拦截 true请求会被执行
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { }
//modelAndView 参数来改变显示的视图或者发往视图的方法modelAndView.setViewName();
default void afterCompletion(HttpServletResquest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { }}
有时我们需要其中的某个方法,并实现其他的方法有些冗余,这时Spring提供适配器
(HandlerInterceptorAdapter)的方法,继承HandlerInterceptorAdapter可以任意实现自己需要的方法。
三个方法执行的顺序:
preHandle(),在Controller执行前执行,比如进行数据校验
postHandle(),在Controller执行完后,但没有进行ModelAndView渲染时,执行。
afterCompletion,在ModelAndView渲染完后执行。
2.添加SpringMVC拦截器
2.1编写拦截器
package com.intercepter;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* Created on 2017/8/17.
*/
public class loginCtrl implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, Object o) throws Exception {
System.out.println(getClass().getName()+" preHandle");
return true;
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
System.out.println(getClass().getName()+" postHandle");
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse
httpServletResponse, Object o, Exception e) throws Exception {
System.out.println(getClass().getName()+" afterCompletion");
}
}
2.2编写控制器
@Controller
public class LoginCtrl {
//..
}
2.3将控制器和拦截器注册成Bean
先按照简单的<bean>标签来注册,后续会介绍利用JavaConfig配置和注解配置
<bean class="xxx.ClassName"/>
2.4在SpringMVC配置文件中配置拦截器
HandlerMapping将请求映射为HandlerExecutionChain对象,而该对象包含一个Handler(处理器)和多个
Handler-Interceptor(拦截器)。可想而知,需要在HandlerMapping中配置HandlerInterceptor,提倡使用
下面这中方式:
<bean
class="org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping">
<mvc:interceptors>
<mvc:interceptor>
<!--
/**的意思是所有文件夹及里面的子文件夹
/*是所有文件夹,不含子文件夹
/是web项目的根目录
-->
<mvc:mapping path="/**" />
<!-- 需排除拦截的地址 -->
<!-- <mvc:exclude-mapping path="/userController/login"/> -->
<bean id="loginCtrl" class="com.loginCtrl"></bean> <!--这个类就是我们自定
义的Interceptor -->
</mvc:interceptor>
<!-- 当设置多个拦截器时,先按顺序调用preHandle方法,然后逆序调用每个拦截器的
postHandle和afterCompletion方法 -->
</mvc:interceptors>
3:Filter工作原理
HandlerInterceptor必须基于SpringMVC环境下才能使用,是有局限性的。所以推荐使用符合Servlet规范的Filter,它是最通用,而且是最先使用的。Filter对请求进行预处理,对响应进行后处理。可以依次定义多个Filter,它们会形成FilterChain,按照栈模型的方式,依次执行。了解下Filter的内部结构:
public interface Filter {
void init(FilterConfig filterconfig) throws ServletException;
void doFilter(ServletRequest request, ServletResponse response,
FilterChain filterChain) throws ServletException, IOException;
void destory();
}
从代码中可见,Filter,FilterConfig,FilterChain是实现过滤器的关键。
FilterConfig的内部实现如下:
public interface FilterConfig {
String getFilterName(); //获取FilterName
String getInitParameter(String name); //获取初始化的参数值
Enumeration<String> getInitParameterNames(); //通过枚举获取参数
String getServletContext(); //获取Filter所属的上下文
从代码中可见,Filter,FilterConfig,FilterChain是实现过滤器的关键。
该接口用于init(FilterConfig filterConfig)方法中,获取web.xml中Filter的配置。可以在filter标签中初始化变量,然后通过filterConfig来获取。可以理解成,web.xml中某个Filter是对应的FilterConfig的实例对象
init()方法,由web容器来调用,仅初始化一次,初始化Filter。
doFilter()方法,调用filterChain.doFilter(req, res)对请求或响应进行处理。
destory()方法,由web容器来调用,仅初始化一次,通常用做释放资源。
4:添加Filter
servlet3.0开始支持注解开发了,这里先介绍用xm配置Filter,这里简单描述添加步骤
4.1编写自己的Filter实现Filter中的接口
public class MyFilter implements Filter {
//init, doFilter, destory实现
}
4.2:在web.xml中注册Filter并设置映射路径
filter>
<!--类似于配置Servlet,需要class位置,该class的代号 -->
<filter-name>filterName</filter-name>
<filter-class></filter-class>
<!-- 可初始化参数-->
<init-param>
</init-param>
<!--允许多个初始化多个参数 -->
<init-param>
</init-param>
</filter>
<filter-mapping>
<filter-name>filterName</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>