SpringBoot整合Redis實(shí)現(xiàn)刷票過(guò)濾功能
引言
隨著互聯(lián)網(wǎng)的不斷發(fā)展,網(wǎng)站或APP的用戶流量增加,也衍生出了一些惡意刷量等問(wèn)題,給數(shù)據(jù)分析及運(yùn)營(yíng)帶來(lái)極大的困難,出現(xiàn)的刷票問(wèn)題更是造成了嚴(yán)重的經(jīng)濟(jì)損失,所以網(wǎng)站或APP對(duì)惡意刷票進(jìn)行過(guò)濾是十分必要的。Redis提供了很好的解決方案,其提供的內(nèi)存存儲(chǔ)和Key-Value的存儲(chǔ)結(jié)構(gòu),能夠高效地實(shí)現(xiàn)刷票過(guò)濾。
本文主要介紹如何使用SpringBoot和Redis實(shí)現(xiàn)刷票過(guò)濾,自定義同一IP每天刷票不得超過(guò)次數(shù)。
一、概述
本文主要分為以下幾個(gè)模塊:
1.開發(fā)環(huán)境
2.使用Redis存儲(chǔ)數(shù)據(jù)
3.使用SpringBoot開發(fā)應(yīng)用
4.實(shí)現(xiàn)同一IP每天刷票不得超過(guò)次數(shù)
二、技術(shù)選型
SpringBoot2.2.5.RELEASE
Spring5.2.4.RELEASE
JDK8
Redis
三、搭建開發(fā)環(huán)境
1.安裝JDK8
2.安裝Redis(版本不限,最好使用穩(wěn)定版)
3.新建SpringBoot項(xiàng)目
使用IDEA新建SpringBoot項(xiàng)目
四、使用Redis存儲(chǔ)數(shù)據(jù)
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: 63793. 在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開發(fā)應(yīng)用
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;
// 先判斷是否已經(jīng)投票,如果已經(jīng)投票,則返回
if(redisTemplate.opsForValue().get(key) != null){
return "您已經(jīng)投過(guò)票了!";
}
// 獲取當(dāng)天的日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date = sdf.format(new Date());
// 拼接當(dāng)天投票的key
String voteKey = "vote:" + date;
// 將IP添加到Set中,記錄當(dāng)天所有投票的IP
redisTemplate.opsForSet().add(voteKey,ip);
// 獲取當(dāng)天已經(jīng)投票的IP數(shù)量
long voteCount = redisTemplate.opsForSet().size(voteKey);
// 判斷是否超過(guò)投票限制
if(voteCount > 10){
return "您今天的投票數(shù)已經(jīng)用盡!";
}
// 記錄已經(jīng)投票,設(shè)置過(guò)期時(shí)間為1天
redisTemplate.opsForValue().set(key,"已經(jīng)投票", 1, TimeUnit.DAYS);
return "投票成功!";
}
}六、 實(shí)現(xiàn)同一IP每天刷票不得超過(guò)次數(shù)
1. 在VoteController的submit接口中實(shí)現(xiàn)同一IP每天刷票不得超過(guò)次數(shù)
每次投票時(shí),先通過(guò)Redis查看是否已經(jīng)投過(guò)票,如果已經(jīng)投過(guò)票,則返回“您已經(jīng)投過(guò)票了!”,否則將該IP添加到當(dāng)天投票的Set中,再通過(guò)Redis查看當(dāng)天投票的IP數(shù)量是否超過(guò)設(shè)定的閾值,如果超過(guò)則返回“您今天的投票數(shù)已經(jīng)用盡!”,否則記錄已經(jīng)投票,并將該條記錄設(shè)置為1天后過(guò)期。
上述邏輯可以采用Redis提供的Set和過(guò)期時(shí)間來(lái)完成,便捷高效。
2. 優(yōu)化方案
上述實(shí)現(xiàn)在高并發(fā)情況下可能存在問(wèn)題,比如多個(gè)用戶同時(shí)投票,從而同時(shí)訪問(wèn)Redis,產(chǎn)生并發(fā)問(wèn)題或者性能問(wèn)題,為此可以通過(guò)Redis的分布式鎖或者使用Redisson等第三方庫(kù)來(lái)解決。
下面簡(jiǎn)單介紹一下使用Redisson來(lái)實(shí)現(xiàn)分布式鎖。
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:6379c. 新建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 {
// 先判斷是否已經(jīng)投票,如果已經(jīng)投票,則返回
if (redisTemplate.opsForValue().get(key) != null) {
return "您已經(jīng)投過(guò)票了!";
}
// 獲取當(dāng)天的日期
SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");
String date = sdf.format(new Date());
// 拼接當(dāng)天投票的key
String voteKey = "vote:" + date;
// 將IP添加到Set中,記錄當(dāng)天所有投票的IP
redisTemplate.opsForSet().add(voteKey, ip);
// 獲取當(dāng)天已經(jīng)投票的IP數(shù)量
long voteCount = redisTemplate.opsForSet().size(voteKey);
// 判斷是否超過(guò)投票限制
if (voteCount > 10) {
return "您今天的投票數(shù)已經(jīng)用盡!";
}
// 記錄已經(jīng)投票,設(shè)置過(guò)期時(shí)間為1天
redisTemplate.opsForValue().set(key, "已經(jīng)投票", 1, TimeUnit.DAYS);
return "投票成功!";
} finally {
lock.unlock();
}
}
}以上是使用Redisson實(shí)現(xiàn)分布式鎖的思路及代碼,從而在高并發(fā)情況下,避免了多個(gè)用戶同時(shí)對(duì)Redis進(jìn)行訪問(wèn)的并發(fā)問(wèn)題。
七、總結(jié)
本文介紹了如何使用SpringBoot和Redis實(shí)現(xiàn)刷票過(guò)濾,自定義同一IP每天刷票不得超過(guò)次數(shù)的功能。
通過(guò)使用Redis的Set和過(guò)期時(shí)間,實(shí)現(xiàn)了同一IP每天刷票不得超過(guò)次數(shù)的限制,并且代碼簡(jiǎn)單高效。
在高并發(fā)情況下,通過(guò)使用Redisson等庫(kù)實(shí)現(xiàn)分布式鎖,避免了多個(gè)用戶同時(shí)訪問(wèn)Redis的性能問(wèn)題。
在實(shí)際應(yīng)用中,除了IP限制和過(guò)期時(shí)間設(shè)置外,還可以根據(jù)具體需求,對(duì)投票做更細(xì)粒度的控制,比如設(shè)置對(duì)投票用戶的身份驗(yàn)證、對(duì)投票的時(shí)間和場(chǎng)次進(jìn)行限制等等。
最后,需要注意的是,防范惡意刷票是非常重要的,但是過(guò)度的限制可能也會(huì)造成用戶體驗(yàn)不佳,需要在保障數(shù)據(jù)安全的前提下,兼顧用戶體驗(yàn)的優(yōu)化。
本文主要介紹了如何使用SpringBoot和Redis實(shí)現(xiàn)刷票過(guò)濾,自定義同一IP每天刷票不得超過(guò)次數(shù)的功能。同時(shí),還對(duì)高并發(fā)情況下可能存在的問(wèn)題進(jìn)行了分析,并提出了一些優(yōu)化的方案。
到此這篇關(guān)于SpringBoot整合Redis實(shí)現(xiàn)刷票過(guò)濾功能的文章就介紹到這了,更多相關(guān)SpringBoot Redis刷票過(guò)濾內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
如何讓java只根據(jù)數(shù)據(jù)庫(kù)表名自動(dòng)生成實(shí)體類
今天給大家?guī)?lái)的知識(shí)是關(guān)于Java的,文章圍繞著如何讓java只根據(jù)數(shù)據(jù)庫(kù)表名自動(dòng)生成實(shí)體類展開,文中有非常詳細(xì)的介紹,需要的朋友可以參考下2021-06-06
Redis 集成Spring的示例代碼(spring-data-redis)
本篇文章主要介紹了Redis 集成Spring的示例代碼(spring-data-redis) ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2017-09-09
java使用FastJson解析Json數(shù)據(jù)
本篇文章主要介紹了java使用FastJson解析Json數(shù)據(jù),fastjson 是一個(gè)性能極好的用 Java 語(yǔ)言實(shí)現(xiàn)的 JSON 解析器和生成器,有興趣的可以了解一下。2017-02-02
關(guān)于JavaEE內(nèi)部類的部分注意事項(xiàng)
這篇文章主要介紹了關(guān)于JavaEE內(nèi)部類的部分注意事項(xiàng),將一個(gè)類定義在另一個(gè)類里面或者一個(gè)方法里面,這樣的類稱為內(nèi)部類,這是一種封裝思想,那么使用內(nèi)部類的時(shí)候要注意些什么呢,讓我們一起來(lái)看看吧2023-03-03
mybatis的動(dòng)態(tài)SQL以及連接池詳解
這篇文章主要介紹了mybatis的動(dòng)態(tài)SQL以及連接池詳解,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2022-02-02
SpringBoot概述及在idea中創(chuàng)建方式
SpringBoot提供了一種快速使用Spring的方式,基于約定大于配置的思想,可以讓開發(fā)人員不必在配置與邏輯業(yè)務(wù)之間進(jìn)行思維的切換,這篇文章主要介紹了SpringBoot概述及在idea中創(chuàng)建方式,需要的朋友可以參考下2022-09-09
Java中ExecutorService和ThreadPoolExecutor運(yùn)行原理
本文主要介紹了Java中ExecutorService和ThreadPoolExecutor運(yùn)行原理,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08
java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)簡(jiǎn)易點(diǎn)菜器,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2019-12-12
為IntelliJ IDEA配置JVM參數(shù)的兩種方法
在使用IntelliJ IDEA進(jìn)行Java開發(fā)時(shí),合理配置JVM參數(shù)對(duì)于優(yōu)化項(xiàng)目性能和資源管理至關(guān)重要,IntelliJ IDEA提供了兩種方便的方式來(lái)設(shè)置JVM參數(shù),本文將詳細(xì)介紹這兩種方法:通過(guò)工具欄編輯配置和通過(guò)服務(wù)編輯配置,需要的朋友可以參考下2024-12-12

