Commit 0885eb7c70d35f1be52d5d5b837d358f94849239

Authored by 芋道源码
Committed by Gitee
2 parents bbc59e44 cf40cce5

!1219 【依赖升级】AWS SDK for Java 1.x to 2.x

Merge pull request !1219 from puhui999/develop
yudao-dependencies/pom.xml
... ... @@ -71,7 +71,7 @@
71 71 <!-- 三方云服务相关 -->
72 72 <commons-io.version>2.17.0</commons-io.version>
73 73 <commons-compress.version>1.27.1</commons-compress.version>
74   - <aws-java-sdk-s3.version>1.12.777</aws-java-sdk-s3.version>
  74 + <awssdk.version>2.30.14</awssdk.version>
75 75 <justauth.version>2.0.5</justauth.version>
76 76 <jimureport.version>1.8.1</jimureport.version>
77 77 <weixin-java.version>4.7.2.B</weixin-java.version>
... ... @@ -94,6 +94,13 @@
94 94 <type>pom</type>
95 95 <scope>import</scope>
96 96 </dependency>
  97 + <dependency>
  98 + <groupId>software.amazon.awssdk</groupId>
  99 + <artifactId>bom</artifactId>
  100 + <version>${awssdk.version}</version>
  101 + <type>pom</type>
  102 + <scope>import</scope>
  103 + </dependency>
97 104  
98 105 <!-- 业务组件 -->
99 106 <dependency>
... ... @@ -551,13 +558,6 @@
551 558 <version>${jsoup.version}</version>
552 559 </dependency>
553 560  
554   - <!-- 三方云服务相关 -->
555   - <dependency>
556   - <groupId>com.amazonaws</groupId>
557   - <artifactId>aws-java-sdk-s3</artifactId>
558   - <version>${aws-java-sdk-s3.version}</version>
559   - </dependency>
560   -
561 561 <dependency>
562 562 <groupId>com.xingyuv</groupId>
563 563 <artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
... ...
yudao-module-infra/yudao-module-infra-biz/pom.xml
... ... @@ -115,9 +115,18 @@
115 115 <groupId>com.jcraft</groupId>
116 116 <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 -->
117 117 </dependency>
  118 + <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
118 119 <dependency>
119   - <groupId>com.amazonaws</groupId>
120   - <artifactId>aws-java-sdk-s3</artifactId><!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
  120 + <groupId>software.amazon.awssdk</groupId>
  121 + <artifactId>s3</artifactId>
  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>
121 130 </dependency>
122 131  
123 132 <dependency>
... ...
yudao-module-infra/yudao-module-infra-biz/src/main/java/cn/iocoder/yudao/module/infra/framework/file/core/client/s3/S3FileClient.java
... ... @@ -4,29 +4,28 @@ import cn.hutool.core.io.IoUtil;
4 4 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   -import com.amazonaws.HttpMethod;
8   -import com.amazonaws.auth.AWSStaticCredentialsProvider;
9   -import com.amazonaws.auth.BasicAWSCredentials;
10   -import com.amazonaws.client.builder.AwsClientBuilder;
11   -import com.amazonaws.services.s3.AmazonS3Client;
12   -import com.amazonaws.services.s3.AmazonS3ClientBuilder;
13   -import com.amazonaws.services.s3.model.ObjectMetadata;
14   -import com.amazonaws.services.s3.model.S3Object;
15   -
16   -import java.io.ByteArrayInputStream;
17   -import java.util.Date;
18   -import java.util.concurrent.TimeUnit;
  7 +import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
  8 +import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
  9 +import software.amazon.awssdk.core.sync.RequestBody;
  10 +import software.amazon.awssdk.regions.Region;
  11 +import software.amazon.awssdk.services.s3.S3Client;
  12 +import software.amazon.awssdk.services.s3.model.DeleteObjectRequest;
  13 +import software.amazon.awssdk.services.s3.model.GetObjectRequest;
  14 +import software.amazon.awssdk.services.s3.model.PutObjectRequest;
  15 +import software.amazon.awssdk.services.s3.presigner.S3Presigner;
  16 +import software.amazon.awssdk.services.s3.presigner.model.PutObjectPresignRequest;
  17 +
  18 +import java.net.URI;
  19 +import java.time.Duration;
19 20  
20 21 /**
21 22 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务
22   - * <p>
23   - * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库
24 23 *
25 24 * @author 芋道源码
26 25 */
27 26 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
28 27  
29   - private AmazonS3Client client;
  28 + private S3Client client;
