Spring MVC拦截器
文章目录
拦截器 - Interceptor
- 拦截器(Interceptor)用于对URL请求进行前置/后置过滤
- Interceptor与Filter用于相似,但实现方式不同
- Interceptor底层就是基于Spring AOP面向切面编程实现
拦截器开发流程
- Maven依赖servlet-api
- 实现HandlerInterceptor接口
- application Context配置过滤地址
沿用上一篇RESTful风格应用的工程
Maven依赖servlet-api
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>4.0.1</version>
<scope>provided</scope> <!--只有在开发编译进行引用,防止与tomcat打包对servlet冲突-->
</dependency>
实现HandlerInterceptor接口
preHandle - 前置执行处理
postHandle - 目标资源已被Spring MVC框架处理(比如在控制器类中内部方法已经return后但并没有产生响应文本之前执行)
afterCompletion - 响应文本已经产生
interceptor.MyInterceptor
package restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class MyInterceptor implements HandlerInterceptor {
@Override
//参数都是引入servlet后的原生对象
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURI() + "准备执行");
//如果return true;请求会被送达给后面的拦截器或控制器,否则直接被阻止响应给客户端
return true;
}
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURI() + "目标处理成功");
}
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURI() + "响应内容已产生");
}
}
applicationContext配置过滤地址
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<bean class="restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
拦截器使用规则
拦截器不受之前配置的将静态资源排除在外影响,只要符合URL的过滤条件都会被拦截器处理
<!--将图片/js/css等静态资源排除在外,可提高执行效率-->
<mvc:default-servlet-handler/>
所以访问网页中的html,一系列js,图片等都会进行处理
排除静态资源,可以列出所有,也可以规范静态资源目录一次性排除
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/**.ico"/>
<mvc:exclude-mapping path="/**.jpg"/>
<mvc:exclude-mapping path="/**.js"/>
<mvc:exclude-mapping path="/**.css"/>
<!-- 规范静态资源目录一次性排除所有静态文件-->
<mvc:exclude-mapping path="/resources/**"/>
<bean class="restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
也可以反过来,只拦截指定URI前缀的所有请求
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/restful/**"/>
<mvc:mapping path="/webapi/**"/>
<bean class="restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
执行顺序
如果项目中存在多个拦截器,前置请求拦截执行按照配置顺序执行,后置响应拦截执行顺序反过来;如果前面拦截器的preHandle return false;后面的拦截器就不会执行,实现阻断器的效果。
开发用户流量拦截器
利用用户访问的URL就可以知道什么商品最受欢迎,用户访问时间知道用户的作息时间推荐相应内容,根据发送的请求中附带的用户环境可以知道用户使用电脑还是手机访问,用的安卓机还是苹果机,地址等等。
利用logback日志组件对用户访问进行管理。
pom.xml引入logback,tomcat部署中增加引用
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
配置logback:
在src/main/resources目录下新建logback.xml文件
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<appender name="console" class="ch.qos.logback.core.ConsoleAppender">
<encoder>
<!--[线程名] 产生日志时间 日志级别 产生日志包.类名{类别太长压缩最大长度} - 日志内容 换行-->
<pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<!--RollingFileAppender生成按天滚动对文件-->
<appender name="accessHistoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<rollingPolicy name="accessHistoryLog" class="ch.qos.logback.core.rolling.TimeBasedFileNamingAndTriggeringPolicy">
<fileNamePattern>文件路径,我用的mac系统可能是文件夹权限的问题产生不了?,用的时候再说,这个说win的:D:/history.%d.log</fileNamePattern>
</rollingPolicy>
<encoder>
<!--[线程名] 产生日志时间 日志级别 产生日志包.类名{类别太长压缩最大长度} - 日志内容 换行-->
<pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<!--最低允许输出debug级别对日志-->
<root level="debug">
<!--按照引用上面对console格式输出-->
<appender-ref ref="console"/>
</root>
<!--引用上面的accessHistoryLog,让AccessHistoryInterceptor产生的日志启动,additivity="false"只向文件中输出不在控制台显示-->
<logger name="restful.interceptor.AccessHistoryInterceptor" level="INFO" additivity="true">
<appender-ref ref="accessHistoryLog"/>
</logger>
</configuration>
applicationContext.xml启用拦截器
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/resources"/>
<bean class="restful.interceptor.AccessHistoryInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
interceptor.AccessHistoryInterceptor拦截器类,访问时生成日志信息
package restful.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AccessHistoryInterceptor implements HandlerInterceptor {
private Logger logger = LoggerFactory.getLogger(AccessHistoryInterceptor.class);
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
StringBuffer log = new StringBuffer();
//用户地址
log.append(request.getRemoteAddr());
log.append("|");
//访问网址
log.append(request.getRequestURL());
log.append("|");
//用户环境
log.append(request.getHeader("user-agent"));
logger.info(log.toString());
return true;
}
}
Spring MVC处理流程
执行链