From 7ed5a76d2fee6cd692d1f3ef90c3a7cd51a15fc3 Mon Sep 17 00:00:00 2001 From: Leo Date: Wed, 4 Feb 2026 23:59:36 +0800 Subject: [PATCH] 1 --- .../jarvis/TencentDocController.java | 20 ++++++++++--------- .../TencentDocDelayedPushServiceImpl.java | 2 +- .../ruoyi/jarvis/util/TencentDocApiUtil.java | 13 +++++++++--- 3 files changed, 22 insertions(+), 13 deletions(-) diff --git a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java index 01ac52e..5dfce13 100644 --- a/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java +++ b/ruoyi-admin/src/main/java/com/ruoyi/web/controller/jarvis/TencentDocController.java @@ -57,8 +57,10 @@ public class TencentDocController extends BaseController { /** Redis key前缀,用于存储上次处理的最大行数 */ private static final String LAST_PROCESSED_ROW_KEY_PREFIX = "tendoc:last_row:"; - /** 单次请求最大行数(腾讯文档 API range 限制,避免 invalid param range) */ - private static final int API_MAX_ROWS_PER_REQUEST = 200; + /** 单次请求最大行数(腾讯文档 API:行数≤1000,一次拉 500 行) */ + private static final int API_MAX_ROWS_PER_REQUEST = 500; + /** 数据区 range 列尾(30 列 = A 到 AD,API 列数≤200) */ + private static final String DATA_RANGE_COL_END = "AD"; /** 回溯行数:下次起始行 = 本次扫描终点 + 1 - 回溯,用于覆盖物流变更或延后补填 */ private static final int BACKTRACK_ROWS = 80; /** 整批都跳过(0 写入)时使用的回溯行数,减小回溯以尽快扫到后续行(如 308) */ @@ -1168,7 +1170,7 @@ public class TencentDocController extends BaseController { if (tryEndRow < startRow) { continue; } - String range = String.format("A%d:Z%d", startRow, tryEndRow); + String range = String.format("A%d:%s%d", startRow, DATA_RANGE_COL_END, tryEndRow); log.info("开始读取数据行 - 行号: {} ~ {} (共 {} 行), range: {} (尝试 decrement={})", startRow, tryEndRow, tryRowCount, range, decrement); try { sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range); @@ -1198,7 +1200,7 @@ public class TencentDocController extends BaseController { for (int decrement : new int[] { 1, 10 }) { int tryEndRow = Math.max(startRow, effectiveEndRow - decrement); if (tryEndRow >= startRow) { - String retryRange = String.format("A%d:Z%d", startRow, tryEndRow); + String retryRange = String.format("A%d:%s%d", startRow, DATA_RANGE_COL_END, tryEndRow); try { sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, retryRange); if (sheetData != null) { @@ -1221,7 +1223,7 @@ public class TencentDocController extends BaseController { } } endRow = effectiveEndRow; // 后续统一使用实际读取成功的 endRow - String range = String.format("A%d:Z%d", startRow, endRow); + String range = String.format("A%d:%s%d", startRow, DATA_RANGE_COL_END, endRow); log.info("解析后的数据行数: {}", values != null ? values.size() : "null"); if (values == null || values.isEmpty()) { @@ -2122,8 +2124,8 @@ public class TencentDocController extends BaseController { int skippedCount = 0; int errorCount = 0; - // 分批读取数据,每批200行(避免单次读取过多数据导致API限制) - final int BATCH_SIZE = 200; + // 分批读取数据,每批500行(API 行数≤1000,列数≤200) + final int BATCH_SIZE = 500; int currentStartRow = startRow; int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE); int currentBatch = 0; @@ -2421,8 +2423,8 @@ public class TencentDocController extends BaseController { int errorCount = 0; // 错误数量 java.util.List updatedOrderNos = new java.util.ArrayList<>(); // 更新的单号列表 - // 分批读取数据,每批200行(避免单次读取过多数据导致API限制) - final int BATCH_SIZE = 200; + // 分批读取数据,每批500行(API 行数≤1000,列数≤200) + final int BATCH_SIZE = 500; int currentStartRow = startRow; int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE); int currentBatch = 0; diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TencentDocDelayedPushServiceImpl.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TencentDocDelayedPushServiceImpl.java index 1feb494..69c0d3f 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TencentDocDelayedPushServiceImpl.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/service/impl/TencentDocDelayedPushServiceImpl.java @@ -292,7 +292,7 @@ public class TencentDocDelayedPushServiceImpl implements ITencentDocDelayedPushS "AUTO", "DELAYED_TIMER", startRow, - startRow + 199 // 与 Controller API_MAX_ROWS_PER_REQUEST=200 一致(单批最多200行) + startRow + 499 // 与 Controller API_MAX_ROWS_PER_REQUEST=500 一致(单批最多500行) ); log.info("✓ 创建批量推送记录,批次ID: {}", batchId); diff --git a/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/TencentDocApiUtil.java b/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/TencentDocApiUtil.java index 3e2e3be..b8d2c5a 100644 --- a/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/TencentDocApiUtil.java +++ b/ruoyi-system/src/main/java/com/ruoyi/jarvis/util/TencentDocApiUtil.java @@ -11,6 +11,7 @@ import java.io.InputStreamReader; import java.io.OutputStream; import java.io.OutputStreamWriter; import java.net.HttpURLConnection; +import java.net.URLEncoder; import java.net.URL; import java.nio.charset.StandardCharsets; @@ -344,9 +345,15 @@ public class TencentDocApiUtil { */ public static JSONObject readSheetData(String accessToken, String appId, String openId, String fileId, String sheetId, String range, String apiBaseUrl) { // V3版本API路径格式:/openapi/spreadsheet/v3/files/{fileId}/{sheetId}/{range} - // range格式:A1表示法(Excel格式),如 A10:D11 - String apiUrl = String.format("%s/files/%s/%s/%s", apiBaseUrl, fileId, sheetId, range); - log.info("读取表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl); + // range 需 URL 编码,否则 path 中的 ":" 会导致网关/服务端报 range invalid (400001) + String encodedRange; + try { + encodedRange = URLEncoder.encode(range, StandardCharsets.UTF_8.name()); + } catch (java.io.UnsupportedEncodingException e) { + encodedRange = range.replace(":", "%3A"); + } + String apiUrl = String.format("%s/files/%s/%s/%s", apiBaseUrl, fileId, sheetId, encodedRange); + log.info("读取表格数据 - fileId: {}, sheetId: {}, range: {} (encoded: {}), apiUrl: {}", fileId, sheetId, range, encodedRange, apiUrl); return callApi(accessToken, appId, openId, apiUrl, "GET", null); }