30 29  
31 30 public S3FileClient(Long id, S3FileClientConfig config) {
32 31 super(id, config);
... ... @@ -38,31 +37,82 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
38 37 if (StrUtil.isEmpty(config.getDomain())) {
39 38 config.setDomain(buildDomain());
40 39 }
41   - // 初始化客户端
42   - client = (AmazonS3Client)AmazonS3ClientBuilder.standard()
43   - .withCredentials(buildCredentials())
44   - .withEndpointConfiguration(buildEndpointConfiguration())
  40 + // 初始化 S3 客户端
  41 + 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 访问
  46 + .build();
  47 + }
  48 +
  49 + @Override
  50 + public String upload(byte[] content, String path, String type) {
  51 + // 构造 PutObjectRequest
  52 + PutObjectRequest putRequest = PutObjectRequest.builder()
  53 + .bucket(config.getBucket())
  54 + .key(path)
  55 + .contentType(type)
  56 + .contentLength((long) content.length)
  57 + .build();
  58 +
  59 + // 上传文件
  60 + client.putObject(putRequest, RequestBody.fromBytes(content));
  61 + // 拼接返回路径
  62 + return config.getDomain() + "/" + path;
  63 + }
  64 +
  65 + @Override
  66 + public void delete(String path) {
  67 + DeleteObjectRequest deleteRequest = DeleteObjectRequest.builder()
  68 + .bucket(config.getBucket())
  69 + .key(path)
45 70 .build();
  71 + client.deleteObject(deleteRequest);
  72 + }
  73 +
  74 + @Override
  75 + public byte[] getContent(String path) {
  76 + GetObjectRequest getRequest = GetObjectRequest.builder()
  77 + .bucket(config.getBucket())
  78 + .key(path)
  79 + .build();
  80 +
  81 + return IoUtil.readBytes(client.getObject(getRequest));
  82 + }
  83 +
  84 + @Override
  85 + public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) {
  86 + return new FilePresignedUrlRespDTO(getPresignedUrl(path, Duration.ofMinutes(10)), config.getDomain() + "/" + path);
46 87 }
47 88  
48 89 /**
49   - * 基于 config 秘钥,构建 S3 客户端的认证信息
  90 + * 动态创建 S3Presigner
50 91 *
51   - * @return S3 客户端的认证信息
  92 + * @return S3Presigner
52 93 */
53   - private AWSStaticCredentialsProvider buildCredentials() {
54   - return new AWSStaticCredentialsProvider(
55   - new BasicAWSCredentials(config.getAccessKey(), config.getAccessSecret()));
  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();
56 100 }
57 101  
58 102 /**
59   - * 构建 S3 客户端的 Endpoint 配置,包括 region、endpoint
  103 + * 生成动态的预签名上传 URL
60 104 *
61   - * @return S3 客户端的 EndpointConfiguration 配置
  105 + * @param path 相对路径
  106 + * @param duration 过期时间
  107 + * @return 生成的上传 URL
62 108 */
63   - private AwsClientBuilder.EndpointConfiguration buildEndpointConfiguration() {
64   - return new AwsClientBuilder.EndpointConfiguration(config.getEndpoint(),
65   - null); // 无需设置 region
  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 + }
66 116 }
67 117  
68 118 /**
... ... @@ -79,40 +129,27 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
79 129 return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint());
80 130 }
81 131  
82   - @Override
83   - public String upload(byte[] content, String path, String type) throws Exception {
84   - // 元数据,主要用于设置文件类型
85   - ObjectMetadata objectMetadata = new ObjectMetadata();
86   - objectMetadata.setContentType(type);
87   - objectMetadata.setContentLength(content.length); // 如果不设置,会有 “ No content length specified for stream data” 警告日志
88   - // 执行上传
89   - client.putObject(config.getBucket(),
90   - path, // 相对路径
91   - new ByteArrayInputStream(content), // 文件内容
92   - objectMetadata);
93   -
94   - // 拼接返回路径
95   - return config.getDomain() + "/" + path;
96   - }
97   -
98   - @Override
99   - public void delete(String path) throws Exception {
100   - client.deleteObject(config.getBucket(), path);
101   - }
102   -
103   - @Override
104   - public byte[] getContent(String path) throws Exception {
105   - S3Object tempS3Object = client.getObject(config.getBucket(), path);
106   - return IoUtil.readBytes(tempS3Object.getObjectContent());
  132 + /**
  133 + * 基于 config 秘钥,构建 S3 客户端的认证信息
  134 + *
  135 + * @return S3 客户端的认证信息
  136 + */
  137 + private StaticCredentialsProvider buildCredentials() {
  138 + return StaticCredentialsProvider.create(
  139 + AwsBasicCredentials.create(config.getAccessKey(), config.getAccessSecret()));
107 140 }
108 141  
109   - @Override
110   - public FilePresignedUrlRespDTO getPresignedObjectUrl(String path) throws Exception {
111   - // 设定过期时间为 10 分钟。取值范围:1 秒 ~ 7 天
112   - Date expiration = new Date(System.currentTimeMillis() + TimeUnit.MINUTES.toMillis(10));
113   - // 生成上传 URL
114   - String uploadUrl = String.valueOf(client.generatePresignedUrl(config.getBucket(), path, expiration , HttpMethod.PUT));
115   - return new FilePresignedUrlRespDTO(uploadUrl, config.getDomain() + "/" + path);
  142 + /**
  143 + * 节点地址补全协议头
  144 + *
  145 + * @return 节点地址
  146 + */
  147 + private String buildEndpoint() {
  148 + // 如果已经是 http 或者 https,则不进行拼接
  149 + if (HttpUtil.isHttp(config.getEndpoint()) || HttpUtil.isHttps(config.getEndpoint())) {
  150 + return config.getEndpoint();
  151 + }
  152 + return StrUtil.format("https://{}", config.getEndpoint());
116 153 }
117 154  
118 155 }
... ...