拦截器使用

一、概念理解

1.执行顺序图

图

2.特性区别

  • Tomcat是一个web容器,也叫web服务器。Tomcat采用Java servlet API的标准实现,servlet采用Java Servlet API接口,实现了Tomcat与Servlet的请求传递。

  • Filter,过滤器,顾名思义,即是对数据等的过滤,预处理过程。引入目的,在平常访问网站的时候,有时候发一些敏感的信息,发出后显示时 就会将敏感信息用*等字符替代,这就是用过滤器对信息进行了处理。
    Filter是在servlet与Tomcat之间的一个类似于过滤网的东西。

  • Servlet是一个Java应用程序,运行在服务器端,用来处理客户端请求并作出响应的程序。 通俗点说,servlet 就是运行在java服务器后端的一个程序,如果有人想访问我们的服务器,发来一个 http 请求,我们的 Tomcat 会将它解析为 request 请求。但是怎么处理这个请求呢?servlet 就是用于处理这个请求的,它接收request请求,并处理它,返回response响应。由Tomcat转换为http请求,返回给客户端。

  • 拦截器是Spring中的概念,和过滤器类似,可以对用户请求进行拦截过滤处理。但是相对于过滤器而言,拦截器要的控制更加的细节,拦截器可以在三个地方进行执行。

3.实现方式

1) 实现Spring的HandlerInterceptor接口

2) 继承Spring的HandlerInterceptorAdapter类

其实HandlerInterceptorAdapter类 也是实现的HandlerInterceptor接口

HandlerInterceptor接口方法:

  • preHandler(): 这个方法在业务处理器处理请求之前被调用,Interceptor是链式调用的,该方法返回false时表示请求结束,后续的Interceptor和Controller都不会再执行,当返回true时就会调用下一个Interceptor的preHandler()方法。如果已经是最后一个Interceptor时会调用当前请求的Controller方法。
  • postHandler(): 在Controller方法调用之后执行,但是它会在DispatcherServlet进行视图返回之前被调用,所有可以在这个方法中对Controller处理后的ModelAndView对象进行操作。
  • afterCompletion(): preHandler()方法返回值为true时才会执行。

4.拦截器注册

有了拦截器的类之后还需要注册拦截器,编写一个类继承WebMvcConfigurationSupport(或实现 WebMvcConfigurer 接口),并重写addInterceptors来注册拦截器。
多个拦截器的执行顺序取决于拦截器注册的顺序。

图

二、应用场景

拦截器本质上是面向切面编程(AOP),符合横切关注点的功能都可以放在拦截器中来实现,主要的应用场景包括:

  • 登录验证,判断用户是否登录

  • 权限验证,判断用户是否有权限访问资源,比如校验token

  • 日志记录,记录请求操作日志(用户IP,访问时间等),以便统计请求访问量

  • 处理cookie、本地化、国际化、主题等

  • 性能监控,监控请求处理时长等

  • 通用行为:读取cookie得到用户信息并将用户对象放入请求,从而方便后续流程使用,还有比如提取Locale、Theme信息等,只要是多个处理器都需要的即可使用拦截器实现

三、扩展示例

应用场景:日志记录,记录指定请求操作日志,便于对慢接口进行优化

1.创建拦截器

首先写一个类(TestLogInterceptor),让他继承HandlerInterceptorAdapter,并重写其中的三个方法,例如:

package com.yonyou.ucf.mdf.app.interceptor;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.ModelAndView;
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

/**
 * @project: devcom2021-be
 * @package: com.yonyou.ucf.mdf.app.interceptor
 * @description: TODO 利用Spring的拦截器监测每个Controller或方法的执行时长
 * @author: zhangshuai
 * @date: 2021年11月24日 9:17
 * @version: v1.0
 */

@Slf4j
@Component
@RequiredArgsConstructor
public class TestLogInterceptor extends HandlerInterceptorAdapter {

    private long time;
    private String url;


