Java利用redis限制用户频繁点击操作

 更新时间:2026年04月27日 10:10:49   作者:考拉在编程  
文章讨论了如何使用Redis和拦截器来限制用户行为,以保障系统安全,具体来说,作者提出了一种解决方案,包括使用注解来精确限制用户行为,并 使用拦截器记录并处理用户行为,文章还指出,需要添加crosFilter方法来解决拦截器的跨域问题

一、场景

为了系统安全,有时候需要做一些限制用户的操作。比如用户恶意刷接口,或者系统卡顿时候频繁点击,轻则造成系统崩溃,重则可能造成数据丢失。不得不引起重视。

解决方案:使用redis和拦截器来记录并控制用户行为

二、拦截器

 ResponseParams为本地的一个异常处理对象,自己可以使用自己的对象

package simple.cloud.config.myInterceptor;
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Method;
import java.util.concurrent.TimeUnit;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import net.sf.json.JSONArray;
import simple.cloud.components.common.params.ResponseParams;
import simple.cloud.components.common.utils.MyUtils;
@Component
@CrossOrigin("*")
public class MyInterceptor implements HandlerInterceptor {
	@Resource 
	private RedisTemplate<String, Object> redisTemplate;
	/**
	 * 1、过滤封禁IP 
     * 2、过滤恶意IP
	 */
	@Override
	@CrossOrigin("*")
	public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
			throws Exception {
		if (handler.getClass().isAssignableFrom(HandlerMethod.class)) { // 判断此class对象所表示的类或接口与指定的class参数所表示的类或接口是否相同
			//1、校验IP合法
			String ip = MyUtils.getIpAddress(request);
			String limitKey = request.getServletPath() + MyUtils.getIpAddress(request);
			Object blackIp = redisTemplate.opsForValue().get(ip);
			if (MyUtils.isNotNull(blackIp)) {
				respouseOut(response, ResponseParams.error("禁止使用!"));
				return false;
			}
			//2、校验重复点击
//          HandlerMethod封装方法定义相关的信息,如类、方法、参数等
			HandlerMethod handlerMethod = (HandlerMethod) handler;
			Method method = handlerMethod.getMethod();
//           获取方法中是否包含注解
			MyLimit methodAnnotation = method.getAnnotation(MyLimit .class);
//           获取类中是否包含注解
			MyLimit classAnnotation = method.getDeclaringClass().getAnnotation(MyLimit .class);
//           如果方法上有注解 就优先选择方法上的参数
			MyLimit myLimit = methodAnnotation != null ? methodAnnotation : classAnnotation;
			if (requestLimit != null) {
				if (checkLimit(limitKey, myLimit )) {
					respouseOut(response, ResponseParams.error("您点击的太频繁啦!"));
                    //将被封禁的IP加入缓存,下次访问时不必校验其点击情况
					redisTemplate.opsForValue().set(ip  , 1, 30, TimeUnit.SECONDS);
					return false;
				}
			}
		}
		return true;
	}
	/**
	 * 回写给客户端
	 */
	private void respouseOut(HttpServletResponse response, ResponseParams resp) throws IOException {
		response.setCharacterEncoding("UTF-8");
		response.setContentType("application/json;charaset=utf-8");
		PrintWriter out = null;
		String json = com.alibaba.fastjson.JSONObject.toJSON(resp).toString();
		out = response.getWriter();
		out.append(json);
	}
	/**
	 * 判断请求是否受限
	 */
	private boolean checkLimit(String limitKey, RequestLimit requestLimit) {
        //使用IP+请求地址作为key
        //从缓存中获取,当前这个请求访问了几次
		Integer redisCount = (Integer) redisTemplate.opsForValue().get(limitKey);
		if (redisCount == null) {
            //初始次数
			redisTemplate.opsForValue().set(limitKey, 1, requestLimit.second(), TimeUnit.SECONDS);
		} else {
            //若在指定时间内超过了访问次数限制,则返回true
			if (redisCount.intValue() >= requestLimit.maxCount()) {
			   //将其设置超过限制次数,并延迟30秒,30秒之后可以重新访问
			   redisTemplate.opsForValue().set(limitKey, requestLimit.maxCount()+1, 30, TimeUnit.SECONDS);
				return true;
			}
            //次数自增
			redisTemplate.opsForValue().increment(limitKey, 1);
		}
		return false;
	}
}

 MyLimit为一个注解,可以添加在指定controller上,来精确限制用户行为

