SpringMVC拦截器Interceptor

一、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中)的请求进行拒绝;
环境:jdk 1.8 、 spring-webmvc 5.1.5.RELEASE

二、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),继承该抽象类后可以仅仅实现其中的一个方法 ,所以我们日常用的时候一般是继承HandlerInterceptorAdapter,并重写其中一个或多个方法。

三、实现拦截器

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

四、注册拦截器

这里预先生成了@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);
}

}

五、注意事项

  • preHandle 方法,如果返回的是flase,本次请求结束;
  • 本示例基于java类配置,基于xml配同理;

转载:https://www.cnblogs.com/kangoroo/p/7652484.html

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值