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

8.9 KiB
Raw Blame History

腾讯文档 API 修复日志

版本 2.0 - 2025-11-05根据官方文档的关键修复

🔥 重大变更

1. 修复获取用户信息接口的鉴权方式

问题描述

  • 之前使用 Authorization: Bearer {token} 请求头,与官方文档不符
  • 导致无法正确获取用户信息和 Open ID

解决方案

  • 改为使用查询参数:/oauth/v2/userinfo?access_token={token}
  • 严格按照官方文档实现

影响文件

  • TencentDocApiUtil.java
    • getUserInfo() 方法完全重写约60行代码
    • 删除 callApiLegacy() 方法约50行代码

2. 修复用户信息响应结构解析

问题描述

  • 之前直接从根对象获取 openId 字段
  • 实际响应结构为 { "ret": 0, "msg": "Succeed", "data": { "openID": "xxx" } }
  • 字段名也不正确(应为 openID,大写 ID

解决方案

  • data 对象中获取用户信息
  • 使用正确的字段名 openID(大写 ID
  • 检查业务返回码 ret 是否为 0

影响文件

  • TencentDocApiUtil.java
    • callApiSimple() 方法更新
  • TencentDocServiceImpl.java
    • 所有获取 Open ID 的地方都已更新6个方法

📝 详细修改

TencentDocApiUtil.java

修改前(错误):
public static JSONObject getUserInfo(String accessToken) {
    String apiUrl = "https://docs.qq.com/oauth/v2/userinfo";
    return callApiLegacy(accessToken, apiUrl, "GET", null);
}

private static JSONObject callApiLegacy(String accessToken, String apiUrl, String method, String body) {
    // ...
    conn.setRequestProperty("Authorization", "Bearer " + accessToken);
    // ...
}
修改后(正确):
public static JSONObject getUserInfo(String accessToken) {
    try {
        // 官方文档要求使用查询参数传递 access_token
        String apiUrl = "https://docs.qq.com/oauth/v2/userinfo?access_token=" + accessToken;
        
        URL url = new URL(apiUrl);
        HttpURLConnection conn = (HttpURLConnection) url.openConnection(java.net.Proxy.NO_PROXY);
        
        conn.setRequestMethod("GET");
        conn.setRequestProperty("Accept", "application/json");
        
        // 读取响应
        int responseCode = conn.getResponseCode();
        // ... 解析响应 ...
        
        JSONObject result = JSONObject.parseObject(responseBody);
        Integer ret = result.getInteger("ret");
        if (ret != null && ret == 0) {
            return result;  // 返回完整响应,包含 data 对象
        } else {
            String msg = result.getString("msg");
            throw new RuntimeException("获取用户信息失败: " + msg);
        }
    } catch (Exception e) {
        // ... 错误处理 ...
    }
}

TencentDocServiceImpl.java

修改前(错误):
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
String openId = userInfo.getString("openId");  // 错误:字段名和位置都不对
修改后(正确):
// 官方响应格式:{ "ret": 0, "msg": "Succeed", "data": { "openID": "xxx", ... } }
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
JSONObject data = userInfo.getJSONObject("data");
if (data == null) {
    throw new RuntimeException("无法获取用户数据请检查Access Token是否有效");
}
String openId = data.getString("openID");  // 正确:从 data 对象获取,字段名为 openID
if (openId == null || openId.isEmpty()) {
    throw new RuntimeException("无法获取Open-Id请检查Access Token是否有效");
}

📊 修改统计

文件 修改行数 新增行数 删除行数
TencentDocApiUtil.java ~100 ~60 ~50
TencentDocServiceImpl.java ~60 ~36 ~24
总计 ~160 ~96 ~74

验证状态

  • 编译通过(无错误,无警告)
  • 代码逻辑审查通过
  • 符合官方文档规范
  • 集成测试(待执行)
  • 性能测试(待执行)

📚 相关文档

本次修复创建/更新的文档:

  1. 腾讯文档API关键修复_根据官方文档.md - 详细的修复说明
  2. 腾讯文档API测试验证指南.md - 完整的测试指南
  3. CHANGELOG_腾讯文档API修复.md - 本文档

🔗 官方文档链接

本次修复严格参考以下官方文档:


版本 1.0 - 2025-11-05初始修复

修改内容

1. 更新 API 基础路径

  • https://docs.qq.com/open/v1 改为 https://docs.qq.com/openapi/spreadsheet/v3
  • 影响文件:
    • TencentDocConfig.java
    • application-dev.yml
    • application-prod.yml

2. 修正 API 端点路径

  • /spreadsheets/ 改为 /files/
  • 影响的 API
    • 读取表格数据:/files/{fileId}/{sheetId}/{range}
    • 写入表格数据:/files/{fileId}/batchUpdate
    • 获取文件信息:/files/{fileId}
    • 获取工作表列表:/files/{fileId}

3. 更新鉴权方式

  • V3 Spreadsheet API 使用三个独立请求头:
    • Access-Token: {access_token}
    • Client-Id: {app_id}
    • Open-Id: {open_id}
  • 影响文件:TencentDocApiUtil.java
    • callApi() 方法签名更新

4. 更新所有 API 方法签名

添加 appIdopenId 参数:

  • readSheetData()
  • writeSheetData()
  • appendSheetData()
  • getFileInfo()
  • getSheetList()

5. 更新 Service 层调用

所有 Service 方法都更新为在调用前先获取 Open ID。


升级指南

从版本 1.0 升级到版本 2.0

1. 代码无需修改

如果您使用的是 Service 层接口(ITencentDocService),无需修改任何代码,接口签名保持不变。

2. 如果直接使用工具类

如果您直接调用了 TencentDocApiUtil

需要注意的变更

// 之前1.0
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
String openId = userInfo.getString("openId");

// 现在2.0
JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
JSONObject data = userInfo.getJSONObject("data");
String openId = data.getString("openID");  // 注意openID 大写

3. 重新测试

建议执行完整的测试流程,特别是:

  1. OAuth2 授权流程
  2. 获取用户信息(关键)
  3. 表格数据读写操作

参考:腾讯文档API测试验证指南.md


已知问题

1. Open ID 重复获取

问题:每次调用 V3 API 前都会调用 getUserInfo 获取 Open ID可能影响性能。

建议:实现 Open ID 缓存机制,按 Access Token 缓存。

临时方案:使用 callApiSimple() 方法,会自动处理 Open ID 获取。

2. Access Token 过期处理

问题:当 Access Token 过期时,需要手动刷新。

建议:实现自动刷新机制,在检测到 401 错误时自动使用 Refresh Token 刷新。


性能优化建议

1. Open ID 缓存

@Cacheable(value = "openIdCache", key = "#accessToken")
public String getOpenId(String accessToken) {
    JSONObject userInfo = TencentDocApiUtil.getUserInfo(accessToken);
    JSONObject data = userInfo.getJSONObject("data");
    return data.getString("openID");
}

2. Access Token 自动刷新

public String getValidAccessToken(String userId) {
    TokenInfo token = tokenRepository.findByUserId(userId);
    
    if (token.isExpired()) {
        // 自动刷新
        JSONObject newTokens = tencentDocService.refreshAccessToken(token.getRefreshToken());
        token.update(newTokens);
        tokenRepository.save(token);
    }
    
    return token.getAccessToken();
}

3. 批量操作优化

对于需要多次写入的场景,使用 batchUpdate API 一次性提交所有操作。


兼容性说明

向后兼容性

  • Service 层接口签名未变化,完全向后兼容
  • 配置文件格式未变化
  • ⚠️ 工具类方法有破坏性变更(getUserInfo 返回值结构)

环境要求

  • Java 8+
  • Spring Boot 2.x
  • Fastjson 2.x

贡献者

  • 初始实现System
  • 版本 1.0 修复AI Assistant
  • 版本 2.0 修复关键修复AI Assistant基于官方文档

许可证

本项目遵循 MIT 许可证。


联系方式

如有问题,请查看:

  1. 项目文档:doc/ 目录
  2. 腾讯文档开放平台:https://docs.qq.com/open/
  3. Issue 追踪:(待添加)

最后更新时间2025-11-05 当前版本2.0 状态 稳定