@Documented
@Inherited
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyLimit {
    int second() default 1;
    int maxCount() default 15;
}

三、添加拦截器

 值得注意的是需要添加crosFiter方法,来解决拦截器跨越问题

@Resource
    private MyInterceptor myInterceptor;
	/**
	 * 让cors高于拦截器的权限
	 * 解决拦截器CROS问题
	 * @return
	 */
    @Bean
    public CorsFilter corsFilter() {
        CorsConfiguration config = new CorsConfiguration();
        config.addAllowedOrigin("*");
        config.setAllowCredentials(true);
        config.addAllowedMethod("*");
        config.addAllowedHeader("*");
        UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();
        configSource.registerCorsConfiguration("/**", config);
        return new CorsFilter(configSource);
    }
    /**
     * 添加我的默认的拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(myInterceptor).addPathPatterns("/**");
    }

到此这篇关于Java利用redis限制用户频繁点击操作的文章就介绍到这了,更多相关java redis限制频繁点击内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

相关文章

  • SpringBoot自定义Redis代码实践指南

    SpringBoot自定义Redis代码实践指南

    文章主要介绍了如何通过自定义RedisCacheConfiguration和RedisCacheManager来解决Spring Boot整合Redis过程中出现的序列化问题、Key命名冗余和缺乏过期限制等问题,通过这些定制,可以实现规范化的缓存存储策略,感兴趣的朋友跟随小编一起看看吧
    2025-12-12
  • Java中Date与LocalDate的区别及使用指南

    Java中Date与LocalDate的区别及使用指南

    在 Java 中处理时间和日期是开发中非常常见的需求,许多老项目仍然使用 java.util.Date,而现代 Java 程序推荐使用 Java 8 引入的 java.time API 中的类,比如 LocalDate,本文将详细比较这两者的区别,以及在实际项目中应该如何选择使用,需要的朋友可以参考下
    2026-03-03
  • Intellij IDEA官方最完美编程字体Mono使用

    Intellij IDEA官方最完美编程字体Mono使用

    这篇文章主要介绍了Intellij IDEA官方最完美编程字体Mono使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2020-03-03
  • Java commons io包实现多线程同步图片下载入门教程

    Java commons io包实现多线程同步图片下载入门教程

    这篇文章主要介绍了Java commons io包实现多线程同步图片下载入门,commons io: 是针对开发IO流功能的工具类库,其中包含了许多可调用的函数,感兴趣的朋友跟随小编一起看看吧
    2021-04-04
  • Java求素数和最大公约数的简单代码示例

    Java求素数和最大公约数的简单代码示例

    这篇文章主要介绍了Java求素数和最大公约数的简单代码示例,其中作者创建的Fraction类可以用来进行各种分数运算,需要的朋友可以参考下
    2015-09-09
  • 实例讲解Java并发编程之变量

    实例讲解Java并发编程之变量

    这篇文章主要介绍了实例讲解Java并发编程之变量,本文讲解了编写线程安全需要关心的共享变量和可变变量,需要的朋友可以参考下
    2015-04-04
  • Netty分布式固定长度解码器实现原理剖析

    Netty分布式固定长度解码器实现原理剖析

    这篇文章主要为大家介绍了Netty分布式固定长度解码器原理剖析,有需要的朋友可以借鉴参考下,希望能够有所帮助,祝大家多多进步,早日升职加薪
    2022-03-03
  • IntelliJ IDEA 无法正常使用SVN的问题和完美解决办法

    IntelliJ IDEA 无法正常使用SVN的问题和完美解决办法

    这篇文章主要介绍了IntelliJ IDEA 无法正常使用SVN的问题和解决办法,本文给大家分享完美解决方案,通过图文并茂的形式给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2023-08-08
  • 使用maven-assembly-plugin如何将system 依赖范围的jar以class 方式打包进 jar包中

    使用maven-assembly-plugin如何将system 依赖范围的jar以class 方式

    这篇文章主要介绍了使用maven-assembly-plugin如何将system 依赖范围的jar以class 方式打包进 jar包中,本文给大家分享完美解决思路,结合实例代码给大家介绍的非常详细,需要的朋友可以参考下
    2023-06-06
  • java poi导出图片到excel示例代码

    java poi导出图片到excel示例代码

    这篇文章主要介绍java poi如何导出图片到excel,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03

最新评论