Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
G
gk
Project
Project
Details
Activity
Releases
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
micro_app
gk
Commits
54b44882
Commit
54b44882
authored
Oct 20, 2025
by
daniel
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
fix(websocket): 使用redis解决多节点问题
parent
10ce27d3
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
104 additions
and
10 deletions
+104
-10
RedisConfig.java
src/main/java/com/dlbridge/jadp/config/web/RedisConfig.java
+27
-4
WebSocketMessage.java
...in/java/com/dlbridge/jadp/websocket/WebSocketMessage.java
+16
-1
WebSocketRedisSubscriber.java
...com/dlbridge/jadp/websocket/WebSocketRedisSubscriber.java
+32
-0
WebSocketSessionService.java
.../com/dlbridge/jadp/websocket/WebSocketSessionService.java
+29
-5
No files found.
src/main/java/com/dlbridge/jadp/config/web/RedisConfig.java
View file @
54b44882
package
com
.
dlbridge
.
jadp
.
config
.
web
;
package
com
.
dlbridge
.
jadp
.
config
.
web
;
import
com.dlbridge.jadp.websocket.WebSocketRedisSubscriber
;
import
com.fasterxml.jackson.annotation.JsonAutoDetect
;
import
com.fasterxml.jackson.annotation.JsonAutoDetect
;
import
com.fasterxml.jackson.annotation.PropertyAccessor
;
import
com.fasterxml.jackson.annotation.PropertyAccessor
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
com.fasterxml.jackson.databind.ObjectMapper
;
import
lombok.extern.log4j.Log4j
;
import
lombok.extern.log4j.Log4j
;
import
org.springframework.boot.autoconfigure.data.redis.RedisProperties
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Bean
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Configuration
;
import
org.springframework.context.annotation.Profile
;
import
org.springframework.context.annotation.Profile
;
...
@@ -13,14 +13,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
...
@@ -13,14 +13,14 @@ import org.springframework.data.redis.connection.RedisConnectionFactory;
import
org.springframework.data.redis.connection.RedisNode
;
import
org.springframework.data.redis.connection.RedisNode
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.connection.jedis.JedisConnectionFactory
;
import
org.springframework.data.redis.core.*
;
import
org.springframework.data.redis.core.*
;
import
org.springframework.data.redis.listener.ChannelTopic
;
import
org.springframework.data.redis.listener.RedisMessageListenerContainer
;
import
org.springframework.data.redis.listener.adapter.MessageListenerAdapter
;
import
org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
;
import
org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer
;
import
org.springframework.data.redis.serializer.StringRedisSerializer
;
import
org.springframework.data.redis.serializer.StringRedisSerializer
;
import
org.springframework.stereotype.Component
;
import
org.springframework.stereotype.Component
;
import
redis.clients.jedis.JedisPoolConfig
;
import
redis.clients.jedis.JedisPoolConfig
;
import
javax.annotation.Resource
;
import
java.util.List
;
/**
/**
* date : 2019/1/21
* date : 2019/1/21
* author : yangshuxing
* author : yangshuxing
...
@@ -40,6 +40,27 @@ public class RedisConfig {
...
@@ -40,6 +40,27 @@ public class RedisConfig {
return
config
;
return
config
;
}
}
@Bean
public
ChannelTopic
topic
()
{
return
new
ChannelTopic
(
"websocket:message"
);
}
@Bean
public
RedisMessageListenerContainer
redisContainer
(
RedisConnectionFactory
connectionFactory
,
MessageListenerAdapter
listenerAdapter
,
ChannelTopic
topic
)
{
RedisMessageListenerContainer
container
=
new
RedisMessageListenerContainer
();
container
.
setConnectionFactory
(
connectionFactory
);
container
.
addMessageListener
(
listenerAdapter
,
topic
);
return
container
;
}
@Bean
public
MessageListenerAdapter
listenerAdapter
(
WebSocketRedisSubscriber
subscriber
)
{
return
new
MessageListenerAdapter
(
subscriber
,
"onMessage"
);
}
@Bean
@Bean
@Profile
(
"production"
)
@Profile
(
"production"
)
public
RedisClusterConfiguration
predisClusterConfiguration
()
{
public
RedisClusterConfiguration
predisClusterConfiguration
()
{
...
@@ -169,4 +190,6 @@ public class RedisConfig {
...
@@ -169,4 +190,6 @@ public class RedisConfig {
return
redisTemplate
.
opsForZSet
();
return
redisTemplate
.
opsForZSet
();
}
}
}
}
src/main/java/com/dlbridge/jadp/websocket/WebSocketMessage.java
View file @
54b44882
...
@@ -53,7 +53,7 @@ public class WebSocketMessage {
...
@@ -53,7 +53,7 @@ public class WebSocketMessage {
return
new
WebSocketMessage
(
MessageType
.
INFO
.
getValue
(),
ticketNo
,
message
,
data
);
return
new
WebSocketMessage
(
MessageType
.
INFO
.
getValue
(),
ticketNo
,
message
,
data
);
}
}
// 转 JSON 字符串
//
✅
转 JSON 字符串
public
String
toJson
()
{
public
String
toJson
()
{
JSONObject
obj
=
JSONUtil
.
createObj
()
JSONObject
obj
=
JSONUtil
.
createObj
()
.
set
(
"type"
,
type
)
.
set
(
"type"
,
type
)
...
@@ -66,4 +66,19 @@ public class WebSocketMessage {
...
@@ -66,4 +66,19 @@ public class WebSocketMessage {
return
obj
.
toString
();
return
obj
.
toString
();
}
}
// ✅ 从 JSON 字符串反序列化(自动修复多重转义问题)
public
static
WebSocketMessage
fromJson
(
String
jsonStr
)
{
if
(
jsonStr
==
null
)
{
return
null
;
}
// 处理双重转义的情况:比如 "{\"type\":\"success\"...}"
if
(
jsonStr
.
startsWith
(
"\""
)
&&
jsonStr
.
endsWith
(
"\""
))
{
jsonStr
=
jsonStr
.
substring
(
1
,
jsonStr
.
length
()
-
1
);
jsonStr
=
jsonStr
.
replace
(
"\\\""
,
"\""
);
}
return
JSONUtil
.
toBean
(
jsonStr
,
WebSocketMessage
.
class
);
}
}
}
\ No newline at end of file
src/main/java/com/dlbridge/jadp/websocket/WebSocketRedisSubscriber.java
0 → 100644
View file @
54b44882
package
com
.
dlbridge
.
jadp
.
websocket
;
import
cn.hutool.json.JSONUtil
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.redis.connection.Message
;
import
org.springframework.data.redis.connection.MessageListener
;
import
org.springframework.stereotype.Component
;
import
javax.annotation.Resource
;
@Slf4j
@Component
public
class
WebSocketRedisSubscriber
implements
MessageListener
{
private
final
WebSocketSessionService
sessionService
;
public
WebSocketRedisSubscriber
(
WebSocketSessionService
sessionService
)
{
this
.
sessionService
=
sessionService
;
}
@Override
public
void
onMessage
(
Message
message
,
byte
[]
pattern
)
{
try
{
String
msgStr
=
new
String
(
message
.
getBody
());
log
.
info
(
"接收到 Redis 分发的 WebSocket 消息: {}"
,
msgStr
);
// ✅ 自动修复双引号问题
WebSocketMessage
wsMsg
=
WebSocketMessage
.
fromJson
(
msgStr
);
sessionService
.
sendToUser
(
wsMsg
.
getTicketNo
(),
wsMsg
);
}
catch
(
Exception
e
)
{
log
.
error
(
"Redis 消息处理异常: {}"
,
e
.
getMessage
(),
e
);
}
}
}
src/main/java/com/dlbridge/jadp/websocket/WebSocketSessionService.java
View file @
54b44882
package
com
.
dlbridge
.
jadp
.
websocket
;
package
com
.
dlbridge
.
jadp
.
websocket
;
import
lombok.extern.slf4j.Slf4j
;
import
lombok.extern.slf4j.Slf4j
;
import
org.springframework.data.redis.core.RedisTemplate
;
import
org.springframework.data.redis.listener.ChannelTopic
;
import
org.springframework.stereotype.Service
;
import
org.springframework.stereotype.Service
;
import
java.util.*
;
import
java.util.HashSet
;
import
java.util.Map
;
import
java.util.Set
;
import
java.util.concurrent.ConcurrentHashMap
;
import
java.util.concurrent.ConcurrentHashMap
;
@Slf4j
@Slf4j
@Service
@Service
public
class
WebSocketSessionService
{
public
class
WebSocketSessionService
{
private
final
RedisTemplate
<
String
,
Object
>
redisTemplate
;
private
final
ChannelTopic
topic
;
public
WebSocketSessionService
(
RedisTemplate
<
String
,
Object
>
redisTemplate
,
ChannelTopic
topic
)
{
this
.
redisTemplate
=
redisTemplate
;
this
.
topic
=
topic
;
}
private
final
Map
<
String
,
String
>
sessionUserMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
String
>
sessionUserMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
Set
<
String
>>
userTicketsMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
Set
<
String
>>
userTicketsMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
String
>
ticketUserMap
=
new
ConcurrentHashMap
<>();
private
final
Map
<
String
,
String
>
ticketUserMap
=
new
ConcurrentHashMap
<>();
...
@@ -68,7 +81,7 @@ public class WebSocketSessionService {
...
@@ -68,7 +81,7 @@ public class WebSocketSessionService {
});
});
return
sessionIds
;
return
sessionIds
;
}
}
// 发送消息给客户
public
void
sendToUser
(
String
userId
,
WebSocketMessage
message
)
{
public
void
sendToUser
(
String
userId
,
WebSocketMessage
message
)
{
String
payload
=
message
.
toJson
();
String
payload
=
message
.
toJson
();
getSessionIdsByUserId
(
userId
).
forEach
(
sessionId
->
{
getSessionIdsByUserId
(
userId
).
forEach
(
sessionId
->
{
...
@@ -77,13 +90,24 @@ public class WebSocketSessionService {
...
@@ -77,13 +90,24 @@ public class WebSocketSessionService {
});
});
log
.
info
(
"用户通知已发送 - 用户: {}, 类型: {}"
,
userId
,
message
.
getType
());
log
.
info
(
"用户通知已发送 - 用户: {}, 类型: {}"
,
userId
,
message
.
getType
());
}
}
// 发送核销验证成功的通知
public
void
sendVerificationSuccess
(
String
ticketNo
,
String
msg
)
{
public
void
sendVerificationSuccess
(
String
ticketNo
,
String
msg
)
{
WebSocketMessage
message
=
WebSocketMessage
.
success
(
ticketNo
,
msg
);
String
userId
=
ticketUserMap
.
get
(
ticketNo
);
// 本地推送
sendLocal
(
ticketNo
,
message
);
// if (userId == null) {
// 发布到 Redis,让其他节点同步
redisTemplate
.
convertAndSend
(
topic
.
getTopic
(),
message
.
toJson
());
// }
}
// 本地推送消息给客户
private
void
sendLocal
(
String
ticketNo
,
WebSocketMessage
message
)
{
String
userId
=
ticketUserMap
.
get
(
ticketNo
);
String
userId
=
ticketUserMap
.
get
(
ticketNo
);
if
(
userId
!=
null
)
sendToUser
(
userId
,
WebSocketMessage
.
success
(
ticketNo
,
msg
)
);
if
(
userId
!=
null
)
sendToUser
(
userId
,
message
);
else
log
.
warn
(
"未找到用户,无法发送核销消息 - 票号: {}"
,
ticketNo
);
else
log
.
warn
(
"未找到用户,无法发送核销消息 - 票号: {}"
,
ticketNo
);
}
}
// 发送错误消息给客户
public
void
sendError
(
String
ticketNo
,
String
errorMsg
)
{
public
void
sendError
(
String
ticketNo
,
String
errorMsg
)
{
String
userId
=
ticketUserMap
.
get
(
ticketNo
);
String
userId
=
ticketUserMap
.
get
(
ticketNo
);
if
(
userId
!=
null
)
sendToUser
(
userId
,
WebSocketMessage
.
error
(
ticketNo
,
errorMsg
));
if
(
userId
!=
null
)
sendToUser
(
userId
,
WebSocketMessage
.
error
(
ticketNo
,
errorMsg
));
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment