297 lines
7.4 KiB
Markdown
297 lines
7.4 KiB
Markdown
|
|
# 离线消息模块
|
|||
|
|
|
|||
|
|
## 模块概述
|
|||
|
|
离线消息模块负责管理用户离线期间收到的消息,包括消息存储、查询、清除等功能,确保用户上线后能够接收到离线期间的消息。
|
|||
|
|
|
|||
|
|
## 相关文件
|
|||
|
|
- `MessagesActivity.java` - 消息列表(显示离线消息提示)
|
|||
|
|
- `ConversationActivity.java` - 聊天界面(加载离线消息)
|
|||
|
|
- `UnreadMessageManager.java` - 未读消息管理器
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 接口列表
|
|||
|
|
|
|||
|
|
### 1. 获取离线消息数量
|
|||
|
|
**接口地址**: `GET /api/front/online/offline/count/{userId}`
|
|||
|
|
|
|||
|
|
**路径参数**:
|
|||
|
|
```
|
|||
|
|
userId: integer // 用户ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**请求参数**: 无
|
|||
|
|
|
|||
|
|
**返回数据**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "success",
|
|||
|
|
"data": {
|
|||
|
|
"userId": "integer", // 用户ID
|
|||
|
|
"totalCount": "integer", // 总离线消息数
|
|||
|
|
"privateCount": "integer", // 私聊消息数
|
|||
|
|
"systemCount": "integer", // 系统消息数
|
|||
|
|
"lastOfflineTime": "long" // 最后离线时间
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 2. 获取离线消息列表
|
|||
|
|
**接口地址**: `GET /api/front/online/offline/messages/{userId}`
|
|||
|
|
|
|||
|
|
**路径参数**:
|
|||
|
|
```
|
|||
|
|
userId: integer // 用户ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**请求参数**:
|
|||
|
|
```
|
|||
|
|
limit: integer // 获取数量限制,默认100
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**返回数据**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "success",
|
|||
|
|
"data": {
|
|||
|
|
"userId": "integer",
|
|||
|
|
"messages": [
|
|||
|
|
{
|
|||
|
|
"id": "long", // 消息ID
|
|||
|
|
"messageType": "string", // 消息类型: private/system/notification
|
|||
|
|
"senderId": "integer", // 发送者ID
|
|||
|
|
"senderNickname": "string", // 发送者昵称
|
|||
|
|
"senderAvatar": "string", // 发送者头像
|
|||
|
|
"content": "string", // 消息内容
|
|||
|
|
"conversationId": "long", // 会话ID(私聊消息)
|
|||
|
|
"createTime": "long", // 消息时间戳
|
|||
|
|
"extra": {} // 额外信息
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"totalCount": "integer",
|
|||
|
|
"hasMore": "boolean" // 是否还有更多消息
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
### 3. 清除离线消息
|
|||
|
|
**接口地址**: `DELETE /api/front/online/offline/messages/{userId}`
|
|||
|
|
|
|||
|
|
**路径参数**:
|
|||
|
|
```
|
|||
|
|
userId: integer // 用户ID
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
**请求参数**: 无
|
|||
|
|
|
|||
|
|
**返回数据**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"code": 200,
|
|||
|
|
"msg": "清除成功",
|
|||
|
|
"data": "success"
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 功能说明
|
|||
|
|
|
|||
|
|
### 离线消息类型
|
|||
|
|
|
|||
|
|
| 类型 | 值 | 说明 |
|
|||
|
|
|------|-----|------|
|
|||
|
|
| 私聊消息 | private | 用户之间的私聊消息 |
|
|||
|
|
| 系统消息 | system | 系统通知消息 |
|
|||
|
|
| 通知消息 | notification | 应用内通知 |
|
|||
|
|
|
|||
|
|
### 离线消息机制
|
|||
|
|
1. 用户离线时,服务器会保存发送给该用户的消息
|
|||
|
|
2. 用户上线后,自动推送离线消息
|
|||
|
|
3. 离线消息保存时间:7天
|
|||
|
|
4. 超过7天的离线消息会被自动清除
|
|||
|
|
|
|||
|
|
### 消息推送流程
|
|||
|
|
1. 用户登录/连接WebSocket
|
|||
|
|
2. 服务器检测到用户上线
|
|||
|
|
3. 查询该用户的离线消息
|
|||
|
|
4. 通过WebSocket推送离线消息
|
|||
|
|
5. 推送完成后标记消息已送达
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 使用场景
|
|||
|
|
|
|||
|
|
### 1. 用户登录后获取离线消息数量
|
|||
|
|
```java
|
|||
|
|
// 登录成功后查询离线消息数量
|
|||
|
|
int userId = AuthStore.getUserId(context);
|
|||
|
|
|
|||
|
|
ApiService apiService = ApiClient.getService(context);
|
|||
|
|
Call<ApiResponse<Map<String, Object>>> call =
|
|||
|
|
apiService.getOfflineMessageCount(userId);
|
|||
|
|
|
|||
|
|
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
|||
|
|
@Override
|
|||
|
|
public void onResponse(Call<ApiResponse<Map<String, Object>>> call,
|
|||
|
|
Response<ApiResponse<Map<String, Object>>> response) {
|
|||
|
|
if (response.isSuccessful() && response.body() != null) {
|
|||
|
|
Map<String, Object> data = response.body().getData();
|
|||
|
|
int totalCount = (int) data.get("totalCount");
|
|||
|
|
|
|||
|
|
if (totalCount > 0) {
|
|||
|
|
// 显示离线消息提示
|
|||
|
|
showOfflineMessageNotification(totalCount);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
|
|||
|
|
// 处理错误
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 获取并显示离线消息
|
|||
|
|
```java
|
|||
|
|
// 获取离线消息列表
|
|||
|
|
int userId = AuthStore.getUserId(context);
|
|||
|
|
|
|||
|
|
ApiService apiService = ApiClient.getService(context);
|
|||
|
|
Call<ApiResponse<Map<String, Object>>> call =
|
|||
|
|
apiService.getOfflineMessages(userId, 100);
|
|||
|
|
|
|||
|
|
call.enqueue(new Callback<ApiResponse<Map<String, Object>>>() {
|
|||
|
|
@Override
|
|||
|
|
public void onResponse(Call<ApiResponse<Map<String, Object>>> call,
|
|||
|
|
Response<ApiResponse<Map<String, Object>>> response) {
|
|||
|
|
if (response.isSuccessful() && response.body() != null) {
|
|||
|
|
Map<String, Object> data = response.body().getData();
|
|||
|
|
List<Map<String, Object>> messages =
|
|||
|
|
(List<Map<String, Object>>) data.get("messages");
|
|||
|
|
|
|||
|
|
// 处理离线消息
|
|||
|
|
for (Map<String, Object> message : messages) {
|
|||
|
|
String messageType = (String) message.get("messageType");
|
|||
|
|
|
|||
|
|
if ("private".equals(messageType)) {
|
|||
|
|
// 处理私聊消息
|
|||
|
|
handlePrivateMessage(message);
|
|||
|
|
} else if ("system".equals(messageType)) {
|
|||
|
|
// 处理系统消息
|
|||
|
|
handleSystemMessage(message);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// 处理完成后清除离线消息
|
|||
|
|
clearOfflineMessages(userId);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onFailure(Call<ApiResponse<Map<String, Object>>> call, Throwable t) {
|
|||
|
|
// 处理错误
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 3. 清除离线消息
|
|||
|
|
```java
|
|||
|
|
// 用户查看完离线消息后清除
|
|||
|
|
int userId = AuthStore.getUserId(context);
|
|||
|
|
|
|||
|
|
ApiService apiService = ApiClient.getService(context);
|
|||
|
|
Call<ApiResponse<String>> call =
|
|||
|
|
apiService.clearOfflineMessages(userId);
|
|||
|
|
|
|||
|
|
call.enqueue(new Callback<ApiResponse<String>>() {
|
|||
|
|
@Override
|
|||
|
|
public void onResponse(Call<ApiResponse<String>> call,
|
|||
|
|
Response<ApiResponse<String>> response) {
|
|||
|
|
if (response.isSuccessful() && response.body() != null) {
|
|||
|
|
Log.d("OfflineMessage", "离线消息已清除");
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
@Override
|
|||
|
|
public void onFailure(Call<ApiResponse<String>> call, Throwable t) {
|
|||
|
|
// 处理错误
|
|||
|
|
}
|
|||
|
|
});
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## WebSocket自动推送
|
|||
|
|
|
|||
|
|
用户上线后,服务器会自动通过WebSocket推送离线消息,无需手动调用接口。
|
|||
|
|
|
|||
|
|
**推送消息格式**:
|
|||
|
|
```json
|
|||
|
|
{
|
|||
|
|
"type": "offline_message",
|
|||
|
|
"messages": [
|
|||
|
|
{
|
|||
|
|
"id": 123,
|
|||
|
|
"messageType": "private",
|
|||
|
|
"senderId": 456,
|
|||
|
|
"senderNickname": "张三",
|
|||
|
|
"content": "你好",
|
|||
|
|
"createTime": 1703001234567
|
|||
|
|
}
|
|||
|
|
],
|
|||
|
|
"totalCount": 5
|
|||
|
|
}
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 最佳实践
|
|||
|
|
|
|||
|
|
### 1. 登录后处理流程
|
|||
|
|
```
|
|||
|
|
用户登录
|
|||
|
|
↓
|
|||
|
|
连接WebSocket
|
|||
|
|
↓
|
|||
|
|
查询离线消息数量
|
|||
|
|
↓
|
|||
|
|
显示离线消息提示(如果有)
|
|||
|
|
↓
|
|||
|
|
用户点击查看
|
|||
|
|
↓
|
|||
|
|
获取离线消息列表
|
|||
|
|
↓
|
|||
|
|
显示消息内容
|
|||
|
|
↓
|
|||
|
|
清除离线消息
|
|||
|
|
```
|
|||
|
|
|
|||
|
|
### 2. 消息处理建议
|
|||
|
|
- 私聊消息:更新对应会话的未读数
|
|||
|
|
- 系统消息:显示在通知中心
|
|||
|
|
- 通知消息:显示应用内通知
|
|||
|
|
|
|||
|
|
### 3. 性能优化
|
|||
|
|
- 分批获取离线消息(每次100条)
|
|||
|
|
- 优先显示最新的消息
|
|||
|
|
- 后台异步处理历史消息
|
|||
|
|
|
|||
|
|
---
|
|||
|
|
|
|||
|
|
## 注意事项
|
|||
|
|
1. 离线消息保存时间为7天
|
|||
|
|
2. 获取离线消息后建议及时清除,避免重复推送
|
|||
|
|
3. 离线消息数量过多时建议分批获取
|
|||
|
|
4. WebSocket连接成功后会自动推送离线消息
|
|||
|
|
5. 清除操作不可恢复,请谨慎使用
|
|||
|
|
6. 建议在用户查看完消息后再清除
|
|||
|
|
7. 系统会自动清理已读的离线消息
|