要学习拦截器,我们先学习两个东西,HandlerInterceptor 和 WebMvcConfigurer。
HandleInterceptor: 在Spring中定义一个Interceptor是非常简单的,主要有两种方式:
第一种:实现HandlerInterceptor 接口,或者是继承实现了HandlerInterceptor 接口的类,例如HandlerInterceptorAdapter;
第二种:实现Spring的WebRequestInterceptor接口,或者继承实现类:WebMvcConfigurerAdapter。
HandlerInterceptorAdapter这个适配器,它有三个方法:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)throws Exception {
return true;
}
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)throws Exception {
}
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)throws Exception {
}
- preHandle() 该方法在处理请求之前进行调用,就是在执行Controller的任务之前。如果返回true就继续往下执行,返回false就放弃执行。可以进行编码、安全控制,用户是否登录等处理;
- postHandle() 该方法将在请求处理之后,DispatcherServlet进行视图返回渲染之前进行调用,可以在这个方法中对Controller 处理之后的ModelAndView 对象进行操作;
- afterCompletion该方法也是需要当前对应的Interceptor的preHandle方法的返回值为true时才会执行,该方法将在整个请求结束之后,也就是在DispatcherServlet 渲染了对应的视图之后执行,用于进行资源清理;可以根据ex是否为null判断是否发生了异常,进行日志记录;
如果基于XML配置使用Spring MVC,可以利用SimpleUrlHandlerMapping、BeanNameUrlHandlerMapping进行Url映射(相当于struts的path映射)和拦截请求(注入interceptors)。如果基于注解使用Spring MVC,可以使用DefaultAnnotationHandlerMapping注入interceptors。注意无论基于XML还是基于注解,HandlerMapping Bean都是需要在XML中配置的。
xml文件配置拦截器:
<!--配置拦截器, 多个拦截器,顺序执行 -->
<mvc:interceptors>
<!-- 进入和退出 web会话的时候, 记录相关请求信息-->
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**" />
<beans:bean class="com.daling.hawk.common.platform.aop.LogInterceptor" />
</mvc:interceptor>
<!-- 用户登录状态检查, 定义不需要登陆检查的URL-->
<mvc:interceptor>
<mvc:mapping path="/**" />
<beans:bean class="com.daling.hawk.common.platform.aop.LoginValidateInterceptor">
<beans:property name="uncheckedUrlPrefix">
<beans:list>
<beans:value>inner/</beans:value>
<beans:value>openapi/</beans:value>
<beans:value>outer/</beans:value>
</beans:list>
</beans:property>
<beans:property name="uncheckedUrls">
<beans:list>
<beans:value>main/login.do</beans:value>
</beans:list>
</beans:property>
</beans:bean>
</mvc:interceptor>
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**" />
<beans:bean class="com.daling.hawk.common.platform.aop.JdbcUtilsInterceptor" />
</mvc:interceptor>
<mvc:interceptor>
<!-- 匹配的是url路径, 如果不配置或/**,将拦截所有的Controller -->
<mvc:mapping path="/**" />
<beans:ref bean="localeChangeInterceptor" />
</mvc:interceptor>
</mvc:interceptors>
LoginValidateInterceptor 负责检查用户是否登录,如果未登录,则跳到登录页面
public class LoginValidateInterceptor extends HandlerInterceptorAdapter {
static Logger log = LoggerFactory.getLogger(LoginValidateInterceptor.class);
// 不需要检查的URL前缀
private List<String> uncheckedUrlPrefix;
// 不需要检查的URL
private List<String> uncheckedUrls;
// get/set方法省略
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object target) throws Exception {
String realUri = ******;//需要检查的请求路径
//获取不包含应用名字的URI的路径, 并去掉最前面的"/"
//如路径为http://localhost:8080/appName/user/list.do, 得到的值为"user/list.do",其中 appNames为应用的名字
// 如果配置了不需要检查的url前缀,而且是以该前缀为开头,则通过
if (uncheckedUrlPrefix != null && !uncheckedUrlPrefix.isEmpty()) {
for (String s : uncheckedUrlPrefix) {
if (realUri.startsWith(s.trim())) {
log.info("REQ_URL:[{}] matchs UNCHK_URL:[{}]", realUri, s);
return true;
}
}
}
if (uncheckedUrls != null && !uncheckedUrls.isEmpty() && uncheckedUrls.contains(realUri)) {
// 不需要检查
log.info("REQ_URL:[{}] is UNCHK_URL", realUri);
return true;
}
log.info("start try fetch user info...");
DLoginUser dLoginUser = Users.getUser(request);
if (dLoginUser == null || !dLoginUser.isLogined()) {
// 未登录,转向登录页面!
log.info("User Not Logined...");
response.setContentType("application/json;charset=UTF-8");
response.setCharacterEncoding("UTF-8");
response.setHeader("relogin", "t");
return false;
}
return true;
}
}
WebMvcConfigurerAdapter:对Spring进行配置
@Configuration
public class WebSecurityConfig extends WebMvcConfigurerAdapter {
@Override
public void addInterceptors(InterceptorRegistry registry) {
/*调用我们创建的SessionInterceptor。
* addPathPatterns("/api/**)的意思是这个链接下的都要进入到SessionInterceptor里面去执行
* excludePathPatterns("/login")的意思是login的url可以不用进入到SessionInterceptor中,直接
* 放过执行。
* */
SessionInterceptor sessionInterceptor=new SessionInterceptor();
registry.addInterceptor(sessionInterceptor).addPathPatterns("/api/**")
.excludePathPatterns("/login","/verify");
/* 注意:如果像下面代码那样写是不可以的。这样等于是创建了多个Interceptor。而不是只有一个Interceptor
* /
// registry.addInterceptor(sessionInterceptor).excludePathPatterns("/login");
// registry.addInterceptor(sessionInterceptor).excludePathPatterns("/verify");
}
}