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>

 

posted @   扰扰  阅读(88)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 零经验选手,Compose 一天开发一款小游戏!
· 因为Apifox不支持离线,我果断选择了Apipost!
· 通过 API 将Deepseek响应流式内容输出到前端
点击右上角即可分享
微信分享提示