集成Redisson和添加过滤器及红包功能

- 集成Redisson客户端并配置相关属性- 添加自定义过滤器配置和实现
- 实现红包领取功能和分布式锁测试
- 更新pom.xml,添加Redisson依赖
This commit is contained in:
whaifree 2024-10-13 11:38:54 +08:00
parent f768ea78f0
commit 5f2cb9f209
11 changed files with 525 additions and 5 deletions

View File

@ -0,0 +1,114 @@
package cn.whaifree.interview.mhy;
import java.util.*;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 15:02
* @注释
*/
public class Main
{
public static void main(String args[])
{
Scanner cin = new Scanner(System.in);
int i = cin.nextInt();
int[] nums = new int[i];
for (int i1 = 0; i1 < nums.length; i1++) {
nums[i1] = cin.nextInt();
}
method(nums);
}
public static void method(int[] nums) {
int[] tmp = Arrays.copyOf(nums, nums.length);
int sum = 0;
for (int i = 0; i < nums.length - 1; i++) {
int a = i;
int b = i + 1;
if (nums[a] < 0 && nums[b] > 0) {
nums[a] = -nums[a];
nums[b] = -nums[b];
}
if (nums[a] < 0 && nums[b] < 0) {
nums[a] = -nums[a];
nums[b] = -nums[b];
}
sum += nums[a];
}
sum += nums[nums.length - 1];
nums = tmp;
int sumB = 0;
for (int i = tmp.length - 1; i > 0; i--) {
int a = i;
int b = i - 1;
if (nums[a] < 0 && nums[b] > 0) {
nums[a] = -nums[a];
nums[b] = -nums[b];
}
if (nums[a] < 0 && nums[b] < 0) {
nums[a] = -nums[a];
nums[b] = -nums[b];
}
sumB += nums[a];
}
sumB += nums[0];
System.out.println(Math.max(sumB, sum));
}
}
class p3{
public static void main(String[] args) {
LinkedList<Integer> lis = new LinkedList<>();
for (int i = 0; i < 9; i++) {
lis.add(i, i * i);
}
System.out.println(lis.indexOf(4));
}
}
class P2{
public static void main(String args[])
{
Scanner cin = new Scanner(System.in);
int i = cin.nextInt();
LinkedList<Integer> lis = new LinkedList<>();
for (int i1 = 0; i1 < i; i1++) {
lis.add(1 + i1);
}
int x = cin.nextInt();
for (int j = 0; j < x; j++) {
int a = cin.nextInt();
int b = cin.nextInt();
int c = cin.nextInt();
method(lis, a, b, c);
}
for (Integer li : lis) {
System.out.println(li+" ");
}
}
public static void method(LinkedList<Integer> list, int a, int b, int c) {
Integer A = list.get(list.indexOf(a));
list.remove(a - 1);
int i = list.indexOf(b);
int indexOfB = i;
if (c == 0) {
list.add(indexOfB, A);
}else {
list.add(indexOfB + 1, A);
}
}
}

View File

@ -0,0 +1,103 @@
package cn.whaifree.redo.redo_all_240924;
import org.junit.Test;
import java.util.Arrays;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 12:01
* @注释
*/
public class LeetCode289 {
@Test
public void test() {
int[][] board = {{0,1,0},{0,0,1},{1,1,1},{0,0,0}};
new Solution().gameOfLife(board);
for (int i = 0; i < board.length; i++) {
System.out.println(Arrays.toString(board[i]));
}
}
class Solution {
/**
* 为了保证当前修改后的状态不会影响下一个状态的判定设置另外的状态
* 如题所示只有三种
* 1. 如果当前是活细胞但是变成了死细胞那么设置为-1 math.abs为1
* 2. 如果当前是活细胞仍然是活细胞那么不变仍为1 math.abs还是1
* 3. 如果当前是死细胞但是变成了活细胞那么设置为2
* 那么最后遍历修改完状态之后-1修改回为02修改回为1
*
* @param board
*/
public void gameOfLife(int[][] board) {
// 设置方向来遍历某个节点周围的另外几个节点
int[] ner = new int[] { -1, 0, 1 };
// 获取行和列
int rows = board.length;
int cols = board[0].length;
// 遍历每一个节点格子
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
// 设置当前节点周围的存活细胞的数量
int liveNer = 0;
/**
* 当前节点是[ i , j ]
* [i-1,j-1] [i-1,j] [i-1,j+1]
* [ i ,j-1] [ i ,j] [ i ,j+1]
* [i+1,j-1] [i+1,j] [i+1,j+1]
* 那么以当前节点为中心要求周围的节点则最多是3*3形式
* 并且所有的行和列都是用当前节点+1或者-1或者不变构成
* 所以我们设置 ner = {-1,0,1} 来形成遍历
*/
for (int i = 0; i < 3; i++) {
for (int j = 0; j < 3; j++) {
// 必须保证不计算当前节点(不计算自己)
if (!(ner[i] == 0 && ner[j] == 0)) {
// 当前节点的相邻节点坐标
int r = row + ner[i];
int c = col + ner[j];
/**
* 判断当前周围节点的存活状态要求满足两个状态
* 1. 必须保证要在 board 矩阵中
* 2. 并且起始状态要是存活则当前状态为1或者-1都可以(因为这两个状态都表示起始状态为活细胞)
**/
if ((r >= 0 && r < rows) && (c >= 0 && c < cols) && (Math.abs(board[r][c]) == 1)) {
liveNer++;
}
}
}
}
/**
* 开始判断当前节点的存活状态
* 因为遍历到当前节点的时候还没有开始修改细胞状态所以还是0和1的细胞状态
* 那么只需要判断状态变化的即可否则状态不变
**/
if ((board[row][col] == 1) && (liveNer > 3 || liveNer < 2)) {
// -1 代表这个细胞过去是活的现在死了
board[row][col] = -1;
}
if (board[row][col] == 0 && (liveNer == 3)) {
// 2 代表这个细胞过去是死的现在活了
board[row][col] = 2;
}
}
}
// 再把额外的状态修改回去
for (int row = 0; row < rows; row++) {
for (int col = 0; col < cols; col++) {
if (board[row][col] == 2) {
board[row][col] = 1;
}
if (board[row][col] == -1) {
board[row][col] = 0;
}
}
}
}
}
}

