SpringCloud后端要对前端请求进行拦截,也就是日志记录,使用SpringAOP方式即面向切面方式进行拦截。
首先,拦截请求地址(ip),使用HandlerInterceptorAdapter,它拦截的是请求地址,所以针对请求地址做一些验证、预处理操作比较合适,比如下面,我用它来统计请求访问这个地址的响应时间。
RequestLog
import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.web.method.HandlerMethod;import org.springframework.web.servlet.ModelAndView;import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;import javax.servlet.http.HttpServletRequest;import javax.servlet.http.HttpServletResponse;import java.lang.reflect.Method;import java.time.Instant;/* HandlerInterceptoer拦截的是请求地址,所以针对请求地址做一些验证、预处理等操作比较合适, 比如需要统计请求这个地址的响应时间*//* Filter是Servlet规范规定的,不属于spring框架,也是用于请求的拦截。 但是它适合更粗粒度的拦截,在请求前后做一些编解码处理、日志记录等。*/public class RequestLog extends HandlerInterceptorAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(RequestLog.class); /** * 前置检查,方法执行前 */ @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { String ip = request.getRemoteAddr(); Instant startTime = Instant.now(); request.setAttribute("logrequestStartTime", startTime); HandlerMethod handlerMethod = (HandlerMethod) handler; // 获取用户token Method method = handlerMethod.getMethod(); LOGGER.info("用户:"+ip+",访问目标:"+method.getDeclaringClass().getName() + "." + method.getName()); return true; } /** * 方法执行中 * @param request * @param response * @param handler * @param modelAndView * @throws Exception */ // controller处理完成 public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { HandlerMethod handlerMethod = (HandlerMethod) handler; Method method = handlerMethod.getMethod(); Instant startTime = (Instant) request.getAttribute("logrequestStartTime"); Instant endTime = Instant.now(); long executeTime = endTime.toEpochMilli()- startTime.toEpochMilli(); // log it if (executeTime > 1000) { LOGGER.info("[" + method.getDeclaringClass().getName() + "." + method.getName() + "] 执行耗时 : " + executeTime + "ms"); } else { LOGGER.info("[" + method.getDeclaringClass().getSimpleName() + "." + method.getName() + "] 执行耗时 : " + executeTime + "ms"); } }}
然后,进行面向切面拦截,将请求日志记录下来
import org.aspectj.lang.ProceedingJoinPoint;import org.aspectj.lang.annotation.Around;import org.aspectj.lang.annotation.Aspect;import org.aspectj.lang.annotation.Pointcut;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import org.springframework.context.annotation.Configuration;import org.springframework.web.context.request.RequestAttributes;import org.springframework.web.context.request.RequestContextHolder;import org.springframework.web.context.request.ServletRequestAttributes;import javax.servlet.http.HttpServletRequest;/** * Created by pd on 17/12/07. *///描述切面类@Aspect //@Aspect注解就是告诉spring 这是一个aop类,AOP切面@Configuration //可理解为用spring的时候xml里面的标签,类中 @Bean可以理解为用Spring的时候xml里面的 标签public class LogRecordAspect {private static final Logger logger = LoggerFactory.getLogger(LogRecordAspect.class); // 用@Pointcut来注解一个切入方法 //@Pointcut注解 声明这是一个需要拦截的切面,也就是说,当调用任何一个controller方法的时候,都会激活这个aop @Pointcut("execution(* com.pengda.controller.*Controller.*(..))") //两个..代表所有子目录,最后括号里的两个..代表所有参数 public void excudeService() { } //@Around注解 环绕执行,就是在调用之前和调用之后,都会执行一定的逻辑 @Around("excudeService()") public Object doAround(ProceedingJoinPoint pjp) throws Throwable { RequestAttributes ra = RequestContextHolder.getRequestAttributes(); ServletRequestAttributes sra = (ServletRequestAttributes) ra; HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest(); String url = request.getRequestURL().toString(); String method = request.getMethod(); String uri = request.getRequestURI(); String queryString = request.getQueryString(); try{ Object[] args =pjp.getArgs(); for(int i=0;i ){ RequestInfo r= (RequestInfo ) args[i]; logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri, r.toString()); }else{ logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri,args[i]); } } }catch (Exception e){ logger.info("请求开始, 各个参数, url: {}, method: {}, uri: {}, params: {}", url, method, uri,queryString); } // result的值就是被拦截方法的返回值 Object result = pjp.proceed(); //logger.info("请求结束,controller的返回值是 " + result.toString()); //logger.info("请求结束,controller的返回值是 " + result); return result; }}