diff --git a/magic-starter-oss/README.md b/magic-starter-oss/README.md index 05d2570..8244f05 100644 --- a/magic-starter-oss/README.md +++ b/magic-starter-oss/README.md @@ -11,7 +11,7 @@ ## 简介 -`magic-starter-oss` 主要是对一些常用的对象存储的封装,支持`阿里云OSS、腾讯云COS、七牛云存储、MinIO`。 +`magic-starter-oss` 主要是对一些常用的对象存储的封装,支持`阿里云OSS、腾讯云COS、七牛云存储、MinIO`、`AwsS3`。 ## 使用 @@ -25,12 +25,13 @@ ## 快速上手 -> magic-starter-oss 提供了 4 种常见的对象云存储的支持。 +> magic-starter-oss 提供了 5 种常见的对象云存储的支持。 > > 1. 阿里云 OSS > 2. 腾讯云 COS > 3. 七牛云存储 > 4. MinIO 自建 +> 5. AwsS3 服务 > > 懒人请直接看demo:https://github.com/xkcoding/magic-starter-oss-demo @@ -140,6 +141,33 @@ magic: endpoint: http://192.168.31.8:9000 ``` +#### AwsS3 + +##### 引入依赖 + +```xml + + com.amazonaws + aws-java-sdk-s3 + ${awss3.oss.version} + +``` + +##### 配置文件 + +```yaml +magic: + oss: + aws-s3: + enabled: true + access-key: accesskey + secret-key: secretkey + bucket-name: tmp + endpoint: https://***.amazonaws.com + https: true + region: xxx-west-1 # 自建服务,可不填 +``` + ### 使用 #### 阿里云 OSS @@ -170,8 +198,15 @@ private QiNiuCloudTemplate qiNiuCloudTemplate; private MinIoTemplate minIoTemplate; ``` +#### AwsS3 + +```java +@Autowired +private AwsS3Template awsS3Template; +``` + ## 特点 - 提供了存储桶生成策略、及文件名生成策略,用户自定义只需要自定义 `com.xkcoding.magic.oss.support.rule.OssRule`,同时加入到 Spring 容器中即可 - 提供了统一的操作接口,`com.xkcoding.magic.oss.OssTemplate` 后续集成其他对象存储,只需要实现该接口即可 -- 虽然有 4 种实现,但是对外暴露的 API 一致,减去记忆的烦恼 \ No newline at end of file +- 虽然有 5 种实现,但是对外暴露的 API 一致,减去记忆的烦恼 \ No newline at end of file diff --git a/magic-starter-oss/pom.xml b/magic-starter-oss/pom.xml index 0810038..968d11b 100644 --- a/magic-starter-oss/pom.xml +++ b/magic-starter-oss/pom.xml @@ -31,7 +31,7 @@ jar - Magic Oss 集成多种对象存储,包括七牛云bucket、阿里云OSS、腾讯云COS、minio + Magic Oss 集成多种对象存储,包括七牛云bucket、阿里云OSS、腾讯云COS、minio、AwsS3 @@ -39,6 +39,7 @@ 5.6.8 7.2.23 6.0.7 + 1.11.782 @@ -80,6 +81,12 @@ ${minio.oss.version} provided + + com.amazonaws + aws-java-sdk-s3 + ${awss3.oss.version} + provided + com.xkcoding.magic diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/AbstractOssTemplate.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/AbstractOssTemplate.java index 1555750..fe5e92b 100644 --- a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/AbstractOssTemplate.java +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/AbstractOssTemplate.java @@ -60,6 +60,10 @@ protected String getBucketName() { defaultBucketName = ossProperties.getMinIo() .getBucketName(); break; + case AWSS3: + defaultBucketName = ossProperties.getAwsS3() + .getBucketName(); + break; default: defaultBucketName = MagicConsts.MAGIC; break; diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/OssProperties.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/OssProperties.java index 32e8843..8a72af2 100644 --- a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/OssProperties.java +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/OssProperties.java @@ -49,6 +49,10 @@ public class OssProperties { * MinIO */ private MinIoProperties minIo = new MinIoProperties(); + /** + * AwsS3 + */ + private AwsS3Properties awsS3 = new AwsS3Properties(); /** * 阿里云 OSS 配置 @@ -104,6 +108,24 @@ public static class QiNiuCloudProperties extends CommonProperties { public static class MinIoProperties extends CommonProperties { } + /** + * AwsS3 配置 + */ + @Data + @EqualsAndHashCode(callSuper = true) + public static class AwsS3Properties extends CommonProperties { + /** + * 是否使用 https + */ + private Boolean https = false; + + /** + * 设置区,自建服务,可不填 + * the region to use for SigV4 signing of requests (e.g. us-west-1) + */ + private String region; + } + /** * 通用配置 */ diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/awss3/AwsS3AutoConfiguration.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/awss3/AwsS3AutoConfiguration.java new file mode 100644 index 0000000..afd16d8 --- /dev/null +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/awss3/AwsS3AutoConfiguration.java @@ -0,0 +1,90 @@ +/* + * Copyright (c) 2019-2029, xkcoding & Yangkai.Shen & 沈扬凯 (237497819@qq.com & xkcoding.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xkcoding.magic.oss.autoconfigure.awss3; + +import com.amazonaws.ClientConfiguration; +import com.amazonaws.Protocol; +import com.amazonaws.auth.AWSStaticCredentialsProvider; +import com.amazonaws.auth.BasicAWSCredentials; +import com.amazonaws.client.builder.AwsClientBuilder; +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.AmazonS3ClientBuilder; +import com.xkcoding.magic.oss.autoconfigure.OssAutoConfiguration; +import com.xkcoding.magic.oss.autoconfigure.OssProperties; +import com.xkcoding.magic.oss.support.awss3.AwsS3Template; +import com.xkcoding.magic.oss.support.rule.OssRule; +import lombok.RequiredArgsConstructor; +import lombok.SneakyThrows; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.autoconfigure.AutoConfigureAfter; +import org.springframework.boot.autoconfigure.condition.ConditionalOnBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; +import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + +/** + *

