1
This commit is contained in:
398
doc/腾讯文档API快速参考.md
Normal file
398
doc/腾讯文档API快速参考.md
Normal file
@@ -0,0 +1,398 @@
|
||||
# 腾讯文档 API V3 快速参考指南
|
||||
|
||||
## API 配置
|
||||
|
||||
### 基础 URL
|
||||
```
|
||||
https://docs.qq.com/openapi/spreadsheet/v3
|
||||
```
|
||||
|
||||
### 配置文件位置
|
||||
- 开发环境:`ruoyi-admin/src/main/resources/application-dev.yml`
|
||||
- 生产环境:`ruoyi-admin/src/main/resources/application-prod.yml`
|
||||
- Java 配置:`ruoyi-system/src/main/java/com/ruoyi/jarvis/config/TencentDocConfig.java`
|
||||
|
||||
## 鉴权方式
|
||||
|
||||
### V3 API 请求头(Spreadsheet 操作)
|
||||
```http
|
||||
Access-Token: {access_token}
|
||||
Client-Id: {app_id}
|
||||
Open-Id: {open_id}
|
||||
Content-Type: application/json
|
||||
```
|
||||
|
||||
### OAuth2 用户信息请求头
|
||||
```http
|
||||
Authorization: Bearer {access_token}
|
||||
```
|
||||
|
||||
## 主要 API 端点
|
||||
|
||||
### 1. 读取表格数据
|
||||
```
|
||||
GET /files/{fileId}/{sheetId}/{range}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
JSONObject result = TencentDocApiUtil.readSheetData(
|
||||
accessToken,
|
||||
appId,
|
||||
openId,
|
||||
fileId,
|
||||
sheetId,
|
||||
"A1:Z100",
|
||||
apiBaseUrl
|
||||
);
|
||||
```
|
||||
|
||||
### 2. 写入表格数据
|
||||
```
|
||||
PUT /files/{fileId}/batchUpdate
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
Object[][] values = {
|
||||
{"姓名", "年龄", "城市"},
|
||||
{"张三", "25", "北京"}
|
||||
};
|
||||
|
||||
JSONObject result = TencentDocApiUtil.writeSheetData(
|
||||
accessToken,
|
||||
appId,
|
||||
openId,
|
||||
fileId,
|
||||
sheetId,
|
||||
"A1",
|
||||
values,
|
||||
apiBaseUrl
|
||||
);
|
||||
```
|
||||
|
||||
### 3. 追加表格数据
|
||||
```
|
||||
自动计算位置 + PUT /files/{fileId}/batchUpdate
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
Object[][] values = {
|
||||
{"李四", "30", "上海"}
|
||||
};
|
||||
|
||||
JSONObject result = TencentDocApiUtil.appendSheetData(
|
||||
accessToken,
|
||||
appId,
|
||||
openId,
|
||||
fileId,
|
||||
sheetId,
|
||||
values,
|
||||
apiBaseUrl
|
||||
);
|
||||
```
|
||||
|
||||
### 4. 获取文件信息
|
||||
```
|
||||
GET /files/{fileId}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
JSONObject result = TencentDocApiUtil.getFileInfo(
|
||||
accessToken,
|
||||
appId,
|
||||
openId,
|
||||
fileId,
|
||||
apiBaseUrl
|
||||
);
|
||||
```
|
||||
|
||||
### 5. 获取工作表列表
|
||||
```
|
||||
GET /files/{fileId}
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
JSONObject result = TencentDocApiUtil.getSheetList(
|
||||
accessToken,
|
||||
appId,
|
||||
openId,
|
||||
fileId,
|
||||
apiBaseUrl
|
||||
);
|
||||
```
|
||||
|
||||
### 6. 获取用户信息(含 Open-Id)
|
||||
```
|
||||
GET https://docs.qq.com/oauth/v2/userinfo
|
||||
```
|
||||
|
||||
**示例**:
|
||||
```java
|
||||
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
|
||||
String openId = userInfo.getString("openId");
|
||||
```
|
||||
|
||||
## Service 层使用示例
|
||||
|
||||
### 读取表格数据
|
||||
```java
|
||||
@Autowired
|
||||
private ITencentDocService tencentDocService;
|
||||
|
||||
public void readData() {
|
||||
String accessToken = "..."; // 从授权流程获取
|
||||
String fileId = "..."; // 表格文件ID
|
||||
String sheetId = "..."; // 工作表ID
|
||||
String range = "A1:Z100"; // 读取范围
|
||||
|
||||
JSONObject result = tencentDocService.readSheetData(
|
||||
accessToken, fileId, sheetId, range
|
||||
);
|
||||
|
||||
JSONArray values = result.getJSONArray("values");
|
||||
// 处理数据...
|
||||
}
|
||||
```
|
||||
|
||||
### 写入表格数据
|
||||
```java
|
||||
public void writeData() {
|
||||
String accessToken = "...";
|
||||
String fileId = "...";
|
||||
String sheetId = "...";
|
||||
String range = "A1";
|
||||
|
||||
Object[][] values = {
|
||||
{"列1", "列2", "列3"},
|
||||
{"数据1", "数据2", "数据3"}
|
||||
};
|
||||
|
||||
JSONObject result = tencentDocService.writeSheetData(
|
||||
accessToken, fileId, sheetId, range, values
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
### 追加订单数据
|
||||
```java
|
||||
public void appendOrder(JDOrder order) {
|
||||
String accessToken = "...";
|
||||
String fileId = "...";
|
||||
String sheetId = "...";
|
||||
|
||||
JSONObject result = tencentDocService.appendLogisticsToSheet(
|
||||
accessToken, fileId, sheetId, order
|
||||
);
|
||||
}
|
||||
```
|
||||
|
||||
## 常见参数说明
|
||||
|
||||
### fileId(文件ID)
|
||||
- 从腾讯文档 URL 中获取
|
||||
- 示例 URL:`https://docs.qq.com/sheet/DQXxxxxxxxxxxxxxx?tab=BB08J2`
|
||||
- fileId:`DQXxxxxxxxxxxxxxx`
|
||||
|
||||
### sheetId(工作表ID)
|
||||
- 从腾讯文档 URL 的 tab 参数中获取
|
||||
- 示例 URL:`https://docs.qq.com/sheet/DQXxxxxxxxxxxxxxx?tab=BB08J2`
|
||||
- sheetId:`BB08J2`
|
||||
|
||||
### range(单元格范围)
|
||||
- 格式:`起始列字母 + 起始行号 : 结束列字母 + 结束行号`
|
||||
- 示例:
|
||||
- `A1:Z100` - 从 A1 到 Z100 的矩形区域
|
||||
- `A1` - 单个单元格
|
||||
- `A:A` - 整个 A 列
|
||||
- `1:1` - 整个第 1 行
|
||||
|
||||
### values(数据值)
|
||||
- 二维数组格式
|
||||
- 示例:
|
||||
```java
|
||||
// Java 数组
|
||||
Object[][] values = {
|
||||
{"行1列1", "行1列2", "行1列3"},
|
||||
{"行2列1", "行2列2", "行2列3"}
|
||||
};
|
||||
|
||||
// JSONArray
|
||||
JSONArray values = new JSONArray();
|
||||
JSONArray row1 = new JSONArray();
|
||||
row1.add("行1列1");
|
||||
row1.add("行1列2");
|
||||
values.add(row1);
|
||||
```
|
||||
|
||||
## OAuth2 授权流程
|
||||
|
||||
### 1. 获取授权 URL
|
||||
```java
|
||||
String authUrl = tencentDocService.getAuthUrl();
|
||||
// 重定向用户到 authUrl 进行授权
|
||||
```
|
||||
|
||||
### 2. 处理回调获取 Access Token
|
||||
```java
|
||||
@GetMapping("/callback")
|
||||
public String callback(@RequestParam String code) {
|
||||
JSONObject tokenResponse = tencentDocService.getAccessTokenByCode(code);
|
||||
String accessToken = tokenResponse.getString("access_token");
|
||||
String refreshToken = tokenResponse.getString("refresh_token");
|
||||
Integer expiresIn = tokenResponse.getInteger("expires_in");
|
||||
|
||||
// 保存 tokens...
|
||||
return "授权成功";
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 刷新 Access Token
|
||||
```java
|
||||
public void refreshToken(String refreshToken) {
|
||||
JSONObject tokenResponse = tencentDocService.refreshAccessToken(refreshToken);
|
||||
String newAccessToken = tokenResponse.getString("access_token");
|
||||
String newRefreshToken = tokenResponse.getString("refresh_token");
|
||||
|
||||
// 更新保存的 tokens...
|
||||
}
|
||||
```
|
||||
|
||||
## 错误处理
|
||||
|
||||
### 常见错误码
|
||||
|
||||
#### 401 Unauthorized
|
||||
- **原因**:Access Token 无效或过期
|
||||
- **解决**:使用 Refresh Token 刷新 Access Token
|
||||
|
||||
#### 403 Forbidden
|
||||
- **原因**:用户没有访问该文档的权限
|
||||
- **解决**:检查文档权限设置,确保授权用户有访问权限
|
||||
|
||||
#### 404 Not Found
|
||||
- **原因**:文件ID或工作表ID不存在,或 API 路径错误
|
||||
- **解决**:
|
||||
1. 检查 fileId 和 sheetId 是否正确
|
||||
2. 检查 API 基础路径配置是否为 `https://docs.qq.com/openapi/spreadsheet/v3`
|
||||
|
||||
#### 429 Too Many Requests
|
||||
- **原因**:API 调用频率超过限制
|
||||
- **解决**:实现请求限流和重试机制
|
||||
|
||||
### 异常捕获示例
|
||||
```java
|
||||
try {
|
||||
JSONObject result = tencentDocService.readSheetData(
|
||||
accessToken, fileId, sheetId, range
|
||||
);
|
||||
} catch (RuntimeException e) {
|
||||
if (e.getMessage().contains("401")) {
|
||||
// Token 过期,刷新 token
|
||||
refreshToken(savedRefreshToken);
|
||||
} else if (e.getMessage().contains("404")) {
|
||||
// 文件不存在
|
||||
log.error("文件不存在: fileId={}", fileId);
|
||||
} else if (e.getMessage().contains("无法获取Open-Id")) {
|
||||
// Access Token 无效
|
||||
log.error("Access Token 无效,需要重新授权");
|
||||
} else {
|
||||
// 其他错误
|
||||
log.error("API调用失败", e);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 性能优化建议
|
||||
|
||||
### 1. Open-Id 缓存
|
||||
当前实现在每次调用 API 前都会获取 Open-Id,建议添加缓存:
|
||||
|
||||
```java
|
||||
// 使用 Spring Cache
|
||||
@Cacheable(value = "openIdCache", key = "#accessToken")
|
||||
public String getOpenId(String accessToken) {
|
||||
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
|
||||
return userInfo.getString("openId");
|
||||
}
|
||||
```
|
||||
|
||||
### 2. Access Token 缓存和自动刷新
|
||||
```java
|
||||
// 在数据库或 Redis 中存储 token 及过期时间
|
||||
public String getValidAccessToken(String userId) {
|
||||
TokenInfo tokenInfo = tokenRepository.findByUserId(userId);
|
||||
|
||||
if (tokenInfo.isExpired()) {
|
||||
// 自动刷新
|
||||
JSONObject newTokens = tencentDocService.refreshAccessToken(
|
||||
tokenInfo.getRefreshToken()
|
||||
);
|
||||
tokenInfo.update(newTokens);
|
||||
tokenRepository.save(tokenInfo);
|
||||
}
|
||||
|
||||
return tokenInfo.getAccessToken();
|
||||
}
|
||||
```
|
||||
|
||||
### 3. 批量操作
|
||||
对于多次写入,优先使用 `batchUpdate` API 一次性提交多个操作。
|
||||
|
||||
## 调试技巧
|
||||
|
||||
### 1. 启用详细日志
|
||||
在 `application-dev.yml` 中设置:
|
||||
```yaml
|
||||
logging:
|
||||
level:
|
||||
com.ruoyi.jarvis.util.TencentDocApiUtil: DEBUG
|
||||
com.ruoyi.jarvis.service.impl.TencentDocServiceImpl: DEBUG
|
||||
```
|
||||
|
||||
### 2. 查看完整请求和响应
|
||||
`TencentDocApiUtil` 已包含详细的日志记录:
|
||||
- 请求 URL
|
||||
- 请求方法
|
||||
- 请求体
|
||||
- 响应状态码
|
||||
- 响应内容
|
||||
|
||||
### 3. 测试 API 连接
|
||||
```java
|
||||
@Test
|
||||
public void testConnection() {
|
||||
String accessToken = "your_test_token";
|
||||
|
||||
// 1. 测试获取用户信息
|
||||
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
|
||||
System.out.println("User Info: " + userInfo);
|
||||
|
||||
// 2. 测试获取文件信息
|
||||
String fileId = "your_test_file_id";
|
||||
JSONObject fileInfo = tencentDocService.getFileInfo(accessToken, fileId);
|
||||
System.out.println("File Info: " + fileInfo);
|
||||
}
|
||||
```
|
||||
|
||||
## 官方文档链接
|
||||
|
||||
- [OAuth2 授权](https://docs.qq.com/open/document/app/oauth2/authorize.html)
|
||||
- [获取用户信息](https://docs.qq.com/open/document/app/oauth2/userinfo.html)
|
||||
- [表格 API 概览](https://docs.qq.com/open/document/app/openapi/v3/sheet/model/spreadsheet.html)
|
||||
- [批量更新表格](https://docs.qq.com/open/document/app/openapi/v3/sheet/batchUpdate.html)
|
||||
|
||||
## 技术支持
|
||||
|
||||
如遇到问题,请查看:
|
||||
1. 项目文档目录下的 `腾讯文档API完整修复总结.md`
|
||||
2. 项目日志文件(位于 `logs/` 目录)
|
||||
3. 腾讯文档开放平台官方文档
|
||||
|
||||
---
|
||||
|
||||
**最后更新时间**:2025-11-05
|
||||
|
||||
Reference in New Issue
Block a user