1
This commit is contained in:
@@ -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