aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/StorageConfig.java
@@ -8,92 +8,8 @@ @ConfigurationProperties(prefix = "aiflowy.storage") public class StorageConfig { //支持 local、minio... //支持 local、s3、xfile... private String type; /** * 域名 */ private String endpoint; /** * 自定义域名 */ private String domain; /** * 前缀 */ private String prefix; /** * ACCESS_KEY */ private String accessKey; /** * SECRET_KEY */ private String secretKey; /** * 存储空间名 */ private String bucketName; /** * 存储区域 */ private String region; /** * 是否https(1=是) */ private int isHttps = 1; /** * 桶权限类型(0private 1public 2custom) */ private int accessPolicy; public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public int getIsHttps() { return isHttps; } public void setIsHttps(int isHttps) { this.isHttps = isHttps; } public int getAccessPolicy() { return accessPolicy; } public void setAccessPolicy(int accessPolicy) { this.accessPolicy = accessPolicy; } public String getType() { return type; @@ -103,39 +19,7 @@ this.type = type; } public String getEndpoint() { return endpoint; } public void setEndpoint(String endpoint) { this.endpoint = endpoint; } public String getAccessKey() { return accessKey; } public void setAccessKey(String accessKey) { this.accessKey = accessKey; } public String getSecretKey() { return secretKey; } public void setSecretKey(String secretKey) { this.secretKey = secretKey; } public String getBucketName() { return bucketName; } public void setBucketName(String bucketName) { this.bucketName = bucketName; } public static StorageConfig getInstance(){ public static StorageConfig getInstance() { return SpringContextUtil.getBean(StorageConfig.class); } aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/impl/S3FileStorageServiceImpl.java
@@ -2,24 +2,17 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.context.event.ApplicationReadyEvent; import org.springframework.context.event.EventListener; import org.springframework.core.io.ClassPathResource; import org.springframework.stereotype.Component; import org.springframework.util.StringUtils; import org.springframework.web.multipart.MultipartFile; import tech.aiflowy.common.filestorage.FileStorageService; import tech.aiflowy.common.filestorage.OssClient; import tech.aiflowy.common.filestorage.StorageConfig; import tech.aiflowy.common.util.DateUtil; import tech.aiflowy.common.filestorage.s3.S3Client; import tech.aiflowy.common.filestorage.s3.S3StorageConfig; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.util.Date; import java.util.UUID; @Component("s3") @@ -27,13 +20,13 @@ private static final Logger LOG = LoggerFactory.getLogger(S3FileStorageServiceImpl.class); private OssClient client; private S3Client client; @EventListener(ApplicationReadyEvent.class) public void init() { StorageConfig instance = StorageConfig.getInstance(); if (!"local".equals(instance.getType())){ client = new OssClient(instance); if ("s3".equals(instance.getType())) { client = new S3Client(); } } @@ -41,8 +34,7 @@ @Override public String save(MultipartFile file) { try { String path = client.upload(file); return path; return client.upload(file); } catch (Exception e) { throw new RuntimeException(e.getMessage()); } aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/impl/XFileStorageServiceImpl.java
@@ -12,11 +12,12 @@ import org.springframework.web.multipart.MultipartFile; import tech.aiflowy.common.filestorage.FileStorageService; import javax.annotation.Resource; import java.io.ByteArrayInputStream; import java.io.InputStream; @Component("xFileStorageServiceImpl") @Component("xfile") @ConditionalOnBean(org.dromara.x.file.storage.core.FileStorageService.class) public class XFileStorageServiceImpl implements FileStorageService { @@ -26,7 +27,7 @@ @Value("${aiflowy.storage.x-file-storage.platform}") private String platform; @Autowired @Resource private org.dromara.x.file.storage.core.FileStorageService xFileStorageService; @EventListener(ApplicationReadyEvent.class) aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/s3/AccessPolicyType.java
File was renamed from aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/AccessPolicyType.java @@ -1,4 +1,4 @@ package tech.aiflowy.common.filestorage; package tech.aiflowy.common.filestorage.s3; import com.amazonaws.services.s3.model.CannedAccessControlList; aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/s3/PolicyType.java
File was renamed from aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/PolicyType.java @@ -1,4 +1,4 @@ package tech.aiflowy.common.filestorage; package tech.aiflowy.common.filestorage.s3; aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/s3/S3Client.java
File was renamed from aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/OssClient.java @@ -1,4 +1,4 @@ package tech.aiflowy.common.filestorage; package tech.aiflowy.common.filestorage.s3; import cn.hutool.core.date.DateField; @@ -7,12 +7,10 @@ import cn.hutool.core.io.IoUtil; import cn.hutool.core.io.file.FileNameUtil; import cn.hutool.core.util.IdUtil; import cn.hutool.core.util.ObjectUtil; import cn.hutool.core.util.StrUtil; import com.amazonaws.ClientConfiguration; import com.amazonaws.HttpMethod; import com.amazonaws.Protocol; import com.amazonaws.SdkClientException; import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentialsProvider; import com.amazonaws.auth.AWSStaticCredentialsProvider; @@ -25,6 +23,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.web.multipart.MultipartFile; import tech.aiflowy.common.filestorage.StorageConfig; import java.io.*; import java.net.URL; @@ -33,22 +32,20 @@ /** * S3 存储协议 所有兼容S3协议的云厂商均支持 阿里云 腾讯云 七牛云 minio * * */ public class OssClient { private static final Logger log = LoggerFactory.getLogger(OssClient.class); public class S3Client { private static final Logger log = LoggerFactory.getLogger(S3Client.class); /** * https 状态 */ private final String[] CLOUD_SERVICE = new String[] {"aliyun", "qcloud", "qiniu", "obs"}; private final String[] CLOUD_SERVICE = new String[]{"aliyun", "qcloud", "qiniu", "obs"}; private static final int IS_HTTPS = 1; private final StorageConfig properties; private final S3StorageConfig properties; private final AmazonS3 client; public OssClient(StorageConfig ossProperties) { this.properties = ossProperties; public S3Client() { this.properties = S3StorageConfig.getInstance(); try { AwsClientBuilder.EndpointConfiguration endpointConfig = new AwsClientBuilder.EndpointConfiguration(properties.getEndpoint(), properties.getRegion()); @@ -79,6 +76,7 @@ return !StrUtil.containsAny(endpoint, CLOUD_SERVICE); } public void createBucket() { try { String bucketName = properties.getBucketName(); @@ -98,6 +96,7 @@ public void upload(byte[] data, String objectPath, String contentType) { upload(new ByteArrayInputStream(data), objectPath, contentType); } public void upload(InputStream inputStream, String objectPath, String contentType) { if (!(inputStream instanceof ByteArrayInputStream)) { inputStream = new ByteArrayInputStream(IoUtil.readBytes(inputStream)); @@ -152,11 +151,11 @@ } return hexString.toString(); // 返回字符串类型的哈希值 } /** * 根据OSS对象存储路径, 从OSS存储删除文件 * * @param objectPath * 文件访问路径 * * @param objectPath 文件访问路径 */ public void delete(String objectPath) { try { @@ -169,9 +168,8 @@ /** * 根据OSS对象存储路径, 获取文件元数据 * * @param objectPath * 文件访问路径(对应OSS存储数据的key) * * @param objectPath 文件访问路径(对应OSS存储数据的key) */ public ObjectMetadata getObjectMetadata(String objectPath) { return client.getObjectMetadata(properties.getBucketName(), objectPath); @@ -179,9 +177,8 @@ /** * 根据OSS对象存储路径, 获取文件内容 * * @param objectPath * 文件访问路径 * * @param objectPath 文件访问路径 * @return 文件内容 */ public InputStream getObjectContent(String objectPath) { @@ -190,13 +187,10 @@ /** * 根据OSS对象存储路径, 获取文件内容(指定文件字节范围) * * @param objectPath * 文件访问路径 * @param start * 起始字节 * @param end * 结束字节 * * @param objectPath 文件访问路径 * @param start 起始字节 * @param end 结束字节 * @return 文件内容(指定文件字节范围) */ public InputStream getObjectContent(String objectPath, Long start, Long end) { @@ -219,7 +213,7 @@ /** * 获取OSS基础路径 * * * @return 基础路径 */ public String getBasePath() { @@ -235,7 +229,7 @@ /** * 根据访问url, 获取OSS对象存储路径 * * * @return OSS对象存储路径 */ public String getObjectPath(String url) { @@ -247,9 +241,8 @@ /** * 根据OSS对象存储路径, 获取访问url * * @param objectPath * 文件访问路径 * * @param objectPath 文件访问路径 * @return 访问url */ public String getUrl(String objectPath) { @@ -269,11 +262,9 @@ /** * 根据前缀和后缀, 生成OSS对象存储路径 * * @param prefix * 前缀 * @param suffix * 后缀 * * @param prefix 前缀 * @param suffix 后缀 * @return OSS对象存储路径 */ public String getObjectPath(String prefix, String suffix) { @@ -290,15 +281,13 @@ /** * 获取私有URL链接 * * @param objectKey * 对象KEY * @param second * 授权时间 * @param objectKey 对象KEY * @param second 授权时间 */ public String getPrivateUrl(String objectKey, Integer second) { GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey).withMethod(HttpMethod.GET) .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey).withMethod(HttpMethod.GET) .withExpiration(new Date(System.currentTimeMillis() + 1000L * second)); URL url = client.generatePresignedUrl(generatePresignedUrlRequest); return url.toString(); } @@ -334,7 +323,7 @@ builder.append("\"\n},\n"); if (policyType == PolicyType.READ) { builder.append( "{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); "{\n\"Action\": [\n\"s3:ListBucket\"\n],\n\"Effect\": \"Deny\",\n\"Principal\": \"*\",\n\"Resource\": \"arn:aws:s3:::"); builder.append(bucketName); builder.append("\"\n},\n"); } @@ -342,11 +331,11 @@ switch (policyType) { case WRITE: builder.append( "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"); "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"); break; case READ_WRITE: builder.append( "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"); "[\n\"s3:AbortMultipartUpload\",\n\"s3:DeleteObject\",\n\"s3:GetObject\",\n\"s3:ListMultipartUploadParts\",\n\"s3:PutObject\"\n],\n"); break; default: builder.append("\"s3:GetObject\",\n"); @@ -360,8 +349,7 @@ /** * @param path * 相对路径 * @param path 相对路径 * @return 文件内容 * @throws Exception * @description 获取文件内容 @@ -383,13 +371,12 @@ /** * 获取私有URL链接 * * @param objectKey * 对象KEY * @param objectKey 对象KEY */ public String getPreSignedAccessUrl(String objectKey, DateField dateField, Integer time) { GeneratePresignedUrlRequest generatePresignedUrlRequest = new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey).withMethod(HttpMethod.GET) .withExpiration(DateUtil.offset(DateUtil.date(), dateField, time)); new GeneratePresignedUrlRequest(properties.getBucketName(), objectKey).withMethod(HttpMethod.GET) .withExpiration(DateUtil.offset(DateUtil.date(), dateField, time)); URL url = client.generatePresignedUrl(generatePresignedUrlRequest); return url.toString(); } aiflowy-commons/aiflowy-common-file-storage/src/main/java/tech/aiflowy/common/filestorage/s3/S3StorageConfig.java
New file @@ -0,0 +1,131 @@ package tech.aiflowy.common.filestorage.s3; import org.springframework.boot.context.properties.ConfigurationProperties; import org.springframework.context.annotation.Configuration; import tech.aiflowy.common.util.SpringContextUtil; @Configuration @ConfigurationProperties(prefix = "aiflowy.storage.s3") public class S3StorageConfig { /** * 域名 */ private String endpoint; /** * 自定义域名 */ private String domain; /** * 前缀 */ private String prefix; /** * ACCESS_KEY */ private String accessKey; /** * SECRET_KEY */ private String secretKey; /** * 存储空间名 */ private String bucketName; /** * 存储区域 */ private String region; /** * 是否https(1=是) */ private int isHttps = 1; /** * 桶权限类型(0private 1public 2custom) */ private int accessPolicy; public String getDomain() { return domain; } public void setDomain(String domain) { this.domain = domain; } public String getPrefix() { return prefix; } public void setPrefix(String prefix) { this.prefix = prefix; } public String getRegion() { return region; } public void setRegion(String region) { this.region = region; } public int getIsHttps() { return isHttps; } public void setIsHttps(int isHttps) { this.isHttps = isHttps; } public int getAccessPolicy() { return accessPolicy; } public void setAccessPolicy(int accessPolicy) { this.accessPolicy = accessPolicy; } public String getEndpoint() { return endpoint; } public void setEndpoint(String endpoint) { this.endpoint = endpoint; } public String getAccessKey() { return accessKey; } public void setAccessKey(String accessKey) { this.accessKey = accessKey; } public String getSecretKey() { return secretKey; } public void setSecretKey(String secretKey) { this.secretKey = secretKey; } public String getBucketName() { return bucketName; } public void setBucketName(String bucketName) { this.bucketName = bucketName; } public static S3StorageConfig getInstance(){ return SpringContextUtil.getBean(S3StorageConfig.class); } }