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个方法分别是preHandlepostHandleafterCompletion,这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和网页图标,都会触发拦截器。如下图:
在这里插入图片描述
但我们并不希望,这些静态资源被拦截处理。需要将这些不需要的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>

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

多拦截器的执行顺序:
在这里插入图片描述

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

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

案例的需求就是,当用户在访问我们的应用的时候,自动对用户的一些底层信息进行收集。比如说访问的时间,访问的网址,用户用的是什么浏览器什么系统或者什么手机访问的,用户的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>

在这里插入图片描述
但是只有这些系统日志是远远不够的,我们就要对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>
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

害恶细君

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值