SpringCloud後端要對前端請求進行攔截,也就是日誌記錄,使用SpringAOP方式即面向切面方式進行攔截。前端
首先,攔截請求地址(ip),使用HandlerInterceptorAdapter,它攔截的是請求地址,因此針對請求地址作一些驗證、預處理操做比較合適,好比下面,我用它來統計請求訪問這個地址的響應時間。java
RequestLogweb
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"); } } }
而後,進行面向切面攔截,將請求日誌記錄下來spring
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裏面的<beans>標籤,類中 @Bean能夠理解爲用Spring的時候xml裏面的<bean>標籤 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<args.length;i++){ if(args[i] instanceof RequestInfo<?>){ 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; } }