• springboot三种过滤功能的使用与比较


    若要实现对请求的过滤,有三种方式可供选择:filter、interceptort和aop。本文主要讨论三种拦截器的使用场景与使用方式。

    下文中的举例功能是计算每个请求的从开始到结束的时间,例子来源是慕课网。

    一、filter

    特点:可以获取原始的ServletRequest,但无法获取具体方法

    实现:

    1.继承javax.servlet.Filter类,

    2.@Component注解将其注入到框架中

    3.实现其中的dofilter方法,所有的请求都会经过该方法,可以在此计算出每个请求的耗时,代码如下:

     1 package com.zzy.web.filter;
     2 
     3 import java.io.IOException;
     4 import java.util.Date;
     5 
     6 import javax.servlet.Filter;
     7 import javax.servlet.FilterChain;
     8 import javax.servlet.FilterConfig;
     9 import javax.servlet.ServletException;
    10 import javax.servlet.ServletRequest;
    11 import javax.servlet.ServletResponse;
    12 
    13 import org.springframework.stereotype.Component;
    14 
    15 @Component
    16 public class TimeFilter implements Filter{
    17 
    18     @Override
    19     public void init(FilterConfig filterConfig) throws ServletException {
    20         // TODO Auto-generated method stub
    21         System.out.println("filter init");
    22         
    23     }
    24 
    25     @Override
    26     public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
    27             throws IOException, ServletException {
    28         // TODO Auto-generated method stub
    29         Long startTime = new Date().getTime();
    30         System.out.println("filter 请求开始时间:"+ startTime);
    31         chain.doFilter(request, response);
    32          Long endTime = new Date().getTime();
    33         System.out.println("filter 请求结束时间:" + endTime +",请求耗时:" + (endTime - startTime));
    34         
    35     }
    36 
    37     @Override
    38     public void destroy() {
    39         // TODO Auto-generated method stub
    40         
    41     }
    42 
    43 }

    注:如果有的框架没有@Component 这个注解,可以自己写一个配置类,在该类中指定过滤器,而且还可以指定过滤的url,配置类如下:

     1 package com.zzy.web.config;
     2 
     3 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
     4 
     5 import java.util.ArrayList;
     6 import java.util.List;
     7 
     8 import org.springframework.beans.factory.annotation.Autowired;
     9 import org.springframework.boot.web.servlet.FilterRegistrationBean;
    10 import org.springframework.context.annotation.Bean;
    11 import org.springframework.context.annotation.Configuration;
    12 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    13 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    14 
    15 import com.zzy.web.filter.TimeFilter;
    16 import com.zzy.web.interceptor.TimeInterceptor;
    17 
    18 @Configuration
    19 public class WebConfig extends WebMvcConfigurerAdapter {
    20     
    21     @Autowired
    22     private TimeInterceptor timeInterceptor;
    23     
    24 //    @Override
    25 //    public void addInterceptors(InterceptorRegistry registry) {
    26 //        // TODO Auto-generated method stub
    27 //        registry.addInterceptor(timeInterceptor);
    28 //    }
    29     
    30     @Bean
    31     public FilterRegistrationBean timeFilter() {
    32         FilterRegistrationBean registrationBean = new FilterRegistrationBean();
    33         TimeFilter timeFilter = new TimeFilter();
    34         registrationBean.setFilter(timeFilter);
    35         List<String> urls = new ArrayList<>();
    36         urls.add("/user/*");
    37         registrationBean.setUrlPatterns(urls);
    38         return registrationBean;
    39     }
    40 
    41 }

    二、interceptor

    特点:可以获取到原始的request和请求的方法,但无法获取方法的具体参数的值。

    实现:

    1.继承HandlerInterceptor接口

    2.请求前的逻辑写在prehandle(请求前调用)

    3.请求后的逻辑写在posthandle(请求成功后调用,失败则不调用)

    4.请求后,不管成功失败都会调用aftercompletion。

    5.intceptor方式继承了之后还没起作用,还需要在配置类里面加一下,把刚声明的拦截器注册一下。

    代码示例:

     1 package com.zzy.web.interceptor;
     2 
     3 import java.util.Arrays;
     4 import java.util.Date;
     5 
     6 import javax.servlet.http.HttpServletRequest;
     7 import javax.servlet.http.HttpServletResponse;
     8 
     9 import org.springframework.stereotype.Component;
    10 import org.springframework.web.method.HandlerMethod;
    11 import org.springframework.web.servlet.HandlerInterceptor;
    12 import org.springframework.web.servlet.ModelAndView;
    13 @Component
    14 public class TimeInterceptor implements HandlerInterceptor {
    15 
    16     @Override
    17     public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
    18             throws Exception {
    19         // TODO Auto-generated method stub
    20         System.out.println("interceptor 执行preHandle");
    21 
    22         request.setAttribute("startTime", new Date().getTime());
    23         return true;
    24     }
    25 
    26     @Override
    27     public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
    28             ModelAndView modelAndView) throws Exception {
    29         // TODO Auto-generated method stub
    30         Long startTime = Long.parseLong(request.getAttribute("startTime").toString());
    31         Long endTime = new Date().getTime();
    32         System.out.println("interceptor 执行postHandle");
    33         System.out.println("interceptor 请求类:"+((HandlerMethod)handler).getBean().getClass().getName());
    34         System.out.println("interceptor 请求方法:"+((HandlerMethod)handler).getMethod());
    35 //        System.out.println("interceptor 请求参数:");
    36 //        Arrays.asList(((HandlerMethod)handler).getMethodParameters()).stream().forEach(arg->System.out.println(arg));
    37         System.out.println("interceptor 请求耗时:" + (endTime - startTime));
    38 
    39     }
    40 
    41     @Override
    42     public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
    43             throws Exception {
    44         // TODO Auto-generated method stub
    45         Long startTime = Long.parseLong(request.getAttribute("startTime").toString());
    46         Long endTime = new Date().getTime();
    47         System.out.println("interceptor 执行afterCompletion");
    48         System.out.println("interceptor 请求类:"+((HandlerMethod)handler).getBean().getClass().getName());
    49         System.out.println("interceptor 请求方法:"+((HandlerMethod)handler).getMethod());
    50         System.out.println("interceptor 请求耗时:" + (endTime - startTime));
    51         System.out.println("interceptor 请求异常:" + ex);
    52 
    53     }
    54 
    55 }

    配置类如下:

     1 package com.zzy.web.config;
     2 
     3 import static org.assertj.core.api.Assertions.failBecauseExceptionWasNotThrown;
     4 
     5 import java.util.ArrayList;
     6 import java.util.List;
     7 
     8 import org.springframework.beans.factory.annotation.Autowired;
     9 import org.springframework.boot.web.servlet.FilterRegistrationBean;
    10 import org.springframework.context.annotation.Bean;
    11 import org.springframework.context.annotation.Configuration;
    12 import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
    13 import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
    14 
    15 import com.zzy.web.filter.TimeFilter;
    16 import com.zzy.web.interceptor.TimeInterceptor;
    17 
    18 @Configuration
    19 public class WebConfig extends WebMvcConfigurerAdapter {
    20     
    21     @Autowired
    22     private TimeInterceptor timeInterceptor;
    23     
    24     @Override
    25     public void addInterceptors(InterceptorRegistry registry) {
    26         // TODO Auto-generated method stub
    27         registry.addInterceptor(timeInterceptor);
    28     }
    29 
    30 
    31 }

    三、aop

    特点:能拿到方法和具体参数的值,但是拿不到原始的servletrequest的信息。

    实现:

    1.使用@aspect注解

    2.@execution声明切面,声明切面的语法可参考官网https://docs.spring.io/spring/docs/4.3.18.RELEASE/spring-framework-reference/htmlsingle/#aop-pointcuts

    3.使用@Around(方法前和方法后),@Before(方法前)或@After(方法后)

    以下为@Around举例,代码如下:

     1 package com.zzy.web.aspect;
     2 
     3 import java.util.Date;
     4 
     5 import org.aspectj.lang.ProceedingJoinPoint;
     6 import org.aspectj.lang.annotation.Around;
     7 import org.aspectj.lang.annotation.Aspect;
     8 import org.codehaus.jackson.map.ObjectMapper;
     9 import org.springframework.stereotype.Component;
    10 
    11 @Aspect
    12 @Component
    13 public class TimeAspect {
    14 
    15     @Around("execution(* com.zzy.web.controller.UserController.*(..))")
    16     public Object test(ProceedingJoinPoint pjp) throws Throwable {
    17         Long startTime = new Date().getTime();
    18         Object[] args = pjp.getArgs();
    19         for (Object arg : args) {
    20             System.out.println("aspect 参数:" + arg);
    21         }
    22         Object object = pjp.proceed();
    23         System.out.println("aspect 请求耗时:" + (new Date().getTime() - startTime));
    24         System.out.println("aspect 请求结果:" + new ObjectMapper().writeValueAsString(object));
    25 
    26         return object;
    27 
    28     }
    29 }

     下图是三种方式的拦截顺序,图片来自慕课网:

  • 相关阅读:
    Web API系列(三)统一异常处理
    Web API系列(二)接口安全和参数校验
    Web API系列(一)设计经验与总结
    文件并发(日志处理)--队列--Redis+Log4Net
    Jquery手机下拉刷新,下拉加载数据
    nginx 几个参数
    op cache config
    历史问题回顾
    第三方服务的使用
    nginx+php-fpm json_encode 到client pages 截断
  • 原文地址:https://www.cnblogs.com/zuxiaoyuan/p/9702363.html
Copyright © 2020-2023  润新知