专栏首页扎心了老铁SpringMVC拦截器Interceptor

SpringMVC拦截器Interceptor

SpringMVC拦截器(Interceptor)实现对每一个请求处理前后进行相关的业务处理,类似与servlet中的Filter。

SpringMVC 中的Interceptor 拦截请求是通过HandlerInterceptor来实现的。

在SpringMVC中定义一个Interceptor非常简单,主要有4种方式:

1)实现Spring的HandlerInterceptor接口;

2)继承实现了HandlerInterceptor接口的类,比如Spring 已经提供的实现了HandlerInterceptor 接口的抽象类HandlerInterceptorAdapter;

3)实现Spring的WebRequestInterceptor接口;

4)继承实现了WebRequestInterceptor的类;

实现了拦截器之后,我们可以通过重写WebMvcConfigurerAdapter的addInterceptors方法来注册自己的拦截器。

我们这里只通过实现HandlerInterceptor接口的方式给出实例。实例中使用拦截器实现两个功能

1)计算每一次请求的处理时间

2)并对特定时间和特定用户(数据在codis中)的请求进行拒绝

 1、HandlerInterceptor接口

public interface HandlerInterceptor {
    boolean preHandle(HttpServletRequest request, 
                      HttpServletResponse response, 
                      Object handler) throws Exception;

    void postHandle(HttpServletRequest request, 
                    HttpServletResponse response, 
                    Object handler, ModelAndView modelAndView) throws Exception;

    void afterCompletion(HttpServletRequest request, 
                         HttpServletResponse response, 
                         Object handler, Exception ex) throws Exception;
}
  • preHandle():预处理回调方法,若方法返回值为true,请求继续(调用下一个拦截器或处理器方法);若方法返回值为false,请求处理流程中断,不会继续调用其他的拦截器或处理器方法,此时需要通过response产生响应;
  • postHandle():后处理回调方法,实现处理器的后处理(但在渲染视图之前),此时可以通过modelAndView对模型数据进行处理或对视图进行处理
  • afterCompletion():整个请求处理完毕回调方法,即在视图渲染完毕时调用

HandlerInterceptor有三个方法需要实现,但大部分时候可能只需要实现其中的一个方法,HandlerInterceptorAdapter是一个实现了HandlerInterceptor的抽象类,它的三个实现方法都为空实现(或者返回true),继承该抽象类后可以仅仅实现其中的一个方法。

2、实现拦截器

package com.xiaoju.dqa.sentinel.monitor.interceptor;


import com.xiaoju.dqa.sentinel.common.client.redis.CodisClient;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.util.Calendar;
import java.util.Set;


public class AuthInterceptor implements HandlerInterceptor {

    protected final Logger logger = LoggerFactory.getLogger(this.getClass());

    @Autowired
    private CodisClient codisClient;

    /*
    *   视图函数执行成功后执行
    * */
    @Override
    public void afterCompletion(HttpServletRequest arg0, HttpServletResponse arg1, Object arg2, Exception arg3)
            throws Exception {
    }

    /*
    *   在视图函数之后执行
    *   本函数的作用:计算处理时间
    * */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        long startTime = (Long) request.getAttribute("startTime");
        request.removeAttribute("startTime");
        logger.info("处理时间: {}", System.currentTimeMillis() - startTime);
    }

    /*
    *   在视图函数之前执行
    *   返回true, 继续执行视图函数
    *   返回false, 终止请求流程
    *   本函数的作用,:拒绝特定时间sentinel:forbidden:hours; 特定用户的sentinel:forbidden:users请求, 并记录startTime
    * */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        boolean going = true;
        long startTime = System.currentTimeMillis();
        request.setAttribute("startTime", startTime);
        Calendar ca = Calendar.getInstance();
        String  currentHour = String.valueOf(ca.get(Calendar.HOUR_OF_DAY));
        try {
            boolean isForbidHour = codisClient.sismember("sentinel:forbidden:hours", currentHour);
            if (isForbidHour) {
                Set<String> forbiddenUsers = codisClient.smembers("sentinel:forbidden:users");
                if (forbiddenUsers != null) {
                    for (Cookie cookie : request.getCookies()) {
                        if("username".equals(cookie.getName()) && forbiddenUsers.contains(cookie.getValue())) {
                            logger.info("[拦截器] 禁止访问. 时间:{}, 用户:{}", currentHour, cookie.getValue());
                            going = false;
                        }
                    }
                }
            }
        } catch (Exception e) {
            logger.info("[拦截器] 有问题", e);
        }
        return going;
    }
}

3、注册拦截器

 这里预先生成了@bean - authInterceptor是为了让AuthInterceptor类中的codisClient的注入成功,否则即使自动注入了codisClient也无法注入成功。

package com.xiaoju.dqa.sentinel.configuration;

import com.xiaoju.dqa.sentinel.monitor.interceptor.AuthInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;


@Configuration
public class WebInterceptorConfig extends WebMvcConfigurerAdapter {

    @Bean
    public AuthInterceptor authInterceptor() {
        return new AuthInterceptor();
    }

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 多个拦截器组成一个拦截器链
        // addPathPatterns 用于添加拦截规则
        // excludePathPatterns 用户排除拦截
        registry.addInterceptor(authInterceptor()).addPathPatterns("/**").excludePathPatterns("/sentinel/monitor/**");
        super.addInterceptors(registry);
    }

}

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • springboot scheduled并发配置

    本文介绍如何使用springboot的sheduled实现任务的定时调度,并将调度的任务实现为并发的方式。 1、定时调度配置scheduled 1)注册定时任务...

    用户1225216
  • springboot与thrift集成实现服务端和客户端

    我们这里用一个简单的小功能来演示一下如何使用springboot集成thrift 这个功能是,判断hdfs路径存在。 1、先解决依赖 <dependencie...

    用户1225216
  • Hadoop通过HCatalog编写Mapreduce任务访问hive库中schema数据

    1、dirver package com.kangaroo.hadoop.drive; import java.util.Map; import java.u...

    用户1225216
  • SpringFramework之mvc controller的单元测试

        项目里面经常会将controller的扫描配置与其它的分开以便于管理开发,但是controller的bean是在webApplicationContex...

    克虏伯
  • MongoDB导入Shapefile数据

    两种解决方案: 一、将整个shapefile转为GeoJSON然后直接导入mongoDB数据库中 首先,将shapefile数据转为WGS84地理坐标,...

    卡尔曼和玻尔兹曼谁曼
  • 注解 springMVC

    web.xml中配置servlet <?xml version="1.0" encoding="UTF-8"?> <web-app xmlns:xsi="htt...

    yawn
  • Spring Cloud(2)——服务提供者

    前言: 本文中的注册中心基于Spring Cloud(1)——服务注册中心,请先了解注册中心的相关知识后再阅读本文。

    会跳舞的机器人
  • Quartz集成Spring 原

    (3):HelloWorldJob.java没有改动,HWTest.java修改如下

    wuweixiang
  • 15.selenium_case03

    hankleo
  • spring-boot-2.0.3之redis缓存实现,不是你想的那样哦!

        小白问小明:“你前面有一个5米深的坑,里面没有水,如果你跳进去后该怎样出来了?”小明:“躺着出来呗,还能怎么出来?”小白:“为什么躺着出来?”小明:“5...

扫码关注云+社区

领取腾讯云代金券