概述
有时候我们需要进行一些预处理和后处理,或者是拦截请求,在请求前后后做一些处理使用Spring MVC框架,那么建议使用HandlerInterceptor,它可以类似于普通bean直接注册到Spring容器中被管理
HandlerInterceptor的三个抽象方法
public interface HandlerInterceptor {
default boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
default void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable ModelAndView modelAndView) throws Exception {
}
default void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, @Nullable Exception ex) throws Exception {
}
}
preHandle
在执行Handler之前(执行业务逻辑之前),根据拦截器链顺序执行
-
每个Interceptor
的调用会依据它的声明顺序依次执行,而且最先执行的都是Interceptor 中的preHandle 方法
- 所以可以在这个方法中进行一些前置
初始化操作或者是对当前请求的一个预处理
, - 也可以在这个方法中进行一些判断来
决定请求是否要继续进行下去
。 - 该方法的返回值是布尔值Boolean 类型的,
- 当它返回为false 时,表示请求结束,后续的Interceptor 和Controller 都不会再执行;
- 当返回值为true 时就会继续调用下一个Interceptor 的preHandle 方法,
如果已经是最后一个Interceptor 的时候就会是调用当前请求的Controller 方法
。
postHandle
在执行Handler成功(执行业务逻辑成功)之后,根据拦截器链倒序执行,如果前面的流程中抛出异常或者请求被拦截则不会执行!
- 在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用
- 在当前请求进行处理之后,也就是Controller 方法调用之后执行,但是它会在DispatcherServlet 进行视图返回渲染之前被调用,
- 所以我们可以在这个方法中
对Controller 处理之后的ModelAndView 对象进行操作
postHandle 方法被调用的方向跟preHandle 是相反的,也就是说先声明的Interceptor 的postHandle 方法反而会后执行
afterCompletion
在请求处理完毕之后执行,无论是否有响应视图,无论有没有通过preHandle,无论有没有抛出异常。只会对此前放行成功(preHandle返回true)的拦截器进行倒序调用
。
- 在当前所属的Interceptor 的preHandle 方法的返回值为true 时才能被调用
- 该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行。
这个方法的主要作用是用于进行资源清理工作的
使用
构建拦截器(HandlerInterceptor )
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.context.SecurityContext;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import com.gildata.gup.domain.User;
import com.gildata.gup.domain.UserEncryptReset;
import com.gildata.gup.repository.UserEncryptResetRepository;
@Component // 不可少
public class xxxStateInterceptor implements HandlerInterceptor { // 必须实现HandlerInterceptor接口
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
// TODO Auto-generated method stub
// ....
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
// TODO Auto-generated method stub
return;
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
// TODO Auto-generated method stub
}
}
注册拦截器(WebMvcConfigurerAdapter )
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import com.gildata.gup.interceptor.PasswordStateInterceptor;
@Configuration // 配置
public class WebConfigfilter extends WebMvcConfigurerAdapter{
@Autowired
private XxxStateInterceptor xxxStateInterceptor ; // 实例化拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// super.addInterceptors(registry);
// 注册自定义的拦截器passwordStateInterceptor
registry.addInterceptor(xxxStateInterceptor)
.addPathPatterns("/api/*") //匹配要过滤的路径
.excludePathPatterns("/api/changeUser/*") //匹配不过滤的路径。/api/changeUser后面的所有接口不能拦截
.excludePathPatterns("/api/getAge", "/api/getName") // /api/getAge也不能拦截,/api/getName这个接口的请求不能拦截
}
}
两个常用方法:
- .addPathPatterns():增加url的拦截路径,“/**”意思是所有请求都要拦截;
- .excludePathPatterns():排除url的拦截路径,如:“/api/getAge”, “/api/getName”:意为这两个接口不做拦截;
注意
springBoot2.0以上 WebMvcConfigurerAdapter 方法过时,有两种替代方案:
- 继承 WebMvcConfigurationSupport 类;
- 实现 WebMvcConfigurer 接口;
- 但是,
继承WebMvcConfigurationSupport会让Spring-boot对mvc的自动配置失效
,所以建议用实现WebMvcConfigurer接口的方式
- 所以上面的注册拦截器更改为:
@Configuration // 配置
public class WebConfigfilter implements WebMvcConfigurer{
@Autowired
private XxxStateInterceptor xxxStateInterceptor ; // 实例化拦截器
@Override
public void addInterceptors(InterceptorRegistry registry) {
// super.addInterceptors(registry);
// 注册自定义的拦截器passwordStateInterceptor
registry.addInterceptor(xxxStateInterceptor)
.addPathPatterns("/api/*") //匹配要过滤的路径
.excludePathPatterns("/api/changeUser/*") //匹配不过滤的路径。/api/changeUser后面的所有接口不能拦截
.excludePathPatterns("/api/getAge", "/api/getName") // /api/getAge也不能拦截,/api/getName这个接口的请求不能拦截
}
}