Browse Source

feat: 跟新为阿里云oss

master
yuanjs@qutke.com 2 months ago
parent
commit
f5b380ace7
  1. 6225
      README.md
  2. 112
      src/main/java/org/ycloud/aipan/component/OSSFileStoreEngine.java
  3. 28
      src/main/java/org/ycloud/aipan/config/AliOssConfig.java
  4. 20
      src/main/java/org/ycloud/aipan/config/AmazonS3Config.java
  5. 8
      src/main/resources/application.yml
  6. 6
      src/test/java/org/ycloud/aipan/AmazonS3ClientTests.java

6225
README.md

File diff suppressed because it is too large

112
src/main/java/org/ycloud/aipan/component/OSSFileStoreEngine.java

@ -1,68 +1,160 @@
package org.ycloud.aipan.component; package org.ycloud.aipan.component;
import com.amazonaws.services.s3.model.Bucket; import com.amazonaws.services.s3.AmazonS3Client;
import com.amazonaws.services.s3.model.S3ObjectSummary; import com.amazonaws.services.s3.model.*;
import jakarta.annotation.Resource;
import jakarta.servlet.http.HttpServletResponse; import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.apache.tomcat.util.http.fileupload.IOUtils;
import org.springframework.context.annotation.Primary;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile; import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
@Slf4j
//@Component @Component
@Primary
public class OSSFileStoreEngine implements StoreEngine { public class OSSFileStoreEngine implements StoreEngine {
@Resource
private AmazonS3Client amazonS3Client;
// 缓存 bucket 存在性
private final Map<String, Boolean> bucketCache = new ConcurrentHashMap<>();
@Override @Override
public boolean bucketExists(String bucketName) { public boolean bucketExists(String bucketName) {
return false; return bucketCache.computeIfAbsent(bucketName, key -> amazonS3Client.doesBucketExistV2(key));
} }
@Override @Override
public boolean removeBucket(String bucketName) { public boolean removeBucket(String bucketName) {
if (bucketExists(bucketName)) {
try {
amazonS3Client.deleteBucket(bucketName);
bucketCache.remove(bucketName);
return true;
} catch (Exception e) {
log.error("删除 bucket {} 失败: {}", bucketName, e.getMessage(), e);
}
}
return false; return false;
} }
@Override @Override
public void createBucket(String bucketName) { public void createBucket(String bucketName) {
log.info("创建 bucket: {}", bucketName);
if (!bucketExists(bucketName)) {
try {
amazonS3Client.createBucket(bucketName);
bucketCache.put(bucketName, true);
} catch (Exception e) {
log.error("创建 bucket {} 失败: {}", bucketName, e.getMessage(), e);
}
} else {
log.info("bucket 已存在");
}
} }
@Override @Override
public List<Bucket> getAllBucket() { public List<Bucket> getAllBucket() {
return List.of(); return amazonS3Client.listBuckets();
} }
@Override @Override
public List<S3ObjectSummary> listObjects(String bucketName) { public List<S3ObjectSummary> listObjects(String bucketName) {
if (bucketExists(bucketName)) {
return amazonS3Client.listObjects(bucketName).getObjectSummaries();
}
return List.of(); return List.of();
} }
@Override @Override
public boolean doesObjectExist(String bucketName, String objectKey) { public boolean doesObjectExist(String bucketName, String objectKey) {
if (bucketExists(bucketName)) {
return amazonS3Client.doesObjectExist(bucketName, objectKey);
}
return false; return false;
} }
@Override @Override
public boolean upload(String bucketName, String objectKey, String localFileName) { public boolean upload(String bucketName, String objectKey, String localFileName) {
if (bucketExists(bucketName)) {
try {
amazonS3Client.putObject(bucketName, objectKey, new File(localFileName));
return true;
} catch (Exception e) {
log.error("上传文件到 bucket {} 失败: {}", bucketName, e.getMessage(), e);
}
}
return false; return false;
} }
@Override @Override
public boolean upload(String bucketName, String objectKey, MultipartFile file) { public boolean upload(String bucketName, String objectKey, MultipartFile file) {
if (bucketExists(bucketName)) {
try {
ObjectMetadata objectMetadata = new ObjectMetadata();
objectMetadata.setContentType(file.getContentType());
objectMetadata.setContentLength(file.getSize());
amazonS3Client.putObject(bucketName, objectKey, file.getInputStream(), objectMetadata);
return true;
} catch (Exception e) {
log.error("上传文件到 bucket {} 失败: {}", bucketName, e.getMessage(), e);
}
}
return false; return false;
} }
@Override @Override
public boolean delete(String bucketName, String objectKey) { public boolean delete(String bucketName, String objectKey) {
if (bucketExists(bucketName)) {
try {
amazonS3Client.deleteObject(bucketName, objectKey);
return true;
} catch (Exception e) {
log.error("删除 bucket {} 中的对象 {} 失败: {}", bucketName, objectKey, e.getMessage(), e);
}
}
return false; return false;
} }
@Override @Override
public String getDownloadUrl(String bucketName, String remoteFileName, long timeout, TimeUnit unit) { public String getDownloadUrl(String bucketName, String objectKey, long timeout, TimeUnit unit) {
return ""; try {
Date expiration = new Date(System.currentTimeMillis() + unit.toMillis(timeout));
return amazonS3Client.generatePresignedUrl(bucketName, objectKey, expiration).toString();
} catch (Exception e) {
log.error("生成 bucket {} 中对象 {} 的下载 URL 失败: {}", bucketName, objectKey, e.getMessage(), e);
return null;
}
} }
@Override @Override
public void download2Response(String bucketName, String objectKey, HttpServletResponse response) { public void download2Response(String bucketName, String objectKey, HttpServletResponse response) {
try (S3Object s3Object = amazonS3Client.getObject(bucketName, objectKey)) {
response.setHeader("Content-Disposition", "attachment;filename=" + objectKey.substring(objectKey.lastIndexOf("/") + 1));
response.setContentType("application/force-download");
response.setCharacterEncoding("UTF-8");
IOUtils.copy(s3Object.getObjectContent(), response.getOutputStream());
} catch (IOException e) {
log.error("下载 bucket {} 中对象 {} 失败: {}", bucketName, objectKey, e.getMessage(), e);
} }
} }
// 拼接路径
// public static void main(String[] args) {
// String fileSeparator = System.getProperty("file.separator");
// System.out.println("dir" + fileSeparator + "time" + fileSeparator + "index.html");
// String files = String.join("/", List.of("dir", "time", "index.html"));
// System.out.println(files);
// Path file = Paths.get("dir", "time", "index.html");
// System.out.println(file);
// }
}

