From 5f2cb9f2092b489659233d1adc9a9a483fc83e24 Mon Sep 17 00:00:00 2001 From: whaifree Date: Sun, 13 Oct 2024 11:38:54 +0800 Subject: [PATCH] =?UTF-8?q?=E9=9B=86=E6=88=90Redisson=E5=92=8C=E6=B7=BB?= =?UTF-8?q?=E5=8A=A0=E8=BF=87=E6=BB=A4=E5=99=A8=E5=8F=8A=E7=BA=A2=E5=8C=85?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 集成Redisson客户端并配置相关属性- 添加自定义过滤器配置和实现 - 实现红包领取功能和分布式锁测试 - 更新pom.xml,添加Redisson依赖 --- .../java/cn/whaifree/interview/mhy/Main.java | 114 ++++++++++++++++++ .../redo/redo_all_240924/LeetCode289.java | 103 ++++++++++++++++ springDemo/pom.xml | 22 +++- .../springdemo/config/FilterConfig.java | 32 +++++ .../springdemo/config/RedissonConfig.java | 26 ++++ .../redEnvelope/RedEnvelopeController.java | 63 ++++++++++ .../springdemo/utils/Filter/SelfFilter.java | 34 ++++++ .../src/main/resources/application.yaml | 9 ++ .../src/main/resources/lua/RobEnvelope.lua | 27 +++++ springDemo/src/main/resources/redisson.yaml | 42 +++++++ .../SpringDemoApplicationTests.java | 58 +++++++++ 11 files changed, 525 insertions(+), 5 deletions(-) create mode 100644 ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java create mode 100644 ForJdk17/src/main/java/cn/whaifree/redo/redo_all_240924/LeetCode289.java create mode 100644 springDemo/src/main/java/cn/whaifree/springdemo/config/FilterConfig.java create mode 100644 springDemo/src/main/java/cn/whaifree/springdemo/config/RedissonConfig.java create mode 100644 springDemo/src/main/java/cn/whaifree/springdemo/controller/redEnvelope/RedEnvelopeController.java create mode 100644 springDemo/src/main/java/cn/whaifree/springdemo/utils/Filter/SelfFilter.java create mode 100644 springDemo/src/main/resources/lua/RobEnvelope.lua create mode 100644 springDemo/src/main/resources/redisson.yaml create mode 100644 springDemo/src/test/java/cn/whaifree/springdemo/SpringDemoApplicationTests.java diff --git a/ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java b/ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java new file mode 100644 index 0000000..1d4bfd5 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java @@ -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 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 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 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); + } + } +} diff --git a/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_240924/LeetCode289.java b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_240924/LeetCode289.java new file mode 100644 index 0000000..e886836 --- /dev/null +++ b/ForJdk17/src/main/java/cn/whaifree/redo/redo_all_240924/LeetCode289.java @@ -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修改回为0,2修改回为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; + } + } + } + + } + + } +} diff --git a/springDemo/pom.xml b/springDemo/pom.xml index c9a71c1..f980632 100644 --- a/springDemo/pom.xml +++ b/springDemo/pom.xml @@ -37,6 +37,18 @@ 4.4.0 + + + + + + + + + org.redisson + redisson + 3.16.8 + @@ -92,11 +104,11 @@ spring-boot-starter-test test - - org.springframework.amqp - spring-rabbit-test - test - + + + + + diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/config/FilterConfig.java b/springDemo/src/main/java/cn/whaifree/springdemo/config/FilterConfig.java new file mode 100644 index 0000000..7c7bd62 --- /dev/null +++ b/springDemo/src/main/java/cn/whaifree/springdemo/config/FilterConfig.java @@ -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 customFilterRegistration() { + FilterRegistrationBean registration = new FilterRegistrationBean<>(); + registration.setFilter(new SelfFilter()); + registration.addUrlPatterns("/*"); // 指定过滤器应用的 URL 模式 + registration.setName("customFilter"); + registration.setOrder(1); // 设置过滤器的顺序 + return registration; + } + + +} diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/config/RedissonConfig.java b/springDemo/src/main/java/cn/whaifree/springdemo/config/RedissonConfig.java new file mode 100644 index 0000000..48d5f49 --- /dev/null +++ b/springDemo/src/main/java/cn/whaifree/springdemo/config/RedissonConfig.java @@ -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; + } +} diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/controller/redEnvelope/RedEnvelopeController.java b/springDemo/src/main/java/cn/whaifree/springdemo/controller/redEnvelope/RedEnvelopeController.java new file mode 100644 index 0000000..2068f3f --- /dev/null +++ b/springDemo/src/main/java/cn/whaifree/springdemo/controller/redEnvelope/RedEnvelopeController.java @@ -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 redPacket = new HashMap<>(); + redPacket.put("amount", amount); + redPacket.put("id", System.currentTimeMillis()); // 使用当前时间戳作为红包 ID + + // 存入 Redis 红包列表 + RBucket redPacketList = redissonClient.getBucket("red_packet_list"); + redPacketList.set(redPacket); + + return "Distributed successfully"; + } + + + @PostMapping("rob") + public String rob(String userId) { + + return ""; + } + +} diff --git a/springDemo/src/main/java/cn/whaifree/springdemo/utils/Filter/SelfFilter.java b/springDemo/src/main/java/cn/whaifree/springdemo/utils/Filter/SelfFilter.java new file mode 100644 index 0000000..e004eac --- /dev/null +++ b/springDemo/src/main/java/cn/whaifree/springdemo/utils/Filter/SelfFilter.java @@ -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(); + } +} diff --git a/springDemo/src/main/resources/application.yaml b/springDemo/src/main/resources/application.yaml index 1aa6f99..b9b8c3b 100644 --- a/springDemo/src/main/resources/application.yaml +++ b/springDemo/src/main/resources/application.yaml @@ -12,6 +12,15 @@ spring: port: 6379 # 选择db1 database: 3 + redis: + redisson: + file: classpath:redisson.yaml + + + rabbitmq: + listener: + direct: + auto-startup: false # springdoc-openapi项目配置 diff --git a/springDemo/src/main/resources/lua/RobEnvelope.lua b/springDemo/src/main/resources/lua/RobEnvelope.lua new file mode 100644 index 0000000..7bf4d56 --- /dev/null +++ b/springDemo/src/main/resources/lua/RobEnvelope.lua @@ -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 diff --git a/springDemo/src/main/resources/redisson.yaml b/springDemo/src/main/resources/redisson.yaml new file mode 100644 index 0000000..53f2ba2 --- /dev/null +++ b/springDemo/src/main/resources/redisson.yaml @@ -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: ! {} +## 传输模式 +#transportMode : "NIO" +# diff --git a/springDemo/src/test/java/cn/whaifree/springdemo/SpringDemoApplicationTests.java b/springDemo/src/test/java/cn/whaifree/springdemo/SpringDemoApplicationTests.java new file mode 100644 index 0000000..388b500 --- /dev/null +++ b/springDemo/src/test/java/cn/whaifree/springdemo/SpringDemoApplicationTests.java @@ -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); + } +}