|
|
@@ -5,32 +5,43 @@ import com.alibaba.fastjson.JSONArray;
|
|
|
import com.alibaba.fastjson.JSONObject;
|
|
|
import com.tzld.ad.util.MapBuilder;
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
+import okhttp3.*;
|
|
|
import org.springframework.data.util.Pair;
|
|
|
-import org.springframework.http.*;
|
|
|
-import org.springframework.web.client.RestTemplate;
|
|
|
|
|
|
+import java.io.IOException;
|
|
|
import java.util.List;
|
|
|
import java.util.Map;
|
|
|
import java.util.Objects;
|
|
|
+import java.util.concurrent.TimeUnit;
|
|
|
import java.util.stream.Collectors;
|
|
|
|
|
|
@Slf4j
|
|
|
public class FeishuExcelUtil {
|
|
|
|
|
|
+ private static final MediaType JSON_MEDIA_TYPE = MediaType.parse("application/json; charset=utf-8");
|
|
|
+
|
|
|
+ private static final OkHttpClient httpClient = new OkHttpClient.Builder()
|
|
|
+ .connectTimeout(30, TimeUnit.SECONDS)
|
|
|
+ .readTimeout(30, TimeUnit.SECONDS)
|
|
|
+ .writeTimeout(30, TimeUnit.SECONDS)
|
|
|
+ .build();
|
|
|
+
|
|
|
public static void feishuSheetDelete(String sheetToken,
|
|
|
String sheetId,
|
|
|
int rowNum,
|
|
|
int startRowIndex,
|
|
|
- HttpHeaders httpHeaders,
|
|
|
- RestTemplate restTemplate,
|
|
|
+ Map<String, String> headers,
|
|
|
List<String> dateStrList) {
|
|
|
- HttpEntity<Object> queryEntity = new HttpEntity<>(httpHeaders);
|
|
|
+ Map<String, String> queryEntity = headers;
|
|
|
int deleteRowNum = rowNum < 20 ? startRowIndex + dateStrList.size() * rowNum : startRowIndex + (rowNum * 2);
|
|
|
- ResponseEntity<String> queryResponseEntity = restTemplate.exchange(
|
|
|
- String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values/%s!A"
|
|
|
- + startRowIndex + ":A" + deleteRowNum, sheetToken, sheetId),
|
|
|
- HttpMethod.GET, queryEntity, String.class);
|
|
|
- JSONArray values = JSON.parseObject(queryResponseEntity.getBody())
|
|
|
+
|
|
|
+ String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values/%s!A"
|
|
|
+ + startRowIndex + ":A" + deleteRowNum, sheetToken, sheetId);
|
|
|
+
|
|
|
+ String responseBody = doGet(url, queryEntity);
|
|
|
+ if (responseBody == null) return;
|
|
|
+
|
|
|
+ JSONArray values = JSON.parseObject(responseBody)
|
|
|
.getJSONObject("data")
|
|
|
.getJSONObject("valueRange")
|
|
|
.getJSONArray("values");
|
|
|
@@ -53,19 +64,16 @@ public class FeishuExcelUtil {
|
|
|
int delNum = 0;
|
|
|
do {
|
|
|
// 删除当前日期已存在的旧数据
|
|
|
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
|
|
- HttpEntity<Object> deleteEntity = new HttpEntity<>(
|
|
|
- String.format("{\n" +
|
|
|
+ String deleteUrl = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken);
|
|
|
+ String jsonBody = String.format("{\n" +
|
|
|
" \"dimension\": {\n" +
|
|
|
" \"sheetId\": \"%s\",\n" +
|
|
|
" \"majorDimension\": \"ROWS\",\n" +
|
|
|
" \"startIndex\": %s,\n" +
|
|
|
" \"endIndex\": %s\n" +
|
|
|
" }\n" +
|
|
|
- "}", sheetId, startRowIndex, Math.min(startRowIndex + 4000, count - delNum + startRowIndex) - 1),
|
|
|
- httpHeaders);
|
|
|
- restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken),
|
|
|
- HttpMethod.DELETE, deleteEntity, String.class);
|
|
|
+ "}", sheetId, startRowIndex, Math.min(startRowIndex + 4000, count - delNum + startRowIndex) - 1);
|
|
|
+ doDelete(deleteUrl, jsonBody, headers);
|
|
|
delNum = Math.min(delNum + 4000, count);
|
|
|
} while (delNum < count);
|
|
|
}
|
|
|
@@ -74,31 +82,29 @@ public class FeishuExcelUtil {
|
|
|
public static void feishuSheetInsert(String sheetToken,
|
|
|
String sheetId,
|
|
|
Integer startRowIndex,
|
|
|
- HttpHeaders httpHeaders,
|
|
|
- RestTemplate restTemplate,
|
|
|
+ Map<String, String> headers,
|
|
|
List<List<List<Object>>> partitions) {
|
|
|
int startRow = startRowIndex;
|
|
|
for (List<List<Object>> partition : partitions) {
|
|
|
// 插入数据
|
|
|
- HttpEntity<Object> postEntity = new HttpEntity<>(MapBuilder
|
|
|
+ String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values_prepend", sheetToken);
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
|
|
|
.builder()
|
|
|
.put("valueRange", MapBuilder
|
|
|
.builder()
|
|
|
.put("range", String.format("%s!A" + startRow + ":CI", sheetId) + (partition.size() + startRow - 1))
|
|
|
.put("values", partition)
|
|
|
.build())
|
|
|
- .build(), httpHeaders);
|
|
|
- ResponseEntity<String> response = restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/values_prepend",
|
|
|
- sheetToken),
|
|
|
- HttpMethod.POST, postEntity, String.class);
|
|
|
- JSONObject responseJSON = JSONObject.parseObject(response.getBody());
|
|
|
- if (0 != responseJSON.getInteger("code")) {
|
|
|
+ .build();
|
|
|
+ String response = doPost(url, JSON.toJSONString(bodyMap), headers);
|
|
|
+ JSONObject responseJSON = JSONObject.parseObject(response);
|
|
|
+ if (responseJSON != null && 0 != responseJSON.getInteger("code")) {
|
|
|
log.error("doSendFeishuSheet write error :{}", responseJSON.getString("msg"));
|
|
|
}
|
|
|
// 设置行高
|
|
|
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
|
|
|
- HttpEntity<Object> putEntity = new HttpEntity<>(
|
|
|
- String.format("{\n" +
|
|
|
+ String putUrl = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken);
|
|
|
+ String putBody = String.format("{\n" +
|
|
|
" \"dimension\": {\n" +
|
|
|
" \"sheetId\": \"%s\",\n" +
|
|
|
" \"majorDimension\": \"ROWS\",\n" +
|
|
|
@@ -108,10 +114,8 @@ public class FeishuExcelUtil {
|
|
|
" \"dimensionProperties\":{\n" +
|
|
|
" \"fixedSize\":27\n" +
|
|
|
" }\n" +
|
|
|
- "}", sheetId, startRow, Math.min(startRow + 4000, startRow + partition.size()) - 1),
|
|
|
- httpHeaders);
|
|
|
- restTemplate.exchange(String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dimension_range", sheetToken),
|
|
|
- HttpMethod.PUT, putEntity, String.class);
|
|
|
+ "}", sheetId, startRow, Math.min(startRow + 4000, startRow + partition.size()) - 1);
|
|
|
+ doPut(putUrl, putBody, headers);
|
|
|
startRow += partition.size();
|
|
|
}
|
|
|
}
|
|
|
@@ -120,13 +124,14 @@ public class FeishuExcelUtil {
|
|
|
String sheetId,
|
|
|
int rowNum,
|
|
|
Integer startRowIndex,
|
|
|
- HttpHeaders httpHeaders,
|
|
|
- RestTemplate restTemplate,
|
|
|
+ Map<String, String> headers,
|
|
|
List<Pair<String, Map<Object, Object>>> styles) {
|
|
|
Integer startRow = startRowIndex;
|
|
|
do {
|
|
|
for (Pair<String, Map<Object, Object>> style : styles) {
|
|
|
- HttpEntity<Map<Object, Object>> styleEntity = new HttpEntity<>(MapBuilder
|
|
|
+ String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/style", sheetToken);
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
|
|
|
.builder()
|
|
|
.put("appendStyle",
|
|
|
MapBuilder
|
|
|
@@ -137,14 +142,8 @@ public class FeishuExcelUtil {
|
|
|
.put("style", style.getSecond())
|
|
|
.build()
|
|
|
)
|
|
|
- .build(), httpHeaders);
|
|
|
- restTemplate.exchange(
|
|
|
- String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/style",
|
|
|
- sheetToken),
|
|
|
- HttpMethod.PUT,
|
|
|
- styleEntity,
|
|
|
- String.class
|
|
|
- );
|
|
|
+ .build();
|
|
|
+ doPut(url, JSON.toJSONString(bodyMap), headers);
|
|
|
}
|
|
|
startRow += 4000;
|
|
|
} while (startRow < rowNum);
|
|
|
@@ -154,15 +153,16 @@ public class FeishuExcelUtil {
|
|
|
String sheetId,
|
|
|
int rowNum,
|
|
|
Integer startRowIndex,
|
|
|
- HttpHeaders httpHeaders,
|
|
|
- RestTemplate restTemplate,
|
|
|
+ Map<String, String> headers,
|
|
|
List<Pair<String, List<Pair<String, String>>>> thanks) {
|
|
|
Integer startRow = startRowIndex;
|
|
|
do {
|
|
|
for (Pair<String, List<Pair<String, String>>> thank : thanks) {
|
|
|
List<String> keyList = thank.getSecond().stream().map(Pair::getFirst).collect(Collectors.toList());
|
|
|
List<String> colorList = thank.getSecond().stream().map(Pair::getSecond).collect(Collectors.toList());
|
|
|
- HttpEntity<Map<Object, Object>> styleEntity = new HttpEntity<>(MapBuilder
|
|
|
+ String url = String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dataValidation", sheetToken);
|
|
|
+ @SuppressWarnings("unchecked")
|
|
|
+ Map<String, Object> bodyMap = (Map<String, Object>) (Map<?, Object>) MapBuilder
|
|
|
.builder()
|
|
|
.put("range", String.format("%s!%s" + startRow + ":%s", sheetId,
|
|
|
thank.getFirst(), thank.getFirst())
|
|
|
@@ -175,16 +175,59 @@ public class FeishuExcelUtil {
|
|
|
.put("colors", colorList)
|
|
|
.build()
|
|
|
).build())
|
|
|
- .build(), httpHeaders);
|
|
|
- restTemplate.exchange(
|
|
|
- String.format("https://open.feishu.cn/open-apis/sheets/v2/spreadsheets/%s/dataValidation",
|
|
|
- sheetToken),
|
|
|
- HttpMethod.POST,
|
|
|
- styleEntity,
|
|
|
- String.class
|
|
|
- );
|
|
|
+ .build();
|
|
|
+ doPost(url, JSON.toJSONString(bodyMap), headers);
|
|
|
}
|
|
|
startRow += 4000;
|
|
|
} while (startRow < rowNum);
|
|
|
}
|
|
|
+
|
|
|
+ // HTTP Helper Methods
|
|
|
+
|
|
|
+ private static String doGet(String url, Map<String, String> headers) {
|
|
|
+ Request.Builder requestBuilder = new Request.Builder().url(url).get();
|
|
|
+ if (headers != null) {
|
|
|
+ headers.forEach(requestBuilder::addHeader);
|
|
|
+ }
|
|
|
+ return executeRequest(requestBuilder.build());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String doPost(String url, String jsonBody, Map<String, String> headers) {
|
|
|
+ RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
|
|
|
+ Request.Builder requestBuilder = new Request.Builder().url(url).post(body);
|
|
|
+ if (headers != null) {
|
|
|
+ headers.forEach(requestBuilder::addHeader);
|
|
|
+ }
|
|
|
+ requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
|
|
|
+ return executeRequest(requestBuilder.build());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String doPut(String url, String jsonBody, Map<String, String> headers) {
|
|
|
+ RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
|
|
|
+ Request.Builder requestBuilder = new Request.Builder().url(url).put(body);
|
|
|
+ if (headers != null) {
|
|
|
+ headers.forEach(requestBuilder::addHeader);
|
|
|
+ }
|
|
|
+ requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
|
|
|
+ return executeRequest(requestBuilder.build());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String doDelete(String url, String jsonBody, Map<String, String> headers) {
|
|
|
+ RequestBody body = RequestBody.create(JSON_MEDIA_TYPE, jsonBody != null ? jsonBody : "");
|
|
|
+ Request.Builder requestBuilder = new Request.Builder().url(url).delete(body);
|
|
|
+ if (headers != null) {
|
|
|
+ headers.forEach(requestBuilder::addHeader);
|
|
|
+ }
|
|
|
+ requestBuilder.addHeader("Content-Type", "application/json; charset=utf-8");
|
|
|
+ return executeRequest(requestBuilder.build());
|
|
|
+ }
|
|
|
+
|
|
|
+ private static String executeRequest(Request request) {
|
|
|
+ try (Response response = httpClient.newCall(request).execute()) {
|
|
|
+ return response.body() != null ? response.body().string() : null;
|
|
|
+ } catch (IOException e) {
|
|
|
+ log.error("HTTP request error, url:{}", request.url(), e);
|
|
|
+ return null;
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|