diff --git a/src/main/java/com/corewing/app/util/OSSUploadUtil.java b/src/main/java/com/corewing/app/util/OSSUploadUtil.java index ef3765f..78665ee 100644 --- a/src/main/java/com/corewing/app/util/OSSUploadUtil.java +++ b/src/main/java/com/corewing/app/util/OSSUploadUtil.java @@ -2,21 +2,31 @@ package com.corewing.app.util; import com.aliyun.oss.OSS; import com.aliyun.oss.OSSClientBuilder; -import com.aliyun.oss.model.ObjectMetadata; -import com.aliyun.oss.model.PutObjectRequest; -import com.aliyun.oss.model.PutObjectResult; +import com.aliyun.oss.OSSException; +import com.aliyun.oss.model.*; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; import java.io.InputStream; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; @Component public class OSSUploadUtil { + /** + * 用户登录名称 oss@1563058769875871.onaliyun.com + * AccessKey ID LTAI5tKUhXrGxZ5Gj3exWpkG + * AccessKey Secret PaBTMp3BhcOUgLQhJWmOkhfJhTlzhV + */ private static final String ENDPOINT = "oss-cn-shenzhen.aliyuncs.com"; // 地域节点 - private static final String ACCESS_KEY_ID = "your-access-key-id"; // 替换为你的 AccessKey ID - private static final String ACCESS_KEY_SECRET = "your-access-key-secret"; // 替换为你的 AccessKey Secret + private static final String ACCESS_KEY_ID = "LTAI5tKUhXrGxZ5Gj3exWpkG"; // 替换为你的 AccessKey ID + private static final String ACCESS_KEY_SECRET = "PaBTMp3BhcOUgLQhJWmOkhfJhTlzhV"; // 替换为你的 AccessKey Secret private static final String BUCKET_NAME = "corewing-app"; // 替换为你的 Bucket 名称 /** @@ -67,6 +77,137 @@ public class OSSUploadUtil { } } + /** + * 从 OSS 下载文件到本地路径 + * @param objectName OSS 中存储的文件路径(如 "firmware/20231104/update.bin") + * @param localFilePath 本地保存路径(如 "D:/downloads/update.bin") + * @return 下载是否成功 + */ + public static boolean downloadFileToLocal(String objectName, String localFilePath) { + OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET); + try { + // 检查文件是否存在 + if (!ossClient.doesObjectExist(BUCKET_NAME, objectName)) { + throw new FileNotFoundException("OSS 文件不存在:" + objectName); + } + + // 下载文件到本地 + ossClient.getObject(new GetObjectRequest(BUCKET_NAME, objectName), new File(localFilePath)); + return true; + } catch (OSSException | FileNotFoundException e) { + return false; + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + } + + + /** + * 从 OSS 获取文件输入流(需手动关闭流) + * @param objectName OSS 中存储的文件路径 + * @return 文件输入流(使用后需调用 close() 关闭) + * @throws IOException 当文件不存在或下载失败时抛出 + */ + public static InputStream downloadFileToStream(String objectName) throws IOException { + OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET); + try { + // 检查文件是否存在 + if (!ossClient.doesObjectExist(BUCKET_NAME, objectName)) { + throw new FileNotFoundException("OSS 文件不存在:" + objectName); + } + + // 获取 OSS 文件对象并返回输入流 + OSSObject ossObject = ossClient.getObject(BUCKET_NAME, objectName); + return ossObject.getObjectContent(); + } catch (OSSException e) { + throw new IOException("OSS 服务异常:" + e.getMessage(), e); + } finally { + // 注意:此处不能关闭 ossClient!否则输入流会被提前关闭 + // 需在调用方使用完输入流后,手动关闭 ossClient 和输入流 + // (或通过 try-with-resources 自动关闭) + } + } + + /** + * 从 OSS 删除单个文件 + * @param objectName OSS 中存储的文件路径(如 "firmware/20231104/update.bin") + * @return 删除是否成功(文件不存在时返回 false) + */ + public static boolean deleteFile(String objectName) { + OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET); + try { + // 先检查文件是否存在 + if (!ossClient.doesObjectExist(BUCKET_NAME, objectName)) { + System.out.println("OSS 文件不存在,删除失败:" + objectName); + return false; + } + + // 执行删除操作 + ossClient.deleteObject(BUCKET_NAME, objectName); + System.out.println("OSS 文件删除成功:" + objectName); + return true; + } catch (OSSException e) { + System.err.println("OSS 服务异常,删除失败:" + e.getMessage()); + return false; + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + } + + + /** + * 批量删除 OSS 文件(3.17.4 版本终极兼容方案) + * 逻辑:先执行批量删除,再逐个校验文件是否存在,确认删除结果 + * @param objectNames OSS 文件路径列表(如 ["firmware/update1.bin", "firmware/update2.bin"]) + * @return 批量删除结果(key:文件路径,value:是否删除成功) + */ + public static Map batchDeleteFiles(List objectNames) { + Map deleteResult = new HashMap<>(); + if (objectNames == null || objectNames.isEmpty()) { + System.out.println("批量删除失败:文件列表为空"); + return deleteResult; + } + + OSS ossClient = new OSSClientBuilder().build(ENDPOINT, ACCESS_KEY_ID, ACCESS_KEY_SECRET); + try { + // 第一步:执行批量删除(忽略 SDK 返回结果,只保证执行删除操作) + DeleteObjectsRequest request = new DeleteObjectsRequest(BUCKET_NAME); + request.setKeys(objectNames); // 直接传入文件路径列表 + ossClient.deleteObjects(request); // 执行删除,不依赖返回结果 + + // 第二步:逐个校验文件是否存在,确认删除结果 + for (String objectName : objectNames) { + boolean isDeleted = !ossClient.doesObjectExist(BUCKET_NAME, objectName); + deleteResult.put(objectName, isDeleted); + if (isDeleted) { + System.out.println("删除成功:" + objectName); + } else { + System.err.println("删除失败:文件仍存在 -> " + objectName); + } + } + + } catch (OSSException e) { + System.err.printf("OSS 服务异常:错误码=%s,原因=%s%n", + e.getErrorCode(), e.getErrorMessage()); + // 服务异常时,所有文件标记为删除失败 + objectNames.forEach(name -> deleteResult.put(name, false)); + } catch (Exception e) { + System.err.println("批量删除未知异常:" + e.getMessage()); + objectNames.forEach(name -> deleteResult.put(name, false)); + } finally { + if (ossClient != null) { + ossClient.shutdown(); + } + } + + return deleteResult; + } + + /** * 根据文件名获取 Content-Type * @param fileName 文件名(如 "update.bin")