当前位置:   article > 正文

SpringMVC,拦截器接口HandlerInterceptor_handlerinterceptor接口

handlerinterceptor接口

前言

拦截器是Web中常见,重要的一种机制,用来对数据进行预处理等操作,本文主要是Spring对HandlerInterceptor这个接口进行解析,这个接口属于SpringMVC包中。

分析

三个方法

HandlerInterceptor,这个Handler可以认为就是Controller的方法,这个接口有三个方法,分别是:

其中:

  • preHandler是处理前的逻辑,返回true表示应该继续处理,否则表示响应结束;
  • postHandler是处理后的逻辑;
  • afterCompletion是在渲染完试图后的逻辑,通常用来清理资源的操作,这里注意,如果preHandler里面返回false,那么将触发这个afterCompletion的逻辑,这部分要注意的是,如果返回false,那么将执行的是所有的拦截器的afterCompletion方法,具体逻辑如下所示。
  1. boolean applyPreHandle(HttpServletRequest request, HttpServletResponse response) throws Exception {
  2. for (int i = 0; i < this.interceptorList.size(); i++) {
  3. HandlerInterceptor interceptor = this.interceptorList.get(i);
  4. if (!interceptor.preHandle(request, response, this.handler)) {
  5. triggerAfterCompletion(request, response, null);
  6. return false;
  7. }
  8. this.interceptorIndex = i;
  9. }
  10. return true;
  11. }
  12. void triggerAfterCompletion(HttpServletRequest request, HttpServletResponse response, @Nullable Exception ex) {
  13. for (int i = this.interceptorIndex; i >= 0; i--) {
  14. HandlerInterceptor interceptor = this.interceptorList.get(i);
  15. try {
  16. interceptor.afterCompletion(request, response, this.handler, ex);
  17. }
  18. catch (Throwable ex2) {
  19. logger.error("HandlerInterceptor.afterCompletion threw exception", ex2);
  20. }
  21. }
  22. }

它和Servlet Filter的区别

  • 处理器拦截器HandlerInterceptor是Spring MVC提供的特性,依赖于Spring MVC框架,而不依赖Servlet容器,Filter则是Servlet的特性,属于Servlet的规范,并且依赖Servlet容器。
  • 应用中可以存在多个拦截器形成拦截器链,也可以存在多个过滤器形成过滤器链!
  • 拦截器链和过滤器链的预处理和后处理的调用顺序都是相反的,即预处理调用时按照链从前向后调用,而后处理调用时则按照链从后向前调用。
  • 过滤器可用于对所有到达该应用的请求进行拦截,而拦截器则只能对通过DispatcherServlet进行处理的请求进行拦截。
  • 在Request请求到达Servlet之前执行过滤器的预处理逻辑,在请求到达DispatcherServlet之后、执行Handler之前执行拦截器的预处理逻辑,并在成功执行Handler之后执行拦截器的后处理逻辑,在DispatcherServlet返回之后最后执行过滤器的后处理逻辑。
  • Filter在doFilter一个方法中定义预处理和后处理逻辑,在方法中通过filterChain.doFilter进行分隔,而HandlerInterceptor将预处理和后处理逻辑拆分成两个方法,即preHandle、postHandle方法。
  • Filter有该类本身的初始化和销毁的回调方法,即init和destroy,而HandlerInterceptor则没有,但是HandlerInterceptor拥有afterCompletion处理方法,无论有没有抛出异常,在DispatcherServlet请求处理的最后都会执行!

实现的原理

通过的是责任链的设计模式,关键角色是HandlerExecutionChain,这个类里面有一个容器,管理了HandlerInterceptor接口。

如何使用

注册Interceptor

  1. @Configuration
  2. public class HeaderParamExtInterceptorConfig implements WebMvcConfigurer {
  3. @Override
  4. public void addInterceptors(InterceptorRegistry registry){
  5. // 这个Interceptor实现了HandlerInterceptor接口
  6. registry.addInterceptor(new HeaderParamExtInterceptor()).order(-1);
  7. // 还可以制定拦截的路径
  8. registry.addInterceptor(new ThemeChangeInterceptor()).addPathPatterns("/**").excludePathPatterns("/admin/**");
  9. registry.addInterceptor(new HeaderParamInterceptor()).addPathPatterns(new String[]{"/**"}).excludePathPatterns(new String[]{"*.js,*.gif,*.jpg,*.png,*.css,*.ico"});
  10. }
  11. }

