文章目录
SpringMVC拦截器
一、拦截器-Interceptor
拦截器(Interceptor)用于对URL请求进行前置/后置过滤。
Interceptor与Filter用途相似,但实现方式不同。
Interceptor为SpringMVC的标准组件。
Filter为J2EE的标准组件。
Interceptor底层就是基于Spring AOP面向切面编程实现。
1、HandlerInterceptor接口
preHandle - 前置执行处理
postHandle - 目标资源已被SpringMVC框架处理
afterCompletion - 响应文本已经产生
2、拦截器开发流程
Maven依赖servlet-api
实现HandlerInterceptor接口
applicationContext配置过滤地址
新建工程interceptor并把RESTful风格的应用部分的restfull工程源代码复制到当前工程
打开pom.xml引入servlet依赖
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.1.0</version>
<scope>provided</scope>
<!--<scope>provided</scope>含义是只有开发编译才会引用,
项目最终运行环境tomcat会自带servlet-api jar包,如果不引用该属性,
可能会出现jar包版本冲突等问题-->
</dependency>
在com.ql.restful.interceptor包下创建MyInterceptor类
package com.ql.restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURL()+"准备执行");
return true;
}
@Override
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURL()+"-目标处理成功");
}
@Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURL()+"-响应内容已产生");
}
}
修改com.ql.restful.controller包下RestfulController类的findPersons方法
@GetMapping("/persons")
public List<Person> findPersons(){
List list = new ArrayList();
Person person1 = new Person();
person1.setName("lily");
person1.setAge(23);
person1.setBirthday(new Date());
list.add(person1);
Person person2 = new Person();
person2.setName("smith");
person2.setAge(22);
person2.setBirthday(new Date());
list.add(person2);
System.out.println("RestfulController.findPersons() - return list");
return list;
在applicationContext.xml中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!--<mvc:mapping path="/**"/>-->
<!--对指定路径进行拦截-->
<mvc:mapping path="/restful/**"/>
<!--对指定类型资源不拦截-->
<mvc:exclude-mapping path="/**.js"/>
<mvc:exclude-mapping path="/**.css"/>
<mvc:exclude-mapping path="/**.ico"/>
<!--对指定路径下所有资源不进行拦截-->
<mvc:exclude-mapping path="/resources/**"/>
<bean class="com.ql.restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
运行工程,在浏览器地址栏中输入http://localhost:8080/restful/persons,控制台中会输出
3、多Interceptor执行顺序
有多个拦截器时按照配置的顺序依次访问执行。
在com.ql.restful.interceptor目录下再创建一个拦截器MyInterceptor1
package com.ql.restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor1 implements HandlerInterceptor {
@Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURL()+"准备执行1");
return true;
}
@Override
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURL()+"-目标处理成功1");
}
@Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURL()+"-响应内容已产生1");
}
}
然后在applicationContext.xml中配置拦截器
<mvc:interceptors>
<mvc:interceptor>
<!--<mvc:mapping path="/**"/>-->
<!--对指定路径进行拦截-->
<mvc:mapping path="/restful/**"/>
<!--对指定类型资源不拦截-->
<mvc:exclude-mapping path="/**.js"/>
<mvc:exclude-mapping path="/**.css"/>
<mvc:exclude-mapping path="/**.ico"/>
<!--对指定路径下所有资源不进行拦截-->
<mvc:exclude-mapping path="/resources/**"/>
<bean class="com.ql.restful.interceptor.MyInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
<mvc:interceptors>
<mvc:interceptor>
<!--<mvc:mapping path="/**"/>-->
<!--对指定路径进行拦截-->
<mvc:mapping path="/restful/**"/>
<!--对指定类型资源不拦截-->
<mvc:exclude-mapping path="/**.js"/>
<mvc:exclude-mapping path="/**.css"/>
<mvc:exclude-mapping path="/**.ico"/>
<!--对指定路径下所有资源不进行拦截-->
<mvc:exclude-mapping path="/resources/**"/>
<bean class="com.ql.restful.interceptor.MyInterceptor1"/>
</mvc:interceptor>
</mvc:interceptors>
运行工程,在浏览器中访问http://localhost:8080/restful/persons控制台输出为
4、preHandle返回值
拦截器中preHandle方法返回boolean值,返回true则请求依次向后传递,如果返回false请求会被中断。
修改com.ql.restful.interceptor包下的MyInterceptor拦截器
package com.ql.restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
public class MyInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler) throws Exception {
System.out.println(request.getRequestURL()+"准备执行");
response.setContentType("text/html;charset=utf-8");
response.getWriter().print("请求被拦截");
return false;
}
@Override
public void postHandle(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
System.out.println(request.getRequestURL()+"-目标处理成功");
}
@Override
public void afterCompletion(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response, Object handler, Exception ex) throws Exception {
System.out.println(request.getRequestURL()+"-响应内容已产生");
}
}
运行项目浏览器中访问http://localhost:8080/restful/persons响应结果为
控制台中也只输出了preHandle中的打印语句内容。
二、开发“用户流量”拦截器
打开上文的interceptor项目。
在com.ql.restful.interceptor包下新建类为AccessHistoryInterceptor
package com.ql.restful.interceptor;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
public class AccessHistoryInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
return true;
}
}
在pom.xml文件,引入Logback组件
<!--Logback日志输出组件-->
<dependency>
<groupId>ch.qos.logback</groupId>
<artifactId>logback-classic</artifactId>
<version>1.2.3</version>
</dependency>
然后在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>
<!--生成按天滚动的日志文件-->
<appender name="accessHistoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
<!--滚动策略-->
<!--TimeBasedRollingPolicy按照时间进行滚动-->
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
<!--配置日志文件存储路径,%d为当天日期-->
<fileNamePattern>d:/logs/history.%d.log</fileNamePattern>
</rollingPolicy>
<encoder>
<pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
</encoder>
</appender>
<!--
日志输出级别(优先级高到低):
error: 错误 - 系统的故障日志
warn: 警告 - 存在风险或使用不当的日志
info: 一般性消息
debug: 程序内部用于调试信息
trace: 程序运行的跟踪信息
-->
<root level="debug">
<appender-ref ref="console"/>
</root>
<!--AccessHistoryInterceptor类中产生的日志都会使用当前标签所描述规则
additivity叠加的意思,若值为true,则当前类的日志也会在控制台中输出,
若值为false,则只会在设置的文件中输出
-->
<logger name="com.ql.restful.interceptor.AccessHistoryInterceptor"
level="INFO" additivity="false">
<appender-ref ref="accessHistoryLog"/>
</logger>
</configuration>
修改AccessHistoryInterceptor拦截器类,编写获取日志代码
package com.ql.restful.interceptor;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
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 {
StringBuilder log = new StringBuilder();
log.append(request.getRemoteAddr());//IP地址
log.append("|");
log.append(request.getRequestURL());//访问地址
log.append("|");
log.append(request.getHeader("user-agent"));//访问客户端信息(操作系统、浏览器等)
logger.info(log.toString());
return true;
}
}
在applicationContext.xml中添加拦截器配置
<mvc:interceptors>
<mvc:interceptor>
<mvc:mapping path="/**"/>
<mvc:exclude-mapping path="/resources/**"/>
<bean class="com.ql.restful.interceptor.AccessHistoryInterceptor"/>
</mvc:interceptor>
</mvc:interceptors>
运行项目,在浏览器中访问http://localhost:8080/client.html并测试相关按钮,在D:\logs目录里生成相应的日志文件
打开日志文件,可以看看获取的日志内容。