package com.hotent.base.aop;

import java.lang.reflect.Method;

import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import com.hotent.base.service.RedisLock;
import com.hotent.base.util.AuthenticationUtil;
import com.hotent.base.util.BeanUtils;
import com.hotent.base.util.HttpUtil;
import com.hotent.base.util.JsonUtil;


/**
 * 防重复提交aop 接口幂等性控制
 * 只有使用了redis 内存缓存时才生效
 *
 * @author: jason
 * @Date: 2021/02/26
 * @Description:
 */
 
@Aspect
@Component
public class AvoidRepeatableCommitAspect {
 
	private Logger logger = LoggerFactory.getLogger(AvoidRepeatableCommitAspect.class);
	
	@Autowired
	RedisLock redisLock;
	
    /**
     * @param point
     */
	@Around("@annotation(com.hotent.base.annotation.AvoidRepeatableCommit)")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
 
        HttpServletRequest request = HttpUtil.getRequest();
        String uri = request.getRequestURI();
        //获取注解
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();
        //获取请求参数    
        Object[] args = joinPoint.getArgs();
        StringBuffer sb = new StringBuffer();
		if(BeanUtils.isNotEmpty(args)){
			for (Object object : args) {
				if(object instanceof ServletRequest || object instanceof ServletResponse) {
					continue;
				}
				try {
					String json = JsonUtil.toJson(object);
					sb.append(json);
				} catch (Exception e) {
					sb.append(object.toString());
				}
			}
		}
		String queryStr = sb.toString();
        
        //目标类、方法
        String className = method.getDeclaringClass().getName();
        String name = method.getName();
        String uriKey = String.format("%s#%s#%s#%s#%s", uri, className, name, queryStr,AuthenticationUtil.getCurrentUserId());
        int hashCode = Math.abs(uriKey.hashCode());
        String key = String.format("%s_%d", uri, hashCode);
        logger.info("uriKey={},hashCode={},key={}", uriKey, hashCode, key);
        logger.info("防止重复提交");        
        return redisLock.commitRedisLock(key, joinPoint);
    }
}

