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,7 +71,7 @@
71 <!-- 三方云服务相关 --> 71 <!-- 三方云服务相关 -->
72 <commons-io.version>2.17.0</commons-io.version> 72 <commons-io.version>2.17.0</commons-io.version>
73 <commons-compress.version>1.27.1</commons-compress.version> 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 <justauth.version>2.0.5</justauth.version> 75 <justauth.version>2.0.5</justauth.version>
76 <jimureport.version>1.8.1</jimureport.version> 76 <jimureport.version>1.8.1</jimureport.version>
77 <weixin-java.version>4.7.2.B</weixin-java.version> 77 <weixin-java.version>4.7.2.B</weixin-java.version>
@@ -94,6 +94,13 @@ @@ -94,6 +94,13 @@
94 <type>pom</type> 94 <type>pom</type>
95 <scope>import</scope> 95 <scope>import</scope>
96 </dependency> 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 <dependency> 106 <dependency>
@@ -551,13 +558,6 @@ @@ -551,13 +558,6 @@
551 <version>${jsoup.version}</version> 558 <version>${jsoup.version}</version>
552 </dependency> 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 <dependency> 561 <dependency>
562 <groupId>com.xingyuv</groupId> 562 <groupId>com.xingyuv</groupId>
563 <artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) --> 563 <artifactId>spring-boot-starter-justauth</artifactId> <!-- 社交登陆(例如说,个人微信、企业微信等等) -->
yudao-module-infra/yudao-module-infra-biz/pom.xml
@@ -115,9 +115,18 @@ @@ -115,9 +115,18 @@
115 <groupId>com.jcraft</groupId> 115 <groupId>com.jcraft</groupId>
116 <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 --> 116 <artifactId>jsch</artifactId> <!-- 文件客户端:解决 sftp 连接 -->
117 </dependency> 117 </dependency>
  118 + <!-- 文件客户端:解决阿里云、腾讯云、minio 等 S3 连接 -->
118 <dependency> 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 </dependency> 130 </dependency>
122 131
123 <dependency> 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,29 +4,28 @@ import cn.hutool.core.io.IoUtil;
4 import cn.hutool.core.util.StrUtil; 4 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 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 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务 22 * 基于 S3 协议的文件客户端,实现 MinIO、阿里云、腾讯云、七牛云、华为云等云服务
22 - * <p>  
23 - * S3 协议的客户端,采用亚马逊提供的 software.amazon.awssdk.s3 库  
24 * 23 *
25 * @author 芋道源码 24 * @author 芋道源码
26 */ 25 */
27 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> { 26 public class S3FileClient extends AbstractFileClient<S3FileClientConfig> {
28 27
29 - private AmazonS3Client client; 28 + private S3Client client;
30 29
31 public S3FileClient(Long id, S3FileClientConfig config) { 30 public S3FileClient(Long id, S3FileClientConfig config) {
32 super(id, config); 31 super(id, config);
@@ -38,31 +37,82 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; { @@ -38,31 +37,82 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
38 if (StrUtil.isEmpty(config.getDomain())) { 37 if (StrUtil.isEmpty(config.getDomain())) {
39 config.setDomain(buildDomain()); 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 .build(); 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,40 +129,27 @@ public class S3FileClient extends AbstractFileClient&lt;S3FileClientConfig&gt; {
79 return StrUtil.format("https://{}.{}", config.getBucket(), config.getEndpoint()); 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 }