Commit 46676a439d22477b9e240c81614cdc594c2dbb94

Authored by YunaiV
1 parent 0885eb7c

feat:【INFRA】文件存储,增加 enablePathStyleAccess 选项

yudao-dependencies/pom.xml
@@ -96,10 +96,8 @@ @@ -96,10 +96,8 @@
96 </dependency> 96 </dependency>
97 <dependency> 97 <dependency>
98 <groupId>software.amazon.awssdk</groupId> 98 <groupId>software.amazon.awssdk</groupId>
99 - <artifactId>bom</artifactId> 99 + <artifactId>s3</artifactId>
100 <version>${awssdk.version}</version> 100 <version>${awssdk.version}</version>
101 - <type>pom</type>  
102 - <scope>import</scope>  
103 </dependency> 101 </dependency>
104 102
105 <!-- 业务组件 --> 103 <!-- 业务组件 -->
yudao-module-infra/yudao-module-infra-biz/pom.xml
@@ -120,14 +120,6 @@ @@ -120,14 +120,6 @@
120 <groupId>software.amazon.awssdk</groupId> 120 <groupId>software.amazon.awssdk</groupId>
121 <artifactId>s3</artifactId> 121 <artifactId>s3</artifactId>
122 </dependency> 122 </dependency>
123 - <dependency>  
124 - <groupId>software.amazon.awssdk</groupId>  
125 - <artifactId>auth</artifactId>  
126 - </dependency>  
127 - <dependency>  
128 - <groupId>software.amazon.awssdk</groupId>  
129 - <artifactId>regions</artifactId>  
130 - </dependency>  
131 123
132 <dependency> 124 <dependency>
133 <groupId>org.apache.tika</groupId> 125 <groupId>org.apache.tika</groupId>
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
@@ -5,10 +5,12 @@ import cn.hutool.core.util.StrUtil; @@ -5,10 +5,12 @@ import cn.hutool.core.util.StrUtil;
5 import cn.hutool.http.HttpUtil; 5 import cn.hutool.http.HttpUtil;
6 import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; 6 import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient;
7 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; 7 import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
  8 +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
8 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; 9 import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
9 import software.amazon.awssdk.core.sync.RequestBody; 10 import software.amazon.awssdk.core.sync.RequestBody;
10 import software.amazon.awssdk.regions.Region; 11 import software.amazon.awssdk.regions.Region;
11 import software.amazon.awssdk.services.s3.S3Client; 12 import software.amazon.awssdk.services.s3.S3Client;
  13 +import software.amazon.awssdk.services.s3.S3Configuration;
12 import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; 14 import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
13 import software.amazon.awssdk.services.s3.model.GetObjectRequest; 15 import software.amazon.awssdk.services.s3.model.GetObjectRequest;
14 import software.amazon.awssdk.services.s3.model.PutObjectRequest; 16 import software.amazon.awssdk.services.s3.model.PutObjectRequest;
@@ -26,6 +28,7 @@ import java.time.Duration; @@ -26,6 +28,7 @@ import java.time.Duration;
26 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { 28 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
27 29
28 private S3Client client; 30 private S3Client client;
  31 + private S3Presigner presigner;
29 32
30 public S3FileClient(Long id, S3FileClientConfig config) { 33 public S3FileClient(Long id, S3FileClientConfig config) {
31 super(id, config); 34 super(id, config);
@@ -38,11 +41,23 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -38,11 +41,23 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
38 config.setDomain(buildDomain()); 41 config.setDomain(buildDomain());
39 } 42 }
40 // 初始化 S3 客户端 43 // 初始化 S3 客户端
  44 + Region region = Region.of("us-east-1"); // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错
  45 + AwsCredentialsProvider credentialsProvider = StaticCredentialsProvider.create(
  46 + AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret()));
  47 + URI endpoint = URI.create(buildEndpoint());
  48 + S3Configuration serviceConfiguration = S3Configuration.builder() // Path-style 访问
  49 + .pathStyleAccessEnabled(Boolean.TRUE.equals(config.getEnablePathStyleAccess())).build();
41 client = S3Client.builder() 50 client = S3Client.builder()
42 - .credentialsProvider(buildCredentials())  
43 - .region(Region.of("us-east-1")) // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错  
44 - .endpointOverride(URI.create(buildEndpoint()))  
45 - //.serviceConfiguration(S3Configuration.builder().pathStyleAccessEnabled(true).build()) // Path-style 访问 51 + .credentialsProvider(credentialsProvider)
  52 + .region(region)
  53 + .endpointOverride(endpoint)
  54 + .serviceConfiguration(serviceConfiguration)
  55 + .build();
  56 + presigner = S3Presigner.builder()
  57 + .credentialsProvider(credentialsProvider)
  58 + .region(region)
  59 + .endpointOverride(endpoint)
  60 + .serviceConfiguration(serviceConfiguration)
