This commit is contained in:
2025-11-06 02:12:12 +08:00
parent ffc8984534
commit a3aa8c74e6
5 changed files with 299 additions and 66 deletions

View File

@@ -29,8 +29,8 @@ public class TencentDocConfig {
/** 授权回调地址 */
private String redirectUri;
/** API基础地址 */
private String apiBaseUrl = "https://docs.qq.com/open/v1";
/** API基础地址 - V3版本注意是 /openapi/v3 不是 /open/v3 */
private String apiBaseUrl = "https://docs.qq.com/openapi/v3";
/** OAuth授权地址 */
private String oauthUrl = "https://docs.qq.com/oauth/v2/authorize";

View File

@@ -258,101 +258,138 @@ public class TencentDocApiUtil {
}
/**
* 读取表格数据
* 读取表格数据 - V3 API
*
* @param accessToken 访问令牌
* @param fileId 文件ID
* @param sheetId 工作表ID
* @param range 范围,例如 "A1:Z100"
* @param apiBaseUrl API基础地址
* @return 表格数据
* @param fileId 文件ID(在线表格的唯一标识)
* @param sheetId 工作表ID(可从表格链接中获取,如 ?tab=BB08J2 中的 BB08J2
* @param range 范围,例如 "A1:Z100"行列从0开始遵循左闭右开原则
* @param apiBaseUrl API基础地址默认https://docs.qq.com/openapi/v3
* @return 表格数据JSON格式包含values数组
*/
public static JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range, String apiBaseUrl) {
// V3版本API路径格式/open/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
// V3版本API路径格式/openapi/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
String apiUrl = String.format("%s/spreadsheets/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
log.info("读取表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl);
return callApi(accessToken, apiUrl, "GET", null);
}
/**
* 写入表格数据
* 写入表格数据V3 API
*
* @param accessToken 访问令牌
* @param fileId 文件ID
* @param sheetId 工作表ID
* @param range 范围,例如 "A1"
* @param values 要写入的数据,二维数组格式 [[["值1"], ["值2"]], [["值3"], ["值4"]]]
* @param apiBaseUrl API基础地址
* @param fileId 文件ID(在线表格的唯一标识)
* @param sheetId 工作表ID(可从表格链接中获取,如 ?tab=BB08J2 中的 BB08J2
* @param range 范围,例如 "A1"(起始单元格位置)
* @param values 要写入的数据,支持两种格式:
* 1. 简单二维数组:[["值1", "值2"], ["值3", "值4"]]
* 2. V3 API完整格式包含CellData结构
* @param apiBaseUrl API基础地址默认https://docs.qq.com/openapi/v3
* @return 写入结果
*/
public static JSONObject writeSheetData(String accessToken, String fileId, String sheetId, String range, Object values, String apiBaseUrl) {
// V3版本API路径格式/open/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
// V3版本API路径格式/openapi/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}/ranges/{range}
String apiUrl = String.format("%s/spreadsheets/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
// 构建V3 API规范的请求体
// 根据腾讯文档V3 API文档https://docs.qq.com/open/document/app/openapi/v3/sheet/model/spreadsheet.html
// 对于简单的文本数据写入可以直接使用values二维数组
// 对于复杂的单元格数据包含格式、类型等需要使用完整的CellData结构
JSONObject requestBody = new JSONObject();
requestBody.put("values", values);
log.info("写入表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl);
log.debug("写入表格数据 - 请求体: {}", requestBody.toJSONString());
return callApi(accessToken, apiUrl, "PUT", requestBody.toJSONString());
}
/**
* 追加表格数据(在最后一行追加)
* 追加表格数据(在最后一行追加)- V3 API
*
* @param accessToken 访问令牌
* @param fileId 文件ID
* @param sheetId 工作表ID
* @param values 要追加的数据,二维数组格式
* @param apiBaseUrl API基础地址
* @param fileId 文件ID(在线表格的唯一标识)
* @param sheetId 工作表ID(可从表格链接中获取,如 ?tab=BB08J2 中的 BB08J2
* @param values 要追加的数据,二维数组格式,例如:[["值1", "值2"], ["值3", "值4"]]
* @param apiBaseUrl API基础地址默认https://docs.qq.com/openapi/v3
* @return 追加结果
*/
public static JSONObject appendSheetData(String accessToken, String fileId, String sheetId, Object values, String apiBaseUrl) {
// 先获取表格信息找到最后一行V3版本路径
String infoUrl = String.format("%s/spreadsheets/%s/sheets/%s", apiBaseUrl, fileId, sheetId);
JSONObject sheetInfo = callApi(accessToken, infoUrl, "GET", null);
// 获取行数根据实际API响应调整
int rowCount = 0;
if (sheetInfo.containsKey("row_count")) {
rowCount = sheetInfo.getIntValue("row_count");
} else if (sheetInfo.containsKey("data") && sheetInfo.getJSONObject("data").containsKey("row_count")) {
rowCount = sheetInfo.getJSONObject("data").getIntValue("row_count");
try {
// 先获取工作表信息找到最后一行V3版本路径
// V3版本API路径格式/openapi/v3/spreadsheets/{spreadsheetId}/sheets/{sheetId}
String infoUrl = String.format("%s/spreadsheets/%s/sheets/%s", apiBaseUrl, fileId, sheetId);
log.info("获取工作表信息以追加数据 - apiUrl: {}", infoUrl);
JSONObject sheetInfo = callApi(accessToken, infoUrl, "GET", null);
// 获取行数根据实际API响应调整
// V3 API可能返回的字段名rowCount, row_count, properties.rowCount
// 根据腾讯文档V3 API文档工作表信息返回格式
// { "properties": { "sheetId": "xxx", "rowCount": 100, "columnCount": 10, ... } }
int rowCount = 0;
if (sheetInfo.containsKey("properties")) {
JSONObject properties = sheetInfo.getJSONObject("properties");
if (properties != null && properties.containsKey("rowCount")) {
rowCount = properties.getIntValue("rowCount");
}
} else if (sheetInfo.containsKey("rowCount")) {
rowCount = sheetInfo.getIntValue("rowCount");
} else if (sheetInfo.containsKey("row_count")) {
rowCount = sheetInfo.getIntValue("row_count");
} else if (sheetInfo.containsKey("data")) {
JSONObject data = sheetInfo.getJSONObject("data");
if (data != null && data.containsKey("row_count")) {
rowCount = data.getIntValue("row_count");
}
}
if (rowCount == 0) {
log.warn("无法从API响应中获取行数使用默认值1。响应数据: {}", sheetInfo);
rowCount = 1; // 至少有一行(表头)
}
// 计算要写入的起始位置(在最后一行之后追加)
String range = "A" + (rowCount + 1);
log.info("追加数据到第 {} 行range: {}", rowCount + 1, range);
return writeSheetData(accessToken, fileId, sheetId, range, values, apiBaseUrl);
} catch (Exception e) {
log.error("追加表格数据失败 - fileId: {}, sheetId: {}", fileId, sheetId, e);
throw new RuntimeException("追加表格数据失败: " + e.getMessage(), e);
}
if (rowCount == 0) {
rowCount = 1; // 至少有一行(表头)
}
// 计算要写入的起始位置(假设追加一行数据)
String range = "A" + (rowCount + 1);
return writeSheetData(accessToken, fileId, sheetId, range, values, apiBaseUrl);
}
/**
* 获取文件信息
* 获取文件信息 - V3 API
*
* @param accessToken 访问令牌
* @param fileId 文件ID
* @param apiBaseUrl API基础地址
* @return 文件信息
* @param fileId 文件ID(在线表格的唯一标识)
* @param apiBaseUrl API基础地址默认https://docs.qq.com/openapi/v3
* @return 文件信息JSON格式包含metadata、sheets等信息
* 返回格式示例:{ "fileId": "xxx", "metadata": {...}, "sheets": [...] }
*/
public static JSONObject getFileInfo(String accessToken, String fileId, String apiBaseUrl) {
// V3版本API路径格式/open/v3/spreadsheets/{spreadsheetId}
// V3版本API路径格式/openapi/v3/spreadsheets/{spreadsheetId}
String apiUrl = String.format("%s/spreadsheets/%s", apiBaseUrl, fileId);
log.info("获取文件信息 - fileId: {}, apiUrl: {}", fileId, apiUrl);
return callApi(accessToken, apiUrl, "GET", null);
}
/**
* 获取工作表列表
* 获取工作表列表 - V3 API
*
* @param accessToken 访问令牌
* @param fileId 文件ID
* @param apiBaseUrl API基础地址
* @return 工作表列表
* @param fileId 文件ID(在线表格的唯一标识)
* @param apiBaseUrl API基础地址默认https://docs.qq.com/openapi/v3
* @return 工作表列表JSON格式包含所有sheet的properties信息
* 返回格式示例:{ "sheets": [{ "properties": { "sheetId": "xxx", "title": "工作表1", ... } }] }
*/
public static JSONObject getSheetList(String accessToken, String fileId, String apiBaseUrl) {
// V3版本API路径格式/open/v3/spreadsheets/{spreadsheetId}/sheets
// V3版本API路径格式/openapi/v3/spreadsheets/{spreadsheetId}/sheets
String apiUrl = String.format("%s/spreadsheets/%s/sheets", apiBaseUrl, fileId);
log.info("获取工作表列表 - fileId: {}, apiUrl: {}", fileId, apiUrl);
return callApi(accessToken, apiUrl, "GET", null);
}