View File

@ -37,6 +37,18 @@
<version>4.4.0</version>
</dependency>
<!-- &lt;!&ndash; https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter &ndash;&gt;-->
<!-- <dependency>-->
<!-- <groupId>org.redisson</groupId>-->
<!-- <artifactId>redisson-spring-boot-starter</artifactId>-->
<!-- <version>3.23.5</version>-->
<!-- </dependency>-->
<!--redisson-->
<dependency>
<groupId>org.redisson</groupId>
<artifactId>redisson</artifactId>
<version>3.16.8</version>
</dependency>
<!--FastJson-->
<dependency>
@ -92,11 +104,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.amqp</groupId>
<artifactId>spring-rabbit-test</artifactId>
<scope>test</scope>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.springframework.amqp</groupId>-->
<!-- <artifactId>spring-rabbit-test</artifactId>-->
<!-- <scope>test</scope>-->
<!-- </dependency>-->
</dependencies>
<build>

View File

@ -0,0 +1,32 @@
package cn.whaifree.springdemo.config;
import cn.whaifree.springdemo.utils.Filter.SelfFilter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 22:15
* @注释
*/
@Slf4j
@Configuration
public class FilterConfig {
@Bean
public FilterRegistrationBean<SelfFilter> customFilterRegistration() {
FilterRegistrationBean<SelfFilter> registration = new FilterRegistrationBean<>();
registration.setFilter(new SelfFilter());
registration.addUrlPatterns("/*"); // 指定过滤器应用的 URL 模式
registration.setName("customFilter");
registration.setOrder(1); // 设置过滤器的顺序
return registration;
}
}

View File

@ -0,0 +1,26 @@
package cn.whaifree.springdemo.config;
import org.redisson.Redisson;
import org.redisson.api.RedissonClient;
import org.redisson.config.Config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 20:56
* @注释
*/
@Configuration
public class RedissonConfig {
@Bean
public RedissonClient redissonClient() {
Config config = new Config();
config.useSingleServer().setAddress("redis://127.0.0.1:6379");
config.setThreads(10);
RedissonClient redissonClient = Redisson.create(config);
return redissonClient;
}
}

View File

@ -0,0 +1,63 @@
package cn.whaifree.springdemo.controller.redEnvelope;
import jakarta.annotation.Resource;
import org.redisson.api.RBucket;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.web.bind.annotation.*;
import java.util.HashMap;
import java.util.Map;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 20:31
* @注释
*/
@RestController
@RequestMapping("/redEnvelope")
public class RedEnvelopeController {
@Resource
private RedissonClient redissonClient;
@GetMapping(value = "/redisson/{key}")
public String redissonTest(@PathVariable("key") String lockKey) {
RLock lock = redissonClient.getLock(lockKey);
try {
lock.lock();
Thread.sleep(10000);
} catch (Exception e) {
} finally {
lock.unlock();
}
return "已解锁";
}
@PostMapping("distribute")
public String rob(Double amount) {
// 构造红包数据
Map<String, Object> redPacket = new HashMap<>();
redPacket.put("amount", amount);
redPacket.put("id", System.currentTimeMillis()); // 使用当前时间戳作为红包 ID
// 存入 Redis 红包列表
RBucket<Object> redPacketList = redissonClient.getBucket("red_packet_list");
redPacketList.set(redPacket);
return "Distributed successfully";
}
@PostMapping("rob")
public String rob(String userId) {
return "";
}
}

