1. 程式人生 > >[轉]spring boot 攔截器 或 Spring AOP 方式記錄請求日誌

[轉]spring boot 攔截器 或 Spring AOP 方式記錄請求日誌

選擇使用攔截器實現,在實現中遇到兩個個問題:

a. POST請求 @RequestBody 傳的引數不知怎麼獲取?

b. 返回結果如何獲取?

c.攔截器中service 無法注入;(已解決)

不知道有沒有人遇到這種情況,攔截器沒有解決上述問題,後來使用 spring AOP 處理。 

《一》攔截器方式

@Configuration
public class OptPermissionHandlerInterceptor extends HandlerInterceptorAdapter {

    private Logger logger = LoggerFactory.getLogger(OptPermissionHandlerInterceptor.class);

    @Autowired
    private OptLogService optLogService;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

    } 

    @SuppressWarnings("rawtypes")
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView)
            throws Exception {
        try {
            if (handler instanceof HandlerMethod) {
              
                HandlerMethod handlerMethod = (HandlerMethod) handler;
                String beanName = handlerMethod.getBean().getClass().toString();
                String methodName = handlerMethod.getMethod().getName();
                String uri = request.getRequestURI();
                String remoteAddr = getIpAddr(request);
                String sessionId = request.getSession().getId();
                String user = (String) request.getSession().getAttribute(Constant.USER);
                String method = request.getMethod();
                System.out.println("請求方式為="+method);
                Map params = null;
                if("POST".equals(method)){
                    //........
                }else{
                    params = (Map) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                }
                // 取不到值
                MethodParameter[] mps = ((HandlerMethod) handler).getMethodParameters();
                for(MethodParameter mp : mps){
                    System.out.println(mp.getParameterName() + " --  "+ mp.getParameterType());
                }
                // 取不到值
                Map<String, String[]> params2 = request.getParameterMap();   

                 
               //攔截器中optLogService 沒有注入成功時,重新獲取;
               if (optLogService == null) {
                   System.out.println("optLogService is null !!!");
                    BeanFactory factory =
                            WebApplicationContextUtils.getRequiredWebApplicationContext(request.getServletContext());

                    optLogService = (OptLogService) factory.getBean("optLogService");
                    
                }

                optLogService.saveOptLog(.....);
            }
        } catch (Exception e) {
            logger.error("使用者操作日誌記錄異常", e);
        }
        super.postHandle(request, response, handler, modelAndView);
    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex)
            throws Exception {

    }


    //獲取客戶端IP
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }
}

《二》Spring AOP方式(面向切面)

1.在pom.xml 中引入spring aop 依賴

<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-aop</artifactId>
		</dependency>

2.在 application.properties 檔案中新增:

spring.aop.auto=true
spring.aop.proxy-target-class=false

3.實現切面

@Aspect
@Component
public class WebRequestLogAspect {

    private static Logger logger = LoggerFactory.getLogger(WebRequestLogAspect.class);

    private ThreadLocal<OperatorLog> tlocal = new ThreadLocal<OperatorLog>();

    @Autowired
    private OptLogService optLogService;

    @Pointcut("execution(public * com.whitelover.test..*.create*(..))")
    public void webRequestLog() {}

    // @Order(5)
    @Before("webRequestLog()")
    public void doBefore(JoinPoint joinPoint) {
        try {

            long beginTime = System.currentTimeMillis();

            // 接收到請求,記錄請求內容
            ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
            HttpServletRequest request = attributes.getRequest();
            String beanName = joinPoint.getSignature().getDeclaringTypeName();
            String methodName = joinPoint.getSignature().getName();
            String uri = request.getRequestURI();
            String remoteAddr = getIpAddr(request);
            String sessionId = request.getSession().getId();
            String user = (String) request.getSession().getAttribute("user");
            String method = request.getMethod();
            String params = "";
            if ("POST".equals(method)) {
                Object[] paramsArray = joinPoint.getArgs();
                params = argsArrayToString(paramsArray);
            } else {
                Map<?, ?> paramsMap = (Map<?, ?>) request.getAttribute(HandlerMapping.URI_TEMPLATE_VARIABLES_ATTRIBUTE);
                params = paramsMap.toString();
            }

            logger.debug("uri=" + uri + "; beanName=" + beanName + "; remoteAddr=" + remoteAddr + "; user=" + user
                    + "; methodName=" + methodName + "; params=" + params);

            OperatorLog optLog = new OperatorLog();
            optLog.setBeanName(beanName);
            optLog.setCurUser(user);
            optLog.setMethodName(methodName);
            optLog.setParams(params != null ? params.toString() : "");
            optLog.setRemoteAddr(remoteAddr);
            optLog.setSessionId(sessionId);
            optLog.setUri(uri);
            optLog.setRequestTime(beginTime);
            tlocal.set(optLog);

        } catch (Exception e) {
            logger.error("***操作請求日誌記錄失敗doBefore()***", e);
        }
    }

    // @Order(5)
    @AfterReturning(returning = "result", pointcut = "webRequestLog()")
    public void doAfterReturning(Object result) {
        try {
            // 處理完請求,返回內容
            OperatorLog optLog = tlocal.get();
            optLog.setResult(result.toString());
            long beginTime = optLog.getRequestTime();
            long requestTime = (System.currentTimeMillis() - beginTime) / 1000;
            optLog.setRequestTime(requestTime);

            System.out.println("請求耗時:" + optLog.getRequestTime() + optLog.getUri() + "   **  " + optLog.getParams() + " ** "
                    + optLog.getMethodName());
            System.out.println("RESPONSE : " + result);

            optLogService.saveLog(optLog);
        } catch (Exception e) {
            logger.error("***操作請求日誌記錄失敗doAfterReturning()***", e);
        }
    }


    /**
     * 獲取登入使用者遠端主機ip地址
     * 
     * @param request
     * @return
     */
    private String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        return ip;
    }

    /**
     * 請求引數拼裝
     * 
     * @param paramsArray
     * @return
     */
    private String argsArrayToString(Object[] paramsArray) {
        String params = "";
        if (paramsArray != null && paramsArray.length > 0) {
            for (int i = 0; i < paramsArray.length; i++) {
                Object jsonObj = JSON.toJSON(paramsArray[i]);
                params += jsonObj.toString() + " ";
            }
        }
        return params.trim();
    }

}

spring aop參考網站:

http://blog.didispace.com/springbootaoplog/

@PointCut 表示式參考網站:

http://www.cnblogs.com/lic309/p/4079194.html