spring接口重放过滤问题
1、定义注释
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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、添加过滤器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 | 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>
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端