View File

@ -0,0 +1,34 @@
package cn.whaifree.springdemo.utils.Filter;
import jakarta.servlet.*;
import jakarta.servlet.annotation.WebFilter;
import org.springframework.stereotype.Component;
import java.io.IOException;
/**
* @version 1.0
* @Author whai文海
* @Date 2024/10/12 22:13
* @注释
*/
@Component
@WebFilter(filterName = "SelfFilter", urlPatterns = "/*")
public class SelfFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException {
Filter.super.init(filterConfig);
}
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
System.out.println("SelfFilter doFilter");
filterChain.doFilter(servletRequest, servletResponse);
System.out.println("SelfFilter doFilter end");
}
@Override
public void destroy() {
Filter.super.destroy();
}
}

View File

@ -12,6 +12,15 @@ spring:
port: 6379
# 选择db1
database: 3
redis:
redisson:
file: classpath:redisson.yaml
rabbitmq:
listener:
direct:
auto-startup: false
# springdoc-openapi项目配置

View File

@ -0,0 +1,27 @@
local userHashKey = KEYS[1] -- 用户领取记录 Hash 表键
local redPacketListKey = KEYS[2] -- 红包列表键
local userRecordListKey = KEYS[3] -- 用户领取记录列表键
local userId = ARGV[1] -- 用户 ID
-- 检查用户是否已经领取过红包
local exists = redis.call('HEXISTS', userHashKey, userId)
if exists == 1 then
return nil
end
-- 从红包列表中取出一条红包数据
local redPacketData = redis.call('RPOP', redPacketListKey)
if not redPacketData then
return nil
end
-- 解析红包数据
local redPacket = cjson.decode(redPacketData)
-- 存储用户领取记录
redis.call('HSET', userHashKey, userId, redPacketData)
-- 将红包领取信息存入用户领取记录列表
redis.call('LPUSH', userRecordListKey, redPacketData)
return redPacket

View File

@ -0,0 +1,42 @@
# 单节点配置
singleServerConfig:
# 连接空闲超时,单位:毫秒
idleConnectionTimeout: 10000
# 连接超时,单位:毫秒
connectTimeout: 10000
# 命令等待超时,单位:毫秒
timeout: 3000
# 命令失败重试次数,如果尝试达到 retryAttempts命令失败重试次数 仍然不能将命令发送至某个指定的节点时,将抛出错误。
# 如果尝试在此限制之内发送成功,则开始启用 timeout命令等待超时 计时。
retryAttempts: 3
# 命令重试发送时间间隔,单位:毫秒
retryInterval: 1500
# 密码
#password: redis.shbeta
# 单个连接最大订阅数量
subscriptionsPerConnection: 5
# 客户端名称
#clientName: axin
# # 节点地址
address: redis://127.0.0.1:6379
# 发布和订阅连接的最小空闲连接数
subscriptionConnectionMinimumIdleSize: 1
# 发布和订阅连接池大小
subscriptionConnectionPoolSize: 50
# 最小空闲连接数
connectionMinimumIdleSize: 32
# 连接池大小
connectionPoolSize: 64
# 数据库编号
database: 6
# DNS监测时间间隔单位毫秒
dnsMonitoringInterval: 5000
# 线程池数量,默认值: 当前处理核数量 * 2
#threads: 0
# Netty线程池数量,默认值: 当前处理核数量 * 2
#nettyThreads: 0
# 编码
#codec: !<org.redisson.codec.JsonJacksonCodec> {}
## 传输模式
#transportMode : "NIO"
#

View File

@ -0,0 +1,58 @@
package cn.whaifree.springdemo;
import lombok.extern.slf4j.Slf4j;
import org.junit.jupiter.api.Test;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.locks.Lock;
@SpringBootTest
@Slf4j
class SpringDemoApplicationTests {
@Test
void contextLoads() {
}
// 注入 RedissonClient
@Autowired
RedissonClient redissonClient;
// 计数器
private int count;
@Test
public void test() throws InterruptedException {
CountDownLatch countDownLatch = new CountDownLatch(1000);
for (int i = 0; i < 1000; i++) {
new Thread(() -> {
// 每个线程都创建自己的锁对象
// 这是基于 Redis 实现的分布式锁
Lock lock = this.redissonClient.getLock("counterLock");
try {
// 上锁
lock.lock();
// 计数器自增 1
this.count = this.count + 1;
} finally {
// 释放锁
lock.unlock();
}
countDownLatch.countDown();
}).start();
}
countDownLatch.await();
log.info("count = {}", this.count);
}
}