From 2ce45e5ccc100689509d941112bfd5080a6a3339 Mon Sep 17 00:00:00 2001 From: Leo Date: Thu, 15 Jan 2026 21:49:38 +0800 Subject: [PATCH] 1 --- .../controller/jarvis/WPS365Controller.java | 72 +++++++++++++++++ .../jarvis/service/IWPS365ApiService.java | 21 +++++ .../service/impl/WPS365ApiServiceImpl.java | 78 +++++++++++++++++-- .../com/ruoyi/jarvis/util/WPS365ApiUtil.java | 7 +- 4 files changed, 171 insertions(+), 7 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365Controller.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365Controller.java index ee03e3b..2de1a49 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365Controller.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/WPS365Controller.java @@ -494,5 +494,77 @@ public class WPS365Controller extends BaseController { return AjaxResult.error("批量更新单元格数据失败: " + e.getMessage()); } } + + /** + * 读取AirSheet工作表数据 + */ + @GetMapping("/readAirSheetCells") + public AjaxResult readAirSheetCells(@RequestParam String userId, + @RequestParam String worksheetId, + @RequestParam(required = false) String range) { + try { + WPS365TokenInfo tokenInfo = wps365OAuthServiceImpl.getTokenByUserId(userId); + if (tokenInfo == null) { + return AjaxResult.error("用户未授权,请先完成授权"); + } + + // 检查Token是否有效 + if (tokenInfo.isExpired() && tokenInfo.getRefreshToken() != null) { + try { + tokenInfo = wps365OAuthService.refreshAccessToken(tokenInfo.getRefreshToken()); + wps365OAuthService.saveToken(userId, tokenInfo); + } catch (Exception e) { + log.error("刷新Token失败", e); + return AjaxResult.error("Token已过期且刷新失败,请重新授权"); + } + } + + JSONObject result = wps365ApiService.readAirSheetCells(tokenInfo.getAccessToken(), worksheetId, range); + return AjaxResult.success("读取AirSheet数据成功", result); + } catch (Exception e) { + log.error("读取AirSheet数据失败 - worksheetId: {}, range: {}", worksheetId, range, e); + return AjaxResult.error("读取AirSheet数据失败: " + e.getMessage()); + } + } + + /** + * 更新AirSheet工作表数据 + */ + @PostMapping("/updateAirSheetCells") + public AjaxResult updateAirSheetCells(@RequestBody Map params) { + try { + String userId = (String) params.get("userId"); + String worksheetId = (String) params.get("worksheetId"); + String range = (String) params.get("range"); + @SuppressWarnings("unchecked") + List> values = (List>) params.get("values"); + + if (userId == null || worksheetId == null) { + return AjaxResult.error("userId和worksheetId不能为空"); + } + + WPS365TokenInfo tokenInfo = wps365OAuthServiceImpl.getTokenByUserId(userId); + if (tokenInfo == null) { + return AjaxResult.error("用户未授权,请先完成授权"); + } + + // 检查Token是否有效 + if (tokenInfo.isExpired() && tokenInfo.getRefreshToken() != null) { + try { + tokenInfo = wps365OAuthService.refreshAccessToken(tokenInfo.getRefreshToken()); + wps365OAuthService.saveToken(userId, tokenInfo); + } catch (Exception e) { + log.error("刷新Token失败", e); + return AjaxResult.error("Token已过期且刷新失败,请重新授权"); + } + } + + JSONObject result = wps365ApiService.updateAirSheetCells(tokenInfo.getAccessToken(), worksheetId, range, values); + return AjaxResult.success("更新AirSheet数据成功", result); + } catch (Exception e) { + log.error("更新AirSheet数据失败", e); + return AjaxResult.error("更新AirSheet数据失败: " + e.getMessage()); + } + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IWPS365ApiService.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IWPS365ApiService.java index 669d93f..4097507 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IWPS365ApiService.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/IWPS365ApiService.java @@ -90,5 +90,26 @@ public interface IWPS365ApiService { * @return 更新结果 */ JSONObject batchUpdateCells(String accessToken, String fileToken, int sheetIdx, List> updates); + + /** + * 读取AirSheet工作表数据 + * + * @param accessToken 访问令牌 + * @param worksheetId 工作表ID(文件ID) + * @param range 单元格范围(如:A1:B10,可选) + * @return 单元格数据 + */ + JSONObject readAirSheetCells(String accessToken, String worksheetId, String range); + + /** + * 更新AirSheet工作表数据 + * + * @param accessToken 访问令牌 + * @param worksheetId 工作表ID(文件ID) + * @param range 单元格范围(如:A1:B2) + * @param values 单元格值(二维数组,第一维是行,第二维是列) + * @return 更新结果 + */ + JSONObject updateAirSheetCells(String accessToken, String worksheetId, String range, List> values); } diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365ApiServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365ApiServiceImpl.java index d425a00..cca91b1 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365ApiServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/WPS365ApiServiceImpl.java @@ -47,7 +47,9 @@ public class WPS365ApiServiceImpl implements IWPS365ApiService { @Override public JSONObject getFileList(String accessToken, Map params) { try { - StringBuilder url = new StringBuilder(wps365Config.getApiBaseUrl() + "/files"); + // WPS365文件列表API路径可能是 /yundoc/files 而不是 /files + // 根据WPS365 API文档,文件相关API通常在 /yundoc 路径下 + StringBuilder url = new StringBuilder(wps365Config.getApiBaseUrl() + "/yundoc/files"); // 添加查询参数 if (params != null && !params.isEmpty()) { @@ -57,14 +59,22 @@ public class WPS365ApiServiceImpl implements IWPS365ApiService { if (!first) { url.append("&"); } - url.append(entry.getKey()).append("=").append(entry.getValue()); + // URL编码参数值 + try { + String key = entry.getKey(); + String value = entry.getValue() != null ? entry.getValue().toString() : ""; + url.append(key).append("=").append(java.net.URLEncoder.encode(value, "UTF-8")); + } catch (java.io.UnsupportedEncodingException e) { + url.append(entry.getKey()).append("=").append(entry.getValue()); + } first = false; } } + log.debug("调用文件列表API: {}", url.toString()); return WPS365ApiUtil.httpRequest("GET", url.toString(), accessToken, null); } catch (Exception e) { - log.error("获取文件列表失败", e); + log.error("获取文件列表失败 - url: {}", wps365Config.getApiBaseUrl() + "/yundoc/files", e); throw new RuntimeException("获取文件列表失败: " + e.getMessage(), e); } } @@ -72,10 +82,13 @@ public class WPS365ApiServiceImpl implements IWPS365ApiService { @Override public JSONObject getFileInfo(String accessToken, String fileToken) { try { - String url = wps365Config.getApiBaseUrl() + "/files/" + fileToken; + // WPS365文件信息API路径:/yundoc/files/{fileToken} + String url = wps365Config.getApiBaseUrl() + "/yundoc/files/" + fileToken; + log.debug("调用文件信息API: {}", url); return WPS365ApiUtil.httpRequest("GET", url, accessToken, null); } catch (Exception e) { - log.error("获取文件信息失败 - fileToken: {}", fileToken, e); + log.error("获取文件信息失败 - fileToken: {}, url: {}", fileToken, + wps365Config.getApiBaseUrl() + "/yundoc/files/" + fileToken, e); throw new RuntimeException("获取文件信息失败: " + e.getMessage(), e); } } @@ -203,5 +216,60 @@ public class WPS365ApiServiceImpl implements IWPS365ApiService { throw new RuntimeException("批量更新单元格数据失败: " + e.getMessage(), e); } } + + @Override + public JSONObject readAirSheetCells(String accessToken, String worksheetId, String range) { + try { + // WPS365 AirSheet API: GET /api/v1/openapi/airsheet/worksheets/{worksheetId} + // 根据文档:https://open.wps.cn/documents/app-integration-dev/wps365/server/airsheet/worksheets/VbHZwButmh + String url = wps365Config.getApiBaseUrl() + "/openapi/airsheet/worksheets/" + worksheetId; + if (range != null && !range.trim().isEmpty()) { + url += "?range=" + java.net.URLEncoder.encode(range, "UTF-8"); + } + + log.debug("读取AirSheet数据 - url: {}, range: {}", url, range); + return WPS365ApiUtil.httpRequest("GET", url, accessToken, null); + } catch (Exception e) { + log.error("读取AirSheet数据失败 - worksheetId: {}, range: {}", worksheetId, range, e); + throw new RuntimeException("读取AirSheet数据失败: " + e.getMessage(), e); + } + } + + @Override + public JSONObject updateAirSheetCells(String accessToken, String worksheetId, String range, List> values) { + try { + // WPS365 AirSheet API: PUT /api/v1/openapi/airsheet/worksheets/{worksheetId} + String url = wps365Config.getApiBaseUrl() + "/openapi/airsheet/worksheets/" + worksheetId; + + // 构建请求体 + JSONObject requestBody = new JSONObject(); + if (range != null && !range.trim().isEmpty()) { + requestBody.put("range", range); + } + + // 构建values数组 + JSONArray valuesArray = new JSONArray(); + if (values != null) { + for (List row : values) { + JSONArray rowArray = new JSONArray(); + if (row != null) { + for (Object cell : row) { + rowArray.add(cell); + } + } + valuesArray.add(rowArray); + } + } + requestBody.put("values", valuesArray); + + String bodyStr = requestBody.toJSONString(); + log.debug("更新AirSheet数据 - url: {}, range: {}, values: {}", url, range, bodyStr); + + return WPS365ApiUtil.httpRequest("PUT", url, accessToken, bodyStr); + } catch (Exception e) { + log.error("更新AirSheet数据失败 - worksheetId: {}, range: {}", worksheetId, range, e); + throw new RuntimeException("更新AirSheet数据失败: " + e.getMessage(), e); + } + } } diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/WPS365ApiUtil.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/WPS365ApiUtil.java index 0b797fc..8695446 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/WPS365ApiUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/WPS365ApiUtil.java @@ -261,10 +261,13 @@ public class WPS365ApiUtil { } String responseStr = response.toString(); - log.debug("HTTP响应: statusCode={}, response={}", statusCode, responseStr); + log.info("HTTP响应: statusCode={}, url={}, response={}", statusCode, url, responseStr); if (statusCode < 200 || statusCode >= 300) { - throw new RuntimeException("HTTP请求失败: statusCode=" + statusCode + ", response=" + responseStr); + String errorMsg = String.format("HTTP请求失败: statusCode=%d, url=%s, response=%s", + statusCode, url, responseStr); + log.error(errorMsg); + throw new RuntimeException(errorMsg); } if (responseStr == null || responseStr.trim().isEmpty()) {