  /**
   * 1.进入Controller方法之前执行
   *
   * @param request
   * @param response
   * @param handler
   * @return 返回值为true时可继续执行Controller,preHandle()和afterCompletion(),为false时停止执行任何方法。
   * @throws Exception
   */
  @Override
  public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
      time = System.currentTimeMillis();
      url = request.getRequestURL().toString();
      log.info("请求url:{}",url);

      // 可以处理些逻辑

      // 放开拦截
      return true;
  }

  /**
   * 2.Controller方法执行完毕但是未进行视图渲染时执行
   *
   * @param request
   * @param response
   * @param handler
   * @param modelAndView
   * @throws Exception
   */
  @Override
  public void postHandle(HttpServletRequest request,HttpServletResponse response,Object handler,ModelAndView modelAndView)
      throws Exception {
      super.postHandle(request, response, handler, modelAndView);
  }

  /**
   * 3.视图渲染完成(整个请求结束)执行
   *
   * @param request
   * @param response
   * @param handler
   * @param ex
   * @throws Exception
   */
  @Override
  public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
      log.info("请求url:{},耗时{} ms", url , (System.currentTimeMillis() - time));
      super.afterCompletion(request, response, handler, ex);

  }
}

2.注册拦截器

后台脚手架也有注册拦截器,这里自己模块里扩展的(TestWebMvcConfigurer)集成脚手架的(ISVWebMvcConfigurer)即可

package com.yonyou.ucf.mdf.app.interceptor;

import com.yonyou.ucf.mdf.app.controller.interceptor.CookieValueInterceptor;
import com.yonyou.ucf.mdf.app.controller.interceptor.HeaderInterceptor;
import com.yonyou.ucf.mdf.app.controller.interceptor.ISVWebMvcConfigurer;
import com.yonyou.ucf.mdf.app.controller.interceptor.InnerRequestInterceptor;
import com.yonyoucloud.iuap.ucf.mdd.starter.core.UCFCoreProperties;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;

/**
 * @project: devcom2021-be
 * @package: com.yonyou.ucf.mdf.app.interceptor
 * @description: TODO
 * @author: zhangshuai
 * @date: 2021年11月24日 10:48
 * @version: v1.0
 */
@Component
public class TestWebMvcConfigurer extends ISVWebMvcConfigurer {

    private final TestLogInterceptor logInterceptor;

    public TestWebMvcConfigurer(UCFCoreProperties properties, CookieValueInterceptor cookieValueInterceptor, HeaderInterceptor headerInterceptor, InnerRequestInterceptor innerRequestInterceptor, TestLogInterceptor logInterceptor) {
        super(properties, cookieValueInterceptor, headerInterceptor, innerRequestInterceptor);
        this.logInterceptor = logInterceptor;
    }


    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 自己扩展的拦截器
        // 注册自建拦截器
        registry.addInterceptor(logInterceptor)   
                // 拦截指定controller下路径
                .addPathPatterns("/isv/rest/**");
    }

}

3.测试接口

@RestController
@Slf4j
@RequestMapping("/isv/rest")
public class MDDTestController {

    @Value("${ucf.mdd.open-api.tenant-id}")
    String tenantId;

    /**
     *  本地测试:http://127.0.0.1:8080/isv/rest/sqlHelp/test001
     * @throws Exception
     */
    @RequestMapping("/sqlHelp/test001")
    public void test001sql() throws Exception {
        // SqlHelper
        // 1.查询集合
        List<Object> objectsList = SqlHelper.selectList("com.yonyou.ucf.mdf.app.mapper.AdminTestMapper.getListById", this.tenantId);
        System.err.println(objectsList);
        // 2.查询一条
        HashMap<String, String> paramMap = new HashMap<>();
        paramMap.put("tenantId", this.tenantId);
        paramMap.put("new1","0001");
        Object obj = SqlHelper.selectOne("com.yonyou.ucf.mdf.app.mapper.AdminTestMapper.getObjById", paramMap);
        System.err.println(obj);

    }

}

4.测试效果

图

Copyright © 用友 -【生态技术部】 2021 all right reserved,powered by Gitbook修订时间: 2022-01-04 14:38:25

results matching ""

    No results matching ""