28
src/main/java/org/ycloud/aipan/config/AliOssConfig.java

@ -0,0 +1,28 @@
package org.ycloud.aipan.config;
import lombok.Data;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
@Data
@Component
@ConfigurationProperties(prefix = "oss")
public class AliOssConfig {
@Value("endpoint")
private String endpoint;
@Value("access-key")
private String accessKey;
@Value("access-secret")
private String accessSecret;
@Value("bucket-name")
private String bucketName;
// 预签名url过期时间(ms)
private Long PRE_SIGN_URL_EXPIRE = 60 * 10 * 1000L;
}

20
src/main/java/org/ycloud/aipan/config/AmazonS3Config.java

@ -5,6 +5,7 @@ import com.amazonaws.Protocol;
import com.amazonaws.auth.AWSCredentials; import com.amazonaws.auth.AWSCredentials;
import com.amazonaws.auth.AWSStaticCredentialsProvider; import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials; import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.auth.BasicSessionCredentials;
import com.amazonaws.client.builder.AwsClientBuilder; import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.regions.Regions; import com.amazonaws.regions.Regions;
import com.amazonaws.services.s3.AmazonS3; import com.amazonaws.services.s3.AmazonS3;
@ -20,8 +21,10 @@ import org.springframework.context.annotation.Configuration;
public class AmazonS3Config { public class AmazonS3Config {
// 注入Minio配置类,用于获取访问密钥和Endpoint等信息 // 注入Minio配置类,用于获取访问密钥和Endpoint等信息
// @Resource
// private MinioConfig minioConfig;
@Resource @Resource
private MinioConfig minioConfig; private AliOssConfig aliOssConfig;
/** /**
* 创建并配置Amazon S3客户端 * 创建并配置Amazon S3客户端
@ -37,20 +40,19 @@ public class AmazonS3Config {
// 设置网络访问超时时间 // 设置网络访问超时时间
config.setConnectionTimeout(5000); config.setConnectionTimeout(5000);
config.setUseExpectContinue(true); config.setUseExpectContinue(true);
// 使用配置中的访问密钥和秘密密钥创建AWS凭证
// 使用Minio配置中的访问密钥和秘密密钥创建AWS凭证 AWSCredentials credentials = new BasicAWSCredentials(aliOssConfig.getAccessKey(), aliOssConfig.getAccessSecret());
AWSCredentials credentials = new BasicAWSCredentials(minioConfig.getAccessKey(), minioConfig.getAccessSecret());
// 设置Endpoint // 设置Endpoint
AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder
.EndpointConfiguration(minioConfig.getEndpoint(), Regions.US_EAST_1.name()); .EndpointConfiguration(aliOssConfig.getEndpoint(), Regions.US_EAST_1.name());
// 使用以上配置创建并返回Amazon S3客户端实例 // 使用以上配置创建并返回Amazon S3客户端实例
return AmazonS3ClientBuilder.standard() return AmazonS3ClientBuilder.standard()
.withClientConfiguration(config) .withClientConfiguration(config)
.withCredentials(new AWSStaticCredentialsProvider(credentials)) .withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(endpointConfiguration) .withEndpointConfiguration(endpointConfiguration)
.withPathStyleAccessEnabled(true).build(); .withPathStyleAccessEnabled(false) // mino设置为true,oss设置为false
} .build();
} }
}

8
src/main/resources/application.yml

@ -45,3 +45,11 @@ minio:
access-secret: minio_123456 access-secret: minio_123456
bucket-name: ai-pan bucket-name: ai-pan
avatar-bucket-name: avatar avatar-bucket-name: avatar
oss:
endpoint: oss-cn-hangzhou.aliyuncs.com
access-key: LTAI5tRQFFPQWHPZksM9XGHG
access-secret: z4ZSJffdH525Konxz7LBxOSAZP2BXN
bucket-name: forward-tech

6
src/test/java/org/ycloud/aipan/AmazonS3ClientTests.java

@ -32,7 +32,7 @@ class AmazonS3ClientTests {
*/ */
@Test @Test
public void testBucketExists() { public void testBucketExists() {
boolean bucketExist = amazonS3Client.doesBucketExist("ai-pan1"); boolean bucketExist = amazonS3Client.doesBucketExist("forward-tech");
log.info("bucket是否存在:{}", bucketExist); log.info("bucket是否存在:{}", bucketExist);
} }
@ -51,7 +51,7 @@ class AmazonS3ClientTests {
*/ */
@Test @Test
public void testDeleteBucket() { public void testDeleteBucket() {
String bucketName = "ai-pan1"; String bucketName = "tjcz-app";
amazonS3Client.deleteBucket(bucketName); amazonS3Client.deleteBucket(bucketName);
} }
@ -171,7 +171,7 @@ class AmazonS3ClientTests {
// 计算预签名url的过期日期 // 计算预签名url的过期日期
Date expireDate = DateUtil.offsetMillisecond(new Date(), (int) PRE_SIGN_URL_EXPIRE); Date expireDate = DateUtil.offsetMillisecond(new Date(), (int) PRE_SIGN_URL_EXPIRE);
// 创建生成预签名url的请求,并设置过期时间和HTTP方法, withMethod是生成的URL访问方式 // 创建生成预签名url的请求,并设置过期时间和HTTP方法, withMethod是生成的URL访问方式
GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest("avatar", "/2025/3/22/999ae223-cf98-4891-a7da-e3ab1d618719.jpg") GeneratePresignedUrlRequest request = new GeneratePresignedUrlRequest("forward-tech", "confluence/confluence_01.png")
.withExpiration(expireDate).withMethod(HttpMethod.GET); .withExpiration(expireDate).withMethod(HttpMethod.GET);
// 生成预签名url // 生成预签名url
URL preSignedUrl = amazonS3Client.generatePresignedUrl(request); URL preSignedUrl = amazonS3Client.generatePresignedUrl(request);

Loading…
Cancel
Save