+ * 亚马逊 S3 存储自动装配类 + *

+ * + * @author harrylee + * @date Created in 2020/5/15 15:25 + */ +@Configuration +@RequiredArgsConstructor(onConstructor_ = @Autowired) +@AutoConfigureAfter(OssAutoConfiguration.class) +@ConditionalOnProperty(value = "magic.oss.aws-s3.enabled", havingValue = "true") +public class AwsS3AutoConfiguration { + private final OssProperties ossProperties; + + @Bean + @SneakyThrows + @ConditionalOnMissingBean + public AmazonS3 awsS3Client() { + // 设置 AccessKey SecretKey + AWSStaticCredentialsProvider awsStaticCredentialsProvider = new AWSStaticCredentialsProvider( + new BasicAWSCredentials(ossProperties.getAwsS3() + .getAccessKey(), ossProperties.getAwsS3() + .getSecretKey())); + + // 设置 Client + ClientConfiguration clientConfiguration = new ClientConfiguration() + .withProtocol(ossProperties.getAwsS3() + .getHttps() ? Protocol.HTTPS : Protocol.HTTP) + .withRequestTimeout(2000); + + // 设置 Endpoint + AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration( + ossProperties.getAwsS3().getEndpoint(), + ossProperties.getAwsS3().getRegion()); + + return AmazonS3ClientBuilder.standard() + .withCredentials(awsStaticCredentialsProvider) + .withClientConfiguration(clientConfiguration) + .withPathStyleAccessEnabled(true) + .withEndpointConfiguration(endpointConfiguration) + .build(); + } + + @Bean + @ConditionalOnMissingBean + @ConditionalOnBean({AmazonS3.class, OssRule.class}) + public AwsS3Template minIoTemplate(AmazonS3 amazonS3, OssRule ossRule) { + return new AwsS3Template(amazonS3, ossProperties, ossRule); + } +} diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/minio/MinIoAutoConfiguration.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/minio/MinIoAutoConfiguration.java index f61bd2a..d653819 100644 --- a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/minio/MinIoAutoConfiguration.java +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/autoconfigure/minio/MinIoAutoConfiguration.java @@ -33,7 +33,7 @@ /** *

- * 七牛云存储自动装配类 + * MinIo 存储自动装配类 *

* * @author yangkai.shen diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/enums/OssType.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/enums/OssType.java index f641a66..0483180 100644 --- a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/enums/OssType.java +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/enums/OssType.java @@ -45,5 +45,9 @@ public enum OssType { /** * MinIO */ - MINIO; + MINIO, + /** + * AwsS3 + */ + AWSS3; } diff --git a/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/support/awss3/AwsS3Template.java b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/support/awss3/AwsS3Template.java new file mode 100644 index 0000000..59f2062 --- /dev/null +++ b/magic-starter-oss/src/main/java/com/xkcoding/magic/oss/support/awss3/AwsS3Template.java @@ -0,0 +1,338 @@ +/* + * Copyright (c) 2019-2029, xkcoding & Yangkai.Shen & 沈扬凯 (237497819@qq.com & xkcoding.com). + *

+ * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0; + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + *

+ * http://www.gnu.org/licenses/lgpl.html + *

+ * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package com.xkcoding.magic.oss.support.awss3; + +import com.amazonaws.services.s3.AmazonS3; +import com.amazonaws.services.s3.model.*; +import com.xkcoding.magic.core.tool.util.StrUtil; +import com.xkcoding.magic.oss.AbstractOssTemplate; +import com.xkcoding.magic.oss.autoconfigure.OssProperties; +import com.xkcoding.magic.oss.enums.OssType; +import com.xkcoding.magic.oss.model.OssFile; +import com.xkcoding.magic.oss.model.OssFileMetaInfo; +import com.xkcoding.magic.oss.support.minio.enums.PolicyType; +import com.xkcoding.magic.oss.support.rule.OssRule; +import lombok.SneakyThrows; +import org.springframework.web.multipart.MultipartFile; + +import java.io.InputStream; +import java.util.List; + +import static com.xkcoding.magic.oss.support.minio.MinIoTemplate.getPolicyType; + +/** + *

+ * AwsS3 操作,参考文档:https://docs.aws.amazon.com/zh_cn/sdk-for-java/v1/developer-guide/examples-s3.html + *

+ * + * @author harrylee + * @date Created in 2020/05/15 15:38 + */ +public class AwsS3Template extends AbstractOssTemplate { + private final AmazonS3 amazonS3; + private final OssProperties ossProperties; + + public AwsS3Template(AmazonS3 amazonS3, OssProperties ossProperties, OssRule ossRule) { + super(ossProperties, ossRule, OssType.AWSS3); + this.amazonS3 = amazonS3; + this.ossProperties = ossProperties; + } + + /** + * 创建 存储桶 + * + * @param bucketName 存储桶名称 + */ + @Override + @SneakyThrows + public void createBucket(String bucketName) { + if (!bucketExists(bucketName)) { + amazonS3.createBucket(getBucketName(bucketName)); + // 这里使用与 minio 一样的存储桶策略 + amazonS3.setBucketPolicy(getBucketName(bucketName), + getPolicyType(getBucketName(bucketName), PolicyType.READ)); + } + } + + /** + * 删除 存储桶 + * + * @param bucketName 存储桶名称 + */ + @Override + @SneakyThrows + public void deleteBucket(String bucketName) { + if (bucketExists(bucketName)) { + amazonS3.deleteBucket(getBucketName(bucketName)); + } + } + + + /** + * 存储桶是否存在 + * + * @param bucketName 存储桶名称 + * @return boolean + */ + @Override + @SneakyThrows + public boolean bucketExists(String bucketName) { + return amazonS3.doesBucketExistV2(bucketName); + } + + /** + * 拷贝文件 + * + * @param sourceBucketName 源存储桶名称 + * @param fileName 存储桶文件名称 + * @param targetBucketName 目标存储桶名称 + */ + @Override + public void copyFile(String sourceBucketName, String fileName, String targetBucketName) { + copyFile(sourceBucketName, fileName, targetBucketName, fileName); + } + + /** + * 拷贝文件,重命名 + * + * @param sourceBucketName 源存储桶名称 + * @param fileName 存储桶文件名称 + * @param targetBucketName 目标存储桶名称 + * @param targetFileName 目标存储桶文件名称 + */ + @Override + @SneakyThrows + public void copyFile(String sourceBucketName, String fileName, String targetBucketName, String targetFileName) { + amazonS3.copyObject(getBucketName(sourceBucketName), fileName, getBucketName(targetBucketName), targetFileName); + } + + /** + * 获取文件元信息 + * + * @param fileName 存储桶文件名称 + * @return 文件元信息 + */ + @Override + public OssFileMetaInfo getFileMetaInfo(String fileName) { + return getFileMetaInfo(getBucketName(), fileName); + } + + /** + * 获取文件元信息 + * + * @param bucketName 存储桶名称 + * @param fileName 存储桶文件名称 + * @return 文件元信息 + */ + @Override + @SneakyThrows + public OssFileMetaInfo getFileMetaInfo(String bucketName, String fileName) { + final ObjectMetadata objectMetadata = amazonS3.getObjectMetadata(new GetObjectMetadataRequest(getBucketName(bucketName), fileName)); + OssFileMetaInfo metaInfo = new OssFileMetaInfo(); + metaInfo.setName(fileName); + metaInfo.setLink(getFileLink(metaInfo.getName())); + metaInfo.setHash(objectMetadata.getContentMD5()); + metaInfo.setLength(objectMetadata.getContentLength()); + metaInfo.setUploadTime(objectMetadata.getLastModified()); + metaInfo.setContentType(objectMetadata.getContentType()); + return metaInfo; + } + + /** + * 获取文件相对路径 + * + * @param fileName 存储桶对象名称 + * @return 文件相对路径 + */ + @Override + public String getFilePath(String fileName) { + return getBucketName().concat(StrUtil.SLASH) + .concat(fileName); + } + + /** + * 获取文件相对路径 + * + * @param bucketName 存储桶名称 + * @param fileName 存储桶对象名称 + * @return 文件相对路径 + */ + @Override + public String getFilePath(String bucketName, String fileName) { + return getBucketName(bucketName).concat(StrUtil.SLASH) + .concat(fileName); + } + + /** + * 获取文件地址 + * + * @param fileName 存储桶对象名称 + * @return 文件地址 + */ + @Override + public String getFileLink(String fileName) { + return ossProperties.getMinIo() + .getEndpoint() + .concat(StrUtil.SLASH) + .concat(getBucketName()) + .concat(StrUtil.SLASH) + .concat(fileName); + } + + /** + * 获取文件地址 + * + * @param bucketName 存储桶名称 + * @param fileName 存储桶对象名称 + * @return 文件地址 + */ + @Override + public String getFileLink(String bucketName, String fileName) { + return ossProperties.getAwsS3() + .getEndpoint() + .concat(StrUtil.SLASH) + .concat(getBucketName(bucketName)) + .concat(StrUtil.SLASH) + .concat(fileName); + } + + /** + * 上传文件 + * + * @param file 上传文件类 + * @return 文件信息 + */ + @Override + public OssFile uploadFile(MultipartFile file) { + return uploadFile(file.getOriginalFilename(), file); + + } + + /** + * 上传文件 + * + * @param fileName 上传文件名 + * @param file 上传文件类 + * @return 文件信息 + */ + @Override + public OssFile uploadFile(String fileName, MultipartFile file) { + return uploadFile(getBucketName(), fileName, file); + } + + /** + * 上传文件 + * + * @param bucketName 存储桶名称 + * @param fileName 上传文件名 + * @param file 上传文件类 + * @return 文件信息 + */ + @Override + @SneakyThrows + public OssFile uploadFile(String bucketName, String fileName, MultipartFile file) { + return uploadFile(getBucketName(bucketName), fileName, file.getInputStream()); + } + + /** + * 上传文件 + * + * @param fileName 存储桶对象名称 + * @param stream 文件流 + * @return 文件信息 + */ + @Override + public OssFile uploadFile(String fileName, InputStream stream) { + return uploadFile(getBucketName(), fileName, stream); + } + + /** + * 上传文件 + * + * @param bucketName 存储桶名称 + * @param fileName 存储桶对象名称 + * @param stream 文件流 + * @return 文件信息 + */ + @Override + @SneakyThrows + public OssFile uploadFile(String bucketName, String fileName, InputStream stream) { + // 创建存储桶 + createBucket(bucketName); + + ObjectMetadata om = new ObjectMetadata(); + // 获取 oss 存储文件名 + String key = getFileName(fileName); + + om.setContentLength(stream.available()); + PutObjectRequest cannedAcl = new PutObjectRequest(bucketName, key, stream, om) + .withCannedAcl(CannedAccessControlList.PublicRead); + amazonS3.putObject(cannedAcl); + + OssFile ossFile = new OssFile(); + ossFile.setName(key); + ossFile.setOriginalName(fileName); + ossFile.setLink(getFileLink(bucketName, key)); + return ossFile; + } + + /** + * 删除文件 + * + * @param fileName 存储桶对象名称 + */ + @Override + public void deleteFile(String fileName) { + deleteFile(getBucketName(), fileName); + } + + /** + * 批量删除文件 + * + * @param bucketName 存储桶名称 + * @param fileName 存储桶对象名称 + */ + @Override + @SneakyThrows + public void deleteFile(String bucketName, String fileName) { + amazonS3.deleteObject(getBucketName(bucketName), fileName); + } + + /** + * 批量删除文件 + * + * @param fileNames 存储桶对象名称集合 + */ + @Override + public void deleteFiles(List fileNames) { + deleteFiles(getBucketName(), fileNames); + } + + /** + * 批量删除文件 + * + * @param bucketName 存储桶名称 + * @param fileNames 存储桶对象名称集合 + */ + @Override + @SneakyThrows + public void deleteFiles(String bucketName, List fileNames) { + DeleteObjectsRequest dor = new DeleteObjectsRequest(getBucketName(bucketName)) + .withKeys(fileNames.toArray(new String[]{})); + amazonS3.deleteObjects(dor); + } +}