1. 程式人生 > >springboot三種攔截器的使用與比較

springboot三種攔截器的使用與比較

asn return sta nts cto print oid auto 獲取

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 }

springboot三種攔截器的使用與比較