1,自定义注解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
 /**
 * @author zxz
 * @date 2021/8/24 9:30
 **/
 @Retention(RUNTIME)
 @Target(METHOD)
 public @interface AccessLimit {
     //秒
     int seconds() default 3;
     //次数
     int maxCount() default 15;
     //是否登陆
     boolean needLogin()default true;
 }

该注解默认情况下:登陆后访问,每3秒不能超过15

2,redis工具

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
public class RedisUtil {

    @Autowired //操作字符串的template,StringRedisTemplate是RedisTemplate的一个子集
    private StringRedisTemplate stringRedisTemplate;

    @Autowired  // RedisTemplate,可以进行所有的操作
    private RedisTemplate<Object,Object> redisTemplate;

    /**
     * 存储值
     * @param key
     * @param value
     */
    public void set(String key, String value){
        stringRedisTemplate.opsForValue().set(key, value);
    }


    public String get(String key){
        return stringRedisTemplate.opsForValue().get(key);
    }

    /**
     * 存储带有有效期的值
     * @param key
     * @param value
     * @param timeInSeconds
     */
    public void setWithExpireTime(String key, String value, Long timeInSeconds) {
         stringRedisTemplate.opsForValue().set(key, value, timeInSeconds, TimeUnit.SECONDS);
    }

    /**
     * 是否存在key
     */
    public Boolean exists(String key){
        return stringRedisTemplate.hasKey(key);
    }
    /**
     * 删除key
     */

    public void del(String key){
         redisTemplate.delete(key);
    }

}

3,添加拦截器

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
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
/**
 * @author zxz
 * @date 2021/8/24 9:41
 **/
@Component
public class FangshuaInterceptor extends HandlerInterceptorAdapter {
    @Autowired
    private RedisUtil redisUtil;
    public ConcurrentHashMap<String,Integer> timeMap=new ConcurrentHashMap();
    public ConcurrentHashMap<String,Integer> countMap=new ConcurrentHashMap();

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {

        //判断请求是否属于方法的请求
        if(handler instanceof HandlerMethod){
            removeKey();
            HandlerMethod hm = (HandlerMethod) handler;
            //获取方法中的注解,看是否有该注解
            AccessLimit accessLimit = hm.getMethodAnnotation(AccessLimit.class);
            if(accessLimit == null){
                return true;
            }
            //白名单
            String whiteList=redisUtil.get("whitelist");
            if(StringUtils.isNotBlank(whiteList)){
                String ip=getIpAddr(request);
                String[] ips=whiteList.split(",");
                for (int i = 0; i <ips.length ; i++) {
                    if(ip.equals(ips[i])){
                        return true;
                    }
                }
            }
            //黑名单
            String blacklist=redisUtil.get("blacklist");
            if(StringUtils.isNotBlank(blacklist)){
                String ip=getIpAddr(request);
                String[] ips=blacklist.split(",");
                for (int i = 0; i <ips.length ; i++) {
                    if(ip.equals(ips[i])){
                        return false;
                    }
                }
            }

            int seconds = accessLimit.seconds();
            int maxCount = accessLimit.maxCount();
            boolean login = accessLimit.needLogin();
            String key = request.getRequestURI();
            //如果需要登录
            if(login){
                //获取登录的session进行判断
                String sessionId=request.getSession().getId();
                key=key+sessionId;
            }
            Integer second=timeMap.get(key);
            Integer count=countMap.get(key);
            if(count == null){
                //第一次访问
                threadMethodTime(key,seconds);
                countMap.put(key,1);
            }else if(count <= maxCount&&second>0){
                countMap.put(key,count+1);
            }else if(count > maxCount&&second>0){
                //拉入黑名单
                String blacklistStr=redisUtil.get("blacklist");
                blacklistStr= StringUtils.isEmpty(blacklistStr)?getIpAddr(request):blacklistStr+","+getIpAddr(request);
                redisUtil.set("blacklist",blacklistStr);
                //超出访问次数
                render(response, ResultEnums.error1001); //这里的CodeMsg是一个返回参数
                countMap.remove(key);
                return false;
            }else{
                //超出访问次数
                render(response, ResultEnums.error1001); //这里的CodeMsg是一个返回参数
                countMap.remove(key);
                return false;
            }
        }
        return true;

    }
    private void render(HttpServletResponse response, ResultEnums cm)throws Exception {
        response.setContentType("application/json;charset=UTF-8");
        OutputStream out = response.getOutputStream();
        String str  = JSONUtil.toJsonStr(BaseRes.failure(cm.code,cm.value));
        out.write(str.getBytes("UTF-8"));
        out.flush();
        out.close();
    }
//删除时间到期的key
private void removeKey(){
        for (String secondKey:timeMap.keySet()) {
            Integer second=timeMap.get(secondKey);
            if(second!=null&&second==0){
                countMap.remove(secondKey);
                timeMap.remove(secondKey);
            }
        }
    }
    /**
     * 获取真实IP
     * @param request
     * @return
     */
    public  String getIpAddr(HttpServletRequest request) {
        String ip = request.getHeader("x-forwarded-for");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddr();
        }
        if ("0:0:0:0:0:0:0:1".equals(ip)) {
            ip = "127.0.0.1";
        }
        if (ip.split(",").length > 1) {
            ip = ip.split(",")[0];
        }
        return ip;
    }

    //新增线程计算时间
    public void threadMethodTime(String key,Integer seconds) {
        new Thread(() -> {
            // 线程本地变量,线程安全
            ThreadLocal<Integer> local = new ThreadLocal<>();
            local.set(seconds);
            for (int i = 0; i < seconds; i++) {
                if (local.get() != 0) {
                    try {
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    local.set(local.get() - 1);
                    timeMap.put(key,local.get());
                }
            }

        }).start();
    }
}




/**
 * @author zxz
 * @date 2021/8/24 10:27
 **/
@Configuration
public class WebConfig extends WebMvcConfigurationSupport {
    @Autowired
    private FangshuaInterceptor interceptor;

    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(interceptor).addPathPatterns("/**");
    }
}

至此,就可以正常使用了

使用方式:

1
2
3
4
5
6
7
8
9
10
11
12
13
     //默认
    @AccessLimit
    @GetMapping("/getOneLiveAddress")
    public BaseRes getOneLiveAddress(HKVidiconDTO hkVidiconDTO){
        return null;
    }
    
    //自定义
    @AccessLimit(seconds = 5,maxCount = 100,needLogin = false)
    @GetMapping("/getOneLiveAddress")
    public BaseRes getOneLiveAddress(HKVidiconDTO hkVidiconDTO){
        return null;
    }