一,filter/interceptor/aop在獲取參數上有什么區別?
1,filter可以修改HttpServletRequest的參數(doFilter方法的功能),
interceptor/aop都沒有這個功能
但它不提供到被過濾的方法的訪問
注意區分請求request的方法
2, interceptor能得到所攔截的方法名和參數名,
不能得到參數值,
interceptor的postHandle方法能得到ModelAndView參數,
用來處理模板的公共參數,把頁面的公共內容傳遞給模板
3, aspect(Aop)能得到注解所在方法的方法名和參數名、參數值,
還可以修改方法的參數值
另外:
filter/interceptor都是針對請求,
aop則是針對方法
看代碼,有更直觀的感受
說明:劉宏締的架構森林是一個專注架構的博客,地址:https://www.cnblogs.com/architectforest
對應的源碼可以訪問這里獲取: https://github.com/liuhongdi/
說明:作者:劉宏締 郵箱: 371125307@qq.com
二,演示項目的相關信息
1,項目地址
https://github.com/liuhongdi/filterinterceptoraop
2,項目原理:
我們在controller中的一個方法上,
添加了filter/interceptor/aspect
然后比較我們能得到哪些參數,對參數做哪些處理?
3,項目結構:
如圖:
三,java代碼說明:
1,ParamFilter.java
@Component public class ParamFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { System.out.println("----------------filter init"); } //過濾功能 @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { System.out.println("----------------filter doFilter begin"); //打印得到的request參數 Enumeration paramNames = servletRequest.getParameterNames(); while (paramNames.hasMoreElements()) { String paramName = (String) paramNames.nextElement(); String[] paramValues = servletRequest.getParameterValues(paramName); if (paramValues.length == 1) { String paramValue = paramValues[0]; if (paramValue.length() != 0) { System.out.println("[filter] request parameter name:"+paramName+";value:"+paramValue); } } } //修改請求參數 HashMap m = new HashMap(servletRequest.getParameterMap()); m.put("newp", new String[] { "abcd" }); m.put("v", new String[] { "filterv" }); HttpServletRequest req = (HttpServletRequest) servletRequest; CustomRequestWrapper wrapRequest = new CustomRequestWrapper(req, m); servletRequest = wrapRequest; filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { System.out.println("----------------filter destroy"); } }
說明:filter中可以修改request參數,
但不能對方法進行訪問
2,ValidateorInterceptor.java
@Component public class ValidatorInterceptor implements HandlerInterceptor { @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { System.out.println("---------------interceptor begin"); //打印request參數 Enumeration<?> temp = request.getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String) temp.nextElement(); String value = request.getParameter(en); System.out.println("[interceptor] request parameters: name:"+en+";value:"+value); } } //打印method的相關信息 if(handler instanceof HandlerMethod) { HandlerMethod handlerMethod = (HandlerMethod) handler; // 獲取處理當前請求的 handler 信息 System.out.println("[interceptor] method 類名:" + handlerMethod.getBeanType().getName()); System.out.println("[interceptor] method 方法:" + handlerMethod.getMethod().getName()); MethodParameter[] methodParameters = handlerMethod.getMethodParameters(); for (MethodParameter methodParameter : methodParameters) { // 只能獲取參數的名稱,type,index,不能獲取到參數的值 System.out.println("[interceptor] method parameter Name: " + methodParameter.getParameterName()); System.out.println("[interceptor] method parameter Type: " + methodParameter.getParameterType()); System.out.println("[interceptor] method parameter Index: " + methodParameter.getParameterIndex()); } } //sign校驗無問題,放行 return true; } @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { } }
說明:interceptor中,只能得到方法的參數名,不能得到參數值
3,RedisRateLimiterAspect.java
@Component @Aspect public class RedisRateLimiterAspect { @Pointcut("@annotation(com.filterinterceptoraop.demo.annotation.RedisRateLimiter)") private void pointcut() {} /* * around, * if reach limit in time * return error info * */ @Around(value = "pointcut()") public Object requestLimit(ProceedingJoinPoint joinPoint) throws Exception { System.out.println("---------------aop begin"); HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); //打印request參數 Enumeration<?> temp = request.getParameterNames(); if (null != temp) { while (temp.hasMoreElements()) { String en = (String) temp.nextElement(); String value = request.getParameter(en); System.out.println("[aop] request parameter name:"+en+";value:"+value); } } //打印方法的信息 Object[] args = joinPoint.getArgs(); try { Signature signature = joinPoint.getSignature(); MethodSignature methodSignature = (MethodSignature)signature; //獲取目標方法 Method targetMethod = methodSignature.getMethod(); String method_name = targetMethod.getName(); System.out.println("[aop] method name:"+method_name); String[] paramNames = methodSignature.getParameterNames(); Map<String, Object> nameAndArgs = new HashMap<String, Object>(); for (int i = 0; i < paramNames.length; i++) { nameAndArgs.put(paramNames[i], args[i]);// paramNames即參數名 if (paramNames[i].equals("version")) { //System.out.println("version value:"+args[i]); args[i] = "aopv"; } System.out.println("[aop] method parameter name:"+paramNames[i]+";value:"+args[i]); } if (targetMethod.isAnnotationPresent(RedisRateLimiter.class)) { return joinPoint.proceed(args); } else { return joinPoint.proceed(); } } catch (Throwable e) { e.printStackTrace(); return null; } } }
說明:aop中,可以得到方法的參數名和參數值,而且還可以修改方法的參數值
四,測試效果
1,訪問url:
http://127.0.0.1:8080/home/home?v=1
然后查看控制台的輸出
2,filter的輸出
----------------filter doFilter begin [filter] request parameter name:v;value:1
filter中我們得到了正確的request參數值
3,interceptor的輸出
---------------interceptor begin [interceptor] request parameters: name:v;value:filterv [interceptor] request parameters: name:newp;value:abcd [interceptor] method 類名:com.filterinterceptoraop.demo.controller.HomeController [interceptor] method 方法:homeMethod [interceptor] method parameter Name: version [interceptor] method parameter Type: class java.lang.String [interceptor] method parameter Index: 0 [interceptor] method parameter Name: httpServletRequest [interceptor] method parameter Type: interface javax.servlet.http.HttpServletRequest [interceptor] method parameter Index: 1 [interceptor] method parameter Name: httpServletResponse [interceptor] method parameter Type: interface javax.servlet.http.HttpServletResponse [interceptor] method parameter Index: 2 [interceptor] method parameter Name: modelMap [interceptor] method parameter Type: class org.springframework.ui.ModelMap [interceptor] method parameter Index: 3
請求參數v的值變成了filterv,而且增加了一個請求參數:newp,
這是filter中代碼的作用
可以看到:interceptor得到了它所攔截請求對應的方法名和參數名,
但沒有方法的參數值,它也不能修改request的參數和方法的參數
4,aop的輸出:
---------------aop begin
[aop] request parameter name:v;value:filterv
[aop] request parameter name:newp;value:abcd
[aop] method name:homeMethod
[aop] method parameter name:version;value:aopv
[aop] method parameter name:httpServletRequest;value:com.filterinterceptoraop.demo.wrapper.CustomRequestWrapper@1ce466d8
[aop] method parameter name:httpServletResponse;value:org.apache.catalina.connector.ResponseFacade@45eedc13
[aop] method parameter name:modelMap;value:{}
aop中的請求參數沒有變,
它可以得到方法的參數名和參數值,
在這里我們修改參數version的值為 aopv
5,controller中的輸出:
---------------controller begin
[controller] request parameter name:v;value:filterv
[controller] request parameter name:newp;value:abcd
[controller] method parameter version:aopv
controller中接收到的方法的參數值是我們在aop中修改過的
五,查看spring boot版本
. ____ _ __ _ _ /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \ ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \ \\/ ___)| |_)| | | | | || (_| | ) ) ) ) ' |____| .__|_| |_|_| |_\__, | / / / / =========|_|==============|___/=/_/_/_/ :: Spring Boot :: (v2.3.1.RELEASE)