This commit is contained in:
2025-11-06 10:26:40 +08:00
parent ff2002642a
commit 43cc987d67
9 changed files with 2980 additions and 47 deletions

View File

@@ -0,0 +1,379 @@
# 腾讯文档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 调用是否正常。