diff --git a/src/main/java/cn/isliu/FsHelper.java b/src/main/java/cn/isliu/FsHelper.java index cf73a92..c369c8d 100644 --- a/src/main/java/cn/isliu/FsHelper.java +++ b/src/main/java/cn/isliu/FsHelper.java @@ -1,11 +1,15 @@ package cn.isliu; import cn.isliu.core.BaseEntity; +import cn.isliu.core.FileData; import cn.isliu.core.FsTableData; import cn.isliu.core.Sheet; import cn.isliu.core.client.FeishuClient; import cn.isliu.core.client.FsClient; import cn.isliu.core.config.FsConfig; +import cn.isliu.core.enums.ErrorCode; +import cn.isliu.core.enums.FileType; +import cn.isliu.core.logging.FsLogger; import cn.isliu.core.pojo.FieldProperty; import cn.isliu.core.service.CustomValueService; import cn.isliu.core.utils.*; @@ -137,6 +141,7 @@ public class FsHelper { // 初始化批量插入对象 CustomValueService.ValueRequest.BatchPutValuesBuilder resultValuesBuilder = CustomValueService.ValueRequest.batchPutValues(); + List fileDataList = new ArrayList<>(); FsConfig fsConfig = FsConfig.getInstance(); AtomicInteger rowCount = new AtomicInteger(row[0] + 1); @@ -155,8 +160,19 @@ public class FsHelper { } String position = titlePostionMap.get(field); + + if (fieldValue instanceof FileData) { + FileData fileData = (FileData) fieldValue; + String fileType = fileData.getFileType(); + if (fileType.equals(FileType.IMAGE.getType())) { + fileData.setSheetId(sheetId); + fileData.setSpreadsheetToken(spreadsheetToken); + fileData.setPosition(position + rowNum.get()); + fileDataList.add(fileData); + } + } resultValuesBuilder.addRange(sheetId, position + rowNum.get(), position + rowNum.get()) - .addRow(fieldValue instanceof List ? GenerateUtil.getFieldValueList(fieldValue) : fieldValue); + .addRow(GenerateUtil.getRowData(fieldValue)); }); } else { int rowCou = rowCount.incrementAndGet(); @@ -166,9 +182,15 @@ public class FsHelper { } String position = titlePostionMap.get(field); + if (fieldValue instanceof FileData) { + FileData fileData = (FileData) fieldValue; + fileData.setSheetId(sheetId); + fileData.setSpreadsheetToken(spreadsheetToken); + fileData.setPosition(position + rowCou); + fileDataList.add(fileData); + } resultValuesBuilder.addRange(sheetId, position + rowCou, position + rowCou) - .addRow(fieldValue instanceof List ? GenerateUtil.getFieldValueList(fieldValue) : fieldValue); - + .addRow(GenerateUtil.getRowData(fieldValue)); }); } } @@ -179,6 +201,16 @@ public class FsHelper { FsApiUtil.addRowColumns(sheetId, spreadsheetToken, "ROWS", rowTotal - rowNum, client); } - return FsApiUtil.batchPutValues(sheetId, spreadsheetToken, resultValuesBuilder.build(), client); + Object resp = FsApiUtil.batchPutValues(sheetId, spreadsheetToken, resultValuesBuilder.build(), client); + + fileDataList.forEach(fileData -> { + try { + FsApiUtil.imageUpload(fileData.getImageData(), fileData.getFileName(), fileData.getPosition(), fileData.getSheetId(), fileData.getSpreadsheetToken(), client); + } catch (Exception e) { + FsLogger.error(ErrorCode.BUSINESS_LOGIC_ERROR, "【飞书表格】 文件上传-文件上传异常! " + fileData.getFileUrl()); + } + }); + + return resp; } } \ No newline at end of file diff --git a/src/main/java/cn/isliu/core/FileData.java b/src/main/java/cn/isliu/core/FileData.java new file mode 100644 index 0000000..8a6c48e --- /dev/null +++ b/src/main/java/cn/isliu/core/FileData.java @@ -0,0 +1,107 @@ +package cn.isliu.core; + +import java.util.Arrays; +import java.util.Objects; + +public class FileData { + + private String sheetId; + private String spreadsheetToken; + private String fileName; + private byte[] imageData; + private String position; + private String fileType; + private String fileUrl; + + public FileData() {} + + public FileData(String sheetId, String spreadsheetToken, String fileName, byte[] imageData, String position, String fileType) { + this.sheetId = sheetId; + this.spreadsheetToken = spreadsheetToken; + this.fileName = fileName; + this.imageData = imageData; + this.position = position; + this.fileType = fileType; + } + + public String getSheetId() { + return sheetId; + } + + public void setSheetId(String sheetId) { + this.sheetId = sheetId; + } + + public String getSpreadsheetToken() { + return spreadsheetToken; + } + + public void setSpreadsheetToken(String spreadsheetToken) { + this.spreadsheetToken = spreadsheetToken; + } + + public String getFileName() { + return fileName; + } + + public void setFileName(String fileName) { + this.fileName = fileName; + } + + public byte[] getImageData() { + return imageData; + } + + public void setImageData(byte[] imageData) { + this.imageData = imageData; + } + + public String getPosition() { + return position; + } + + public void setPosition(String position) { + this.position = position; + } + + public String getFileType() { + return fileType; + } + + public void setFileType(String fileType) { + this.fileType = fileType; + } + + public String getFileUrl() { + return fileUrl; + } + + public void setFileUrl(String fileUrl) { + this.fileUrl = fileUrl; + } + + @Override + public boolean equals(Object o) { + if (o == null || getClass() != o.getClass()) return false; + FileData fileData = (FileData) o; + return Objects.equals(sheetId, fileData.sheetId) && Objects.equals(spreadsheetToken, fileData.spreadsheetToken) && Objects.equals(fileName, fileData.fileName) && Objects.deepEquals(imageData, fileData.imageData) && Objects.equals(position, fileData.position) && Objects.equals(fileType, fileData.fileType) && Objects.equals(fileUrl, fileData.fileUrl); + } + + @Override + public int hashCode() { + return Objects.hash(sheetId, spreadsheetToken, fileName, Arrays.hashCode(imageData), position, fileType, fileUrl); + } + + @Override + public String toString() { + return "FileData{" + + "sheetId='" + sheetId + '\'' + + ", spreadsheetToken='" + spreadsheetToken + '\'' + + ", fileName='" + fileName + '\'' + + ", imageData=" + Arrays.toString(imageData) + + ", position='" + position + '\'' + + ", fileType='" + fileType + '\'' + + ", fileUrl='" + fileUrl + '\'' + + '}'; + } +} diff --git a/src/main/java/cn/isliu/core/converters/FieldValueProcess.java b/src/main/java/cn/isliu/core/converters/FieldValueProcess.java index 2eb441c..b6eb4fa 100644 --- a/src/main/java/cn/isliu/core/converters/FieldValueProcess.java +++ b/src/main/java/cn/isliu/core/converters/FieldValueProcess.java @@ -7,5 +7,5 @@ public interface FieldValueProcess { /** * 反向处理,将枚举值转换为原始值 */ - T reverseProcess(Object value); + Object reverseProcess(Object value); } diff --git a/src/main/java/cn/isliu/core/converters/FileUrlProcess.java b/src/main/java/cn/isliu/core/converters/FileUrlProcess.java index 18c5739..333b263 100644 --- a/src/main/java/cn/isliu/core/converters/FileUrlProcess.java +++ b/src/main/java/cn/isliu/core/converters/FileUrlProcess.java @@ -1,7 +1,8 @@ package cn.isliu.core.converters; +import cn.isliu.core.FileData; import cn.isliu.core.client.FsClient; -import cn.isliu.core.config.FsConfig; +import cn.isliu.core.enums.ErrorCode; import cn.isliu.core.utils.FsApiUtil; import cn.isliu.core.utils.FileUtil; import com.google.gson.JsonArray; @@ -15,8 +16,6 @@ import cn.isliu.core.logging.FsLogger; public class FileUrlProcess implements FieldValueProcess { - // 使用统一的FsLogger替代java.util.logging.Logger - @Override public String process(Object value) { if (value instanceof String) { @@ -43,16 +42,27 @@ public class FileUrlProcess implements FieldValueProcess { } @Override - public String reverseProcess(Object value) { - boolean cover = FsConfig.getInstance().isCover(); - if (!cover && value != null) { - String str = value.toString(); - byte[] imageData = FileUtil.getImageData(str); - } + public Object reverseProcess(Object value) { if (value == null) { return null; + } else { + if (value instanceof String) { + String path = value.toString(); + try { + FileData fileData = new FileData(); + fileData.setFileUrl( path); + fileData.setFileType(FileUtil.isImageFile(path) ? "image" : "file"); + fileData.setFileName(FileUtil.getFileName(path)); + fileData.setImageData(FileUtil.getImageData(path)); + return fileData; + } catch (Exception e) { + FsLogger.error(ErrorCode.BUSINESS_LOGIC_ERROR,"【飞书表格】 文件上传-文件URL处理异常!" + e.getMessage(), path, e); + return value; + } + } else { + return value; + } } - return value.toString(); } private synchronized String getUrlByTextFile(JsonObject jsb) { diff --git a/src/main/java/cn/isliu/core/enums/FileType.java b/src/main/java/cn/isliu/core/enums/FileType.java new file mode 100644 index 0000000..db0926e --- /dev/null +++ b/src/main/java/cn/isliu/core/enums/FileType.java @@ -0,0 +1,27 @@ +package cn.isliu.core.enums; + +public enum FileType { + IMAGE("image"), + FILE("file"), + + UNKNOWN("unknown"); + + private String type; + + FileType(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + public static FileType getType(String type) { + for (FileType fileType : FileType.values()) { + if (fileType.getType().equals(type)) { + return fileType; + } + } + return UNKNOWN; + } +} diff --git a/src/main/java/cn/isliu/core/utils/FileUtil.java b/src/main/java/cn/isliu/core/utils/FileUtil.java index 5dc6f0c..0ba5611 100644 --- a/src/main/java/cn/isliu/core/utils/FileUtil.java +++ b/src/main/java/cn/isliu/core/utils/FileUtil.java @@ -7,6 +7,7 @@ import java.io.*; import java.net.HttpURLConnection; import java.net.URL; import java.nio.file.Files; +import java.nio.file.Paths; public class FileUtil { @@ -118,4 +119,35 @@ public class FileUtil { return tempDir; } + + /** + * 判断文件是否为图片类型 + * + * @param filePath 文件路径,可以是URL或本地路径 + * @return 如果是图片类型返回true,否则返回false + */ + public static boolean isImageFile(String filePath) { + if (filePath == null || filePath.isEmpty()) { + return false; + } + + // 常见的图片文件扩展名 + String[] imageExtensions = {".jpg", ".jpeg", ".png", ".gif", ".bmp", ".webp", ".svg", ".ico"}; + + // 转换为小写进行比较 + String path = filePath.toLowerCase(); + + // 检查URL或本地路径是否以图片扩展名结尾 + for (String extension : imageExtensions) { + if (path.endsWith(extension)) { + return true; + } + } + + return false; + } + + public static String getFileName(String path) { + return Paths.get(path).getFileName().toString(); + } } diff --git a/src/main/java/cn/isliu/core/utils/FsApiUtil.java b/src/main/java/cn/isliu/core/utils/FsApiUtil.java index b68aec6..79ac4e7 100644 --- a/src/main/java/cn/isliu/core/utils/FsApiUtil.java +++ b/src/main/java/cn/isliu/core/utils/FsApiUtil.java @@ -38,7 +38,6 @@ import cn.isliu.core.enums.ErrorCode; public class FsApiUtil { private static final Gson gson = new Gson(); - // 使用统一的FsLogger替代java.util.logging.Logger private static final String REQ_TYPE = "JSON_STR"; public static final int DEFAULT_ROW_NUM = 1000; @@ -126,57 +125,6 @@ public class FsApiUtil { } } - /** - * 合并单元格 - * - * 在指定工作表中合并指定范围的单元格 - * - * @param cell 合并范围(如"A1:B2") - * @param sheetId 工作表ID - * @param client 飞书客户端 - * @param spreadsheetToken 电子表格Token - */ - public static void mergeCells(String cell, String sheetId, FeishuClient client, String spreadsheetToken) { - try { - CustomCellService.CellBatchUpdateRequest batchMergeRequest = CustomCellService.CellBatchUpdateRequest.newBuilder() - .addRequest(CustomCellService.CellRequest.mergeCells().setReqType(REQ_TYPE) - .setReqParams(cell.replaceAll("%SHEET_ID%", sheetId)).build()) - .build(); - - ApiResponse batchMergeResp = client.customCells().cellsBatchUpdate(spreadsheetToken, batchMergeRequest); - - if (!batchMergeResp.success()) { - FsLogger.warn("【飞书表格】 合并单元格请求异常!参数:{},错误信息:{}", cell, batchMergeResp.getMsg()); - throw new FsHelperException("【飞书表格】 合并单元格请求异常!"); - } - } catch (Exception e) { - FsLogger.warn("【飞书表格】 合并单元格异常!参数:{},错误信息:{}", cell, e.getMessage()); - throw new FsHelperException("【飞书表格】 合并单元格异常!"); - } - } - - public static void createTemplateHead(String head, String sheetId, FeishuClient client, String spreadsheetToken) { - try { - // 批量操作数据值(在一个请求中同时执行多个数据操作) - CustomValueService.ValueBatchUpdateRequest batchValueRequest = CustomValueService.ValueBatchUpdateRequest.newBuilder() - // 在指定范围前插入数据 - .addRequest(CustomValueService.ValueRequest.batchPutValues() - .setReqType(REQ_TYPE) - .setReqParams(head.replaceAll("%SHEET_ID%", sheetId)) - .build()) - .build(); - - ApiResponse apiResponse = client.customValues().valueBatchUpdate(spreadsheetToken, batchValueRequest); - if (!apiResponse.success()) { - FsLogger.warn("【飞书表格】 写入表格头数据异常!错误信息:{}", apiResponse.getMsg()); - throw new FsHelperException("【飞书表格】 写入表格头数据异常!"); - } - } catch (Exception e) { - FsLogger.warn("【飞书表格】 写入表格头异常!错误信息:{}", e.getMessage()); - throw new FsHelperException("【飞书表格】 写入表格头异常!"); - } - } - public static void setTableStyle(String style, String sheetId, FeishuClient client, String spreadsheetToken) { try { CustomCellService.CellBatchUpdateRequest batchUpdateRequest = CustomCellService.CellBatchUpdateRequest.newBuilder() @@ -497,9 +445,8 @@ public class FsApiUtil { } } - public static Object imageUpload(String filePath, 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 { - byte[] imageData = FileUtil.getImageData(filePath); CustomValueService.ValueRequest imageRequest = CustomValueService.ValueRequest.imageValues() .range(sheetId, position) @@ -514,11 +461,11 @@ public class FsApiUtil { ApiResponse imageResp = client.customValues().valueBatchUpdate(spreadsheetToken, imageWriteRequest); if (!imageResp.success()) { - FsLogger.warn("【飞书表格】 图片上传失败!参数:{},错误信息:{}", filePath, gson.toJson(imageResp)); + FsLogger.error(ErrorCode.API_SERVER_ERROR, "【飞书表格】 文件上传失败!" + gson.toJson(imageResp)); } return imageResp.getData(); } catch (Exception e) { - FsLogger.warn("【飞书表格】 图片上传异常!参数:{},错误信息:{}", filePath, e.getMessage()); + FsLogger.error(ErrorCode.API_SERVER_ERROR,"【飞书表格】 文件上传异常!" + e.getMessage(), fileName, e); } return null; diff --git a/src/main/java/cn/isliu/core/utils/GenerateUtil.java b/src/main/java/cn/isliu/core/utils/GenerateUtil.java index aa47b34..86e0c8d 100644 --- a/src/main/java/cn/isliu/core/utils/GenerateUtil.java +++ b/src/main/java/cn/isliu/core/utils/GenerateUtil.java @@ -1,9 +1,9 @@ package cn.isliu.core.utils; +import cn.isliu.core.FileData; import cn.isliu.core.annotation.TableProperty; -import cn.isliu.core.converters.FieldValueProcess; import cn.isliu.core.enums.BaseEnum; -import cn.isliu.core.utils.StringUtil; +import cn.isliu.core.enums.FileType; import org.jetbrains.annotations.Nullable; import java.lang.reflect.Field; @@ -437,11 +437,23 @@ public class GenerateUtil { return newObject; } - public static Object getFieldValueList(Object fieldValue) { - Map params = new HashMap<>(); - params.put("values", fieldValue); - params.put("type", "multipleValue"); - return params; + public static Object getRowData(Object fieldValue) { + if (fieldValue instanceof FileData) { + FileData fileData = (FileData) fieldValue; + if (Objects.equals(fileData.getFileType(), FileType.IMAGE.getType())) { + return null; + } else if (Objects.equals(fileData.getFileType(), FileType.FILE.getType())) { + return fileData.getFileUrl(); + } + } + + if (fieldValue instanceof List) { + Map params = new HashMap<>(); + params.put("values", fieldValue); + params.put("type", "multipleValue"); + return params; + } + return fieldValue; } public static @Nullable String getUniqueId(T data) {