# AmazonS3Service.java

    package cloud.wconnect.rateshop.service;

    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.stereotype.Service;
    import org.springframework.web.multipart.MultipartFile;
    import software.amazon.awssdk.auth.credentials.AwsBasicCredentials;
    import software.amazon.awssdk.auth.credentials.StaticCredentialsProvider;
    import software.amazon.awssdk.core.sync.RequestBody;
    import software.amazon.awssdk.http.urlconnection.UrlConnectionHttpClient;
    import software.amazon.awssdk.regions.Region;
    import software.amazon.awssdk.services.s3.S3Client;
    import software.amazon.awssdk.services.s3.model.*;

    import jakarta.validation.constraints.NotBlank;

    import java.io.File;
    import java.io.IOException;
    import java.io.InputStream;
    import java.util.List;
    import java.util.Map;
    import java.util.stream.Collectors;

    /**
     * 服务类: AmazonS3
     *
     * @author zc
     * @date 2023/02/08
     */
    @Service
    public class AmazonS3Service {

        @Value("${aws-s3.credentials.access-key}")
        private String awsAccessKey;

        @Value("${aws-s3.credentials.secret-key}")
        private String awsSecretKey;

        @Value("${aws-s3.region}")
        private String awsRegion;

        @Value("${aws-s3.third-party.bucket}")
        private String bucket;

        @Value("#{${aws-s3.function-bucket}}")
        private Map<String, Map<String, Object>> bucketMap;

        /**
         * 初始化 AmazonS3
         *
         * @return AmazonS3
         * @author zc
         * @date 2023/2/9
         */
        private S3Client initS3() {
            return S3Client.builder()
                    .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(awsAccessKey, awsSecretKey)))
                    .region(Region.of(awsRegion))
                    .forcePathStyle(true)
                    .httpClient(UrlConnectionHttpClient.builder().build())
                    .build();
        }

        /**
         * 获取 s3 文件流
         *
         * @param key s3 文件路径
         * @return s3 文件流
         * @author zc
         * @date 2023/2/8
         */
        public InputStream getFile(@NotBlank String key) {
            GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                    .bucket(bucket)
                    .key(key)
                    .build();

            try (S3Client s3 = initS3()) {
                //获取文件的字节流
                return s3.getObjectAsBytes(getObjectRequest).asInputStream();
            }
        }

        /**
         * 获取 s3 文件流
         *
         * @param function 功能
         * @param key      s3 文件路径
         * @return s3 文件流
         * @author yyt
         * @date 2024/2/1
         */
        public InputStream getFile(String function, @NotBlank String key) {
            Map<String, Object> config = bucketMap.get(function);
            GetObjectRequest getObjectRequest = GetObjectRequest.builder()
                    .bucket(config.get("bucket").toString())
                    .key(key)
                    .build();

            try (S3Client s3 = initS3ForImport(config)) {
                return s3.getObjectAsBytes(getObjectRequest).asInputStream();
            }
        }

        /**
         * 上传文件到 s3
         *
         * @param file 上传的文件
         * @param key  文件路径
         * @author zc
         * @date 2023/3/7
         */
        public String uploadFile(MultipartFile file, @NotBlank String key) throws IOException {
            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(bucket)
                    .key(key)
                    .build();

            try (S3Client s3 = initS3()) {
                PutObjectResponse putObjectResponse = s3.putObject(objectRequest, RequestBody.fromBytes(file.getBytes()));
                return putObjectResponse.eTag();
            }
        }

        /**
         * 上传文件到 s3
         *
         * @param file 上传的文件
         * @param key  文件路径
         * @author zc
         * @date 2023/3/7
         */
        public String uploadFile(String function, File file, @NotBlank String key) throws IOException {
            Map<String, Object> config = bucketMap.get(function);
            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(config.get("bucket").toString())
                    .key(key)
                    .build();

            try (S3Client s3 = initS3ForImport(config)) {
                PutObjectResponse putObjectResponse = s3.putObject(objectRequest, RequestBody.fromFile(file));
                return putObjectResponse.eTag();
            }
        }

        /**
         * 初始化 s3
         *
         * @param config s3 配置
         * @return s3
         * @author yyt
         * @date 2024/1/30
         **/
        private S3Client initS3ForImport(Map<String, Object> config) {
            return S3Client.builder()
                    .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(config.get("accessKey").toString(),
                            config.get("secretKey").toString())))
                    .region(Region.of(awsRegion))
                    .forcePathStyle(true)
                    .httpClient(UrlConnectionHttpClient.builder().build())
                    .build();
        }

        /**
         * 上传文件到 s3
         *
         * @param function 功能名称
         * @param file     上传的文件
         * @param key      文件路径
         * @author yyt
         * @date 2024/1/30
         */
        public String uploadFile(String function, MultipartFile file, String key) throws IOException {
            Map<String, Object> config = bucketMap.get(function);
            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(config.get("bucket").toString())
                    .key(key)
                    .build();

            try (S3Client s3 = initS3ForImport(config)) {
                PutObjectResponse putObjectResponse = s3.putObject(objectRequest, RequestBody.fromBytes(file.getBytes()));
                return putObjectResponse.eTag();
            }
        }

        /**
         * 上传文件到 s3
         *
         * @param function    功能名称
         * @param inputStream 上传的文件
         * @param key         文件路径
         * @author yyt
         * @date 2024/1/30
         */
        public String uploadFile(String function, InputStream inputStream, String key) throws IOException {
            Map<String, Object> config = bucketMap.get(function);
            PutObjectRequest objectRequest = PutObjectRequest.builder()
                    .bucket(config.get("bucket").toString())
                    .key(key)
                    .build();

            try (S3Client s3 = initS3ForImport(config)) {
                PutObjectResponse putObjectResponse = s3.putObject(objectRequest, RequestBody.fromBytes(inputStream.readAllBytes()));
                return putObjectResponse.eTag();
            }
        }

        /**
         * 删除文件
         *
         * @param function 功能名称
         * @param keys     文件
         * @author yyt
         * @date 2023/8/28
         */
        public void deleteFile(String function, List<String> keys) {
            Map<String, Object> config = bucketMap.get(function);
            try (S3Client s3 = initS3ForImport(config)) {
                List<ObjectIdentifier> objs = keys.stream().map(item -> ObjectIdentifier.builder().key(item).build()).collect(Collectors.toList());
                s3.deleteObjects(DeleteObjectsRequest.builder().bucket(config.get("bucket").toString()).delete(Delete.builder().objects(objs).build()).build());
            }
        }

        /**
         * 判断文件是否存在
         *
         * @param function 功能名称
         * @param key      文件路径
         * @return boolean
         * @author lichen
         * @date 2025/11/5
         */
        public boolean isFileExists(String function, @NotBlank String key) {
            try {
                Map<String, Object> config = bucketMap.get(function);
                HeadObjectRequest headObjectRequest = HeadObjectRequest.builder()
                        .bucket(config.get("bucket").toString())
                        .key(key)
                        .build();

                try (S3Client s3 = initS3ForImport(config)) {
                    s3.headObject(headObjectRequest);
                    return true;
                }
            } catch (NoSuchKeyException e) {
                return false;
            } catch (S3Exception e) {
                if (e.statusCode() == 403) {
                    return false;
                }
                throw e;
            }
        }

    }