代购集运打包功能的前后端协作:WebSocket实时同步打包状态-阿里云开发者社区
视角:技术开发者**
一、打包业务的特殊性
在
代购集运
中,仓库打包员需要将多个商品合并到一个包裹(或者分多个包裹),并填写最终快递单号、重量、尺寸。这个过程可能需要多次扫描、绑定。如果用传统HTTP请求,每次操作都要刷新页面,效率低。我们采用WebSocket + 临时会话的方式,实现打包员实时操作、实时反馈。
二、打包会话设计
@Data
public
class
PackingSession
{
private
Long packageId
;
// 当前包裹ID
private
Long warehouseId
;
private
List
<
Long
>
boundItemIds
;
// 已绑定的商品ID
private
String outTrackingNo
;
// 最终快递单号
private
Double finalWeight
;
private
Double finalLength
;
private
Double finalWidth
;
private
Double finalHeight
;
private
LocalDateTime createTime
;
}
后端维护一个内存中的会话Map(生产环境可用Redis存储)。
@Component
public
class
PackingSessionManager
{
private
final
Map
<
String
,
PackingSession
>
sessions
=
new
ConcurrentHashMap
<
>
(
)
;
public
void
createSession
(
String sessionId
,
Long packageId
)
{
PackingSession session
=
new
PackingSession
(
)
;
session
.
setPackageId
(
packageId
)
;
session
.
setCreateTime
(
LocalDateTime
.
now
(
)
)
;
sessions
.
put
(
sessionId
,
session
)
;
}
public
PackingSession
getSession
(
String sessionId
)
{
PackingSession session
=
sessions
.
get
(
sessionId
)
;
if
(
session
==
null
)
{
throw
new
BusinessException
(
"会话已过期,请重新进入打包"
)
;
}
return
session
;
}
public
void
bindItem
(
String sessionId
,
Long itemId
)
{
PackingSession session
=
getSession
(
sessionId
)
;
session
.
getBoundItemIds
(
)
.
add
(
itemId
)
;
}
public
void
updateTracking
(
String sessionId
,
String trackingNo
)
{
getSession
(
sessionId
)
.
setOutTrackingNo
(
trackingNo
)
;
}
public
void
updateWeight
(
String sessionId
,
Double weight
)
{
getSession
(
sessionId
)
.
setFinalWeight
(
weight
)
;
}
public
void
complete
(
String sessionId
)
{
PackingSession session
=
sessions
.
remove
(
sessionId
)
;
// 保存到数据库
savePackingResult
(
session
)
;
}
}
三、WebSocket消息处理
@Controller
@MessageMapping
(
"/packing"
)
public
class
PackingWebSocketController
{
@Autowired
private
PackingSessionManager sessionManager
;
@MessageMapping
(
"/bind"
)
@SendTo
(
"/topic/packing/status"
)
public
PackingStatus
bindItem
(
@Payload
BindItemMessage msg
)
{
sessionManager
.
bindItem
(
msg
.
getSessionId
(
)
,
msg
.
getItemId
(
)
)
;
return
new
PackingStatus
(
"bound"
,
msg
.
getItemId
(
)
,
sessionManager
.
getBoundCount
(
msg
.
getSessionId
(
)
)
)
;
}
@MessageMapping
(
"/tracking"
)
@SendTo
(
"/topic/packing/status"
)
public
PackingStatus
updateTracking
(
@Payload
TrackingMessage msg
)
{
sessionManager
.
updateTracking
(
msg
.
getSessionId
(
)
,
msg
.
getTrackingNo
(
)
)
;
return
new
PackingStatus
(
"tracking_updated"
,
msg
.
getTrackingNo
(
)
,
null
)
;
}
@MessageMapping
(
"/complete"
)
public
void
complete
(
@Payload
CompleteMessage msg
)
{
sessionManager
.
complete
(
msg
.
getSessionId
(
)
)
;
// 广播打包完成
messagingTemplate
.
convertAndSend
(
"/topic/packing/complete"
,
msg
.
getPackageId
(
)
)
;
}
}
四、前端实现(Vue3 + Stomp)
import
{
Stomp
}
from
'@stomp/stompjs'
;
const
stompClient
=
Stomp
.
over
(
(
)
=>
new
SockJS
(
'/ws'
)
)
;
stompClient
.
connect
(
{
}
,
(
)
=>
{
stompClient
.
subscribe
(
'/topic/packing/status'
,
(
message
)
=>
{
const
data
=
JSON
.
parse
(
message
.
body
)
;
if
(
data
.
type
===
'bound'
)
{
showToast
(
`已绑定商品:
${
data
.
itemId
}
`
)
;
refreshBoundList
(
)
;
}
else
if
(
data
.
type
===
'tracking_updated'
)
{
showToast
(
`运单号:
${
data
.
trackingNo
}
`
)
;
}
}
)
;
}
)
;
function
bindItem
(
itemId
)
{
stompClient
.
send
(
'/app/packing/bind'
,
{
}
,
JSON
.
stringify
(
{
sessionId
:
sessionId
,
itemId
:
itemId
}
)
)
;
}
五、打包完成后的运费补差
打包完成后,后端自动计算实际运费与预付运费的差额,触发补差流程。这部分逻辑在第4篇文章中已详述。
六、与Taocarts系统的集成
Taocarts系统
的
代购集运
打包模块正是基于上述WebSocket方案实现的。仓库打包员使用PDA或PC浏览器,实时绑定商品、填写运单号,全程无需刷新页面,效率提升50%以上。如果你正在开发
跨境独立站
的
代购系统
,这套方案值得参考。