我的消息
「我的消息」是消息中心的用户侧。所有接口都挂在 /system/messageCenter 下,只操作当前登录用户自己的数据,不需要分配权限。
接口
| 方法 | 路径 | 说明 |
|---|---|---|
| GET | /system/messageCenter/myMessages | 我的消息分页 |
| PUT | /system/messageCenter/markRead/{logId} | 单条标记已读 |
| PUT | /system/messageCenter/markAllRead | 全部标记已读 |
| DELETE | /system/messageCenter/{logIds} | 删除我的消息 |
| GET | /system/messageCenter/unreadCount | 未读数量 |
| GET | /system/messageCenter/settings | 读取消息偏好 |
| PUT | /system/messageCenter/settings | 保存消息偏好 |
分页参数与平台其他列表一致(pageNum / pageSize),查询条件:
| 参数 | 说明 |
|---|---|
isRead | Y 已读 / N 未读,不传为全部 |
messageType | 消息类型,按 sys_message.message_type 过滤 |
messageTitle | 标题模糊搜索 |
列表按 send_time 倒序,返回的是 消息日志(SysMessageLogVo),因此同一个公告不会因为多通道而重复展示——每条消息对每个用户只有一条主日志记录。
已读逻辑
markRead 的处理顺序:
- 按
logId查询日志; - 校验
receiver_id是否等于当前用户,不是自己的消息直接返回失败; - 已读则幂等返回成功;
- 更新
is_read=Y、read_time; - 重新统计该消息的已读人数并回写
sys_message.read_count; - 未读计数器减一,并清除该用户的消息摘要缓存。
markAllRead 会把当前用户所有 is_read=N 的日志批量置为已读,并按消息去重回写已读人数,随后把未读计数清零。重复调用不会产生副作用。
删除
DELETE /system/messageCenter/{logIds} 要求传入的每一条日志都属于当前用户。服务端会先按 logIds + receiver_id 查询,数量不一致就整体拒绝,避免越权删除。删除成功后按数据库重新计算未读数。
删除只影响用户自己的收件箱,不会删除管理端的消息主体;重新发布该消息时,用户会再次收到。
消息偏好
设置按用户维度保存在 Redis,键为 GLOBAL_REDIS_KEY + message:settings:{userId},有效期 7 天。首次读取时返回默认值并写入缓存。
| 字段 | 默认 | 说明 |
|---|---|---|
systemNotify | true | 站内消息通知 |
emailNotify | true | 邮件通知 |
smsNotify | false | 短信通知 |
systemMessageTypes | ["system","maintenance"] | 订阅的系统类消息 |
businessMessageTypes | ["order","payment","refund"] | 订阅的业务类消息 |
activityMessageTypes | ["promotion"] | 订阅的活动类消息 |
doNotDisturb | false | 免打扰开关 |
doNotDisturbStart / doNotDisturbEnd | — | 免打扰时间段 |
autoCleanRead | false | 自动清理已读消息 |
readRetentionDays | 30 | 已读消息保留天数 |
当前实现边界:这些字段目前只负责保存和回显,投递链路尚未读取它们来决定是否发送。实际是否发邮件、发短信由消息本身的
send_method决定。接入前不要向用户承诺「关闭邮件通知就一定收不到邮件」。
设置没有数据库表,属于缓存型偏好:
- 7 天不访问会过期并恢复默认值;
- 清除 Redis 或切换租户缓存后同样会丢失;
- 如果业务需要长期保存,应在业务侧另建表,而不是依赖这份缓存。
未读计数与缓存
| 数据 | 存储 | 有效期 | 失效方式 |
|---|---|---|---|
| 未读数量 | Redis 原子值 message:unread:count:{userId} | 5 分钟 | 标记已读、全部已读、删除后更新 |
| 消息摘要 | Redis message:summary:{userId} | 15 秒 | 已读操作后主动删除 |
| 消息偏好 | Redis message:settings:{userId} | 7 天 | 保存时覆盖 |
未读数走 Redis 原子计数,避免每次打开页面都 count(*)。键不存在时会从数据库重新统计并回填;计数出现偏差时,删除或全部已读操作会以数据库为准重新校准。
SSE 推送的消息体里已经带有最新的 unreadCount,前端收到事件后直接刷新角标即可;页面初始化时再调用一次 unreadCount 作为兜底。
前端接入建议
// 打开消息中心
const page = await get('/system/messageCenter/myMessages', {
pageNum: 1,
pageSize: 20,
isRead: 'N',
});
// 点击消息
await put(`/system/messageCenter/markRead/${log.logId}`);
// 全部已读
await put('/system/messageCenter/markAllRead');配合 SSE 时注意:
- SSE 连接按用户维度建立,多标签页会各自收到同一事件,未读数应以事件里的值为准,不要本地累加;
- 消息列表页收到新消息事件后,可只更新角标,等用户下拉刷新再拉列表,避免打断阅读;
- 删除接口返回失败时,优先检查传入的
logIds是否混入了其他用户或其他环境的数据。