集成Redisson和添加过滤器及红包功能
- 集成Redisson客户端并配置相关属性- 添加自定义过滤器配置和实现 - 实现红包领取功能和分布式锁测试 - 更新pom.xml,添加Redisson依赖
This commit is contained in:
parent
f768ea78f0
commit
5f2cb9f209
114
ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java
Normal file
114
ForJdk17/src/main/java/cn/whaifree/interview/mhy/Main.java
Normal 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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -37,6 +37,18 @@
|
||||
<version>4.4.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <!– https://mvnrepository.com/artifact/org.redisson/redisson-spring-boot-starter –>-->
|
||||
<!-- <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>
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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 "";
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -12,6 +12,15 @@ spring:
|
||||
port: 6379
|
||||
# 选择db1
|
||||
database: 3
|
||||
redis:
|
||||
redisson:
|
||||
file: classpath:redisson.yaml
|
||||
|
||||
|
||||
rabbitmq:
|
||||
listener:
|
||||
direct:
|
||||
auto-startup: false
|
||||
|
||||
|
||||
# springdoc-openapi项目配置
|
||||
|
27
springDemo/src/main/resources/lua/RobEnvelope.lua
Normal file
27
springDemo/src/main/resources/lua/RobEnvelope.lua
Normal 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
|
42
springDemo/src/main/resources/redisson.yaml
Normal file
42
springDemo/src/main/resources/redisson.yaml
Normal 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"
|
||||
#
|
@ -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);
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user