This commit is contained in:
Leo
2026-02-04 23:59:36 +08:00
parent f928e778da
commit 7ed5a76d2f
3 changed files with 22 additions and 13 deletions

View File

@@ -57,8 +57,10 @@ public class TencentDocController extends BaseController {
/** Redis key前缀用于存储上次处理的最大行数 */ /** Redis key前缀用于存储上次处理的最大行数 */
private static final String LAST_PROCESSED_ROW_KEY_PREFIX = "tendoc:last_row:"; private static final String LAST_PROCESSED_ROW_KEY_PREFIX = "tendoc:last_row:";
/** 单次请求最大行数(腾讯文档 API range 限制,避免 invalid param range */ /** 单次请求最大行数(腾讯文档 API行数≤1000一次拉 500 行 */
private static final int API_MAX_ROWS_PER_REQUEST = 200; private static final int API_MAX_ROWS_PER_REQUEST = 500;
/** 数据区 range 列尾30 列 = A 到 ADAPI 列数≤200 */
private static final String DATA_RANGE_COL_END = "AD";
/** 回溯行数:下次起始行 = 本次扫描终点 + 1 - 回溯,用于覆盖物流变更或延后补填 */ /** 回溯行数:下次起始行 = 本次扫描终点 + 1 - 回溯,用于覆盖物流变更或延后补填 */
private static final int BACKTRACK_ROWS = 80; private static final int BACKTRACK_ROWS = 80;
/** 整批都跳过0 写入)时使用的回溯行数,减小回溯以尽快扫到后续行(如 308 */ /** 整批都跳过0 写入)时使用的回溯行数,减小回溯以尽快扫到后续行(如 308 */
@@ -1168,7 +1170,7 @@ public class TencentDocController extends BaseController {
if (tryEndRow < startRow) { if (tryEndRow < startRow) {
continue; 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); log.info("开始读取数据行 - 行号: {} ~ {} (共 {} 行), range: {} (尝试 decrement={})", startRow, tryEndRow, tryRowCount, range, decrement);
try { try {
sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range); sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, range);
@@ -1198,7 +1200,7 @@ public class TencentDocController extends BaseController {
for (int decrement : new int[] { 1, 10 }) { for (int decrement : new int[] { 1, 10 }) {
int tryEndRow = Math.max(startRow, effectiveEndRow - decrement); int tryEndRow = Math.max(startRow, effectiveEndRow - decrement);
if (tryEndRow >= startRow) { 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 { try {
sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, retryRange); sheetData = tencentDocService.readSheetData(accessToken, fileId, sheetId, retryRange);
if (sheetData != null) { if (sheetData != null) {
@@ -1221,7 +1223,7 @@ public class TencentDocController extends BaseController {
} }
} }
endRow = effectiveEndRow; // 后续统一使用实际读取成功的 endRow 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"); log.info("解析后的数据行数: {}", values != null ? values.size() : "null");
if (values == null || values.isEmpty()) { if (values == null || values.isEmpty()) {
@@ -2122,8 +2124,8 @@ public class TencentDocController extends BaseController {
int skippedCount = 0; int skippedCount = 0;
int errorCount = 0; int errorCount = 0;
// 分批读取数据,每批200行避免单次读取过多数据导致API限制 // 分批读取数据,每批500行API 行数≤1000列数≤200
final int BATCH_SIZE = 200; final int BATCH_SIZE = 500;
int currentStartRow = startRow; int currentStartRow = startRow;
int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE); int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE);
int currentBatch = 0; int currentBatch = 0;
@@ -2421,8 +2423,8 @@ public class TencentDocController extends BaseController {
int errorCount = 0; // 错误数量 int errorCount = 0; // 错误数量
java.util.List<String> updatedOrderNos = new java.util.ArrayList<>(); // 更新的单号列表 java.util.List<String> updatedOrderNos = new java.util.ArrayList<>(); // 更新的单号列表
// 分批读取数据,每批200行避免单次读取过多数据导致API限制 // 分批读取数据,每批500行API 行数≤1000列数≤200
final int BATCH_SIZE = 200; final int BATCH_SIZE = 500;
int currentStartRow = startRow; int currentStartRow = startRow;
int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE); int totalBatches = (int) Math.ceil((double)(endRow - startRow + 1) / BATCH_SIZE);
int currentBatch = 0; int currentBatch = 0;

View File

@@ -292,7 +292,7 @@ public class TencentDocDelayedPushServiceImpl implements ITencentDocDelayedPushS
"AUTO", "AUTO",
"DELAYED_TIMER", "DELAYED_TIMER",
startRow, 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); log.info("✓ 创建批量推送记录批次ID: {}", batchId);

View File

@@ -11,6 +11,7 @@ import java.io.InputStreamReader;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.net.HttpURLConnection; import java.net.HttpURLConnection;
import java.net.URLEncoder;
import java.net.URL; import java.net.URL;
import java.nio.charset.StandardCharsets; 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) { 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} // V3版本API路径格式/openapi/spreadsheet/v3/files/{fileId}/{sheetId}/{range}
// range格式A1表示法Excel格式如 A10:D11 // range 需 URL 编码,否则 path 中的 ":" 会导致网关/服务端报 range invalid (400001)
String apiUrl = String.format("%s/files/%s/%s/%s", apiBaseUrl, fileId, sheetId, range); String encodedRange;
log.info("读取表格数据 - fileId: {}, sheetId: {}, range: {}, apiUrl: {}", fileId, sheetId, range, apiUrl); 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); return callApi(accessToken, appId, openId, apiUrl, "GET", null);
} }