com.myb.aop.ResubmitAspectjProcess Maven / Gradle / Ivy
package com.myb.aop;
import cn.hutool.json.JSONUtil;
import com.myb.annotation.Jdlog;
import com.myb.annotation.ResubmitCheck;
import com.myb.config.LogProperties;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Conditional;
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.HttpSession;
import java.util.HashMap;
import java.util.Map;
/**
* @Author meiyubin
* @Date 2023/11/23
* @DESC
*/
@Aspect
@Slf4j
@AllArgsConstructor
public class ResubmitAspectjProcess {
public final String REPEAT_PARAMS = "repeatParams";
public final String REPEAT_TIME = "repeatTime";
public final String SESSION_REPEAT_KEY = "repeatData";
/**
* 判断请求url和数据是否和上一次相同,
* 如果和上次相同,则是重复提交表单。 有效时间为10秒内。
*
*
* 判断是否重复提交,整体的思路:
* * 获取当前请求的URL作为键Key,暂且标记为:A1,其取值为映射Map(Map里面的元素由:请求的链接url 和 请求体的数据组成) 暂且标记为V1;
* * 从缓存中(本地缓存或者分布式缓存)查找Key=A1的值V2,如果V2和V1的值一样,即代表当前请求是重复提交的,拒绝执行后续的请求,否则可以继续往后面执行
* * 其中,设定重复提交的请求的间隔有效时间为8秒
* *
* * 注意点:如果在有效时间内,如10秒内,一直发起同个请求url、同个请求体,那么重复提交的有效时间将会自动延长
*/
//@Before("@annotation(com.junyu.api.common.annotation.ResubmitCheck)")
@Before(value = "@annotation(resubmitCheck)", argNames = "resubmitCheck")
public void resubmitCheck(ResubmitCheck resubmitCheck) {
ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
HttpServletRequest request = attributes.getRequest();
if (isRepeatSubmit(request, resubmitCheck.expireTime())) {
throw new RuntimeException("请勿短时间内重复点击按钮");
}
}
private boolean isRepeatSubmit(HttpServletRequest request, int expireTime) {
// 本次参数及系统时间
String nowParams = JSONUtil.toJsonStr(request.getParameterMap());
Map nowDataMap = new HashMap();
nowDataMap.put(REPEAT_PARAMS, nowParams);
nowDataMap.put(REPEAT_TIME, System.currentTimeMillis());
// 请求地址(作为存放session的key值)
String url = request.getRequestURI();
HttpSession session = request.getSession();
Object sessionObj = session.getAttribute(SESSION_REPEAT_KEY);
if (sessionObj != null) {
Map sessionMap = (Map) sessionObj;
if (sessionMap.containsKey(url)) {
Map preDataMap = (Map) sessionMap.get(url);
if (compareParams(nowDataMap, preDataMap) && compareTime(nowDataMap, preDataMap, expireTime)) {
return true;
}
}
}
Map sessionMap = new HashMap();
sessionMap.put(url, nowDataMap);
session.setAttribute(SESSION_REPEAT_KEY, sessionMap);
return false;
}
/**
* 判断参数是否相同
*/
private boolean compareParams(Map nowMap, Map preMap) {
String nowParams = (String) nowMap.get(REPEAT_PARAMS);
String preParams = (String) preMap.get(REPEAT_PARAMS);
return nowParams.equals(preParams);
}
/**
* 判断两次间隔时间
*/
private boolean compareTime(Map nowMap, Map preMap, int expireTime) {
long time1 = (Long) nowMap.get(REPEAT_TIME);
long time2 = (Long) preMap.get(REPEAT_TIME);
if ((time1 - time2) < (expireTime * 1000)) {
return true;
}
return false;
}
}