0、拦截顺序
Filter
Interceptor
ControllerAdvice
Aspect
Controller
1、过滤器 Filter
可以拿到原始http的请求和响应的信息
但是拿不到请求方法的信息
package com.moon.web.filter;
import java.io.IOException;
import java.util.Date;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
/**
* 可以拿到原始http的请求和响应的信息,但是拿不到请求方法的信息
*/
@Component
public class TimeFilter implements Filter {
@Override
public void destroy() {
System.out.println("time filter destroy");
}
@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
throws IOException, ServletException {
System.out.println("time filter start");
long start = new Date().getTime();
chain.doFilter(request, response);
System.out.println("time filter 耗时:"+ (new Date().getTime() - start));
System.out.println("time filter finish");
}
@Override
public void init(FilterConfig arg0) throws ServletException {
System.out.println("time filter init");
}
}
2、拦截器 interceptor
可以拿到原始http的请求和响应的信息
可以拿到请求方法的信息
但是拿不到调用方法的参数值信息
package com.moon.web.interceptor;
import java.util.Date;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.stereotype.Component;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
/**
* 虽然加了 @Component 注解,但是并不会起作用
* 还需要添加到spring boot的拦截器链上
* 在 WebConfig 类上 extends WebMvcConfigurerAdapter 并实现下面的方法
@Override
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(timeInterceptor);
}
*
*/
@Component
public class TimeInterceptor implements HandlerInterceptor {
/**
* 1、某个类的某个方法调用之前被调用
*
* Object handler 拿不到请求参数,参考源码 DispatcherServlet.java 962 行
// 相当于调用这个方法 preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
if (!mappedHandler.applyPreHandle(processedRequest, response)) {
return;
}
// 参数的封装在这里完成 Actually invoke the handler.
ModelAndView mv = ha.handle(processedRequest, response, mappedHandler.getHandler());
*
*
* 返回 true 调用后面的方法;false 不会调用后面的方法
*/
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
throws Exception {
System.out.println("1、preHandle");
// 可以获取到具体的类名和方法名
System.out.println(((HandlerMethod)handler).getBean().getClass().getName());
System.out.println(((HandlerMethod)handler).getMethod().getName());
request.setAttribute("startTime", new Date().getTime());
return true;
}
/**
* 2、某个类的某个方法调用之后被调用,如果出了异常将不会被调用
*/
@Override
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler,
ModelAndView modelAndView) throws Exception {
System.out.println("2、postHandle");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
}
/**
* 3、某个类的某个方法调用之后被调用,不管出不出异常都会被调用
*/
@Override
public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
throws Exception {
System.out.println("3、afterCompletion");
Long start = (Long) request.getAttribute("startTime");
System.out.println("time interceptor 耗时:"+ (new Date().getTime() - start));
System.out.println("ex is "+ex);
}
}
3、切片 aspect
可以拿到请求方法的信息,
可以拿到调用方法的参数值信息,
直接拿不到http的请求和响应的信息,可以通过下面RequestContextHolder对象拿到
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
String requestParam = getReqParameter(request);
String requestMethod = request.getMethod();
String uri = request.getRequestURI();
spring aop 简介
切片(类)
切入点(注解)
a、在哪些方法上起作用
b、在什么时候起作用
增强(方法)
起作用时执行的业务逻辑
package com.moon.web.aspect;
import java.util.Date;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
/**
*
* @Aspect 需要加入依赖
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
*
*/
@Aspect
@Component
public class TimeAspect {
/**
* 定义了在什么时候起作用 Around
* 在哪些方法上起作用 execution(* com.moon.web.controller.UserController.*(..))
* 具体语法可参考
* https://docs.spring.io/spring/docs/4.3.12.BUILD-SNAPSHOT/spring-framework-reference/htmlsingle/#aop-pointcuts
* 搜关键字 Examples
*
* 优点:能拿到controller方法上参数的值
*
* @param pjp
* @return
* @throws Throwable
*/
@Around("execution(* com.moon.web.controller.UserController.*(..))")
public Object handleControllerMethod(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("time aspect start");
// 获取调用方法的参数
Object[] args = pjp.getArgs();
for (Object arg : args) {
System.out.println("arg is "+arg);
}
long start = new Date().getTime();
Object object = pjp.proceed(); // 调用具体方法,得到返回的对象
System.out.println("time aspect 耗时:"+ (new Date().getTime() - start));
System.out.println("time aspect end");
return object;
}
}