应用场景

  1. 日志记录:通过HandlerInterceptor拦截器记录处理日志,以便后续进行系统监控、问题定位等。
  2. 流量记录:通过HandlerInterceptor拦截器记录系统流量,进行UV、PV统计,同时可以进行业务限流。
  3. 业务鉴权:通过HandlerInterceptor对按照响应需求统一进行校验,校验通过与否进行响应处理。
  4. 修改请求头,将自定义的请求头放在ThreadLocal中进行管理;

示例代码,修改请求头

  1. public class HeaderParamExtInterceptor implements HandlerInterceptor {
  2. @Override
  3. public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
  4. throws Exception {
  5. Map<String, String> headerParamsMap = new HashMap<>(16);
  6. ServletRequestAttributes servletReqAttr = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
  7. if (servletReqAttr != null) {
  8. // 设置账户Id
  9. headerParamsMap.put(CommonConstants.HTTP_HEADER_X_ACCOUNT_ID, request.getHeader(CommonConstants.HTTP_HEADER_X_ACCOUNT_ID));
  10. }
  11. HeaderParamThreadLocalUtils.setHeaderParam(headerParamsMap);
  12. return true;
  13. }
  14. @Override
  15. public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler,
  16. @Nullable Exception ex) throws Exception {
  17. HeaderParamThreadLocalUtils.removeHeaderParam();
  18. }
  19. /**
  20. * 修改请求头信息
  21. */
  22. private void modifyHeaders(Map<String, String> headersTmp, HttpServletRequest request) {
  23. if (headersTmp == null || headersTmp.isEmpty()) {
  24. return;
  25. }
  26. Class<? extends HttpServletRequest> requestClass = request.getClass();
  27. try {
  28. Field request1 = requestClass.getDeclaredField("request");
  29. request1.setAccessible(true);
  30. Object o = request1.get(request);
  31. Field coyoteRequest = o.getClass().getDeclaredField("coyoteRequest");
  32. coyoteRequest.setAccessible(true);
  33. Object o1 = coyoteRequest.get(o);
  34. Field headers = o1.getClass().getDeclaredField("headers");
  35. headers.setAccessible(true);
  36. MimeHeaders o2 = (MimeHeaders)headers.get(o1);
  37. for (Map.Entry<String, String> entry : headersTmp.entrySet()) {
  38. o2.removeHeader(entry.getKey());
  39. o2.addValue(entry.getKey()).setString(entry.getValue());
  40. }
  41. } catch (Exception e) {
  42. e.printStackTrace();
  43. }
  44. }
  45. }
  46. public class HeaderParamThreadLocalUtils {
  47. private static ThreadLocal<Map<String, String>> headerParamThreadLocal = ThreadLocal.withInitial(HashMap::new);
  48. public static void setHeaderParam(Map<String, String> headerParam){
  49. if (!CollectionUtils.isEmpty(headerParam)){
  50. headerParamThreadLocal.set(headerParam);
  51. }
  52. }
  53. /**
  54. * 取当前线程对应http请求的请求头
  55. */
  56. public static Map<String, String> getHeaderParam(){
  57. return headerParamThreadLocal.get();
  58. }
  59. public static void removeHeaderParam(){
  60. headerParamThreadLocal.remove();
  61. }
  62. }

druid中的代码

下面这段代码判断uri后缀是否包某个字符串,取之前的字符串进行处理

  1. if (uriStat == null) {
  2. int index = requestURI.indexOf(";jsessionid=");
  3. if (index != -1) {
  4. requestURI = requestURI.substring(0, index);
  5. uriStat = webAppStat.getURIStat(requestURI, false);
  6. }
  7. }
  8. // 这个方法可以获取正在处理的URI
  9. public String getRequestURI(HttpServletRequest request) {
  10. return (String) request.getAttribute(HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
  11. }


 

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/716499
推荐阅读
相关标签
  

闽ICP备14008679号