package <%=packageName%>.storage.service; import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.model.*; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.time.Instant; import java.util.Date; import java.util.concurrent.ConcurrentHashMap; import static java.time.temporal.ChronoUnit.MINUTES; /** * 对象储存服务 */ @Component public class StorageService { private final Logger log = LoggerFactory.getLogger(StorageService.class); private final AmazonS3 s3Client; private final ConcurrentHashMap<String, Bucket> buckets; private boolean isLocalFileSystem; private File localFileSystemDirectory; @Autowired public StorageService(AmazonS3 s3Client) throws IOException { isLocalFileSystem = s3Client == null; if (isLocalFileSystem) { this.s3Client = null; this.buckets = null; localFileSystemDirectory = new File(String.format("%s/%s", new File("build").getAbsolutePath(), "storage")); FileUtils.forceMkdir(localFileSystemDirectory); } else { this.s3Client = s3Client; this.buckets = new ConcurrentHashMap<>(); this.s3Client.listBuckets().forEach(bucket -> buckets.put(bucket.getName(), bucket)); } } /** * 创建对象 * * @param bucketName 储存桶名称 * @param key 键 * @param input 输入流 * @param objectMetadata 元数据 * @return 储存对象结果 */ public PutObjectResult putObject(String bucketName, String key, InputStream input, ObjectMetadata objectMetadata) throws IOException { // Local file system if (isLocalFileSystem) return writeToLocalFileSystem(bucketName, key, input); // Remote API if (!buckets.containsKey(bucketName)) putBucket(bucketName); return s3Client.putObject(bucketName, key, input, objectMetadata); } /** * 创建安全对象 * * @param bucketName 储存桶名称 * @param key 键 * @param input 输入流 * @param objectMetadata 元数据 * @return 储存对象结果 */ public PutObjectResult putSecureObject(String bucketName, String key, InputStream input, ObjectMetadata objectMetadata) throws IOException { if (isLocalFileSystem) return writeToLocalFileSystem(bucketName, key, input); PutObjectResult result = s3Client.putObject(bucketName, key, input, objectMetadata); s3Client.setObjectAcl(bucketName, key, CannedAccessControlList.Private); return result; } /** * 更新元数据 * * @param bucketName 储存桶名称 * @param key 键 * @param objectMetadata 元数据 * @return 复制对象结果 */ public CopyObjectResult putMetadata(String bucketName, String key, ObjectMetadata objectMetadata) { if (isLocalFileSystem) return new CopyObjectResult(); CopyObjectRequest request = new CopyObjectRequest(bucketName, key, bucketName, key) .withNewObjectMetadata(objectMetadata); return s3Client.copyObject(request); } /** * 获取对象 * * @param bucketName 储存桶名称 * @param key 键 * @return 对象结果 */ public S3Object getObject(String bucketName, String key) throws IOException { if (isLocalFileSystem) { S3Object s3object = new S3Object(); s3object.setBucketName(bucketName); s3object.setKey(key); s3object.setObjectContent(FileUtils.openInputStream( new File(String.format("%s/%s/%s", localFileSystemDirectory.getAbsolutePath(), bucketName, key)) )); return s3object; } return s3Client.getObject(bucketName, key); } /** * 获取对象链接 * * @param bucketName 储存桶名称 * @param key 键 * @return 对象链接 */ public URL getObjectUrl(String bucketName, String key) { if (isLocalFileSystem) { return null; } GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest(bucketName, key); // 5分钟内有效 Instant time = Instant.now(); time.plus(5, MINUTES); request.setExpiration(new Date(time.toEpochMilli())); return s3Client.generatePresignedUrl(request); } /** * 创建储存桶 * * @param bucketName 储存桶名称 */ private void putBucket(String bucketName) throws IOException { if (isLocalFileSystem) { FileUtils.forceMkdir( new File(String.format("%s/%s", localFileSystemDirectory.getAbsolutePath(), bucketName))); } else { buckets.put(bucketName, s3Client.createBucket(bucketName)); } } /** * 写入本地文件系统 * * @param bucketName 文件夹名称 * @param key 文件名称 * @param input 文件流 * @return 储存对象结果 */ private PutObjectResult writeToLocalFileSystem(String bucketName, String key, InputStream input) throws IOException { File directory = new File(String.format("%s/%s", localFileSystemDirectory.getAbsolutePath(), bucketName)); FileUtils.forceMkdir(directory); File file = new File(String.format("%s/%s", directory.getAbsolutePath(), key)); if (!file.exists()) file.createNewFile(); FileUtils.writeByteArrayToFile(file, IOUtils.toByteArray(input)); return new PutObjectResult(); } }