ApiLogAspect.java 12.5 KB
package com.huaheng.framework.aspectj;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.huaheng.common.utils.ServletUtils;
import com.huaheng.common.utils.StringUtils;
import com.huaheng.common.utils.security.ShiroUtils;
import com.huaheng.framework.aspectj.lang.annotation.ApiLogger;
import com.huaheng.framework.web.domain.AjaxResult;
import com.huaheng.pc.config.address.domain.Address;
import com.huaheng.pc.config.address.service.AddressService;
import com.huaheng.pc.monitor.apilog.domain.ApiLog;
import com.huaheng.pc.monitor.apilog.service.IApiLogService;
import org.apache.commons.lang.exception.ExceptionUtils;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;

/**
 * Api调用日志记录处理
 * 
 * @author huaheng
 */
@Aspect
@Component
//@EnableAsync
public class ApiLogAspect
{
    private static final Logger log = LoggerFactory.getLogger(ApiLogAspect.class);

    private static IApiLogService apiLogService;

    private static AddressService addressService;


    @Autowired
    public void setApiLogService(IApiLogService apiLogService){
        ApiLogAspect.apiLogService = apiLogService;
    }

    @Autowired
    public void setAddressService(AddressService addressService){
        ApiLogAspect.addressService = addressService;
    }

    // 配置织入点
    @Pointcut("@annotation(com.huaheng.framework.aspectj.lang.annotation.ApiLogger)")
    public void logPointCut()
    {
    }

    @Around("logPointCut()  && @annotation(apiLogger)")
    public Object around(ProceedingJoinPoint point, ApiLogger apiLogger) throws Throwable
    {
        if("WMS".equalsIgnoreCase(apiLogger.from()))
            //实际上静态方法上的Aop注解无法拦截到
            return aroundWms2XXX(point, apiLogger);
        else
            return aroundXXX2Wms(point, apiLogger);
    }

    /**处理xxx调用wms接口的日志**/
    private Object aroundXXX2Wms(ProceedingJoinPoint point, ApiLogger apiLogger){
        Object ret = null;
        ApiLog log = initApiLog(apiLogger, point);
        try{
            ret = point.proceed();
        }catch (Exception e){
            setApiLogException(log, e);
            throw e;
        }finally{
            finishApiLog(log, ret);
            return ret;
        }
    }

    /**处理WMS调用xxx接口的日志**/
    private Object aroundWms2XXX(ProceedingJoinPoint point, ApiLogger apiLogger){
        Object ret = null;
        ApiLog log = new ApiLog();

        HttpURLConnection connection = null;
        String body = null;

        try {
            HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
            connection = (HttpURLConnection) point.getArgs()[0];
            body = (String) point.getArgs()[1];
            initApiLog(connection, body, ShiroUtils.getWarehouseCode());
        }catch (Exception e){

        }

        try{
            ret = point.proceed();
        }catch (Exception e){
            setApiLogException(log, e);
            throw e;
        }finally{
            if(ret != null) {
                finishApiLog(log, connection, ret.toString());
            }
            return ret;
        }
    }

    /**记录WMS调用外接口的请求信息
     * 在HttpUtils.bodypost方法中直接调用本类static方法**/
    public static  ApiLog initApiLog(HttpURLConnection connection, String body, String warehouseCode){
        ApiLog log = new ApiLog();
        try {
            log.setApiMethod(connection.getRequestMethod());
            log.setUrl(connection.getURL().toString());
            log.setRequestTime(new Date());
            parseUrl(log, connection.getURL(), warehouseCode);

            //请求头
            Set<String> keySet = connection.getRequestProperties().keySet();
            ArrayList<String> headerList = new ArrayList<>();
            Iterator<String> it = keySet.iterator();
            while (it.hasNext()) {
                String name = it.next();
                String header = connection.getRequestProperty(name);
                headerList.add(name + ": " + header);
            }

            log.setRequestHeader(org.apache.commons.lang3.StringUtils.join(headerList, "\n"));
            log.setRequestBody(body);
        }catch (Exception e){
            e.printStackTrace();
        }

        return log;
    }

