package com.njcn.ali.oss.util; import cn.hutool.core.io.FileUtil; import cn.hutool.core.util.ObjUtil; import com.aliyun.oss.OSS; import com.aliyun.oss.common.comm.ResponseMessage; import com.aliyun.oss.model.*; import com.njcn.ali.oss.config.AliYunOssConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.stereotype.Component; import org.springframework.web.multipart.MultipartFile; import javax.annotation.Resource; import java.io.*; import java.net.URL; import java.util.Comparator; import java.util.Date; import java.util.List; /** * 阿里云OSS核心工具类 * 封装常用操作:上传、下载、删除、查询、生成临时访问URL等 * * @author web2023 */ @Component public class AliYunOssUtils { private static final Logger logger = LoggerFactory.getLogger(AliYunOssUtils.class); @Resource private OSS ossClient; @Resource private AliYunOssConfig ossConfig; /** * 上传文件(字节数组) * * @param objectName 文件在OSS中的路径/名称 * @param content 文件字节数组 * @return 上传结果ETag */ public String uploadFile(String objectName, byte[] content) { return uploadFile(objectName, new ByteArrayInputStream(content)); } /** * 上传文件(InputStream) * * @param objectName 文件在OSS中的路径/名称 * @param inputStream 文件输入流 * @return 上传结果ETag */ public String uploadFile(String objectName, InputStream inputStream) { try { PutObjectResult result = ossClient.putObject( ossConfig.getBucket(), objectName, inputStream ); return result.getETag(); } catch (Exception e) { logger.error("文件{}上传失败", objectName, e); throw new RuntimeException("文件上传失败:" + objectName, e); } } /** * 上传文件(MultipartFile) * * @param objectName 文件在OSS中的路径/名称 * @param multipartFile 文件输入流 * @return 上传结果ETag */ public String uploadFile(String objectName, MultipartFile multipartFile) { try { PutObjectResult result = ossClient.putObject( ossConfig.getBucket(), objectName, multipartFile.getInputStream() ); return result.getETag(); } catch (Exception e) { logger.error("文件{}上传失败", objectName, e); throw new RuntimeException("文件上传失败:" + objectName, e); } } /** * 上传本地文件 * * @param objectName 文件在OSS中的路径/名称 * @param localFilePath 本地文件路径 * @return 上传结果ETag */ public String uploadLocalFile(String objectName, String localFilePath) { File file = new File(localFilePath); if (!file.exists()) { throw new RuntimeException("本地文件不存在:" + localFilePath); } try { PutObjectResult result = ossClient.putObject( ossConfig.getBucket(), objectName, file ); return result.getETag(); } catch (Exception e) { logger.error("本地文件{}上传失败", localFilePath, e); throw new RuntimeException("本地文件上传失败:" + localFilePath, e); } } /** * 下载文件到本地 * * @param objectName OSS中的文件名称/路径 * @param localFilePath 本地保存路径 */ public void downloadFile(String objectName, String localFilePath) { try { ossClient.getObject( new GetObjectRequest(ossConfig.getBucket(), objectName), new File(localFilePath) ); } catch (Exception e) { logger.error("文件{}下载失败", objectName, e); throw new RuntimeException("文件下载失败:" + objectName, e); } } /** * 下载文件为字节流 * * @param objectName OSS中的文件名称/路径 * @return 文件字节流 */ public InputStream downloadStream(String objectName) { try (OSSObject ossObject = ossClient.getObject(ossConfig.getBucket(), objectName); InputStream inputStream = ossObject.getObjectContent()) { return inputStream; } catch (Exception e) { logger.error("文件{}下载为字节数组失败", objectName, e); throw new RuntimeException("文件下载为字节数组失败:" + objectName, e); } } /** * 下载文件为字节数组 * * @param objectName OSS中的文件名称/路径 * @return 文件字节数组 */ public byte[] downloadFileToBytes(String objectName) { try (OSSObject ossObject = ossClient.getObject(ossConfig.getBucket(), objectName); InputStream inputStream = ossObject.getObjectContent(); ByteArrayOutputStream outputStream = new ByteArrayOutputStream()) { byte[] buffer = new byte[1024]; int len; while ((len = inputStream.read(buffer)) != -1) { outputStream.write(buffer, 0, len); } return outputStream.toByteArray(); } catch (Exception e) { logger.error("文件{}下载为字节数组失败", objectName, e); throw new RuntimeException("文件下载为字节数组失败:" + objectName, e); } } /** * 下载文件为文件 * * @param folderPath OSS中的文件名称/路径 * @return 文件 */ public File getLastFile(String folderPath) { try { // 列出文件夹下所有文件(分页处理,避免文件过多) ObjectListing objectListing = ossClient.listObjects(ossConfig.getBucket(), folderPath); List objectSummaries = objectListing.getObjectSummaries(); // 处理空文件夹 if (objectSummaries.isEmpty()) { logger.warn("OSS文件夹 {} 下无文件", folderPath); return null; } // 按最后修改时间降序排序,取第一个(最新) String latestFileName = objectSummaries.stream() .filter(summary -> !summary.getKey().equals(folderPath)) .max(Comparator.comparing(OSSObjectSummary::getLastModified)) .map(OSSObjectSummary::getKey) .orElse(null); if (ObjUtil.isNull(latestFileName)) { throw new RuntimeException("OSS文件夹 " + folderPath + " 下无可用文件"); } File file = File.createTempFile(latestFileName.split(".xlsx")[0], ".xlsx"); InputStream inputStream = ossClient.getObject(ossConfig.getBucket(), latestFileName).getObjectContent(); FileUtil.writeFromStream(inputStream, file); inputStream.close(); return file; } catch (Exception e) { logger.error("查找OSS文件夹 {} 最新文件失败", folderPath, e); throw new RuntimeException("查找最新文件失败:" + folderPath, e); }finally { } } public static void main(String[] args) { String latestFileName="latestFileNam.xlsx"; String s = latestFileName.split(".xlsx")[0]; System.out.println(); } /** * 删除单个文件 * * @param objectName OSS中的文件名称/路径 */ public void deleteFile(String objectName) { try { VoidResult voidResult = ossClient.deleteObject(ossConfig.getBucket(), objectName); ResponseMessage response = voidResult.getResponse(); System.out.println(response); } catch (Exception e) { logger.error("文件{}删除失败", objectName, e); throw new RuntimeException("文件删除失败:" + objectName, e); } } /** * 批量删除文件 * * @param objectNames 文件名称列表 */ public void deleteFiles(List objectNames) { try { // 静默删除,不返回删除结果 DeleteObjectsRequest request = new DeleteObjectsRequest(ossConfig.getBucket()) .withKeys(objectNames); ossClient.deleteObjects(request); } catch (Exception e) { logger.error("批量删除文件失败", e); throw new RuntimeException("批量删除文件失败", e); } } /** * 判断文件是否存在 * * @param objectName OSS中的文件名称/路径 * @return true-存在,false-不存在 */ public boolean isFileExist(String objectName) { try { boolean exists = ossClient.doesObjectExist(ossConfig.getBucket(), objectName); return exists; } catch (Exception e) { logger.error("判断文件{}是否存在失败", objectName, e); throw new RuntimeException("判断文件是否存在失败:" + objectName, e); } } /** * 生成文件临时访问URL * * @param objectName OSS中的文件名称/路径 * @param expireSeconds 过期时间(秒) * @return 临时访问URL */ public String generatePresignedUrl(String objectName, int expireSeconds) { try { Date expiration = new Date(System.currentTimeMillis() + expireSeconds * 1000L); URL url = ossClient.generatePresignedUrl( ossConfig.getBucket(), objectName, expiration ); String urlStr = url.toString(); logger.info("文件{}生成临时访问URL成功,过期时间:{}秒", objectName, expireSeconds); return urlStr; } catch (Exception e) { logger.error("生成文件{}临时访问URL失败", objectName, e); throw new RuntimeException("生成临时访问URL失败:" + objectName, e); } } /** * 关闭OSS客户端 */ public void close() { if (ossClient != null) { ossClient.shutdown(); logger.info("OSS客户端已关闭"); } } }