Files
ruoyi-java/doc/腾讯文档API完整修复总结.md
2025-11-06 10:26:40 +08:00

380 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 腾讯文档API完整修复总结
## 修复日期
2025-11-05
## 修复概述
针对腾讯文档开放平台 V3 API 集成,完成了以下全面修复:
1. 修正了 API 基础路径配置
2. 修正了 API 端点路径结构
3. 修正了鉴权方式(从 Authorization: Bearer 改为三个独立请求头)
4. 更新了所有 Service 层调用以支持新的鉴权方式
## 修复详情
### 1. API 基础路径修复
#### 修改文件
- `ruoyi-system/src/main/java/com/ruoyi/jarvis/config/TencentDocConfig.java`
- `ruoyi-admin/src/main/resources/application-dev.yml`
- `ruoyi-admin/src/main/resources/application-prod.yml`
#### 修改内容
```java
// 修改前
private String apiBaseUrl = "https://docs.qq.com/open/v1";
// 修改后
private String apiBaseUrl = "https://docs.qq.com/openapi/spreadsheet/v3";
```
#### 配置文件修改
```yaml
# application-dev.yml 和 application-prod.yml
# 修改前
api-base-url: https://docs.qq.com/open/v1
# 修改后
api-base-url: https://docs.qq.com/openapi/spreadsheet/v3
```
### 2. API 端点路径结构修复
#### 修改文件
- `ruoyi-system/src/main/java/com/ruoyi/jarvis/util/TencentDocApiUtil.java`
#### 修改的 API 端点
##### 2.1 读取表格数据 (readSheetData)
```java
// 修改前
String apiUrl = String.format("%s/spreadsheets/%s/%s/%s", apiBaseUrl, fileId, sheetId, range);
// 修改后
String apiUrl = String.format("%s/files/%s/%s/%s", apiBaseUrl, fileId, sheetId, range);
// 完整路径示例:
// https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}/{sheetId}/{range}
```
##### 2.2 写入表格数据 (writeSheetData)
```java
// 修改前
String apiUrl = String.format("%s/spreadsheets/%s/batchUpdate", apiBaseUrl, fileId);
// 修改后
String apiUrl = String.format("%s/files/%s/batchUpdate", apiBaseUrl, fileId);
// 完整路径示例:
// https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}/batchUpdate
```
##### 2.3 追加表格数据 (appendSheetData)
```java
// 修改前
String infoUrl = String.format("%s/spreadsheets/%s", apiBaseUrl, fileId);
// 修改后
String infoUrl = String.format("%s/files/%s", apiBaseUrl, fileId);
// 完整路径示例:
// https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}
```
##### 2.4 获取文件信息 (getFileInfo)
```java
// 修改前
String apiUrl = String.format("%s/spreadsheets/%s", apiBaseUrl, fileId);
// 修改后
String apiUrl = String.format("%s/files/%s", apiBaseUrl, fileId);
// 完整路径示例:
// https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}
```
##### 2.5 获取工作表列表 (getSheetList)
```java
// 修改前
String apiUrl = String.format("%s/spreadsheets/%s", apiBaseUrl, fileId);
// 修改后
String apiUrl = String.format("%s/files/%s", apiBaseUrl, fileId);
// 完整路径示例:
// https://docs.qq.com/openapi/spreadsheet/v3/files/{fileId}
```
### 3. 鉴权方式修复
#### 3.1 callApi 方法签名修改
```java
// 修改前
public static JSONObject callApi(String accessToken, String apiUrl, String method, String body)
// 修改后
public static JSONObject callApi(String accessToken, String clientId, String openId, String apiUrl, String method, String body)
```
#### 3.2 请求头修改
```java
// 修改前(错误的鉴权方式)
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
// 修改后(正确的鉴权方式)
conn.setRequestProperty("Access-Token", accessToken);
conn.setRequestProperty("Client-Id", clientId);
conn.setRequestProperty("Open-Id", openId);
```
#### 3.3 新增辅助方法
##### getUserInfo 方法
用于获取用户信息(包含 Open-Id使用传统的 Authorization: Bearer 鉴权方式。
```java
/**
* 获取用户信息包含Open-Id
*
* @param accessToken 访问令牌
* @return 用户信息(包含 openId 字段)
*/
public static JSONObject getUserInfo(String accessToken) {
// 腾讯文档用户信息接口https://docs.qq.com/open/document/app/oauth2/userinfo.html
// 注意此接口使用不同的鉴权方式Authorization: Bearer
String apiUrl = "https://docs.qq.com/oauth/v2/userinfo";
return callApiLegacy(accessToken, apiUrl, "GET", null);
}
```
##### callApiLegacy 方法
用于支持旧版 OAuth2 用户信息接口的 Authorization: Bearer 鉴权方式。
```java
/**
* 调用腾讯文档API使用传统的 Authorization: Bearer 鉴权方式)
* 仅用于 OAuth2 用户信息接口
*/
private static JSONObject callApiLegacy(String accessToken, String apiUrl, String method, String body) {
try {
// ... 连接设置 ...
conn.setRequestMethod(method);
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
conn.setRequestProperty("Content-Type", "application/json");
// ... 处理请求和响应 ...
} catch (Exception e) {
// ... 错误处理 ...
}
}
```
### 4. Service 层更新
#### 修改文件
- `ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TencentDocServiceImpl.java`
#### 修改的方法
所有与腾讯文档 API 交互的方法都进行了更新,在调用 API 前先获取 Open-Id
##### 4.1 uploadLogisticsToSheet 方法
```java
@Override
public JSONObject uploadLogisticsToSheet(String accessToken, String fileId, String sheetId, List<JDOrder> orders) {
try {
// ... 参数验证 ...
// 获取用户信息包含Open-Id
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
String openId = userInfo.getString("openId");
if (openId == null || openId.isEmpty()) {
throw new RuntimeException("无法获取Open-Id请检查Access Token是否有效");
}
// ... 构建数据 ...
// 追加数据到表格
return TencentDocApiUtil.appendSheetData(
accessToken,
tencentDocConfig.getAppId(),
openId,
fileId,
sheetId,
values,
tencentDocConfig.getApiBaseUrl()
);
} catch (Exception e) {
// ... 错误处理 ...
}
}
```
##### 4.2 appendLogisticsToSheet 方法
类似的修改模式:先获取 openId然后传递给 API 调用。
##### 4.3 readSheetData 方法
```java
@Override
public JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range) {
try {
// 获取用户信息包含Open-Id
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
String openId = userInfo.getString("openId");
if (openId == null || openId.isEmpty()) {
throw new RuntimeException("无法获取Open-Id请检查Access Token是否有效");
}
return TencentDocApiUtil.readSheetData(
accessToken,
tencentDocConfig.getAppId(),
openId,
fileId,
sheetId,
range,
tencentDocConfig.getApiBaseUrl()
);
} catch (Exception e) {
// ... 错误处理 ...
}
}
```
##### 4.4 writeSheetData 方法
同样的模式。
##### 4.5 getFileInfo 方法
同样的模式。
##### 4.6 getSheetList 方法
同样的模式。
## 完整的修复清单
### 配置文件3个
1.`TencentDocConfig.java` - 修正 API 基础路径
2.`application-dev.yml` - 修正 API 基础路径
3.`application-prod.yml` - 修正 API 基础路径
### Util 工具类1个
4.`TencentDocApiUtil.java`
- 修正 `callApi` 方法签名(添加 clientId, openId 参数)
- 修正请求头设置(改用 Access-Token, Client-Id, Open-Id
- 新增 `getUserInfo` 方法(获取用户信息和 Open-Id
- 新增 `callApiLegacy` 方法(支持旧版 OAuth2 接口)
- 修正 `readSheetData` 方法(更新 API 路径和参数)
- 修正 `writeSheetData` 方法(更新 API 路径和参数)
- 修正 `appendSheetData` 方法(更新 API 路径和参数)
- 修正 `getFileInfo` 方法(更新 API 路径和参数)
- 修正 `getSheetList` 方法(更新 API 路径和参数)
### Service 服务类1个
5.`TencentDocServiceImpl.java`
- 修正 `uploadLogisticsToSheet` 方法(添加 Open-Id 获取逻辑)
- 修正 `appendLogisticsToSheet` 方法(添加 Open-Id 获取逻辑)
- 修正 `readSheetData` 方法(添加 Open-Id 获取逻辑)
- 修正 `writeSheetData` 方法(添加 Open-Id 获取逻辑)
- 修正 `getFileInfo` 方法(添加 Open-Id 获取逻辑)
- 修正 `getSheetList` 方法(添加 Open-Id 获取逻辑)
## 官方文档参考
### API 路径规范
```
基础URLhttps://docs.qq.com/openapi/spreadsheet/v3
API 端点:
- 批量更新POST /files/{fileId}/batchUpdate
- 获取文件信息GET /files/{fileId}
- 读取表格数据GET /files/{fileId}/{sheetId}/{range}
```
### 鉴权方式规范
根据官方文档https://docs.qq.com/open/document/app/openapi/v3/sheet/batchUpdate.html
所有 V3 API 请求必须包含以下三个请求头:
```http
Access-Token: ACCESS_TOKEN
Client-Id: CLIENT_ID
Open-Id: OPEN_ID
```
### Open-Id 获取
通过 OAuth2 用户信息接口获取:
```
GET https://docs.qq.com/oauth/v2/userinfo
Authorization: Bearer ACCESS_TOKEN
```
响应示例:
```json
{
"openId": "用户的开放平台ID",
"unionId": "用户的联合ID",
"nickname": "用户昵称",
...
}
```
## 测试建议
### 1. 配置验证
```bash
# 检查配置文件中的 API 基础地址是否正确
grep "api-base-url" ruoyi-admin/src/main/resources/application-*.yml
```
### 2. 编译验证
```bash
cd ruoyi-java
mvn clean compile
```
### 3. 功能测试步骤
1. 启动应用
2. 进行 OAuth2 授权,获取 Access Token
3. 调用 `getUserInfo` API验证是否能正确获取 Open-Id
4. 调用 `getFileInfo` API验证是否能正确访问文档
5. 调用 `readSheetData` API验证是否能正确读取数据
6. 调用 `writeSheetData` API验证是否能正确写入数据
7. 调用 `appendSheetData` API验证是否能正确追加数据
### 4. 错误排查
如果仍然出现 404 错误:
- 检查 fileId 是否正确
- 检查 sheetId 是否正确
- 检查 Access Token 是否有效
- 检查 Open-Id 是否成功获取
- 检查网络连接和代理设置
如果出现 401 错误:
- 检查 Access Token 是否过期
- 检查 Client-Id (AppId) 是否正确
- 检查 Open-Id 是否正确
- 检查用户是否有权限访问该文档
## 注意事项
1. **代理设置**:代码中已添加 `Proxy.NO_PROXY` 设置,确保直接连接腾讯文档 API避免代理干扰。
2. **Open-Id 获取**:每次调用 V3 API 前都会先调用 getUserInfo 获取 Open-Id。如果频繁调用可能影响性能建议后续优化为缓存机制。
3. **错误处理**:所有 API 调用都包含完善的错误处理和日志记录,便于问题排查。
4. **API 版本**:确保使用 V3 版本的 APIV1 和 V2 版本可能已经废弃或行为不同。
5. **鉴权方式差异**
- V3 Spreadsheet API使用 `Access-Token`, `Client-Id`, `Open-Id` 三个请求头
- OAuth2 用户信息 API使用 `Authorization: Bearer {token}` 请求头
## 总结
本次修复完全基于腾讯文档开放平台官方 V3 API 文档,修正了以下核心问题:
1. ✅ API 基础路径从 `/open/v1` 修正为 `/openapi/spreadsheet/v3`
2. ✅ API 端点路径从 `/spreadsheets/` 修正为 `/files/`
3. ✅ 鉴权方式从 `Authorization: Bearer` 修正为 `Access-Token`, `Client-Id`, `Open-Id` 三个独立请求头
4. ✅ Service 层所有调用都已更新以支持新的鉴权方式
5. ✅ 新增 `getUserInfo` 方法自动获取 Open-Id
所有修改已通过代码编译检查,无 lint 错误。接下来需要进行实际的集成测试以验证 API 调用是否正常。