1. 添加Maven依赖

<dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-data-redis</artifactId></dependency>
</dependencies>

2. 创建自定义注解

import java.lang.annotation.*;/*** 接口防刷注解*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@Documented
public @interface AccessLimit {/*** 限制时间范围(秒)*/int time() default 60;/*** 时间范围内最大访问次数*/int maxCount() default 10;/*** 是否检查IP地址*/boolean checkIp() default true;/*** 是否检查用户身份(需要登录)*/boolean checkUser() default false;/*** 触发限制时的提示信息*/String message() default "操作过于频繁,请稍后再试";
}

3. 创建AOP切面实现防护逻辑

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
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.concurrent.TimeUnit;@Aspect
@Component
public class AccessLimitAspect {@Autowiredprivate RedisTemplate<String, Object> redisTemplate;@Around("@annotation(accessLimit)")public Object around(ProceedingJoinPoint joinPoint, AccessLimit accessLimit) throws Throwable {// 获取请求对象ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();if (attributes == null) {return joinPoint.proceed();}HttpServletRequest request = attributes.getRequest();MethodSignature signature = (MethodSignature) joinPoint.getSignature();Method method = signature.getMethod();// 构建Redis keyString key = buildKey(request, method, accessLimit);// 获取当前计数ValueOperations<String, Object> operations = redisTemplate.opsForValue();Integer count = (Integer) operations.get(key);if (count == null) {// 第一次访问operations.set(key, 1, accessLimit.time(), TimeUnit.SECONDS);} else if (count < accessLimit.maxCount()) {// 计数增加operations.increment(key);} else {// 超出限制,抛出异常throw new RuntimeException(accessLimit.message());}return joinPoint.proceed();}/*** 构建Redis key*/private String buildKey(HttpServletRequest request, Method method, AccessLimit accessLimit) {StringBuilder key = new StringBuilder("access_limit:");// 添加方法标识key.append(method.getDeclaringClass().getName()).append(".").append(method.getName()).append(":");// 添加IP标识if (accessLimit.checkIp()) {String ip = getClientIp(request);key.append(ip).append(":");}// 添加用户标识(需要实现获取当前用户的方法)if (accessLimit.checkUser()) {// 这里需要根据你的用户系统实现获取当前用户ID的方法String userId = getCurrentUserId();if (userId != null) {key.append(userId).append(":");}}return key.toString();}/*** 获取客户端IP*/private String getClientIp(HttpServletRequest request) {String ip = request.getHeader("X-Forwarded-For");if (ip != null && ip.length() != 0 && !"unknown".equalsIgnoreCase(ip)) {// 多次反向代理后会有多个ip值,第一个ip才是真实ipif (ip.contains(",")) {ip = ip.split(",")[0];}}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.getHeader("HTTP_CLIENT_IP");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getHeader("HTTP_X_FORWARDED_FOR");}if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {ip = request.getRemoteAddr();}return ip;}/*** 获取当前用户ID(需要根据实际情况实现)*/private String getCurrentUserId() {// 实现获取当前用户ID的逻辑// 可以从Session、Token或Spring Security上下文等获取return null;}
}

4. 创建全局异常处理器

import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;@RestControllerAdvice
public class GlobalExceptionHandler {@ExceptionHandler(RuntimeException.class)public Result handleRuntimeException(RuntimeException e) {return Result.error(e.getMessage());}
}

5. 在Controller中使用注解

import org.springframework.web.bind.annotation.*;@RestController
@RequestMapping("/api")
public class DemoController {// 基于IP的限制:60秒内最多访问10次@AccessLimit(time = 60, maxCount = 10, checkIp = true, checkUser = false)@GetMapping("/public/data")public String getPublicData() {return "这是公开数据";}// 基于用户的限制:30秒内最多访问5次@AccessLimit(time = 30, maxCount = 5, checkIp = false, checkUser = true)@GetMapping("/user/data")public String getUserData() {return "这是用户数据";}// 同时基于IP和用户的限制:60秒内最多访问3次@AccessLimit(time = 60, maxCount = 3, checkIp = true, checkUser = true)@PostMapping("/submit")public String submitData(@RequestBody String data) {return "提交成功: " + data;}
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/98058.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/98058.shtml
英文地址,请注明出处:http://en.pswp.cn/diannao/98058.shtml

如若内容造成侵权/违法违规/事实不符,请联系英文站点网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

代码随想录二刷之“贪心算法”~GO

简单题目 1.455. 分发饼干 - 力扣&#xff08;LeetCode&#xff09; func findContentChildren(g []int, s []int) int {sort.Ints(g)sort.Ints(s)index : 0for i : 0;i<len(s);i{if index < len(g) && g[index] < s[i]{index}}return index }感悟&#xff…

Pod自动重启问题排查:JDK 17 EA版本G1GC Bug导致的应用崩溃

Pod自动重启问题排查:JDK 17 EA版本G1GC Bug导致的应用崩溃 问题背景 在生产环境中,我们遇到了一个严重的稳定性问题:应用Pod频繁自动重启,导致服务不稳定。通过深入分析JVM崩溃日志,最终定位到是JDK 17 EA版本中G1GC的一个已知Bug导致的。 问题现象 1. Pod重启表现 应…

HTML文本格式化标签

HTML提供了多种标签用于文本的格式化&#xff0c;这些标签可以改变文本的外观&#xff08;如粗细、斜体&#xff09;或赋予文本特定的含义&#xff08;如强调、引用&#xff09;。1. 基本文本样式标签&#xff08;1&#xff09;粗体文本使用<b>或<strong>标签可以使…

数据结构之单链表和环形链表的应用(二)-

目录一、相交链表二、环形链表I三、环形链表II总结一、相交链表 相交链表 首先理解什么是链表相交&#xff0c;相交即存在共用的节点&#xff0c;链表相交有三种情况&#xff0c; 中间位置相交头部就开始相交尾部相交 如图pcurA和pcurB就都有一个next指针指向同一个节点 这…

属性关键字

属性关键字深拷贝与浅拷贝类型各类对象深浅拷贝判断完全深拷贝的实现属性关键字property、synthesize和dynamic原子操作读写权限内存管理strong &#x1f19a; copy总结深拷贝与浅拷贝 先前学习OC时已经对深浅拷贝进行了一次学习&#xff0c;这里进行一个复习总结和补充&#…

突发奇想,还未实践,在Vben5的Antd模式下,将表单从「JS 配置化」改写成「模板可视化」形式(豆包版)

在 Vben5 的 Antd 模式下&#xff0c;完全可以将表单从「JS 配置化」改写成「模板可视化」形式&#xff0c;把表单项直接写在 Vue 模板中&#xff0c;更直观且符合传统 Vue 开发习惯。以下是完整的改写示例&#xff0c;保留原功能但结构更清晰&#xff1a; 改写思路 放弃 JS 中…

【更新完毕】2025数学建模国赛E题思路代码文章高教社杯全国大学生数学建模-AI 辅助智能体测

全部更新完毕 包含完整的文章全部问题的代码、结果、图表 完整内容请看文末最后的推广群基于AI姿态识别的立定跳远运动分析与个性化训练优化研究 随着《国家学生体质健康标准》的颁布实施&#xff0c;通过AI技术辅助体育运动分析已成为提升学生体质健康水平的重要手段。本研究针…

小白友好,无需基础也能快速上手的AI部署工具,一键部署

AI大模型相信已经成为许多人工作和生活中的得力助手。然而&#xff0c;对于大多数普通用户而言&#xff0c;将强大的AI模型部署到自己的电脑上&#xff0c;似乎是一项遥不可及的技术活&#xff0c;往往涉及到复杂的命令行操作、环境配置和代码调试。那有没有一种工具&#xff0…

《Python复刻植物大战僵尸开源项目实战:Pygame框架+JSON关卡设计,解锁塔防游戏开发新技能》​

&#x1f4cc; 大家好&#xff0c;我是智界工具库&#xff0c;每天分享好用实用且智能的开源项目&#xff0c;以及在JAVA语言开发中遇到的问题&#xff0c;如果本篇文章对您有所帮助&#xff0c;请帮我点个小赞小收藏小关注吧&#xff0c;谢谢喲&#xff01;&#x1f618; 博主…

CCS——将工程中的 include / lib 修改为相对路径,方便工程分享

在使用 Code Composer Studio (CCS) 开发 DSP 或 ARM 工程时&#xff0c;经常会遇到这样一个问题&#xff1a;在 A 电脑上能正常编译的工程&#xff0c;拷贝到 B 电脑上后就报错。错误的原因通常是 工程使用了绝对路径&#xff0c;而不同电脑上的文件路径不一致&#xff0c;比如…

java解析网络大端、小端解析方法

文章目录一、背景介绍二、说明核心概念&#xff1a;什么是字节序&#xff08;Endianness&#xff09;&#xff1f;大端字节序 (Big-Endian)小端字节序 (Little-Endian)三、不同解析方式介绍一、背景介绍 中转台通过SNMP协议V1\V2上报中转台IP&#xff0c;然后程序解析入库&…

【数据分享】土地利用矢量shp数据分享-甘肃

今天要说明数据就是土地利用shp数据分享-甘肃。数据介绍▲ 1km土地利用数据&#xff08;2020年&#xff09;▲ 土地利用数据&#xff08;2025年&#xff09;▲土地利用数据&#xff08;2018年&#xff09;▲ 30m土地利用数据&#xff08;2023年&#xff09;▲ 公路铁路道路河流…

java log相关:Log4J、Log4J2、LogBack,SLF4J

目录测试maven依赖logback.xml测试主程序测试输出arthas查看logger总结使用参考文档测试 maven依赖 <dependencies><!-- SLF4J API --><dependency><groupId>org.slf4j</groupId><artifactId>slf4j-api</artifactId><version>…

AES加密算法详细加密步骤代码实现--身份证号码加解密系统

系统概述 本系统是一个基于AES-256-CBC加密算法的身份证号码加解密工具&#xff08;手搓底层步骤&#xff09;&#xff0c;针对的是上一篇文章对的AES加密原理的讲解&#xff0c;虽说是演示&#xff0c;但功能完善&#xff0c;可单独提供接口给项目调用&#xff0c;采用Python…

LangChain: Models, Prompts 模型和提示词

获取openapikey #!pip install python-dotenv #!pip install openai import osimport openai ​ from dotenv import load_dotenv, find_dotenv _ load_dotenv(find_dotenv()) # read local .env file openai.api_key os.environ[OPENAI_API_KEY] # account for deprecat…

ACMESSL自动续签教程

目录 1、选择申请证书 ​编辑2、选择CA机构 ​编辑3、选择自动验签 ​编辑4、证书续签设置 5、自动发布设置 本教程实现ACMESSL自动续签&#xff0c;请按照此教程实现。 1、选择申请证书 点击快捷入口或者订单或证书列表中的【创建证书】按钮&#xff1a; 2、选择CA机构 …

基于飞算JavaAI的在线图书借阅平台设计实现

项目概述与需求分析 1.1 项目背景与意义 随着数字化时代的快速发展&#xff0c;传统图书馆管理模式已无法满足现代读者的需求。在线图书借阅平台通过互联网技术将图书资源数字化&#xff0c;为读者提供便捷的检索、借阅和管理服务&#xff0c;有效解决了传统图书馆开放时间有…

通过API接口管理企业微信通讯录案例

1.开始前需要登录企业微信管理员后台&#xff0c;开启通讯录同步&#xff0c;同时添加企业可信IP地址&#xff0c;记录下Secret信息和企业ID&#xff0c;后面的程序会用到这两个参数。2.下面是用python写的创建企业微信账号的具体案例。#!/usr/bin/env python3 # -*- coding: u…

硬件开发_基于物联网的自动售卖机系统

一.系统概述 物联网自动售卖机系统的主要功能如下&#xff1a; 核心控制器&#xff1a;采用STM32单片机作为系统核心&#xff0c;负责整体数据处理和各设备的统一控制。商品选择&#xff1a;支持语音识别及按键方式&#xff0c;方便用户在售卖机内选择商品。语音播报&#xff1…

AGENTS.md: AI编码代理的开放标准

每个项目都有一个 README.md 文件供人类阅读。但随着 AI 编码代理和 AI 辅助开发的兴起,我们需要一个新标准:AGENTS.md。这个 Markdown 文件定义了代理如何构建、测试和协作。 这就是 AGENTS.md 的作用。 它是一个简单的 Markdown 文件,告诉 AI 助手如何在你的项目中操作:…