前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >SpringMVC拦截器Interceptor

SpringMVC拦截器Interceptor

作者头像
用户1225216
发布2018-03-05 14:42:27
9590
发布2018-03-05 14:42:27
举报
文章被收录于专栏:扎心了老铁扎心了老铁

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);
    }

}

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2017-10-11 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档