S3FileService.java 18 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447
  1. package com.fdkankan.fyun.s3;
  2. import cn.hutool.core.collection.CollUtil;
  3. import com.amazonaws.HttpMethod;
  4. import com.amazonaws.services.s3.AmazonS3;
  5. import com.amazonaws.services.s3.model.*;
  6. import com.fdkankan.fyun.constant.FYunTypeEnum;
  7. import com.fdkankan.fyun.face.AbstractFYunFileService;
  8. import org.apache.commons.lang3.StringUtils;
  9. import org.slf4j.Logger;
  10. import org.slf4j.LoggerFactory;
  11. import org.springframework.beans.factory.annotation.Autowired;
  12. import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
  13. import org.springframework.stereotype.Component;
  14. import org.springframework.util.ObjectUtils;
  15. import java.io.*;
  16. import java.net.URL;
  17. import java.util.*;
  18. import java.util.stream.Collectors;
  19. @Component
  20. @ConditionalOnProperty(name = "fyun.type",havingValue = "aws")
  21. public class S3FileService extends AbstractFYunFileService {
  22. private Logger log = LoggerFactory.getLogger(this.getClass().getName());
  23. @Autowired
  24. private AmazonS3 s3;
  25. @Override
  26. public String uploadFile(String bucket, byte[] data, String remoteFilePath){
  27. try {
  28. ObjectMetadata metadata = new ObjectMetadata();
  29. PutObjectRequest request = new PutObjectRequest(bucket, remoteFilePath, new ByteArrayInputStream(data), metadata);
  30. request.withCannedAcl(CannedAccessControlList.PublicRead);
  31. s3.putObject(request);
  32. } catch (Exception e) {
  33. log.error("s3上传文件失败", e);
  34. }
  35. return null;
  36. }
  37. @Override
  38. public String uploadFile(String bucket, String filePath, String remoteFilePath){
  39. return uploadFile(bucket, filePath, remoteFilePath,null);
  40. }
  41. @Override
  42. public String uploadFile(String bucket, InputStream inputStream, String remoteFilePath) {
  43. try {
  44. s3.putObject(bucket, remoteFilePath, inputStream, null);
  45. } catch (Exception e) {
  46. log.error("文件流上传失败,目标路径:{}", remoteFilePath);
  47. e.printStackTrace();
  48. }
  49. return null;
  50. }
  51. @Override
  52. public String uploadFile(String bucket, String filePath, String remoteFilePath,Map<String, String> headers){
  53. try {
  54. File file = new File(filePath);
  55. if (!file.exists()) {
  56. log.error("要上传的文件不存在:" + filePath);
  57. return null;
  58. }
  59. // 设置文件并设置公读
  60. ObjectMetadata metadata = new ObjectMetadata();
  61. if (filePath.contains(".jpg")) {
  62. metadata.setContentType("image/jpeg");
  63. }
  64. if (filePath.contains(".png")) {
  65. metadata.setContentType("image/png");
  66. }
  67. if(org.apache.commons.lang3.ObjectUtils.isNotEmpty(headers)){
  68. for (Map.Entry<String, String> header : headers.entrySet()) {
  69. metadata.setHeader(header.getKey(),header.getValue());
  70. }
  71. }
  72. PutObjectRequest request = new PutObjectRequest(bucket, remoteFilePath, file);
  73. request.withCannedAcl(CannedAccessControlList.PublicRead);
  74. request.withMetadata(metadata);
  75. // 上传文件
  76. PutObjectResult putObjectResult = s3.putObject(request);
  77. if (StringUtils.isNotEmpty(putObjectResult.getETag())) {
  78. log.info("s3上传文件成功:" + remoteFilePath);
  79. }
  80. } catch (Exception e) {
  81. log.error("文件上传失败:{}",filePath);
  82. e.printStackTrace();
  83. }
  84. return null;
  85. }
  86. @Override
  87. public String uploadFileByCommand(String bucket, String filePath, String remoteFilePath){
  88. try {
  89. String optType = new File(filePath).isDirectory() ? "folder" : "file";
  90. String command = String.format(fYunConstants.UPLOAD_SH, bucket, filePath, remoteFilePath, FYunTypeEnum.AWS.code(), optType);
  91. log.info("开始上传文件, ossPath:{}, srcPath:{}", remoteFilePath, filePath);
  92. callshell(command);
  93. } catch (Exception e) {
  94. log.error("上传文件失败, ossPath:{}, srcPath:{}", remoteFilePath, filePath);
  95. e.printStackTrace();
  96. }
  97. return null;
  98. }
  99. @Override
  100. public void downloadFileByCommand(String bucket, String filePath, String remoteFilePath) {
  101. try {
  102. String optType = remoteFilePath.contains(".") ? "file" : "folder";
  103. String command = String.format(fYunConstants.DOWNLOAD_SH, bucket, remoteFilePath, filePath, FYunTypeEnum.AWS.code(), optType);
  104. log.info("开始下载文件, ossPath:{}, srcPath:{}", remoteFilePath, filePath);
  105. callshell(command);
  106. } catch (Exception e) {
  107. log.error("上传文件失败, ossPath:{}, srcPath:{}", remoteFilePath, filePath);
  108. e.printStackTrace();
  109. }
  110. }
  111. @Override
  112. public void deleteFile(String bucket, String remoteFilePath){
  113. if (remoteFilePath.startsWith("/")) {
  114. remoteFilePath = remoteFilePath.substring(1);
  115. }
  116. try {
  117. s3.deleteObject(bucket, remoteFilePath);
  118. } catch (Exception e) {
  119. log.error("s3删除文件失败,key=" + remoteFilePath, e);
  120. }
  121. }
  122. @Override
  123. public void deleteFolder(String bucket, String remoteFolderPath){
  124. try {
  125. if (!remoteFolderPath.endsWith("/")) {
  126. remoteFolderPath = remoteFolderPath + "/";
  127. }
  128. log.info("开始删除文件夹:{}", remoteFolderPath);
  129. int maxKeys = 1000;
  130. String nextMaker = null;
  131. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  132. listObjectsRequest.setBucketName(bucket);
  133. listObjectsRequest.setPrefix(remoteFolderPath);
  134. listObjectsRequest.setMaxKeys(maxKeys);
  135. ObjectListing objectListing;
  136. DeleteObjectsRequest multiObjectDeleteRequest = new DeleteObjectsRequest(bucket).withQuiet(false);
  137. do {
  138. listObjectsRequest.setMarker(nextMaker);
  139. objectListing = s3.listObjects(listObjectsRequest);
  140. List<S3ObjectSummary> objectSummaries = objectListing.getObjectSummaries();
  141. List<DeleteObjectsRequest.KeyVersion> keys = objectSummaries.stream().map(summary -> new DeleteObjectsRequest.KeyVersion(summary.getKey())).collect(Collectors.toList());
  142. if (!ObjectUtils.isEmpty(keys)) {
  143. multiObjectDeleteRequest.setKeys(keys);
  144. s3.deleteObjects(multiObjectDeleteRequest);
  145. }
  146. nextMaker = objectListing.getNextMarker();
  147. } while (objectListing.isTruncated());
  148. } catch (Exception e) {
  149. log.error("删除aws文件失败,path=" + remoteFolderPath, e);
  150. }
  151. }
  152. @Override
  153. public void uploadMulFiles(String bucket, Map<String, String> filepaths){
  154. try {
  155. for (Map.Entry<String, String> entry : filepaths.entrySet()) {
  156. uploadFile(bucket, entry.getKey(), entry.getValue(),null);
  157. }
  158. } catch (Exception e) {
  159. log.error("OSS批量上传文件失败!");
  160. }
  161. }
  162. @Override
  163. public List<String> listRemoteFiles(String bucket, String sourcePath) {
  164. List<String> keyList = new ArrayList<>();
  165. try {
  166. boolean flag = true;
  167. String nextMaker = null;
  168. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  169. listObjectsRequest.setBucketName(bucket);
  170. listObjectsRequest.setPrefix(sourcePath);
  171. listObjectsRequest.setMaxKeys(200);
  172. do {
  173. listObjectsRequest.setMarker(nextMaker);
  174. ObjectListing objectListing = s3.listObjects(listObjectsRequest);
  175. List<S3ObjectSummary> objectSummaries = objectListing.getObjectSummaries();
  176. List<String> collect = objectSummaries.stream().map(S3ObjectSummary::getKey).collect(Collectors.toList());
  177. if (CollUtil.isNotEmpty(collect)) {
  178. keyList.addAll(collect);
  179. }
  180. nextMaker = objectListing.getNextMarker();
  181. flag = objectListing.isTruncated();
  182. } while (flag);
  183. } catch (Exception e) {
  184. log.error("获取文件列表失败,path=" + sourcePath, e);
  185. e.printStackTrace();
  186. }
  187. return keyList;
  188. }
  189. @Override
  190. public void copyFileBetweenBucket(String sourceBucketName, String sourcePath, String targetBucketName, String targetPath){
  191. try {
  192. List<String> files = listRemoteFiles(sourceBucketName, sourcePath);
  193. if (ObjectUtils.isEmpty(files)) {
  194. return;
  195. }
  196. files.stream().forEach(file -> {
  197. CopyObjectRequest request = new CopyObjectRequest(sourceBucketName, file, targetBucketName, file.replace(sourcePath, targetPath));
  198. request.withCannedAccessControlList(CannedAccessControlList.PublicRead);
  199. s3.copyObject(request);
  200. });
  201. } catch (Exception e) {
  202. log.error("列举文件目录失败,key=" + sourcePath);
  203. }
  204. }
  205. @Override
  206. public void copyFilesBetweenBucket(String sourceBucketName, String targetBucketName, Map<String, String> pathMap){
  207. if (ObjectUtils.isEmpty(pathMap)) {
  208. return;
  209. }
  210. try {
  211. for (Map.Entry<String, String> entry : pathMap.entrySet()) {
  212. copyFileBetweenBucket(sourceBucketName, entry.getKey(), targetBucketName, entry.getValue());
  213. }
  214. } catch (Exception e) {
  215. log.error("批量复制文件失败!");
  216. }
  217. }
  218. @Override
  219. public String getFileContent(String bucketName, String remoteFilePath){
  220. try {
  221. GetObjectRequest request = new GetObjectRequest(bucketName,remoteFilePath);
  222. S3Object object = s3.getObject(request);
  223. S3ObjectInputStream inputStream = object.getObjectContent();
  224. StringBuilder content = new StringBuilder();
  225. try(BufferedReader reader = new BufferedReader(new InputStreamReader(inputStream))){
  226. while (true) {
  227. String line = reader.readLine();
  228. if (line == null) break;
  229. content.append(line);
  230. }
  231. } catch (IOException e) {
  232. log.error("读取aws文件流失败", e);
  233. }
  234. object.close();
  235. return content.toString();
  236. } catch (Exception e) {
  237. log.error("获取文件内容失败:{}", remoteFilePath);
  238. return null;
  239. }
  240. }
  241. @Override
  242. public boolean fileExist(String bucket, String objectName) {
  243. try {
  244. return s3.doesObjectExist(bucket, objectName);
  245. } catch (Exception e) {
  246. log.error("判断文件是否存在失败:{}", objectName);
  247. return false;
  248. }
  249. }
  250. @Override
  251. public void downloadFile(String bucket, String remoteFilePath, String localPath) {
  252. try {
  253. File localFile = new File(localPath);
  254. if (!localFile.getParentFile().exists()) {
  255. localFile.getParentFile().mkdirs();
  256. }
  257. if(localFile.isDirectory()){
  258. String fileName = remoteFilePath.substring(remoteFilePath.lastIndexOf("/")+1);
  259. log.info("未配置文件名,使用默认文件名:{}",fileName);
  260. localPath = localPath.concat(File.separator).concat(fileName);
  261. }
  262. GetObjectRequest request = new GetObjectRequest(bucket, remoteFilePath);
  263. s3.getObject(request,new File(localPath));
  264. } catch (Throwable throwable) {
  265. log.error("文件下载失败:{}", remoteFilePath);
  266. throwable.printStackTrace();
  267. }
  268. }
  269. @Override
  270. public URL getPresignedUrl(String bucket,String url) {
  271. java.util.Date expiration = new java.util.Date();
  272. long expTimeMillis = expiration.getTime();
  273. expTimeMillis += 1000 * 60 * 60 * 8;
  274. expiration.setTime(expTimeMillis);
  275. GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(bucket, url)
  276. .withMethod(HttpMethod.PUT).withExpiration(expiration);
  277. return s3.generatePresignedUrl(generatePresignedUrlRequest);
  278. }
  279. @Override
  280. public long getSubFileNums(String bucket, String url) {
  281. long totalFileNums = 0;
  282. try {
  283. boolean flag = true;
  284. String nextMaker = null;
  285. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  286. listObjectsRequest.setBucketName(bucket);
  287. listObjectsRequest.setPrefix(url);
  288. listObjectsRequest.setMaxKeys(200);
  289. do {
  290. listObjectsRequest.setMarker(nextMaker);
  291. ObjectListing objectListing = s3.listObjects(listObjectsRequest);
  292. List<S3ObjectSummary> objectSummaries = objectListing.getObjectSummaries();
  293. List<String> collect = objectSummaries.stream().map(S3ObjectSummary::getKey).collect(Collectors.toList());
  294. totalFileNums = totalFileNums + collect.size();
  295. nextMaker = objectListing.getNextMarker();
  296. flag = objectListing.isTruncated();
  297. } while (flag);
  298. } catch (Exception e) {
  299. log.error("获取文件数量失败,path=" + url, e);
  300. e.printStackTrace();
  301. }
  302. return totalFileNums;
  303. }
  304. @Override
  305. public void restoreFolder(String bucket, String folderName, Integer priority) {
  306. List<String> objectList = this.listRemoteFiles(bucket, folderName);
  307. if(CollUtil.isEmpty(objectList)){
  308. return;
  309. }
  310. objectList.parallelStream().forEach(objectName -> {
  311. this.restoreFile(bucket, objectName, priority);
  312. });
  313. }
  314. @Override
  315. public void restoreFile(String bucket, String objectName, Integer priority){
  316. // ObjectMetadata objectMetadata = ossClient.getObjectMetadata(bucket, objectName);
  317. //
  318. // // 校验Object是否为归档类型Object。
  319. // StorageClass storageClass = objectMetadata.getObjectStorageClass();
  320. // if (storageClass == StorageClass.ColdArchive) {
  321. // // 设置解冻冷归档Object的优先级。
  322. // // RestoreTier.RESTORE_TIER_EXPEDITED 表示1小时内完成解冻。
  323. // // RestoreTier.RESTORE_TIER_STANDARD 表示2~5小时内完成解冻。
  324. // // RestoreTier.RESTORE_TIER_BULK 表示5~12小时内完成解冻。
  325. // RestoreTier restoreTier = null;
  326. // switch (priority){
  327. // case 1 :
  328. // restoreTier = RestoreTier.RESTORE_TIER_EXPEDITED;
  329. // break;
  330. // case 2 :
  331. // restoreTier = RestoreTier.RESTORE_TIER_STANDARD;
  332. // break;
  333. // default:
  334. // restoreTier = RestoreTier.RESTORE_TIER_BULK;
  335. // }
  336. // RestoreJobParameters jobParameters = new RestoreJobParameters(restoreTier);
  337. // // 配置解冻参数,以设置5小时内解冻完成,解冻状态保持2天为例。
  338. // // 第一个参数表示保持解冻状态的天数,默认是1天,此参数适用于解冻Archive(归档)与ColdArchive(冷归档)类型Object。
  339. // // 第二个参数jobParameters表示解冻优先级,只适用于解冻ColdArchive类型Object。
  340. // RestoreConfiguration configuration = new RestoreConfiguration(1, jobParameters);
  341. // //开始解冻
  342. // ossClient.restoreObject(bucket, objectName, configuration);
  343. //// // 等待解冻完成。
  344. //// do {
  345. //// try {
  346. //// Thread.sleep(1000);
  347. //// } catch (InterruptedException e) {
  348. //// e.printStackTrace();
  349. //// }
  350. //// objectMetadata = ossClient.getObjectMetadata(bucket, objectName);
  351. //// } while (!objectMetadata.isRestoreCompleted());
  352. // }
  353. }
  354. @Override
  355. public Boolean checkStore(String bucket, String url) {
  356. ObjectMetadata objectMetadata = s3.getObjectMetadata(bucket, url);
  357. return !isRestoreCompleted(objectMetadata);
  358. }
  359. private boolean isRestoreCompleted(ObjectMetadata objectMetadata){
  360. Date restoreExpirationTime = objectMetadata.getRestoreExpirationTime();
  361. if(Objects.nonNull(restoreExpirationTime) && restoreExpirationTime.after(Calendar.getInstance().getTime())){
  362. return true;
  363. }
  364. return false;
  365. }
  366. @Override
  367. public void restoreFolder(String bucket, String url) {
  368. ObjectMetadata objectMetadata ;
  369. List<String> objectList = this.listRemoteFiles(bucket, url);
  370. if(CollUtil.isEmpty(objectList)){
  371. return;
  372. }
  373. for (String objectName : objectList) {
  374. objectMetadata = s3.getObjectMetadata(bucket, objectName);
  375. // 校验Object是否为归档类型Object。
  376. StorageClass storageClass = objectMetadata.getArchiveStatus();
  377. if (storageClass == StorageClass.) {
  378. // 解冻Object。
  379. RestoreObjectRequest requestRestore = new RestoreObjectRequest(bucket, url, 1);
  380. s3.restoreObjectV2(requestRestore);
  381. }
  382. }
  383. }
  384. @Override
  385. public Integer getRestoreFolderProcess(String bucket, String url) {
  386. return null;
  387. }
  388. @Override
  389. public Long getSpace(String bucket, String key) {
  390. List<String> keyList = new ArrayList<>();
  391. Long total = 0L;
  392. boolean flag = true;
  393. String nextMaker = null;
  394. ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
  395. listObjectsRequest.setBucketName(bucket);
  396. listObjectsRequest.setPrefix(key);
  397. listObjectsRequest.setMaxKeys(200);
  398. do {
  399. listObjectsRequest.setMarker(nextMaker);
  400. ObjectListing objectListing = s3.listObjects(listObjectsRequest);
  401. List<S3ObjectSummary> objectSummaries = objectListing.getObjectSummaries();
  402. Long space = objectSummaries.stream().mapToLong(S3ObjectSummary::getSize).sum();
  403. total += space;
  404. nextMaker = objectListing.getNextMarker();
  405. flag = objectListing.isTruncated();
  406. } while (flag);
  407. return total;
  408. }
  409. }