1
This commit is contained in:
@@ -0,0 +1,92 @@
|
||||
package com.ruoyi.jarvis.config;
|
||||
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* 腾讯文档开放平台配置
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
@Configuration
|
||||
@ConfigurationProperties(prefix = "tencent.doc")
|
||||
public class TencentDocConfig {
|
||||
|
||||
/** 应用ID */
|
||||
private String appId;
|
||||
|
||||
/** 应用密钥 */
|
||||
private String appSecret;
|
||||
|
||||
/** 授权回调地址 */
|
||||
private String redirectUri;
|
||||
|
||||
/** API基础地址 */
|
||||
private String apiBaseUrl = "https://docs.qq.com/open/v1";
|
||||
|
||||
/** OAuth授权地址 */
|
||||
private String oauthUrl = "https://docs.qq.com/oauth/v2/authorize";
|
||||
|
||||
/** 获取Token地址 */
|
||||
private String tokenUrl = "https://docs.qq.com/oauth/v2/token";
|
||||
|
||||
/** 刷新Token地址 */
|
||||
private String refreshTokenUrl = "https://docs.qq.com/oauth/v2/token";
|
||||
|
||||
public String getAppId() {
|
||||
return appId;
|
||||
}
|
||||
|
||||
public void setAppId(String appId) {
|
||||
this.appId = appId;
|
||||
}
|
||||
|
||||
public String getAppSecret() {
|
||||
return appSecret;
|
||||
}
|
||||
|
||||
public void setAppSecret(String appSecret) {
|
||||
this.appSecret = appSecret;
|
||||
}
|
||||
|
||||
public String getRedirectUri() {
|
||||
return redirectUri;
|
||||
}
|
||||
|
||||
public void setRedirectUri(String redirectUri) {
|
||||
this.redirectUri = redirectUri;
|
||||
}
|
||||
|
||||
public String getApiBaseUrl() {
|
||||
return apiBaseUrl;
|
||||
}
|
||||
|
||||
public void setApiBaseUrl(String apiBaseUrl) {
|
||||
this.apiBaseUrl = apiBaseUrl;
|
||||
}
|
||||
|
||||
public String getOauthUrl() {
|
||||
return oauthUrl;
|
||||
}
|
||||
|
||||
public void setOauthUrl(String oauthUrl) {
|
||||
this.oauthUrl = oauthUrl;
|
||||
}
|
||||
|
||||
public String getTokenUrl() {
|
||||
return tokenUrl;
|
||||
}
|
||||
|
||||
public void setTokenUrl(String tokenUrl) {
|
||||
this.tokenUrl = tokenUrl;
|
||||
}
|
||||
|
||||
public String getRefreshTokenUrl() {
|
||||
return refreshTokenUrl;
|
||||
}
|
||||
|
||||
public void setRefreshTokenUrl(String refreshTokenUrl) {
|
||||
this.refreshTokenUrl = refreshTokenUrl;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,101 @@
|
||||
package com.ruoyi.jarvis.service;
|
||||
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.jarvis.domain.JDOrder;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 腾讯文档服务接口
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
public interface ITencentDocService {
|
||||
|
||||
/**
|
||||
* 获取授权URL
|
||||
*
|
||||
* @return 授权URL
|
||||
*/
|
||||
String getAuthUrl();
|
||||
|
||||
/**
|
||||
* 通过授权码获取访问令牌
|
||||
*
|
||||
* @param code 授权码
|
||||
* @return 访问令牌信息
|
||||
*/
|
||||
JSONObject getAccessTokenByCode(String code);
|
||||
|
||||
/**
|
||||
* 刷新访问令牌
|
||||
*
|
||||
* @param refreshToken 刷新令牌
|
||||
* @return 新的访问令牌信息
|
||||
*/
|
||||
JSONObject refreshAccessToken(String refreshToken);
|
||||
|
||||
/**
|
||||
* 将物流信息上传到腾讯文档表格
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param orders 订单列表
|
||||
* @return 上传结果
|
||||
*/
|
||||
JSONObject uploadLogisticsToSheet(String accessToken, String fileId, String sheetId, List<JDOrder> orders);
|
||||
|
||||
/**
|
||||
* 将单个订单的物流信息追加到表格
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param order 订单信息
|
||||
* @return 上传结果
|
||||
*/
|
||||
JSONObject appendLogisticsToSheet(String accessToken, String fileId, String sheetId, JDOrder order);
|
||||
|
||||
/**
|
||||
* 读取表格数据
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param range 范围
|
||||
* @return 表格数据
|
||||
*/
|
||||
JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range);
|
||||
|
||||
/**
|
||||
* 写入表格数据
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param range 范围,例如 "A1"
|
||||
* @param values 要写入的数据,二维数组格式
|
||||
* @return 写入结果
|
||||
*/
|
||||
JSONObject writeSheetData(String accessToken, String fileId, String sheetId, String range, Object values);
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @return 文件信息
|
||||
*/
|
||||
JSONObject getFileInfo(String accessToken, String fileId);
|
||||
|
||||
/**
|
||||
* 获取工作表列表
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @return 工作表列表
|
||||
*/
|
||||
JSONObject getSheetList(String accessToken, String fileId);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,194 @@
|
||||
package com.ruoyi.jarvis.service.impl;
|
||||
|
||||
import com.alibaba.fastjson2.JSONArray;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.jarvis.config.TencentDocConfig;
|
||||
import com.ruoyi.jarvis.domain.JDOrder;
|
||||
import com.ruoyi.jarvis.service.ITencentDocService;
|
||||
import com.ruoyi.jarvis.util.TencentDocApiUtil;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 腾讯文档服务实现类
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
@Service
|
||||
public class TencentDocServiceImpl implements ITencentDocService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TencentDocServiceImpl.class);
|
||||
|
||||
@Autowired
|
||||
private TencentDocConfig tencentDocConfig;
|
||||
|
||||
@Override
|
||||
public String getAuthUrl() {
|
||||
String appId = tencentDocConfig.getAppId();
|
||||
String redirectUri = tencentDocConfig.getRedirectUri();
|
||||
String oauthUrl = tencentDocConfig.getOauthUrl();
|
||||
|
||||
// 构建授权URL
|
||||
StringBuilder authUrl = new StringBuilder();
|
||||
authUrl.append(oauthUrl);
|
||||
authUrl.append("?client_id=").append(appId);
|
||||
try {
|
||||
authUrl.append("&redirect_uri=").append(java.net.URLEncoder.encode(redirectUri, "UTF-8"));
|
||||
} catch (java.io.UnsupportedEncodingException e) {
|
||||
log.error("URL编码失败", e);
|
||||
authUrl.append("&redirect_uri=").append(redirectUri);
|
||||
}
|
||||
authUrl.append("&response_type=code");
|
||||
authUrl.append("&scope=file.read_write");
|
||||
|
||||
return authUrl.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getAccessTokenByCode(String code) {
|
||||
try {
|
||||
return TencentDocApiUtil.getAccessToken(
|
||||
tencentDocConfig.getAppId(),
|
||||
tencentDocConfig.getAppSecret(),
|
||||
code,
|
||||
tencentDocConfig.getRedirectUri(),
|
||||
tencentDocConfig.getTokenUrl()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("通过授权码获取访问令牌失败", e);
|
||||
throw new RuntimeException("获取访问令牌失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject refreshAccessToken(String refreshToken) {
|
||||
try {
|
||||
return TencentDocApiUtil.refreshAccessToken(
|
||||
tencentDocConfig.getAppId(),
|
||||
tencentDocConfig.getAppSecret(),
|
||||
refreshToken,
|
||||
tencentDocConfig.getRefreshTokenUrl()
|
||||
);
|
||||
} catch (Exception e) {
|
||||
log.error("刷新访问令牌失败", e);
|
||||
throw new RuntimeException("刷新访问令牌失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject uploadLogisticsToSheet(String accessToken, String fileId, String sheetId, List<JDOrder> orders) {
|
||||
try {
|
||||
if (orders == null || orders.isEmpty()) {
|
||||
throw new IllegalArgumentException("订单列表不能为空");
|
||||
}
|
||||
|
||||
// 构建要写入的数据(二维数组格式)
|
||||
JSONArray values = new JSONArray();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
for (JDOrder order : orders) {
|
||||
JSONArray row = new JSONArray();
|
||||
// 根据表格列顺序添加数据
|
||||
// 假设列顺序为:内部单号、订单号、下单时间、型号、地址、物流链接、下单人、付款金额、后返金额、备注
|
||||
row.add(order.getRemark() != null ? order.getRemark() : "");
|
||||
row.add(order.getOrderId() != null ? order.getOrderId() : "");
|
||||
row.add(order.getOrderTime() != null ? sdf.format(order.getOrderTime()) : "");
|
||||
row.add(order.getModelNumber() != null ? order.getModelNumber() : "");
|
||||
row.add(order.getAddress() != null ? order.getAddress() : "");
|
||||
row.add(order.getLogisticsLink() != null ? order.getLogisticsLink() : "");
|
||||
row.add(order.getBuyer() != null ? order.getBuyer() : "");
|
||||
row.add(order.getPaymentAmount() != null ? order.getPaymentAmount().toString() : "");
|
||||
row.add(order.getRebateAmount() != null ? order.getRebateAmount().toString() : "");
|
||||
row.add(order.getStatus() != null ? order.getStatus() : "");
|
||||
|
||||
values.add(row);
|
||||
}
|
||||
|
||||
// 追加数据到表格
|
||||
return TencentDocApiUtil.appendSheetData(accessToken, fileId, sheetId, values, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("上传物流信息到表格失败", e);
|
||||
throw new RuntimeException("上传物流信息失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject appendLogisticsToSheet(String accessToken, String fileId, String sheetId, JDOrder order) {
|
||||
try {
|
||||
if (order == null) {
|
||||
throw new IllegalArgumentException("订单信息不能为空");
|
||||
}
|
||||
|
||||
// 构建单行数据
|
||||
JSONArray values = new JSONArray();
|
||||
JSONArray row = new JSONArray();
|
||||
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
|
||||
|
||||
// 根据表格列顺序添加数据
|
||||
row.add(order.getRemark() != null ? order.getRemark() : "");
|
||||
row.add(order.getOrderId() != null ? order.getOrderId() : "");
|
||||
row.add(order.getOrderTime() != null ? sdf.format(order.getOrderTime()) : "");
|
||||
row.add(order.getModelNumber() != null ? order.getModelNumber() : "");
|
||||
row.add(order.getAddress() != null ? order.getAddress() : "");
|
||||
row.add(order.getLogisticsLink() != null ? order.getLogisticsLink() : "");
|
||||
row.add(order.getBuyer() != null ? order.getBuyer() : "");
|
||||
row.add(order.getPaymentAmount() != null ? order.getPaymentAmount().toString() : "");
|
||||
row.add(order.getRebateAmount() != null ? order.getRebateAmount().toString() : "");
|
||||
row.add(order.getStatus() != null ? order.getStatus() : "");
|
||||
|
||||
values.add(row);
|
||||
|
||||
// 追加数据到表格
|
||||
return TencentDocApiUtil.appendSheetData(accessToken, fileId, sheetId, values, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("追加物流信息到表格失败", e);
|
||||
throw new RuntimeException("追加物流信息失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range) {
|
||||
try {
|
||||
return TencentDocApiUtil.readSheetData(accessToken, fileId, sheetId, range, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("读取表格数据失败", e);
|
||||
throw new RuntimeException("读取表格数据失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject writeSheetData(String accessToken, String fileId, String sheetId, String range, Object values) {
|
||||
try {
|
||||
return TencentDocApiUtil.writeSheetData(accessToken, fileId, sheetId, range, values, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("写入表格数据失败", e);
|
||||
throw new RuntimeException("写入表格数据失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getFileInfo(String accessToken, String fileId) {
|
||||
try {
|
||||
return TencentDocApiUtil.getFileInfo(accessToken, fileId, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("获取文件信息失败", e);
|
||||
throw new RuntimeException("获取文件信息失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public JSONObject getSheetList(String accessToken, String fileId) {
|
||||
try {
|
||||
return TencentDocApiUtil.getSheetList(accessToken, fileId, tencentDocConfig.getApiBaseUrl());
|
||||
} catch (Exception e) {
|
||||
log.error("获取工作表列表失败", e);
|
||||
throw new RuntimeException("获取工作表列表失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,248 @@
|
||||
package com.ruoyi.jarvis.util;
|
||||
|
||||
import com.alibaba.fastjson2.JSON;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import com.ruoyi.common.utils.http.HttpUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.io.BufferedReader;
|
||||
import java.io.InputStreamReader;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.net.HttpURLConnection;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* 腾讯文档API工具类
|
||||
*
|
||||
* @author system
|
||||
*/
|
||||
public class TencentDocApiUtil {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TencentDocApiUtil.class);
|
||||
|
||||
/**
|
||||
* 获取访问令牌
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @param appSecret 应用密钥
|
||||
* @param code 授权码
|
||||
* @param redirectUri 回调地址
|
||||
* @return 包含access_token和refresh_token的JSON对象
|
||||
*/
|
||||
public static JSONObject getAccessToken(String appId, String appSecret, String code, String redirectUri, String tokenUrl) {
|
||||
try {
|
||||
// 构建请求参数
|
||||
StringBuilder params = new StringBuilder();
|
||||
params.append("grant_type=authorization_code");
|
||||
params.append("&client_id=").append(appId);
|
||||
params.append("&client_secret=").append(appSecret);
|
||||
params.append("&code=").append(code);
|
||||
params.append("&redirect_uri=").append(java.net.URLEncoder.encode(redirectUri, "UTF-8"));
|
||||
|
||||
String response = HttpUtils.sendPost(tokenUrl, params.toString());
|
||||
log.info("获取访问令牌响应: {}", response);
|
||||
|
||||
return JSON.parseObject(response);
|
||||
} catch (Exception e) {
|
||||
log.error("获取访问令牌失败", e);
|
||||
throw new RuntimeException("获取访问令牌失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新访问令牌
|
||||
*
|
||||
* @param appId 应用ID
|
||||
* @param appSecret 应用密钥
|
||||
* @param refreshToken 刷新令牌
|
||||
* @param refreshTokenUrl 刷新令牌地址
|
||||
* @return 包含新的access_token和refresh_token的JSON对象
|
||||
*/
|
||||
public static JSONObject refreshAccessToken(String appId, String appSecret, String refreshToken, String refreshTokenUrl) {
|
||||
try {
|
||||
// 构建请求参数
|
||||
StringBuilder params = new StringBuilder();
|
||||
params.append("grant_type=refresh_token");
|
||||
params.append("&client_id=").append(appId);
|
||||
params.append("&client_secret=").append(appSecret);
|
||||
params.append("&refresh_token=").append(refreshToken);
|
||||
|
||||
String response = HttpUtils.sendPost(refreshTokenUrl, params.toString());
|
||||
log.info("刷新访问令牌响应: {}", response);
|
||||
|
||||
return JSON.parseObject(response);
|
||||
} catch (Exception e) {
|
||||
log.error("刷新访问令牌失败", e);
|
||||
throw new RuntimeException("刷新访问令牌失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 调用腾讯文档API
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param apiUrl API地址
|
||||
* @param method 请求方法 GET/POST/PUT/DELETE
|
||||
* @param body 请求体(JSON格式)
|
||||
* @return API响应
|
||||
*/
|
||||
public static JSONObject callApi(String accessToken, String apiUrl, String method, String body) {
|
||||
try {
|
||||
URL url = new URL(apiUrl);
|
||||
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
||||
conn.setRequestMethod(method);
|
||||
conn.setRequestProperty("Authorization", "Bearer " + accessToken);
|
||||
conn.setRequestProperty("Content-Type", "application/json");
|
||||
conn.setRequestProperty("Accept", "application/json");
|
||||
conn.setDoOutput(true);
|
||||
conn.setDoInput(true);
|
||||
conn.setConnectTimeout(10000);
|
||||
conn.setReadTimeout(30000);
|
||||
|
||||
// 写入请求体
|
||||
if (body != null && !body.isEmpty()) {
|
||||
try (OutputStream os = conn.getOutputStream();
|
||||
OutputStreamWriter osw = new OutputStreamWriter(os, StandardCharsets.UTF_8)) {
|
||||
osw.write(body);
|
||||
osw.flush();
|
||||
}
|
||||
}
|
||||
|
||||
// 读取响应
|
||||
int statusCode = conn.getResponseCode();
|
||||
BufferedReader reader;
|
||||
if (statusCode >= 200 && statusCode < 300) {
|
||||
reader = new BufferedReader(new InputStreamReader(conn.getInputStream(), StandardCharsets.UTF_8));
|
||||
} else {
|
||||
reader = new BufferedReader(new InputStreamReader(conn.getErrorStream(), StandardCharsets.UTF_8));
|
||||
}
|
||||
|
||||
StringBuilder response = new StringBuilder();
|
||||
String line;
|
||||
while ((line = reader.readLine()) != null) {
|
||||
response.append(line);
|
||||
}
|
||||
reader.close();
|
||||
|
||||
String responseStr = response.toString();
|
||||
log.debug("腾讯文档API响应: statusCode={}, response={}", statusCode, responseStr);
|
||||
|
||||
JSONObject result = JSON.parseObject(responseStr);
|
||||
|
||||
// 检查错误码
|
||||
if (result.containsKey("error_code") && result.getIntValue("error_code") != 0) {
|
||||
String errorMsg = result.getString("error_msg");
|
||||
log.error("腾讯文档API调用失败: error_code={}, error_msg={}",
|
||||
result.getIntValue("error_code"), errorMsg);
|
||||
throw new RuntimeException("腾讯文档API调用失败: " + errorMsg);
|
||||
}
|
||||
|
||||
if (statusCode < 200 || statusCode >= 300) {
|
||||
throw new RuntimeException("HTTP请求失败: statusCode=" + statusCode + ", response=" + responseStr);
|
||||
}
|
||||
|
||||
return result;
|
||||
} catch (Exception e) {
|
||||
log.error("调用腾讯文档API失败: url={}, method={}", apiUrl, method, e);
|
||||
throw new RuntimeException("调用腾讯文档API失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 读取表格数据
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param range 范围,例如 "A1:Z100"
|
||||
* @param apiBaseUrl API基础地址
|
||||
* @return 表格数据
|
||||
*/
|
||||
public static JSONObject readSheetData(String accessToken, String fileId, String sheetId, String range, String apiBaseUrl) {
|
||||
String apiUrl = String.format("%s/files/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
|
||||
return callApi(accessToken, apiUrl, "GET", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入表格数据
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param range 范围,例如 "A1"
|
||||
* @param values 要写入的数据,二维数组格式 [[["值1"], ["值2"]], [["值3"], ["值4"]]]
|
||||
* @param apiBaseUrl API基础地址
|
||||
* @return 写入结果
|
||||
*/
|
||||
public static JSONObject writeSheetData(String accessToken, String fileId, String sheetId, String range, Object values, String apiBaseUrl) {
|
||||
String apiUrl = String.format("%s/files/%s/sheets/%s/ranges/%s", apiBaseUrl, fileId, sheetId, range);
|
||||
|
||||
JSONObject requestBody = new JSONObject();
|
||||
requestBody.put("values", values);
|
||||
|
||||
return callApi(accessToken, apiUrl, "PUT", requestBody.toJSONString());
|
||||
}
|
||||
|
||||
/**
|
||||
* 追加表格数据(在最后一行追加)
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param sheetId 工作表ID
|
||||
* @param values 要追加的数据,二维数组格式
|
||||
* @param apiBaseUrl API基础地址
|
||||
* @return 追加结果
|
||||
*/
|
||||
public static JSONObject appendSheetData(String accessToken, String fileId, String sheetId, Object values, String apiBaseUrl) {
|
||||
// 先获取表格信息,找到最后一行
|
||||
String infoUrl = String.format("%s/files/%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");
|
||||
}
|
||||
|
||||
if (rowCount == 0) {
|
||||
rowCount = 1; // 至少有一行(表头)
|
||||
}
|
||||
|
||||
// 计算要写入的起始位置(假设追加一行数据)
|
||||
String range = "A" + (rowCount + 1);
|
||||
|
||||
return writeSheetData(accessToken, fileId, sheetId, range, values, apiBaseUrl);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件信息
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param apiBaseUrl API基础地址
|
||||
* @return 文件信息
|
||||
*/
|
||||
public static JSONObject getFileInfo(String accessToken, String fileId, String apiBaseUrl) {
|
||||
String apiUrl = String.format("%s/files/%s", apiBaseUrl, fileId);
|
||||
return callApi(accessToken, apiUrl, "GET", null);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取工作表列表
|
||||
*
|
||||
* @param accessToken 访问令牌
|
||||
* @param fileId 文件ID
|
||||
* @param apiBaseUrl API基础地址
|
||||
* @return 工作表列表
|
||||
*/
|
||||
public static JSONObject getSheetList(String accessToken, String fileId, String apiBaseUrl) {
|
||||
String apiUrl = String.format("%s/files/%s/sheets", apiBaseUrl, fileId);
|
||||
return callApi(accessToken, apiUrl, "GET", null);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user