spring介面重放過濾問題
阿新 • • 發佈:2022-12-02
1、定義註釋
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; @Retention(RetentionPolicy.RUNTIME) @Target({ElementType.METHOD, ElementType.TYPE}) public @interface AvoidRepeatRequest { /** 請求間隔時間,單位秒,該時間範圍內的請求為重複請求 */ int intervalTime() default 3; /** 是否根據引數進行校驗 */ boolean checkParameter() default false; /** 是否根據使用者進行校驗 */ boolean checkUser() default true; /** 返回的提示資訊 */ String msg() default "請不要頻繁重複請求!"; }
2、新增過濾器
import com.alibaba.fastjson.JSON; import net.jodah.expiringmap.ExpirationPolicy; import net.jodah.expiringmap.ExpiringMap; 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.aspectj.lang.reflect.MethodSignature; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.annotation.Order; 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 java.lang.reflect.Method; import java.util.Map; import java.util.concurrent.TimeUnit; /** * @Description : 重複請求過濾器 * @Author : cxw * @Date : 2022/11/30 10:56 * @Version : 1.0 **/ @Component @Aspect @Order(100) public class RepeatRequestFilter { Logger logger= LoggerFactory.getLogger(RepeatRequestFilter.class); ExpiringMap<String,String> cacheMap = ExpiringMap.builder() //設定最大值,新增第101個entry時,會導致第1個立馬過期(即使沒到過期時間) .maxSize(100000) //設定每個key有效時間60s,如果key不設定過期時間,key永久有效 .expiration(60, TimeUnit.SECONDS) //允許更新過期時間值,如果不設定variableExpiration,不允許後面更改過期時間,一旦執行更改過期時間操作會拋異常UnsupportedOperationException .variableExpiration() //CREATED:只在put和replace方法清零過期時間 //ACCESSED:在CREATED策略基礎上增加 在還沒過期時get方法清零過期時間。 //清零過期時間也就是重置過期時間,重新計算過期時間 .expirationPolicy(ExpirationPolicy.CREATED) .build(); private static final String SUFFIX = "C_"; // 定義 註解 型別的切點 @Pointcut("@annotation(com..api.common.annotation.AvoidRepeatRequest)") public void arrPointcut() {} // 實現過濾重複請求功能 @Around("arrPointcut()") public Object arrBusiness(ProceedingJoinPoint joinPoint) throws Throwable { // 獲取 redis key,由 session ID 和 請求URI 構成 ServletRequestAttributes sra = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes(); HttpServletRequest request = sra.getRequest(); String key = SUFFIX + "_" + request.getRequestURI(); // 獲取方法的 AvoidRepeatRequest 註解 Method method = ((MethodSignature) joinPoint.getSignature()).getMethod(); AvoidRepeatRequest arr = method.getAnnotation(AvoidRepeatRequest.class); if(arr!=null&&arr.checkUser()){ key+="_"+ request.getSession().getId(); } if(arr!=null&&arr.checkParameter()){ Map<String, Object> nameAndValue = ParameterNameUtils.getNameAndValue(joinPoint); if(nameAndValue!=null&&nameAndValue.size()>0){ key+="_"+ JSON.toJSONString(nameAndValue); } } // 判斷是否是重複的請求 if (arr!=null&&continceKey(key,arr.intervalTime())) { throw new Exception("提示:"+arr.msg()); } return joinPoint.proceed(); } /** * 驗證 * @param key * @param intervalTime * @return */ private boolean continceKey(String key, int intervalTime) { String s = cacheMap.get(key); cacheMap.put(key,"v",intervalTime,TimeUnit.SECONDS); if(s!=null){ return true; } return false; } }
3、使用
@AvoidRepeatRequest(intervalTime = 30, msg = "不允許重複提交",checkParameter = true,checkUser = false)
4、引用
<!-- 過期map --> <dependency> <groupId>net.jodah</groupId> <artifactId>expiringmap</artifactId> <version>0.5.9</version> </dependency>