package com.fdkanfang.web.aop;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
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;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * Created by owen on 2020/2/25 0025 9:24
 *
 * 日志aop
 */
@Slf4j
@Aspect
@Component
public class WebLogAspect {

    @Autowired
    private HttpServletRequest request;

    @Pointcut("execution(* com.fdkanfang.web.backend.*.*(..))")//切入点描述 这个是controller包的切入点
    public void controllerLog(){}//签名，可以理解成这个切入点的一个名称

    @Before("controllerLog()") //在切入点的方法run之前要干的
    public void logBeforeController(JoinPoint joinPoint) throws Exception {

        // 记录下请求内容
        log.warn("start : {}" , request.getRequestURI());
        log.info("request Method : {}" , request.getMethod());
        log.info("request IP : {}" , request.getRemoteAddr());

        Object[] args = joinPoint.getArgs();
        if (args.length > 0) {
            log.info("request Args : {}" , Arrays.toString(args));
        }


        String description = getControllerLogDescription(joinPoint);
        if (!StringUtils.isAllBlank(description)) {
            log.info("request description : {}", description);
        }

        //下面这个getSignature().getDeclaringTypeName()是获取包+类名的   然后后面的joinPoint.getSignature.getName()获取了方法名
        log.info("request Class_Method : {}" , joinPoint.getSignature().getDeclaringTypeName() + "." + joinPoint.getSignature().getName());

    }


    //使用@AfterReturning在切入点return内容之后切入内容（可以用来对处理返回值做一些加工处理）
    @AfterReturning(returning = "ret", pointcut = "controllerLog()")
    public void doAfterReturning(Object ret) throws Throwable {
        // 处理完请求，返回内容
//        log.info("响应RESPONSE : " + ret.toString());
        log.warn("end : {}", request.getRequestURI());
    }

    /**
     * 获取注解中对方法的描述信息 用于Controller层注解
     *
     * @param joinPoint
     *            切点
     * @return 方法描述
     * @throws Exception
     */
    public static String getControllerLogDescription(JoinPoint joinPoint) throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        String description = "";
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzs = method.getParameterTypes();
                if (clazzs.length == arguments.length) {
                    WebControllerLog annotation = method.getAnnotation(WebControllerLog.class);
                    if (annotation != null) {
                        description = annotation.description();
                        break;
                    }
                }
            }
        }
        return description;
    }

    private static List<String> getDetail(String str){
        String[] split = str.split("-");
        return Arrays.asList(split);
    }
}
