1. 自定義注解
@Target({ElementType.METHOD}) @Retention(RetentionPolicy.RUNTIME) public @interface RateLimit { //默認最大訪問次數 int value() default 3; //默認時間窗口(秒) long duration() default 60; }
2. 創建攔截器處理頻率邏輯
@Slf4j public class RateLimitInterceptor implements HandlerInterceptor { private ConcurrentHashMap<String,Long> requestCountMap = new ConcurrentHashMap<>(); @Override public boolean preHandle(@NotNull HttpServletRequest request, @NotNull HttpServletResponse response, @NotNull Object handler) throws Exception { if (handler instanceof HandlerMethod){ HandlerMethod handlerMethod = (HandlerMethod) handler; RateLimit rateLimitAnnotation = handlerMethod.getMethod().getAnnotation(RateLimit.class); if (rateLimitAnnotation != null){ long duration = rateLimitAnnotation.duration(); int maxRequest = rateLimitAnnotation.value(); String ipAddress = getClientIpAddress(request); String key = ipAddress + ":" + request.getRequestURI(); //獲取上一次請求的時間戳 Long lastAccessTime = requestCountMap.getOrDefault(key, 0L); //獲取當前請求的時間戳 long currentAccessTime = System.currentTimeMillis(); //計算時間間隔 long timeInterval = TimeUnit.MILLISECONDS.toSeconds(currentAccessTime - lastAccessTime); //是否超過時間間隔 if (timeInterval < duration){ //檢查訪問次數是否超過限制 if (requestCountMap.getOrDefault(key + "_count",0L) > maxRequest){ response.getWriter().write("訪問頻率超過限制"); response.setStatus(HttpServletResponse.SC_SERVICE_UNAVAILABLE); return false; } }else { //重置訪問時間和訪問次數 requestCountMap.put(key,currentAccessTime); requestCountMap.put(key + "_count",0L); } //訪問次數 + 1 requestCountMap.put(key + "_count",requestCountMap.getOrDefault(key + "_count",0L) + 1); } } return true; } private String getClientIpAddress(HttpServletRequest request) { // 獲取客戶端IP地址的方法實現,可以根據具體的需求自行實現 // 例如,可以通過HttpServletRequest對象獲取IP地址 // return request.getRemoteAddr(); return "127.0.0.1"; // 這里僅作示例,假設IP地址為本地地址 } }
3. 添加攔截器
@Configuration public class MyConfig implements WebMvcConfigurer { @Override public void addInterceptors(InterceptorRegistry registry) { registry.addInterceptor(new RateLimitInterceptor()); } }
4. 在接口上使用注解
/** * 通過id查詢項目任務書 * @param id id * @return R */ @Operation(summary = "通過id查詢", description = "通過id查詢") @GetMapping("/{id}" ) @RateLimit public R getById(@PathVariable("id" ) String id) { return R.ok(prjAssignService.getByIdAssign(id)); }
在攔截器preHandler中,檢查上次訪問時間和當前時間的時間間隔,根據限制條件判斷是否允許繼續訪問,超過限制則返回對應信息
浙公網安備 33010602011771號