feat(feishu): 添加关闭官方Client连接池功能
- 在FeishuClient中新增closeOfficialPool配置项,用于控制是否关闭官方SDK的连接池- 新增Builder模式下的closeOfficialPool方法,支持链式调用设置该选项 - 修改FsApiUtil工具类,在调用飞书API时根据配置决定是否添加Connection: close头部 - 更新FsClient初始化逻辑,支持传入closeOfficialPool参数并传递给FeishuClient - 调整部分日志级别,将info级别改为debug以减少生产环境日志量 -优化代码格式,移除不必要的空行和注释中的多余换行符号
This commit is contained in:
		
							parent
							
								
									e1b1d5cd01
								
							
						
					
					
						commit
						9500a1df12
					
				@ -22,6 +22,7 @@ public class FeishuClient {
 | 
			
		||||
    private final OkHttpClient httpClient;
 | 
			
		||||
    private final String appId;
 | 
			
		||||
    private final String appSecret;
 | 
			
		||||
    private final boolean closeOfficialPool;
 | 
			
		||||
 | 
			
		||||
    // 自定义服务,处理官方SDK未覆盖的API
 | 
			
		||||
    private volatile CustomSheetService customSheetService;
 | 
			
		||||
@ -37,8 +38,18 @@ public class FeishuClient {
 | 
			
		||||
        this.appSecret = appSecret;
 | 
			
		||||
        this.officialClient = officialClient;
 | 
			
		||||
        this.httpClient = httpClient;
 | 
			
		||||
        this.closeOfficialPool = false;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    private FeishuClient(String appId, String appSecret, Client officialClient, OkHttpClient httpClient, boolean closeOfficialPool) {
 | 
			
		||||
        this.appId = appId;
 | 
			
		||||
        this.appSecret = appSecret;
 | 
			
		||||
        this.officialClient = officialClient;
 | 
			
		||||
        this.httpClient = httpClient;
 | 
			
		||||
        this.closeOfficialPool = closeOfficialPool;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 创建客户端构建器
 | 
			
		||||
     *
 | 
			
		||||
@ -216,12 +227,22 @@ public class FeishuClient {
 | 
			
		||||
        return appSecret;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取是否关闭官方Client连接池
 | 
			
		||||
     *
 | 
			
		||||
     * @return 是否关闭官方Client连接池
 | 
			
		||||
     */
 | 
			
		||||
    public boolean getCloseOfficialPool() {
 | 
			
		||||
        return closeOfficialPool;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * FeishuClient构建器
 | 
			
		||||
     */
 | 
			
		||||
    public static class Builder {
 | 
			
		||||
        private final String appId;
 | 
			
		||||
        private final String appSecret;
 | 
			
		||||
        private boolean closeOfficialPool = false;
 | 
			
		||||
        private OkHttpClient.Builder httpClientBuilder;
 | 
			
		||||
        private AppType appType = AppType.SELF_BUILT;
 | 
			
		||||
        private boolean logReqAtDebug = false;
 | 
			
		||||
@ -268,6 +289,11 @@ public class FeishuClient {
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        public Builder closeOfficialPool(boolean closeOfficialPool) {
 | 
			
		||||
            this.closeOfficialPool = closeOfficialPool;
 | 
			
		||||
            return this;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        /**
 | 
			
		||||
         * 构建FeishuClient实例
 | 
			
		||||
         *
 | 
			
		||||
@ -281,7 +307,7 @@ public class FeishuClient {
 | 
			
		||||
            // 构建OkHttpClient
 | 
			
		||||
            OkHttpClient httpClient = httpClientBuilder.build();
 | 
			
		||||
 | 
			
		||||
            return new FeishuClient(appId, appSecret, officialClient, httpClient);
 | 
			
		||||
            return new FeishuClient(appId, appSecret, officialClient, httpClient, closeOfficialPool);
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
@ -9,6 +9,7 @@ import java.util.concurrent.ConcurrentHashMap;
 | 
			
		||||
 */
 | 
			
		||||
public class FsClient implements AutoCloseable {
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    private static volatile FsClient instance;
 | 
			
		||||
    private final ThreadLocal<FeishuClient> clientHolder = new ThreadLocal<>();
 | 
			
		||||
    private final Map<String, FeishuClient> clientMap = new ConcurrentHashMap<>();
 | 
			
		||||
@ -53,6 +54,10 @@ public class FsClient implements AutoCloseable {
 | 
			
		||||
     * @return 初始化的FeishuClient实例
 | 
			
		||||
     */
 | 
			
		||||
    public FeishuClient initializeClient(String appId, String appSecret) {
 | 
			
		||||
        return initializeClient(appId, appSecret, false);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public FeishuClient initializeClient(String appId, String appSecret, boolean closeOfficialPool) {
 | 
			
		||||
        if (appId == null || appId.trim().isEmpty()) {
 | 
			
		||||
            throw new IllegalArgumentException("appId cannot be null or empty");
 | 
			
		||||
        }
 | 
			
		||||
@ -64,7 +69,7 @@ public class FsClient implements AutoCloseable {
 | 
			
		||||
            clientHolder.set(feishuClient);
 | 
			
		||||
            return feishuClient;
 | 
			
		||||
        } else {
 | 
			
		||||
            FeishuClient client = FeishuClient.newBuilder(appId, appSecret).build();
 | 
			
		||||
            FeishuClient client = FeishuClient.newBuilder(appId, appSecret).closeOfficialPool(closeOfficialPool).build();
 | 
			
		||||
            clientMap.put(appId + "_" + appSecret, client);
 | 
			
		||||
            clientHolder.set(client);
 | 
			
		||||
            return client;
 | 
			
		||||
 | 
			
		||||
@ -14,14 +14,13 @@ import cn.isliu.core.service.*;
 | 
			
		||||
import com.google.gson.Gson;
 | 
			
		||||
import com.google.gson.JsonArray;
 | 
			
		||||
import com.google.gson.JsonObject;
 | 
			
		||||
import com.lark.oapi.core.request.RequestOptions;
 | 
			
		||||
import com.lark.oapi.service.drive.v1.model.*;
 | 
			
		||||
import com.lark.oapi.service.sheets.v3.model.*;
 | 
			
		||||
 | 
			
		||||
import java.io.IOException;
 | 
			
		||||
import java.util.List;
 | 
			
		||||
import java.util.Objects;
 | 
			
		||||
import java.util.*;
 | 
			
		||||
import java.util.concurrent.atomic.AtomicReference;
 | 
			
		||||
import cn.isliu.core.logging.FsLogger;
 | 
			
		||||
import cn.isliu.core.enums.ErrorCode;
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
@ -33,19 +32,24 @@ import cn.isliu.core.enums.ErrorCode;
 | 
			
		||||
public class FsApiUtil {
 | 
			
		||||
 | 
			
		||||
    private static final Gson gson = new Gson();
 | 
			
		||||
    private static final String REQ_TYPE = "JSON_STR";
 | 
			
		||||
    public static final int DEFAULT_ROW_NUM = 1000;
 | 
			
		||||
 | 
			
		||||
    public static final Map<String, List<String>> m = new HashMap<String, List<String>>() {
 | 
			
		||||
        {
 | 
			
		||||
            put("Connection", Collections.singletonList("close"));
 | 
			
		||||
        }
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取工作表数据
 | 
			
		||||
     * <p>
 | 
			
		||||
     *
 | 
			
		||||
     * 从指定的飞书表格中读取指定范围的数据
 | 
			
		||||
     *
 | 
			
		||||
     * @param sheetId          工作表ID
 | 
			
		||||
     * @param sheetId 工作表ID
 | 
			
		||||
     * @param spreadsheetToken 电子表格Token
 | 
			
		||||
     * @param startPosition    起始位置(如"A1")
 | 
			
		||||
     * @param endPosition      结束位置(如"Z100")
 | 
			
		||||
     * @param client           飞书客户端
 | 
			
		||||
     * @param startPosition 起始位置(如"A1")
 | 
			
		||||
     * @param endPosition 结束位置(如"Z100")
 | 
			
		||||
     * @param client 飞书客户端
 | 
			
		||||
     * @return 表格数据对象
 | 
			
		||||
     */
 | 
			
		||||
    public static ValuesBatch getSheetData(String sheetId, String spreadsheetToken, String startPosition, String endPosition, FeishuClient client) {
 | 
			
		||||
@ -78,11 +82,11 @@ public class FsApiUtil {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取工作表元数据
 | 
			
		||||
     * <p>
 | 
			
		||||
     *
 | 
			
		||||
     * 获取指定工作表的元数据信息,包括行列数、工作表名称等
 | 
			
		||||
     *
 | 
			
		||||
     * @param sheetId          工作表ID
 | 
			
		||||
     * @param client           飞书客户端
 | 
			
		||||
     * @param sheetId 工作表ID
 | 
			
		||||
     * @param client 飞书客户端
 | 
			
		||||
     * @param spreadsheetToken 电子表格Token
 | 
			
		||||
     * @return 工作表对象
 | 
			
		||||
     */
 | 
			
		||||
@ -92,8 +96,8 @@ public class FsApiUtil {
 | 
			
		||||
                    .spreadsheetToken(spreadsheetToken)
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            // 发起请求
 | 
			
		||||
            QuerySpreadsheetSheetResp resp = client.sheets().v3().spreadsheetSheet().query(req);
 | 
			
		||||
            QuerySpreadsheetSheetResp resp = client.sheets().v3().spreadsheetSheet().query(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
 | 
			
		||||
            // 处理服务端错误
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
@ -121,6 +125,8 @@ public class FsApiUtil {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static void setTableStyle(CustomCellService.StyleCellsBatchBuilder styleCellsBatchBuilder, FeishuClient client, String spreadsheetToken) {
 | 
			
		||||
        FsLogger.debug("【飞书表格】 写入表格样式参数:{}", gson.toJson(styleCellsBatchBuilder));
 | 
			
		||||
 | 
			
		||||
        try {
 | 
			
		||||
            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
			
		||||
                    .addRequest(styleCellsBatchBuilder.build())
 | 
			
		||||
@ -157,7 +163,7 @@ public class FsApiUtil {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 获取根目录Token
 | 
			
		||||
     * <p>
 | 
			
		||||
     *
 | 
			
		||||
     * 调用飞书开放平台API获取当前租户的根目录token,用于后续的文件夹和文件操作
 | 
			
		||||
     * API接口: GET https://open.feishu.cn/open-apis/drive/v1/files/root_folder/meta
 | 
			
		||||
     *
 | 
			
		||||
@ -195,7 +201,8 @@ public class FsApiUtil {
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            // 发起请求
 | 
			
		||||
            CreateFolderFileResp resp = client.drive().v1().file().createFolder(req);
 | 
			
		||||
            CreateFolderFileResp resp = client.drive().v1().file().createFolder(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
                FsLogger.info("【飞书表格】 创建文件夹成功! {}", gson.toJson(resp));
 | 
			
		||||
                return resp.getData();
 | 
			
		||||
@ -218,7 +225,8 @@ public class FsApiUtil {
 | 
			
		||||
                            .build())
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            CreateSpreadsheetResp resp = client.sheets().v3().spreadsheet().create(req);
 | 
			
		||||
            CreateSpreadsheetResp resp = client.sheets().v3().spreadsheet().create(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
                FsLogger.info("【飞书表格】 创建表格成功! {}", gson.toJson(resp));
 | 
			
		||||
                return resp.getData();
 | 
			
		||||
@ -266,7 +274,7 @@ public class FsApiUtil {
 | 
			
		||||
            String message = e.getMessage();
 | 
			
		||||
            FsLogger.warn("【飞书表格】 创建 sheet 异常!错误信息:{}", message);
 | 
			
		||||
 | 
			
		||||
            throw new FsHelperException(message != null && message.contains("403") ? "请按照上方操作,当前智投无法操作对应文档哦" : "【飞书表格】 创建 sheet 异常!");
 | 
			
		||||
            throw new FsHelperException(message != null && message.contains("403")? "请按照上方操作,当前智投无法操作对应文档哦" : "【飞书表格】 创建 sheet 异常!");
 | 
			
		||||
        }
 | 
			
		||||
        return sheetId;
 | 
			
		||||
    }
 | 
			
		||||
@ -387,7 +395,8 @@ public class FsApiUtil {
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            // 发起请求
 | 
			
		||||
            DownloadMediaResp resp = client.drive().v1().media().download(req);
 | 
			
		||||
            DownloadMediaResp resp = client.drive().v1().media().download(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
 | 
			
		||||
            // 处理服务端错误
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
@ -400,14 +409,15 @@ public class FsApiUtil {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static String downloadTmpMaterialUrl(String fileToken, FeishuClient client) {
 | 
			
		||||
    public static String downloadTmpMaterialUrl(String fileToken,  FeishuClient client) {
 | 
			
		||||
        String tmpUrl = "";
 | 
			
		||||
        try {
 | 
			
		||||
            BatchGetTmpDownloadUrlMediaReq req = BatchGetTmpDownloadUrlMediaReq.newBuilder()
 | 
			
		||||
                    .fileTokens(new String[]{fileToken})
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            BatchGetTmpDownloadUrlMediaResp resp = client.drive().v1().media().batchGetTmpDownloadUrl(req);
 | 
			
		||||
            BatchGetTmpDownloadUrlMediaResp resp = client.drive().v1().media().batchGetTmpDownloadUrl(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
                return resp.getData().getTmpDownloadUrls()[0].getTmpDownloadUrl();
 | 
			
		||||
@ -421,7 +431,7 @@ public class FsApiUtil {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Object putValues(String spreadsheetToken, CustomValueService.ValueRequest putValuesBuilder, FeishuClient client) {
 | 
			
		||||
        FsLogger.info("【飞书表格】 putValues 开始写入数据!参数:{}", gson.toJson(putValuesBuilder));
 | 
			
		||||
        FsLogger.debug("【飞书表格】 putValues 开始写入数据!参数:{}", gson.toJson(putValuesBuilder));
 | 
			
		||||
 | 
			
		||||
        // 添加到批量请求中
 | 
			
		||||
        CustomValueService.ValueBatchUpdateRequest putDataRequest = CustomValueService.ValueBatchUpdateRequest.newBuilder()
 | 
			
		||||
@ -466,7 +476,7 @@ public class FsApiUtil {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Object addRowColumns(String sheetId, String spreadsheetToken, String type, int length, FeishuClient client) {
 | 
			
		||||
    public static Object addRowColumns(String sheetId, String spreadsheetToken, String type, int length,FeishuClient client) {
 | 
			
		||||
 | 
			
		||||
        CustomDimensionService.DimensionBatchUpdateRequest batchRequest = CustomDimensionService.DimensionBatchUpdateRequest.newBuilder()
 | 
			
		||||
                .addRequest(CustomDimensionService.DimensionRequest.addDimension()
 | 
			
		||||
@ -497,7 +507,8 @@ public class FsApiUtil {
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
            // 发起请求
 | 
			
		||||
            GetSpreadsheetResp resp = client.sheets().v3().spreadsheet().get(req);
 | 
			
		||||
            GetSpreadsheetResp resp = client.sheets().v3().spreadsheet().get(req, client.getCloseOfficialPool()
 | 
			
		||||
                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
			
		||||
 | 
			
		||||
            // 处理服务端错误
 | 
			
		||||
            if (resp.success()) {
 | 
			
		||||
@ -512,13 +523,15 @@ public class FsApiUtil {
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * 字符串类型: formatter: "@"
 | 
			
		||||
     *  字符串类型: formatter: "@"
 | 
			
		||||
     */
 | 
			
		||||
    public static void setCellType(String sheetId, String formatter, String startPosition, String endPosition, FeishuClient client, String spreadsheetToken) {
 | 
			
		||||
        try {
 | 
			
		||||
            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
			
		||||
                    .addRequest(CustomCellService.CellRequest.styleCells()
 | 
			
		||||
                            .formatter(formatter).sheetId(sheetId).startPosition(startPosition).endPosition(endPosition)
 | 
			
		||||
                            .backColor("#ffffff")
 | 
			
		||||
                            .bold(false)
 | 
			
		||||
                            .build())
 | 
			
		||||
                    .build();
 | 
			
		||||
 | 
			
		||||
@ -533,7 +546,7 @@ public class FsApiUtil {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public static Object imageUpload(byte[] imageData, String fileName, String position, String sheetId, String spreadsheetToken, FeishuClient client) {
 | 
			
		||||
    public static Object imageUpload(byte[] imageData, String fileName, String position ,String sheetId, String spreadsheetToken, FeishuClient client) {
 | 
			
		||||
        try {
 | 
			
		||||
 | 
			
		||||
            CustomValueService.ValueRequest imageRequest = CustomValueService.ValueRequest.imageValues()
 | 
			
		||||
@ -553,7 +566,7 @@ public class FsApiUtil {
 | 
			
		||||
            }
 | 
			
		||||
            return imageResp.getData();
 | 
			
		||||
        } catch (Exception e) {
 | 
			
		||||
            FsLogger.error(ErrorCode.API_SERVER_ERROR, "【飞书表格】 文件上传异常!" + e.getMessage(), fileName, e);
 | 
			
		||||
            FsLogger.error(ErrorCode.API_SERVER_ERROR,"【飞书表格】 文件上传异常!" + e.getMessage(), fileName, e);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return null;
 | 
			
		||||
 | 
			
		||||
		Loading…
	
		Reference in New Issue
	
	Block a user