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 OkHttpClient httpClient;
 | 
				
			||||||
    private final String appId;
 | 
					    private final String appId;
 | 
				
			||||||
    private final String appSecret;
 | 
					    private final String appSecret;
 | 
				
			||||||
 | 
					    private final boolean closeOfficialPool;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // 自定义服务,处理官方SDK未覆盖的API
 | 
					    // 自定义服务,处理官方SDK未覆盖的API
 | 
				
			||||||
    private volatile CustomSheetService customSheetService;
 | 
					    private volatile CustomSheetService customSheetService;
 | 
				
			||||||
@ -37,8 +38,18 @@ public class FeishuClient {
 | 
				
			|||||||
        this.appSecret = appSecret;
 | 
					        this.appSecret = appSecret;
 | 
				
			||||||
        this.officialClient = officialClient;
 | 
					        this.officialClient = officialClient;
 | 
				
			||||||
        this.httpClient = httpClient;
 | 
					        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;
 | 
					        return appSecret;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    /**
 | 
				
			||||||
 | 
					     * 获取是否关闭官方Client连接池
 | 
				
			||||||
 | 
					     *
 | 
				
			||||||
 | 
					     * @return 是否关闭官方Client连接池
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public boolean getCloseOfficialPool() {
 | 
				
			||||||
 | 
					        return closeOfficialPool;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * FeishuClient构建器
 | 
					     * FeishuClient构建器
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public static class Builder {
 | 
					    public static class Builder {
 | 
				
			||||||
        private final String appId;
 | 
					        private final String appId;
 | 
				
			||||||
        private final String appSecret;
 | 
					        private final String appSecret;
 | 
				
			||||||
 | 
					        private boolean closeOfficialPool = false;
 | 
				
			||||||
        private OkHttpClient.Builder httpClientBuilder;
 | 
					        private OkHttpClient.Builder httpClientBuilder;
 | 
				
			||||||
        private AppType appType = AppType.SELF_BUILT;
 | 
					        private AppType appType = AppType.SELF_BUILT;
 | 
				
			||||||
        private boolean logReqAtDebug = false;
 | 
					        private boolean logReqAtDebug = false;
 | 
				
			||||||
@ -268,6 +289,11 @@ public class FeishuClient {
 | 
				
			|||||||
            return this;
 | 
					            return this;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        public Builder closeOfficialPool(boolean closeOfficialPool) {
 | 
				
			||||||
 | 
					            this.closeOfficialPool = closeOfficialPool;
 | 
				
			||||||
 | 
					            return this;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        /**
 | 
					        /**
 | 
				
			||||||
         * 构建FeishuClient实例
 | 
					         * 构建FeishuClient实例
 | 
				
			||||||
         *
 | 
					         *
 | 
				
			||||||
@ -281,7 +307,7 @@ public class FeishuClient {
 | 
				
			|||||||
            // 构建OkHttpClient
 | 
					            // 构建OkHttpClient
 | 
				
			||||||
            OkHttpClient httpClient = httpClientBuilder.build();
 | 
					            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 {
 | 
					public class FsClient implements AutoCloseable {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static volatile FsClient instance;
 | 
					    private static volatile FsClient instance;
 | 
				
			||||||
    private final ThreadLocal<FeishuClient> clientHolder = new ThreadLocal<>();
 | 
					    private final ThreadLocal<FeishuClient> clientHolder = new ThreadLocal<>();
 | 
				
			||||||
    private final Map<String, FeishuClient> clientMap = new ConcurrentHashMap<>();
 | 
					    private final Map<String, FeishuClient> clientMap = new ConcurrentHashMap<>();
 | 
				
			||||||
@ -53,6 +54,10 @@ public class FsClient implements AutoCloseable {
 | 
				
			|||||||
     * @return 初始化的FeishuClient实例
 | 
					     * @return 初始化的FeishuClient实例
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public FeishuClient initializeClient(String appId, String appSecret) {
 | 
					    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()) {
 | 
					        if (appId == null || appId.trim().isEmpty()) {
 | 
				
			||||||
            throw new IllegalArgumentException("appId cannot be null or empty");
 | 
					            throw new IllegalArgumentException("appId cannot be null or empty");
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@ -64,7 +69,7 @@ public class FsClient implements AutoCloseable {
 | 
				
			|||||||
            clientHolder.set(feishuClient);
 | 
					            clientHolder.set(feishuClient);
 | 
				
			||||||
            return feishuClient;
 | 
					            return feishuClient;
 | 
				
			||||||
        } else {
 | 
					        } else {
 | 
				
			||||||
            FeishuClient client = FeishuClient.newBuilder(appId, appSecret).build();
 | 
					            FeishuClient client = FeishuClient.newBuilder(appId, appSecret).closeOfficialPool(closeOfficialPool).build();
 | 
				
			||||||
            clientMap.put(appId + "_" + appSecret, client);
 | 
					            clientMap.put(appId + "_" + appSecret, client);
 | 
				
			||||||
            clientHolder.set(client);
 | 
					            clientHolder.set(client);
 | 
				
			||||||
            return client;
 | 
					            return client;
 | 
				
			||||||
 | 
				
			|||||||
@ -14,14 +14,13 @@ import cn.isliu.core.service.*;
 | 
				
			|||||||
import com.google.gson.Gson;
 | 
					import com.google.gson.Gson;
 | 
				
			||||||
import com.google.gson.JsonArray;
 | 
					import com.google.gson.JsonArray;
 | 
				
			||||||
import com.google.gson.JsonObject;
 | 
					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.drive.v1.model.*;
 | 
				
			||||||
import com.lark.oapi.service.sheets.v3.model.*;
 | 
					import com.lark.oapi.service.sheets.v3.model.*;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import java.io.IOException;
 | 
					import java.io.IOException;
 | 
				
			||||||
import java.util.List;
 | 
					import java.util.*;
 | 
				
			||||||
import java.util.Objects;
 | 
					 | 
				
			||||||
import java.util.concurrent.atomic.AtomicReference;
 | 
					import java.util.concurrent.atomic.AtomicReference;
 | 
				
			||||||
import cn.isliu.core.logging.FsLogger;
 | 
					 | 
				
			||||||
import cn.isliu.core.enums.ErrorCode;
 | 
					import cn.isliu.core.enums.ErrorCode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -33,12 +32,17 @@ import cn.isliu.core.enums.ErrorCode;
 | 
				
			|||||||
public class FsApiUtil {
 | 
					public class FsApiUtil {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    private static final Gson gson = new Gson();
 | 
					    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 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
 | 
				
			||||||
@ -78,7 +82,7 @@ public class FsApiUtil {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 获取工作表元数据
 | 
					     * 获取工作表元数据
 | 
				
			||||||
     * <p>
 | 
					     *
 | 
				
			||||||
     * 获取指定工作表的元数据信息,包括行列数、工作表名称等
 | 
					     * 获取指定工作表的元数据信息,包括行列数、工作表名称等
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
     * @param sheetId 工作表ID
 | 
					     * @param sheetId 工作表ID
 | 
				
			||||||
@ -92,8 +96,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                    .spreadsheetToken(spreadsheetToken)
 | 
					                    .spreadsheetToken(spreadsheetToken)
 | 
				
			||||||
                    .build();
 | 
					                    .build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 发起请求
 | 
					            QuerySpreadsheetSheetResp resp = client.sheets().v3().spreadsheetSheet().query(req, client.getCloseOfficialPool()
 | 
				
			||||||
            QuerySpreadsheetSheetResp resp = client.sheets().v3().spreadsheetSheet().query(req);
 | 
					                    ? RequestOptions.newBuilder().headers(m).build() : null);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
            // 处理服务端错误
 | 
					            // 处理服务端错误
 | 
				
			||||||
            if (resp.success()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
@ -121,6 +125,8 @@ public class FsApiUtil {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static void setTableStyle(CustomCellService.StyleCellsBatchBuilder styleCellsBatchBuilder, FeishuClient client, String spreadsheetToken) {
 | 
					    public static void setTableStyle(CustomCellService.StyleCellsBatchBuilder styleCellsBatchBuilder, FeishuClient client, String spreadsheetToken) {
 | 
				
			||||||
 | 
					        FsLogger.debug("【飞书表格】 写入表格样式参数:{}", gson.toJson(styleCellsBatchBuilder));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        try {
 | 
					        try {
 | 
				
			||||||
            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
					            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
				
			||||||
                    .addRequest(styleCellsBatchBuilder.build())
 | 
					                    .addRequest(styleCellsBatchBuilder.build())
 | 
				
			||||||
@ -157,7 +163,7 @@ public class FsApiUtil {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
    /**
 | 
					    /**
 | 
				
			||||||
     * 获取根目录Token
 | 
					     * 获取根目录Token
 | 
				
			||||||
     * <p>
 | 
					     *
 | 
				
			||||||
     * 调用飞书开放平台API获取当前租户的根目录token,用于后续的文件夹和文件操作
 | 
					     * 调用飞书开放平台API获取当前租户的根目录token,用于后续的文件夹和文件操作
 | 
				
			||||||
     * API接口: GET https://open.feishu.cn/open-apis/drive/v1/files/root_folder/meta
 | 
					     * API接口: GET https://open.feishu.cn/open-apis/drive/v1/files/root_folder/meta
 | 
				
			||||||
     *
 | 
					     *
 | 
				
			||||||
@ -195,7 +201,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                    .build();
 | 
					                    .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()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
                FsLogger.info("【飞书表格】 创建文件夹成功! {}", gson.toJson(resp));
 | 
					                FsLogger.info("【飞书表格】 创建文件夹成功! {}", gson.toJson(resp));
 | 
				
			||||||
                return resp.getData();
 | 
					                return resp.getData();
 | 
				
			||||||
@ -218,7 +225,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                            .build())
 | 
					                            .build())
 | 
				
			||||||
                    .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()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
                FsLogger.info("【飞书表格】 创建表格成功! {}", gson.toJson(resp));
 | 
					                FsLogger.info("【飞书表格】 创建表格成功! {}", gson.toJson(resp));
 | 
				
			||||||
                return resp.getData();
 | 
					                return resp.getData();
 | 
				
			||||||
@ -387,7 +395,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                    .build();
 | 
					                    .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()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
@ -407,7 +416,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                    .fileTokens(new String[]{fileToken})
 | 
					                    .fileTokens(new String[]{fileToken})
 | 
				
			||||||
                    .build();
 | 
					                    .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()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
                return resp.getData().getTmpDownloadUrls()[0].getTmpDownloadUrl();
 | 
					                return resp.getData().getTmpDownloadUrls()[0].getTmpDownloadUrl();
 | 
				
			||||||
@ -421,7 +431,7 @@ public class FsApiUtil {
 | 
				
			|||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    public static Object putValues(String spreadsheetToken, CustomValueService.ValueRequest putValuesBuilder, FeishuClient client) {
 | 
					    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()
 | 
					        CustomValueService.ValueBatchUpdateRequest putDataRequest = CustomValueService.ValueBatchUpdateRequest.newBuilder()
 | 
				
			||||||
@ -497,7 +507,8 @@ public class FsApiUtil {
 | 
				
			|||||||
                    .build();
 | 
					                    .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()) {
 | 
					            if (resp.success()) {
 | 
				
			||||||
@ -519,6 +530,8 @@ public class FsApiUtil {
 | 
				
			|||||||
            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
					            CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder()
 | 
				
			||||||
                    .addRequest(CustomCellService.CellRequest.styleCells()
 | 
					                    .addRequest(CustomCellService.CellRequest.styleCells()
 | 
				
			||||||
                            .formatter(formatter).sheetId(sheetId).startPosition(startPosition).endPosition(endPosition)
 | 
					                            .formatter(formatter).sheetId(sheetId).startPosition(startPosition).endPosition(endPosition)
 | 
				
			||||||
 | 
					                            .backColor("#ffffff")
 | 
				
			||||||
 | 
					                            .bold(false)
 | 
				
			||||||
                            .build())
 | 
					                            .build())
 | 
				
			||||||
                    .build();
 | 
					                    .build();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user