SpringMVC拦截器

本文涉及的产品
日志服务 SLS,月写入数据量 50GB 1个月
简介: SpringMVC拦截器

一.拦截器入门及使用技巧


Interceptor拦截器入门


拦截器是SpringMVC里的一个高级组件,拦截器英文单词为Interceptor。他的作用和我之前学习过的J2EE中的过滤器filter有非常相似的地方,但是实现的方式不同。。拦截器的主要作用是用于对URL请求进行前置/后置过滤。 interceptor底层就是基于SpringAOP面向切面编程实现。 与SpringAOP的环绕通知非常的像。


下面来了解一下拦截器的开发流程:

1.maven依赖导入servlet-api

2. 实现HandlerInterceptor接口

3. applicationContext配置过滤地址


下面对这几个步骤进行演示:

1.用上一节使用过的restful的项目来进行演示,首先要打开pom.xml导入相关的依赖,如下:


    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.13</version>
        </dependency>
        <!--jackson的核心包-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.13.2</version>
        </dependency>
        <!--jackson数据绑定包-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.13.2</version>
        </dependency>
        <!--jackson注解的包-->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.13.2</version>
        </dependency>
            <!--servlet-api的依赖-->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>javax.servlet-api</artifactId>
            <version>4.0.1</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>


一般把servlet-api依赖的scope设置为provided,因为tomcat里面会有这个依赖,避免冲突。


2.新增加一个包,名为interceptor包,在这个包中出现的所有类都是拦截器,然后再这个包中再创建一个MyInterceptor的类。同时这个类要实现一个接口HandlerInterceptor,这是拦截器必须要实现的接口。这个接口里面包含了3个方法需要我们实现。这3个方法分别是preHandle ,postHandle 和afterCompletion,这3个方法对应了执行的3个不同时机。


package com.haiexijun.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
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        System.out.println(request.getRequestURL()+"---准备执行");
        return true;
    }
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
        System.out.println(request.getRequestURL()+"---请求处理成功");
    }
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        System.out.println(request.getRequestURL()+"---响应内容已经产生");
    }
}


preHandle是前置执行处理,就是在我们的一个请求产生了以后,还没有进controller之前,就会先执行preHandle,对这个请求进行预处理。方法会返回一个boolean类型,如果返回true,请求就会被送达给后面的拦截器或者是控制器,如果返回false的话,那当前的请求就会被阻止,直接产生响应返回客户端了。

postHandle 是目标资源已经被SpringMVC框架处理时执行。举个例子,如果在controller中,postHandle执行时机就是在内部的方法return了以后,但是并没有产生响应文本之前执行的。

afterCompletion是响应文本已经产生后执行。


3.在applicationContext中添加如下的配置


    <mvc:interceptors>
        <mvc:interceptor>
            <!--对所有的请求进行拦截,注意是** ,两个*哦-->
            <mvc:mapping path="/**"/>
            <bean class="com.haiexijun.restful.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>


上面代码,拦截器是配置好了,但是,会出现一个问题。就是当我们访问一个页面时(这里我新建一个页面client.html,代码和index.html一样)。当我们访问client.html这个页面时,会发现请求的所有资源,如js和网页图标,都会触发拦截器。如下图:


20930da3b1a54344b14665591ff39b4f.png


但我们并不希望,这些静态资源被拦截处理。需要将这些不需要的URL排除在外。配置如下:


    <mvc:interceptors>
        <mvc:interceptor>
            <!--对所有的请求进行拦截,注意是** ,两个*哦-->
            <mvc:mapping path="/**"/>
            <!--排除静态资源-->
            <mvc:exclude-mapping path="/**.ico"/>
            <mvc:exclude-mapping path="/**.jpg"/>
            <mvc:exclude-mapping path="/**.gif"/>
            <mvc:exclude-mapping path="/**.js"/>
            <mvc:exclude-mapping path="/**.css"/>
            <bean class="com.haiexijun.restful.interceptor.MyInterceptor"/>
        </mvc:interceptor>
    </mvc:interceptors>


再次运行,发现,那些静态资源就不会被拦截了。


212da3efa4c740dba2d97621cebb6001.png

