JAVA三种拦截方式

02-29 1101阅读

最近面试有遇到拦截方式的场景,结合网上xdm的代码整理了下,分为以下三种:

java原生过滤器Filter、springMVC拦截器、aop切面

目录:

    • 一、java原生过滤器Filter
    • 二、springMVC拦截器
    • 三、aop切面

      一、java原生过滤器Filter

      package com.zhangximing.springbootinterceptor.interceptor;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.stereotype.Component;
      import javax.servlet.*;
      import javax.servlet.annotation.WebFilter;
      import javax.servlet.http.HttpServletRequest;
      import java.io.IOException;
      import java.util.Enumeration;
      /**
       * 自定义Filter
       * 对请求的header 过滤token
       *
       * 过滤器Filter可以拿到原始的HTTP请求和响应的信息,
       *     但是拿不到你真正处理请求方法的信息,也就是方法的信息
       *
       * @Component 注解让拦截器注入Bean,从而让拦截器生效
       * @WebFilter 配置拦截规则
       *
       * 拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
       *
       */
      @Slf4j
      @Component
      @WebFilter(urlPatterns = {"/**"},filterName = "authFilter")
      public class MyFilter implements Filter {
          @Override
          public void init(FilterConfig filterConfig) throws ServletException {
              log.info("TokenFilter init {}",filterConfig.getFilterName());
          }
          @Override
          public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
              String param = request.getParameter("param");
              response.setContentType("text/html;charset=UTF-8");
              //获取请求头token
              String token = "";
              HttpServletRequest httpServletRequest = (HttpServletRequest) request;
              Enumeration headerNames = httpServletRequest.getHeaderNames();
              while(headerNames.hasMoreElements()) {//判断是否还有下一个元素
                  String nextElement = headerNames.nextElement();//获取headerNames集合中的请求头
                  if ("token".equals(nextElement)){
                      token = httpServletRequest.getHeader(nextElement);
                      log.info("请求头key[" + nextElement + "]:" + token);
                  }
              }
              log.info("doFilter-我拦截到了请求:"+ param);
              if (null != param && "pass".equals(param)){
                  //验证token
                  if ("7758258xx".equals(token)){
                      chain.doFilter(request,response);//到下一个链
                  }else{
                      response.getWriter().write("doFilter-请求头token不通过");
                  }
              }else{
                  log.info("doFilter-参数param不符合条件");
                  response.getWriter().write("doFilter-参数param不通过");
              }
          }
          @Override
          public void destroy() {
              log.info("destroy");
          }
      }
      

      简单测试直接用的postman,参数是一个param和一个请求头token:

      JAVA三种拦截方式

      这里补充一下:

      若非springboot的情况下,不使用@WebFilter则需要自己设置配置文件

      你需要在web.xml文件中配置过滤器,指定要拦截的URL以及要使用的过滤器

          MyFilter
          com.zhangximing.springbootinterceptor.interceptor.MyFilter
      
      
          MyFilter
          /example
      
      

      二、springMVC拦截器

      import lombok.extern.slf4j.Slf4j;
      import org.springframework.stereotype.Component;
      import org.springframework.web.method.HandlerMethod;
      import org.springframework.web.servlet.HandlerInterceptor;
      import org.springframework.web.servlet.ModelAndView;
      import org.springframework.web.servlet.resource.ResourceHttpRequestHandler;
      import javax.servlet.http.HttpServletRequest;
      import javax.servlet.http.HttpServletResponse;
      import java.lang.reflect.Method;
      /**
       * 自定义拦截器
       * 自定义拦截器后,需要配置进Spring
       *
       * 拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,
       *    也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。
       *
       *拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
       */
      @Slf4j
      @Component
      public class MyInterceptor implements HandlerInterceptor {
          /**
           * 在访问Controller某个方法之前这个方法会被调用。
           * @param request
           * @param response
           * @param handler
           * @return false则表示不执行postHandle方法,true 表示执行postHandle方法
           * @throws Exception
           */
          @Override
          public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
              log.info("Interceptor preHandle {}","");
              String token = request.getHeader("token");
              log.info("Interceptor preHandle token :{}",token);
              log.info("Interceptor preHandle uri {}",request.getRequestURL().toString());
              response.setContentType("text/html;charset=UTF-8");
              //spring boot 2.0对静态资源也进行了拦截,当拦截器拦截到请求之后,
              // 但controller里并没有对应的请求时,该请求会被当成是对静态资源的请求。
              // 此时的handler就是 ResourceHttpRequestHandler,就会抛出上述错误。
              if (handler instanceof HandlerMethod){
                  HandlerMethod handlerMethod = (HandlerMethod) handler;
                  Method method = handlerMethod.getMethod();
                  log.info("Token Interceptor preHandle getMethod {}",method.getName());
              }else if(handler instanceof ResourceHttpRequestHandler){//静态资源
                  ResourceHttpRequestHandler resourceHttpRequestHandler = (ResourceHttpRequestHandler) handler;
                  log.info("Token Interceptor preHandle getMethod {}",resourceHttpRequestHandler.getMediaTypes());
              }
              if (!"7758258xx".equals(token)){
                  response.getWriter().write("doInterceptor-请求头token不通过");
                  return false;
              }
              //false则表示不执行postHandle方法,不执行下一步chain链,直接返回response
              return true;
          }
          /**
           * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
           * preHandle方法处理之后这个方法会被调用,如果控制器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 {
              log.info("Interceptor postHandle");
          }
          /**
           * 不管有没有异常,这个afterCompletion都会被调用
           * @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("Interceptor afterCompletion");
          }
      

      这里注意下,需要将拦截器配置进spring

      import com.zhangximing.springbootinterceptor.interceptor.MyInterceptor;
      import lombok.extern.slf4j.Slf4j;
      import org.springframework.beans.factory.annotation.Autowired;
      import org.springframework.context.annotation.Configuration;
      import org.springframework.web.servlet.config.annotation.CorsRegistry;
      import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
      import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
      /**
       *  MyInterceptor 自定义拦截器后,需要配置进Spring
       * 也可以mapping,跨域设置
       */
      @Slf4j
      @Configuration
      public class MyInterceptorConfig implements WebMvcConfigurer {
          @Autowired
          MyInterceptor myInterceptor;
          /**
           * 添加拦截器
           * @param registry
           */
          @Override
          public void addInterceptors(InterceptorRegistry registry) {
              log.info("addInterceptors tokenInterceptor");
              registry.addInterceptor(myInterceptor)
                      .addPathPatterns("/**")//指定该类拦截的url
              .excludePathPatterns( "/static/**");//过滤静态资源
          }
          /**
           * 如果实现了Filter跨域拦截,这个跨域无效
           * 拦截器实现 跨域支持
           * @param registry
           */
          @Override
          public void addCorsMappings(CorsRegistry registry) {
              log.info("addInterceptors addCorsMappings");
              registry.addMapping("/**")
                      .allowedOriginPatterns("*")  //本人测试时springboot2.7版本用的是这个
                      .allowCredentials(true)
                      .allowedMethods("GET", "POST", "DELETE", "PUT","OPTIONS","HEAD")
                      .allowedHeaders("*")
                      .maxAge(3600);
          }
      }
      

      测试同理:

      JAVA三种拦截方式

      三、aop切面

      引入maven:

          org.springframework.boot
          spring-boot-starter-aop
      
      

      若出现无法解析aspectjweaver则需要手动加入其他版本maven解决问题

         org.aspectj
          aspectjweaver
          1.9.4
      
      
      import com.alibaba.fastjson.JSONObject;
      import lombok.extern.slf4j.Slf4j;
      import org.aspectj.lang.JoinPoint;
      import org.aspectj.lang.ProceedingJoinPoint;
      import org.aspectj.lang.annotation.*;
      import org.slf4j.Logger;
      import org.slf4j.LoggerFactory;
      import org.springframework.stereotype.Component;
      import org.springframework.web.context.request.RequestContextHolder;
      import org.springframework.web.context.request.ServletRequestAttributes;
      import javax.servlet.http.HttpServletRequest;
      import java.util.Arrays;
      /**
       * @Author: zhangximing
       * @Email: 530659058@qq.com
       * @Date: 2023/8/18 10:15
       * @Description: 切面
       */
      @Slf4j
      @Component  //表示它是一个Spring的组件
      @Aspect  //表示它是一个切面
      public class MyAspect {
          private static final Logger logger = LoggerFactory.getLogger(MyAspect.class);
          ThreadLocal startTime = new ThreadLocal();
          /**
           * 第一个*代表返回类型不限
           * 第二个*代表所有类
           * 第三个*代表所有方法
           * (..) 代表参数不限
           * com.zhangximing.springbootinterceptor.controller 测试的controller层
           */
          @Pointcut("execution(public * com.zhangximing.springbootinterceptor.controller.*.*(..))")
          public void pointCut(){};
          @Before(value = "pointCut()")
          public void before(JoinPoint joinPoint){
              System.out.println("方法执行前执行......before");
              ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
              HttpServletRequest request = attributes.getRequest();
              logger.info("
VPS购买请点击我

文章版权声明:除非注明,否则均为主机测评原创文章,转载或复制请以超链接形式并注明出处。

目录[+]