package com.xm.demo.aop.common.aspect;

import java.lang.reflect.Field;
import java.net.URLDecoder;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import org.apache.commons.lang3.StringUtils;
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.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.web.context.request.RequestAttributes;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.multipart.MultipartFile;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import cn.hutool.core.util.IdUtil;

/**
 * @author mengxc
 * @ClassName: LoggerAspect
 * @Description: 打印请求参数和返回结果
 * @date 2020年12月9日 上午10:22:35
 */
@Aspect
@Configuration
@Order(-9)
@ConditionalOnProperty(value = "print.enable", havingValue = "true", matchIfMissing = false)
public class PrintAspect {

	private static final Logger log = LoggerFactory.getLogger(PrintAspect.class);

	// 定义切点Pointcut
	@Pointcut("execution(* com.xm.demo.aop.controller.*.*(..))")
	public void executeService() {
	}

	@Around("executeService()")
	public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
		String uuid = IdUtil.fastSimpleUUID().toUpperCase();
		try {
			RequestAttributes ra = RequestContextHolder.getRequestAttributes();
			ServletRequestAttributes sra = (ServletRequestAttributes) ra;
			HttpServletRequest request = sra.getRequest();
//			String url = request.getRequestURL().toString();
			String method = request.getMethod();
			String uri = request.getRequestURI();
			String queryString = request.getQueryString();
			Object[] args = pjp.getArgs();
			String params = "";
			// 获取请求参数集合并进行遍历拼接
			if (args.length > 0) {
				if ("POST".equals(method) || "PUT".equals(method) || "DELETE".equals(method)) {
					Map<String, Object> map = new HashMap<>();
					for (int i = 0; i < args.length; i++) {
						Object object = args[i];
						Map<String, Object> mapObj = getKeyAndValue(object);
						if (!mapObj.isEmpty()) {
							map.putAll(mapObj);
						}
					}
					try {
						params = JSON.toJSONString(map);
						JSONObject obj = JSONObject.parseObject(params);
						params = "\n" + JSON.toJSONString(obj, SerializerFeature.PrettyFormat,
								SerializerFeature.WriteMapNullValue, SerializerFeature.WriteDateUseDateFormat);
					} catch (Exception e) {
						try {
							params = JSON.toJSONString(map);
						} catch (Exception exception) {
							log.error("打印参数解析异常");
						}
					}
				} else if ("GET".equals(method)) {
					if (StringUtils.isNotEmpty(queryString)) {
						params = URLDecoder.decode(queryString, "UTF-8");
					}
				}
			}

			log.info(" \n===============================请求->开始===============================" + "\n追踪标记:" + uuid
					+ "\n请求地址:" + uri + "\n请求类型:" + method + "\n请求参数:" + params
					+ "\n===============================请求->结束===============================");
			// result的值就是被拦截方法的返回值
			Object result = null;

			result = pjp.proceed();

			log.info(" \n===============================返回值->开始===============================" + "\n追踪标记:" + uuid
					+ "\n请求地址:" + uri + "\n返回值:" + JSON.toJSON(result)
					+ "\n===============================返回值->结束===============================");
			return result;
		} catch (Exception e) {
			log.info(" \n===============================请求异常->开始===============================" + "\n追踪标记:" + uuid
					+ "\n异常信息:" + e + "\n===============================请求异常->结束===============================");
		}
		return pjp.proceed();
	}

	public static Map<String, Object> getKeyAndValue(Object obj) {
		Map<String, Object> map = new HashMap<>();
		if (obj instanceof MultipartFile || obj instanceof ServletRequest || obj instanceof ServletResponse) {
			log.debug("MultipartFile|HttpServletRequest|HttpServletResponse参数");
			return map;
		}
		try {
			// 得到类对象
			Class<?> userCla = obj.getClass();
			/* 得到类中的所有属性集合 */
			Field[] fs = userCla.getDeclaredFields();
			for (Field f : fs) {
				f.setAccessible(true); // 设置些属性是可以访问的
				Object val;
				try {
					val = f.get(obj);
					// 得到此属性的值
					map.put(f.getName(), val);// 设置键值
				} catch (IllegalArgumentException | IllegalAccessException e) {
					log.error("异常", e);
				}
			}
		} catch (Exception e) {
			log.error("【异常】解析对象异常");
		}
		return map;
	}
}