    /**根据url,从address表中判断调用的去向**/
    public static void parseUrl(ApiLog log, URL url, String warehouseCode){
        try {
            String[] spList = url.toString().split("/");
            String apiName = spList[spList.length - 1];
            int index = url.toString().lastIndexOf(apiName);
            String addUrl = url.toString().substring(0, index);

            Address address = addressService.getAddressByUrl(url.toString(), warehouseCode);
            log.setApiName(apiName);
            log.setRequestFrom("WMS");
            log.setResponseBy(address.getParam().toUpperCase());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**记录响应头信息**/
    public static void finishApiLog(ApiLog log, HttpURLConnection connection, String body){
        try {
            log.setResponseBody(body);
            log.setResponseTime(new Date());
            Long duration = log.getResponseTime().getTime() - log.getRequestTime().getTime();
            log.setDuration(duration.intValue());
            log.setHttpCode(String.valueOf(connection.getResponseCode()));

            //响应头
            Set<String> keyset = connection.getHeaderFields().keySet();
            ArrayList<String> headerList = new ArrayList<>();
            Iterator<String> it = keyset.iterator();
            while(it.hasNext()){
                String name = it.next();
                String header = connection.getHeaderField(name);
                if(name == null || "".equals(name))
                    //第一行没有name
                    //HTTP/1.1 200 OK
                    headerList.add(header);
                else
                    headerList.add(name + ": " + header);
            }
            log.setResponseHeader(org.apache.commons.lang3.StringUtils.join(headerList, "\n"));
            AjaxResult json = JSON.parseObject(body, AjaxResult.class);
            log.setRetCode(String.valueOf(json.getCode()));
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            saveApiLog(log);
        }
    }

    private ApiLog initApiLog(ApiLogger apiLogger, ProceedingJoinPoint point){
        ApiLog log = new ApiLog();
        try{
            log.setRequestTime(new Date());
            log.setRequestFrom(apiLogger.from());
            log.setResponseBy(apiLogger.to());
            log.setApiName(apiLogger.apiName());

            HttpServletRequest request = ServletUtils.getRequest();

            String qryStr = request.getQueryString();
            String url = request.getRequestURL().toString();
            if(StringUtils.isNotEmpty(qryStr))
                url = url + "?" + qryStr;
            log.setUrl(url);

            log.setApiMethod(request.getMethod());
            log.setIp(request.getRemoteAddr());

            rebuildRequestHeader(log);

            rebuildRequestBody(log, request);

            //如果reqeust中取不到post参数,就从接口方法参数中取json对象
            if(StringUtils.isEmpty(log.getRequestBody()))
                rebuildRequestBody(log, point);

        }catch (Exception e){
            e.printStackTrace();
        }

        return log;
    }

    private void finishApiLog(ApiLog log, Object ret){
        try {
            rebuildResponseHeader(log);
            rebuildResponseBody(log, ret);

            log.setResponseTime(new Date());
            Long duration = log.getResponseTime().getTime() - log.getRequestTime().getTime();
            log.setDuration(duration.intValue());

            HttpServletResponse resp = ServletUtils.getResponse();
            log.setHttpCode(String.valueOf(resp.getStatus()));

            if (ret instanceof AjaxResult) {
                int retCode = ((AjaxResult) ret).getCode();
                log.setRetCode(String.valueOf(retCode));
            }
        }catch (Exception e){
            e.printStackTrace();
        }finally {
            saveApiLog(log);
        }
    }

    public static void setApiLogException(ApiLog log, Exception e){
        try {
            String exception = ExceptionUtils.getFullStackTrace(e);
            String shortExpInfo = e.getMessage() + "\n" + org.apache.commons.lang3.StringUtils.left(exception, 1000);
            log.setException(shortExpInfo);
        }catch (Exception ex){
            ex.printStackTrace();
        }
    }

    private void rebuildRequestHeader(ApiLog log){
        try {
            HttpServletRequest req = ServletUtils.getRequest();
            Enumeration names = req.getHeaderNames();
            ArrayList<String> headerList = new ArrayList<>();
            while(names.hasMoreElements()){
                String name = (String)names.nextElement();
                String header = req.getHeader(name);
                headerList.add(name + ": " + header);
            }
            String headers = org.apache.commons.lang3.StringUtils.join(headerList, "\n");
            log.setRequestHeader(headers);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**先从post参数中构造request body*/
    private void rebuildRequestBody(ApiLog log, HttpServletRequest request){
        try{
            Set<String> keySet = request.getParameterMap().keySet();
            Iterator<String> it = keySet.iterator();
            StringBuffer sbf = new StringBuffer();
            while(it.hasNext()){
                String key = it.next();
                String value = request.getParameter(key);
                sbf.append(key).append("=").append(value);
                if(it.hasNext())
                    sbf.append("&");
            }
            log.setRequestBody(sbf.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    /**
     * 根据接口中的参数构造request body
     */
    private void rebuildRequestBody(ApiLog log, ProceedingJoinPoint point)
    {
        try {
            if (point.getArgs().length == 1) {
                log.setRequestBody(JSONObject.toJSONString(point.getArgs()[0]));
                return;
            }

            MethodSignature m = (MethodSignature) point.getSignature();
            HashMap<String, Object> map = new HashMap<>();
            Object[] args = point.getArgs();
            for (int i = 0; i < m.getParameterNames().length; i++) {
                String name = m.getParameterNames()[i];
//                Class type = m.getParameterTypes()[i];
                map.put(name, args[i]);
            }

            if(!map.isEmpty())
                log.setRequestBody(JSONObject.toJSONString(map));
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void rebuildResponseHeader(ApiLog log){
        try {
            HttpServletResponse resp = ServletUtils.getResponse();
            Collection names = resp.getHeaderNames();
            ArrayList<String> headerList = new ArrayList<>();
            Iterator<String> it = names.iterator();
            while(it.hasNext()){
                String name = it.next();
                String header = resp.getHeader(name);
                headerList.add(name + ": " + header);
            }
            String headers = org.apache.commons.lang3.StringUtils.join(headerList, "\n");
            log.setResponseHeader(headers);
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    private void rebuildResponseBody(ApiLog log, Object ret){
        try {
            log.setResponseBody(JSONObject.toJSON(ret).toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }

    public static void saveApiLog(ApiLog log){
        try{
            apiLogService.saveOrUpdate(log);
        }catch (Exception e){
            e.printStackTrace();
        }
    }
}