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

  

最新文章

  1. HTML5资料
  2. MySQL中函数CONCAT及GROUP_CONCAT
  3. 【python】遍历类的所有成员
  4. Java for LintCode 链表插入排序
  5. HDU-1241 Oil Deposits (DFS)
  6. AIX系统上压缩与解压文件
  7. Roy the Robber
  8. TFT ST7735的Netduino驱动
  9. display与visibility的使用(区别)
  10. 在实现从excel中读取数据作为接口参数遇到的问题
  11. 解决Oracle登录时出现无法处理服务名问题
  12. Tree 和ls 的使用
  13. HDU.4903.The only survival(组合 计数)
  14. 将WORD2010文件标记为最终状态
  15. caffe-ssd编译runtest时候报错:g++: internal compiler error: Killed (program cc1plus)
  16. js 可以表示的最大值
  17. 基于Redis的CAS集群
  18. 在jstl表达式中嵌入el表达式
  19. Apache下设置网站目录的访问权限
  20. 深入redis内部--实现字符串

热门文章

  1. c# DateTime 类
  2. java继承中的初始化顺序
  3. 201521123111《Java程序设计》第10周学习总结
  4. 201521123053《Java课程设计》第十四周学习总结
  5. 201521123081《Java程序设计》 第10周学习总结
  6. 在linux下通过hexdump生成一个十六进制的文本保存文件,解析此文件转变成正常源代码文件。
  7. Javascript-正则表达式-开发中的使用.
  8. mysql数据库-初始化sql建库建表-关联查询投影问题
  9. Jenkins使用-windows机器上的文件上传到linux
  10. 自定义工作流活动报错:您无法登陆系统。原因可能是您的用户记录或您所属的业务部门在Microsoft Dynamics 365中已被禁用。