引言
随着互联网的不断发展,网站或app的用户流量增加,也衍生出了一些恶意刷量等问题,给数据分析及运营带来极大的困难,出现的刷票问题更是造成了严重的经济损失,所以网站或app对恶意刷票进行过滤是十分必要的。
redis提供了很好的解决方案,其提供的内存存储和key-value的存储结构,能够高效地实现刷票过滤。
本文主要介绍如何使用springboot和redis实现刷票过滤,自定义同一ip每天刷票不得超过次数。
一、概述
本文主要分为以下几个模块:
- 1.开发环境
- 2.使用redis存储数据
- 3.使用springboot开发应用
- 4.实现同一ip每天刷票不得超过次数
二、技术选型
- springboot2.2.5.release
- spring5.2.4.release
- jdk8
- redis
三、搭建开发环境
- 1.安装jdk8
- 2.安装redis(版本不限,最好使用稳定版)
- 3.新建springboot项目
使用idea新建springboot项目
四、使用redis存储数据
1. 在pom.xml中加入redis依赖
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-data-redis</artifactid> </dependency>
2.在application.yml中配置redis:
spring: redis: host: 127.0.0.1 port: 6379
3. 在redisconfig.java中配置redistemplate和stringredistemplate
@configuration public class redisconfig { @bean public redistemplate<string, object> redistemplate(redisconnectionfactory redisconnectionfactory){ redistemplate<string, object> redistemplate = new redistemplate<>(); redistemplate.setconnectionfactory(redisconnectionfactory); redistemplate.setkeyserializer(new stringredisserializer()); redistemplate.setvalueserializer(new jdkserializationredisserializer()); redistemplate.afterpropertiesset(); return redistemplate; } @bean public stringredistemplate stringredistemplate(redisconnectionfactory redisconnectionfactory){ stringredistemplate stringredistemplate = new stringredistemplate(); stringredistemplate.setconnectionfactory(redisconnectionfactory); return stringredistemplate; } }
四、使用springboot开发应用
1.在pom.xml中加入springboot依赖
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-web</artifactid> </dependency>
2.新建controller
@restcontroller @requestmapping("/vote") public class votecontroller { private final stringredistemplate redistemplate; public votecontroller(stringredistemplate redistemplate) { this.redistemplate = redistemplate; } /** * 投票接口 * @param ip * @return */ @postmapping("/submit") public string submit(@requestparam string ip){ string key = "ip:" + ip; // 先判断是否已经投票,如果已经投票,则返回 if(redistemplate.opsforvalue().get(key) != null){ return "您已经投过票了!"; } // 获取当天的日期 simpledateformat sdf = new simpledateformat("yyyymmdd"); string date = sdf.format(new date()); // 拼接当天投票的key string votekey = "vote:" + date; // 将ip添加到set中,记录当天所有投票的ip redistemplate.opsforset().add(votekey,ip); // 获取当天已经投票的ip数量 long votecount = redistemplate.opsforset().size(votekey); // 判断是否超过投票限制 if(votecount > 10){ return "您今天的投票数已经用尽!"; } // 记录已经投票,设置过期时间为1天 redistemplate.opsforvalue().set(key,"已经投票", 1, timeunit.days); return "投票成功!"; } }
五、 实现同一ip每天刷票不得超过次数
1. 在votecontroller的submit接口中实现同一ip每天刷票不得超过次数
每次投票时,先通过redis查看是否已经投过票,如果已经投过票,则返回“您已经投过票了!”,否则将该ip添加到当天投票的set中,再通过redis查看当天投票的ip数量是否超过设定的阈值,如果超过则返回“您今天的投票数已经用尽!”,否则记录已经投票,并将该条记录设置为1天后过期。
上述逻辑可以采用redis提供的set和过期时间来完成,便捷高效。
2. 优化方案
上述实现在高并发情况下可能存在问题,比如多个用户同时投票,从而同时访问redis,产生并发问题或者性能问题,为此可以通过redis的分布式锁或者使用redisson等第三方库来解决。
下面简单介绍一下使用redisson来实现分布式锁。
- a. 在pom.xml中加入redisson依赖
<dependency> <groupid>org.redisson</groupid> <artifactid>redisson</artifactid> <version>3.12.6</version> </dependency>
- b. 在application.yml中加入redisson配置
spring: redis: host: 127.0.0.1 port: 6379 database: 0 redisson: address: redis://127.0.0.1:6379
- c. 新建redissonconfig.java
@configuration public class redissonconfig { @autowired private environment env; @bean(destroymethod = "shutdown") redissonclient redisson() throws ioexception { // use "redis://" as the protocol config config = new config(); config.usesingleserver().setaddress(env.getproperty("redisson.address")); return redisson.create(config); } }
- d. 在votecontroller中加入redisson分布式锁
@restcontroller @requestmapping("/vote") public class votecontroller { private final stringredistemplate redistemplate; private final redissonclient redissonclient; public votecontroller(stringredistemplate redistemplate, redissonclient redissonclient) { this.redistemplate = redistemplate; this.redissonclient = redissonclient; } /** * 投票接口 * @param ip * @return */ @postmapping("/submit") public string submit(@requestparam string ip){ string key = "ip:" + ip; // 使用redisson加锁 rlock lock = redissonclient.getlock(key); lock.lock(); try { // 先判断是否已经投票,如果已经投票,则返回 if (redistemplate.opsforvalue().get(key) != null) { return "您已经投过票了!"; } // 获取当天的日期 simpledateformat sdf = new simpledateformat("yyyymmdd"); string date = sdf.format(new date()); // 拼接当天投票的key string votekey = "vote:" + date; // 将ip添加到set中,记录当天所有投票的ip redistemplate.opsforset().add(votekey, ip); // 获取当天已经投票的ip数量 long votecount = redistemplate.opsforset().size(votekey); // 判断是否超过投票限制 if (votecount > 10) { return "您今天的投票数已经用尽!"; } // 记录已经投票,设置过期时间为1天 redistemplate.opsforvalue().set(key, "已经投票", 1, timeunit.days); return "投票成功!"; } finally { lock.unlock(); } } }
以上是使用redisson实现分布式锁的思路及代码,从而在高并发情况下,避免了多个用户同时对redis进行访问的并发问题。
六、总结
本文介绍了如何使用springboot和redis实现刷票过滤,自定义同一ip每天刷票不得超过次数的功能。
通过使用redis的set和过期时间,实现了同一ip每天刷票不得超过次数的限制,并且代码简单高效。
在高并发情况下,通过使用redisson等库实现分布式锁,避免了多个用户同时访问redis的性能问题。
在实际应用中,除了ip限制和过期时间设置外,还可以根据具体需求,对投票做更细粒度的控制,比如设置对投票用户的身份验证、对投票的时间和场次进行限制等等。
最后,需要注意的是,防范恶意刷票是非常重要的,但是过度的限制可能也会造成用户体验不佳,需要在保障数据安全的前提下,兼顾用户体验的优化。
这些仅为个人经验,希望能给大家一个参考,也希望大家多多支持代码网。
参考资料:
发表评论