Commit 46676a439d22477b9e240c81614cdc594c2dbb94
1 parent
0885eb7c
feat:【INFRA】文件存储,增加 enablePathStyleAccess 选项
Showing
4 changed files
with
34 additions
and
49 deletions
yudao-dependencies/pom.xml
| ... | ... | @@ -96,10 +96,8 @@ |
| 96 | 96 | </dependency> |
| 97 | 97 | <dependency> |
| 98 | 98 | <groupId>software.amazon.awssdk</groupId> |
| 99 | - <artifactId>bom</artifactId> | |
| 99 | + <artifactId>s3</artifactId> | |
| 100 | 100 | <version>${awssdk.version}</version> |
| 101 | - <type>pom</type> | |
| 102 | - <scope>import</scope> | |
| 103 | 101 | </dependency> |
| 104 | 102 | |
| 105 | 103 | <!-- 业务组件 --> | ... | ... |
yudao-module-infra/yudao-module-infra-biz/pom.xml
| ... | ... | @@ -120,14 +120,6 @@ |
| 120 | 120 | <groupId>software.amazon.awssdk</groupId> |
| 121 | 121 | <artifactId>s3</artifactId> |
| 122 | 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 | 124 | <dependency> |
| 133 | 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 | 5 | import cn.hutool.http.HttpUtil; |
| 6 | 6 | import cn.iocoder.yudao.module.infra.framework.file.core.client.AbstractFileClient; |
| 7 | 7 | import software.amazon.awssdk.auth.credentials.AwsBasicCredentials; |
| 8 | +import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider; | |
| 8 | 9 | import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider; |
| 9 | 10 | import software.amazon.awssdk.core.sync.RequestBody; |
| 10 | 11 | import software.amazon.awssdk.regions.Region; |
| 11 | 12 | import software.amazon.awssdk.services.s3.S3Client; |
| 13 | +import software.amazon.awssdk.services.s3.S3Configuration; | |
| 12 | 14 | import software.amazon.awssdk.services.s3.model.DeleteObjectRequest; |
| 13 | 15 | import software.amazon.awssdk.services.s3.model.GetObjectRequest; |
| 14 | 16 | import software.amazon.awssdk.services.s3.model.PutObjectRequest; |
| ... | ... | @@ -26,6 +28,7 @@ import java.time.Duration; |
| 26 | 28 | public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { |
| 27 | 29 | |
| 28 | 30 | private S3Client client; |
| 31 | + private S3Presigner presigner; | |
| 29 | 32 | |
| 30 | 33 | public S3FileClient(Long id, S3FileClientConfig config) { |
| 31 | 34 | super(id, config); |
| ... | ... | @@ -38,11 +41,23 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { |
| 38 | 41 | config.setDomain(buildDomain()); |
| 39 | 42 | } |
| 40 | 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 | 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 | 61 | .build(); |
| 47 | 62 | } |
| 48 | 63 | |
| ... | ... | @@ -55,7 +70,6 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { |
| 55 | 70 | .contentType(type) |
| 56 | 71 | .contentLength((long) content.length) |
| 57 | 72 | .build(); |
| 58 | - | |
| 59 | 73 | // 上传文件 |
| 60 | 74 | client.putObject(putRequest, RequestBody.fromBytes(content)); |
| 61 | 75 | // 拼接返回路径 |
| ... | ... | @@ -77,42 +91,27 @@ public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { |
| 77 | 91 | .bucket(config.getBucket()) |
| 78 | 92 | .key(path) |
| 79 | 93 | .build(); |
| 80 | - | |
| 81 | 94 | return IoUtil.readBytes(client.getObject(getRequest)); |
| 82 | 95 | } |
| 83 | 96 | |
| 84 | 97 | @Override |
| 85 | 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 | 104 | * 生成动态的预签名上传 URL |
| 104 | 105 | * |
| 105 | 106 | * @param path 相对路径 |
| 106 | - * @param duration 过期时间 | |
| 107 | + * @param expiration 过期时间 | |
| 107 | 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<S3FileClientConfig> { |
| 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 | 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 | 67 | @NotNull(message = "accessSecret 不能为空") |
| 68 | 68 | private String accessSecret; |
| 69 | 69 | |
| 70 | + /** | |
| 71 | + * 是否启用 PathStyle 访问 | |
| 72 | + */ | |
| 73 | + @NotNull(message = "enablePathStyleAccess 不能为空") | |
| 74 | + private Boolean enablePathStyleAccess; | |
| 75 | + | |
| 70 | 76 | @SuppressWarnings("RedundantIfStatement") |
| 71 | 77 | @AssertTrue(message = "domain 不能为空") |
| 72 | 78 | @JsonIgnore | ... | ... |