This commit is contained in:
Leo
2026-02-04 16:26:36 +08:00
parent a05119f99f
commit fe214e689a

View File

@@ -219,178 +219,85 @@ public class WPS365ApiServiceImpl implements IWPS365ApiService {
@Override
public JSONObject readAirSheetCells(String accessToken, String fileId, String worksheetId, String range) {
// 智能表格(AirSheet)与在线表格(KSheet)使用同一 API 基址openapi.wps.cn/v7/airsheet 已 404改用 api/v1 + openapi/airsheet与 KSheet 路径风格一致)
String baseUrl = wps365Config.getApiBaseUrl();
int sheetIdx = parseSheetIndex(worksheetId, fileId);
// 方案1与 KSheet 一致的路径 GET /openapi/airsheet/{fileId}/sheets/{sheetIdx}/cells?range=...
try {
// WPS365 AirSheet API路径格式
// 根据文档https://open.wps.cn/documents/app-integration-dev/wps365/server/airsheet/worksheets/VbHZwButmh
// 注意AirSheet中fileId和worksheetId可能是同一个值或者worksheetId是整数索引
// 如果用户只提供了一个IDfileId则fileId和worksheetId使用同一个值
String baseUrl = "https://openapi.wps.cn/v7";
// 根据WPS365官方文档AirSheet的worksheet_id必须是整数
// 如果worksheetId为空或"0"使用0第一个工作表
// 如果worksheetId与fileId相同说明用户只配置了一个ID尝试使用fileId作为worksheetId
String wsId;
if (worksheetId == null || worksheetId.trim().isEmpty() || "0".equals(worksheetId)) {
// 默认使用0第一个工作表
wsId = "0";
} else if (worksheetId.equals(fileId)) {
// 如果worksheetId与fileId相同说明用户只配置了一个ID类似腾讯文档
// 在AirSheet中这个ID可能既是file_id也是worksheet_id
wsId = fileId;
} else {
// 使用提供的worksheetId应该是整数
wsId = worksheetId;
}
// 根据官方文档https://open.wps.cn/documents/app-integration-dev/wps365/server/airsheet/worksheets/VbHZwButmh
// 正确路径https://openapi.wps.cn/v7/airsheet/{file_id}/worksheets
// 注意:路径中不需要 worksheet_id只需要 file_id
try {
String url = baseUrl + "/airsheet/" + fileId + "/worksheets";
// 如果指定了range添加range参数
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
// 如果指定了worksheetId也可以作为查询参数传递如果API支持
if (worksheetId != null && !worksheetId.trim().isEmpty() && !worksheetId.equals("0") && !worksheetId.equals(fileId)) {
if (url.contains("?")) {
url += "&worksheet_id=" + java.net.URLEncoder.encode(worksheetId, "UTF-8");
} else {
url += "?worksheet_id=" + java.net.URLEncoder.encode(worksheetId, "UTF-8");
}
}
log.debug("使用官方文档路径 - url: {}, fileId: {}, worksheetId: {}, range: {}", url, fileId, worksheetId, range);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e) {
log.debug("官方文档路径失败,尝试其他方案", e);
}
// 尝试多种API路径格式降级方案
// 方案1: 尝试使用fileId作为worksheetId如果用户只配置了一个ID
if (wsId.equals("0") && !fileId.equals(worksheetId)) {
try {
String url = baseUrl + "/airsheet/" + fileId + "/worksheets/" + fileId;
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
log.debug("尝试方案1 - 使用fileId作为worksheetId - url: {}", url);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e) {
log.debug("方案1失败尝试其他方案", e);
}
}
// 方案2: 使用 /range_data 子路径(根据官方文档,这是读取区域数据的标准路径)
// 注意range_data接口需要使用 row_from, row_to, col_from, col_to 参数,而不是 range=A1:B5
try {
String url = baseUrl + "/airsheet/" + fileId + "/worksheets/" + wsId + "/range_data";
if (range != null && !range.trim().isEmpty()) {
// 尝试解析A1:B5格式的range转换为行列参数
int[] rangeParams = parseRangeToRowCol(range);
if (rangeParams != null && rangeParams.length == 4) {
// 使用行列参数格式row_from, row_to, col_from, col_to
// 注意WPS365的行列索引可能从0开始或从1开始需要测试确认
url += "?row_from=" + rangeParams[0] + "&row_to=" + rangeParams[1]
+ "&col_from=" + rangeParams[2] + "&col_to=" + rangeParams[3];
} else {
// 如果解析失败尝试作为range参数传递
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
}
log.debug("尝试方案2 - 使用/range_data子路径 - url: {}", url);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e) {
log.debug("方案2失败尝试其他方案", e);
}
// 方案3: 使用 /values 子路径
try {
String url = baseUrl + "/airsheet/" + fileId + "/worksheets/" + wsId + "/values";
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
log.debug("尝试方案3 - 使用/values子路径 - url: {}", url);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e) {
log.debug("方案3失败尝试其他方案", e);
}
// 方案4: 基础路径(不带子路径)
String url = baseUrl + "/airsheet/" + fileId + "/worksheets/" + wsId;
String url = baseUrl + "/openapi/airsheet/" + fileId + "/sheets/" + sheetIdx + "/cells";
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
log.debug("尝试方案4 - 基础路径 - url: {}", url);
JSONObject result = WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
return result;
log.debug("读取AirSheet - url: {}, fileId: {}, sheetIdx: {}, range: {}", url, fileId, sheetIdx, range);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e) {
log.error("读取AirSheet数据失败 - fileId: {}, worksheetId: {}, range: {}", fileId, worksheetId, range, e);
// 如果失败,尝试使用 /values 子路径
try {
String baseUrl = "https://openapi.wps.cn/v7";
String wsId = (worksheetId != null && !worksheetId.trim().isEmpty() && !worksheetId.equals(fileId)) ? worksheetId : fileId;
String url = baseUrl + "/airsheet/" + fileId + "/worksheets/" + wsId + "/values";
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
log.debug("尝试使用/values子路径 - url: {}", url);
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e2) {
log.error("使用/values子路径也失败", e2);
throw new RuntimeException("读取AirSheet数据失败: " + e.getMessage(), e);
log.warn("AirSheet api/v1 路径失败,尝试 v7 - {}", e.getMessage());
}
// 方案2兼容旧版 v7 路径(若官方恢复或环境不同)
try {
String url = "https://openapi.wps.cn/v7/airsheet/" + fileId + "/sheets/" + sheetIdx + "/cells";
if (range != null && !range.trim().isEmpty()) {
url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8");
}
return WPS365ApiUtil.httpRequest("GET", url, accessToken, null);
} catch (Exception e2) {
throw new RuntimeException("读取AirSheet数据失败: " + e2.getMessage(), e2);
}
}
/** 解析工作表索引0、空或与 fileId 相同时为 0否则按数字解析 */
private int parseSheetIndex(String worksheetId, String fileId) {
if (worksheetId == null || worksheetId.trim().isEmpty() || "0".equals(worksheetId) || (fileId != null && fileId.equals(worksheetId))) {
return 0;
}
try {
return Integer.parseInt(worksheetId.trim());
} catch (NumberFormatException e) {
return 0;
}
}
@Override
public JSONObject updateAirSheetCells(String accessToken, String fileId, String worksheetId, String range, List<List<Object>> values) {
try {
// WPS365 AirSheet API路径格式
// 根据文档https://open.wps.cn/documents/app-integration-dev/wps365/server/airsheet/worksheets/VbHZwButmh
// 正确路径https://openapi.wps.cn/v7/airsheet/{file_id}/worksheets
// 注意:路径中不需要 worksheet_id只需要 file_id
String baseUrl = "https://openapi.wps.cn/v7";
String baseUrl = wps365Config.getApiBaseUrl();
int sheetIdx = parseSheetIndex(worksheetId, fileId);
// 使用官方文档中的正确路径格式
String url = baseUrl + "/airsheet/" + fileId + "/worksheets";
// 构建请求体
JSONObject requestBody = new JSONObject();
if (range != null && !range.trim().isEmpty()) {
requestBody.put("range", range);
}
// 构建values数组
JSONArray valuesArray = new JSONArray();
if (values != null) {
for (List<Object> row : values) {
JSONArray rowArray = new JSONArray();
if (row != null) {
for (Object cell : row) {
rowArray.add(cell);
}
JSONObject requestBody = new JSONObject();
if (range != null && !range.trim().isEmpty()) {
requestBody.put("range", range);
}
JSONArray valuesArray = new JSONArray();
if (values != null) {
for (List<Object> row : values) {
JSONArray rowArray = new JSONArray();
if (row != null) {
for (Object cell : row) {
rowArray.add(cell != null ? cell : "");
}
valuesArray.add(rowArray);
}
valuesArray.add(rowArray);
}
requestBody.put("values", valuesArray);
}
requestBody.put("values", valuesArray);
String bodyStr = requestBody.toJSONString();
// 如果指定了worksheetId也可以添加到请求体中如果API支持
if (worksheetId != null && !worksheetId.trim().isEmpty() && !worksheetId.equals("0") && !worksheetId.equals(fileId)) {
requestBody.put("worksheet_id", worksheetId);
}
String bodyStr = requestBody.toJSONString();
log.debug("更新AirSheet数据 - url: {}, fileId: {}, worksheetId: {}, range: {}, values: {}",
url, fileId, worksheetId, range, bodyStr);
return WPS365ApiUtil.httpRequest("PUT", url, accessToken, bodyStr);
// 方案1与 KSheet 一致的路径 POST /openapi/airsheet/{fileId}/sheets/{sheetIdx}/cells
try {
String url = baseUrl + "/openapi/airsheet/" + fileId + "/sheets/" + sheetIdx + "/cells";
log.debug("更新AirSheet - url: {}, fileId: {}, sheetIdx: {}, range: {}", url, fileId, sheetIdx, range);
return WPS365ApiUtil.httpRequest("POST", url, accessToken, bodyStr);
} catch (Exception e) {
log.error("更新AirSheet数据失败 - fileId: {}, worksheetId: {}, range: {}", fileId, worksheetId, range, e);
throw new RuntimeException("更新AirSheet数据失败: " + e.getMessage(), e);
log.warn("AirSheet api/v1 写入失败,尝试 v7 - {}", e.getMessage());
}
// 方案2兼容 v7 PUT /airsheet/{file_id}/worksheets
try {
String url = "https://openapi.wps.cn/v7/airsheet/" + fileId + "/worksheets";
return WPS365ApiUtil.httpRequest("PUT", url, accessToken, bodyStr);
} catch (Exception e2) {
throw new RuntimeException("更新AirSheet数据失败: " + e2.getMessage(), e2);
}
}