46 .build(); 61 .build();
47 } 62 }
48 63
@@ -55,7 +70,6 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -55,7 +70,6 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
55 .contentType(type) 70 .contentType(type)
56 .contentLength((long) content.length) 71 .contentLength((long) content.length)
57 .build(); 72 .build();
58 -  
59 // 上传文件 73 // 上传文件
60 client.putObject(putRequest, RequestBody.fromBytes(content)); 74 client.putObject(putRequest, RequestBody.fromBytes(content));
61 // 拼接返回路径 75 // 拼接返回路径
@@ -77,42 +91,27 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -77,42 +91,27 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
77 .bucket(config.getBucket()) 91 .bucket(config.getBucket())
78 .key(path) 92 .key(path)
79 .build(); 93 .build();
80 -  
81 return IoUtil.readBytes(client.getObject(getRequest)); 94 return IoUtil.readBytes(client.getObject(getRequest));
82 } 95 }
83 96
84 @Override 97 @Override
85 public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) { 98 public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) {
86 - return new FilePresignedUrlRespDTO(getPresignedUrl(path, Duration.ofMinutes(10)), config.getDomain() + "/" + path);  
87 - }  
88 -  
89 - /**  
90 - * 动态创建 S3Presigner  
91 - *  
92 - * @return S3Presigner  
93 - */  
94 - private S3Presigner createPresigner() {  
95 - return S3Presigner.builder()  
96 - .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret())))  
97 - .region(Region.of("us-east-1")) // 必须填,但填什么都行,常见的值有 "us-east-1",不填会报错  
98 - .endpointOverride(URI.create(buildEndpoint()))  
99 - .build(); 99 + Duration expiration = Duration.ofHours(24);
  100 + return new FilePresignedUrlRespDTO(getPresignedUrl(path, expiration), config.getDomain() + "/" + path);
100 } 101 }
101 102
102 /** 103 /**
103 * 生成动态的预签名上传 URL 104 * 生成动态的预签名上传 URL
104 * 105 *
105 * @param path 相对路径 106 * @param path 相对路径
106 - * @param duration 过期时间 107 + * @param expiration 过期时间
107 * @return 生成的上传 URL 108 * @return 生成的上传 URL
108 */ 109 */
109 - public String getPresignedUrl(String path, Duration duration) {  
110 - try (S3Presigner presigner = createPresigner()) {  
111 - return presigner.presignPutObject(PutObjectPresignRequest.builder()  
112 - .signatureDuration(duration)  
113 - .putObjectRequest(b -> b.bucket(config.getBucket()).key(path))  
114 - .build()).url().toString();  
115 - } 110 + private String getPresignedUrl(String path, Duration expiration) {
  111 + return presigner.presignPutObject(PutObjectPresignRequest.builder()
  112 + .signatureDuration(expiration)
  113 + .putObjectRequest(b -> b.bucket(config.getBucket()).key(path))
  114 + .build()).url().toString();
116 } 115 }
117 116
118 /** 117 /**
@@ -130,16 +129,6 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -130,16 +129,6 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
130 } 129 }
131 130
132 /** 131 /**
133 - * 基于 config 秘钥,构建 S3 客户端的认证信息  
134 - *  
135 - * @return S3 客户端的认证信息  
136 - */  
137 - private StaticCredentialsProvider buildCredentials() {  
138 - return StaticCredentialsProvider.create(  
139 - AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret()));  
140 - }  
141 -  
142 - /**  
143 * 节点地址补全协议头 132 * 节点地址补全协议头
144 * 133 *
145 * @return 节点地址 134 * @return 节点地址
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClientConfig.java
@@ -67,6 +67,12 @@ public class S3FileClientConfig implements FileClientConfig { @@ -67,6 +67,12 @@ public class S3FileClientConfig implements FileClientConfig {
67 @NotNull(message = "accessSecret 不能为空") 67 @NotNull(message = "accessSecret 不能为空")
68 private String accessSecret; 68 private String accessSecret;
69 69
  70 + /**
  71 + * 是否启用 PathStyle 访问
  72 + */
  73 + @NotNull(message = "enablePathStyleAccess 不能为空")
  74 + private Boolean enablePathStyleAccess;
  75 +
70 @SuppressWarnings("RedundantIfStatement") 76 @SuppressWarnings("RedundantIfStatement")
71 @AssertTrue(message = "domain 不能为空") 77 @AssertTrue(message = "domain 不能为空")
72 @JsonIgnore 78 @JsonIgnore