但上面我们这种配置还是有点麻烦,毕竟静态资源的种类也是非常多的,在实际开发中我们可以把这些资源放在webapp下的新建的一个resources目录下,resources下面创建其他目录如js目录,CSS目录等来存放放静态资源,我们就只要把/resource目录排除在外就行了。


多拦截器的执行顺序:


0cc608ba6a49425b9adb55f079028c62.png


二.案例—开发"用户流量"拦截器


本节,要开发一个用户流量拦截器,在前面虽然学习了拦截器的基本使用,但是在项目中到底什么时候使用拦截器还不太清除。在这里,就以这个经典的案例来学习它的用法。


案例的需求就是,当用户在访问我们的应用的时候,自动对用户的一些底层信息进行收集。比如说访问的时间,访问的网址,用户用的是什么浏览器什么系统或者什么手机访问的,用户的IP地址是什么。别看这些简单的数据,如果将他们综合起来,就能得到很多有用的信息。比如说,我们做的是一个电商网站,那么根据URL我们就能分析出来,什么商品是最受用户欢迎的。在根据用户访问的时间,我们就知道到底用户是夜猫子呢,还是白天上班时打开我们的网站。同时,我们这个案例也将学习到如何使用logback日志组件,来对用户数据进行日志存储。


下面就来实现这个需求:

还是在之前用的restful工程下来完成这个案例,打开interceptor这个包,在这个包下额外再创建一个类,叫AccessHistoryInterceptor,然后实现HandlerInterceptor接口。因为是所有请求在处理之前要被AccessHistoryInterceptor这个拦截器所记录,所以这属于一个前置处理,因此我们要实现preHandle这个方法,因为不涉及到请求阻断,return true。


package com.haiexijun.restful.interceptor;
import org.slf4j.LoggerFactory;
import org.springframework.web.servlet.HandlerInterceptor;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.logging.Logger;
public class AccessHistoryInterceptor implements HandlerInterceptor {
    private Logger 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;
    }
}


上面说到,我们一般把用户这些信息放在日志里面存储,所以我们还要再导入logback的依赖,springmvc就能使用logback默认打印最低级别的系统日志了。


        <dependency>
            <groupId>ch.qos.logback</groupId>
            <artifactId>logback-classic</artifactId>
            <version>1.2.3</version>
        </dependency>

6f0a27600ac24e8e8f58e2429e8454b4.png


但是只有这些系统日志是远远不够的,我们就要对logback的配置文件进行设置,同时也要在拦截器中对用户的数据进行登记。


我们打开src,在resource目录下,额外地创建一个新的文件,文件名固定为logback.xml,这是logback的核心配置文件,必需这样命名。

在这个文件中添加如下的配置:


<?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>
    <root level="debug">
    <!--生成按天滚动的日志文件-->
    <appender name="accessHistoryLog" class="ch.qos.logback.core.rolling.RollingFileAppender">
    <!--日志文件存放地址-->
    <rollingPolic clsss="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
    <fileNamePattern>d:/logs/history.%d.log</fileNamePattern>
  </rollingPolic>
   <encoder>
        <pattern>[%thread] %d %level %logger{10} - %msg%n</pattern>
     </encoder>
    </appender>
        <appender-ref ref="console"/>
    </root>
    <loger name="com.haiexijun.restful.interceptor.AccessHistoryInterceptor" level="INFO" additivity="false">
    <<appender-ref ref="accessHistoryLog"/>
    </logger>
</configuration>
相关文章
|
前端开发 Java Spring
56SpringMVC - 拦截器
56SpringMVC - 拦截器
37 0
|
6月前
|
XML Java 数据格式
|
6月前
|
JSON 算法 Java
SpringMVC(五)【拦截器】
SpringMVC(五)【拦截器】
|
7月前
|
数据采集 监控 前端开发
SpringMVC 拦截器
SpringMVC 拦截器
59 0
|
7月前
|
数据安全/隐私保护
SpringMVC拦截器
SpringMVC拦截器
62 0
|
7月前
springMVC之拦截器
springMVC之拦截器
|
Java
SpringMVC-拦截器
SpringMVC-拦截器
60 0
SpringMVC-拦截器
|
前端开发 JavaScript Java
SpringMVC 中的拦截器
SpringMVC 中的拦截器
|
XML 数据格式 容器
springmvc之拦截器
springmvc之拦截器
114 2