SpringBoot 2.x集成AWS S3对象存储

1、pom配置

<!--锁定对象存储版本-->
    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>software.amazon.awssdk</groupId>
                <artifactId>bom</artifactId>
                <version>2.17.136</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>
<!--对象存储 S3 start-->
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3</artifactId>
</dependency>
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3-transfer-manager</artifactId>
    <version>2.17.103-PREVIEW</version>
</dependency>
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>kms</artifactId>
</dependency>
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>s3control</artifactId>
</dependency>
<!--对象存储 S3  end-->

 

2、application.yml增加配置

#AWS S3配置
aws:
  s3:
    accessKeyId: A81BFFE58AKIBB950
    secretKey: Fkb7Yw3aIMAPyst7c5ISGthSKi4mfBDk09HS
    s3Uri: https://s3.test.com
    bucket:  test-bucket

 

3、FileS3Util工具类

import cn.hutool.core.util.StrUtil;
import com.test.common.constant.CommonConstant;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
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.regions.Region;
import software.amazon.awssdk.services.s3.S3Client;
import software.amazon.awssdk.services.s3.S3Configuration;
import software.amazon.awssdk.services.s3.model.*;
import software.amazon.awssdk.services.s3.presigner.S3Presigner;
import software.amazon.awssdk.services.s3.presigner.model.GetObjectPresignRequest;
import software.amazon.awssdk.services.s3.presigner.model.PresignedGetObjectRequest;

import javax.annotation.PostConstruct;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.net.URI;
import java.text.SimpleDateFormat;
import java.time.Duration;
import java.util.*;


@Slf4j
@Component
public class FileS3Util {

    @Value("${aws.s3.accessKeyId}")
    private String accessKeyId;

    @Value("${aws.s3.secretKey}")
    private String secretKey;

    @Value("${aws.s3.s3Uri}")
    private String s3Uri;

    @Value("${aws.s3.bucket}")
    private String bucketName;

    public static String S3_ACCESS_KEY_ID = null;

    public static String S3_SECRET_KEY = null;

    public static String S3_URI = null;

    public static String S3_BUCKET = null;


    @PostConstruct
    public void init() {
        S3_ACCESS_KEY_ID = accessKeyId;
        S3_SECRET_KEY = secretKey;
        S3_URI = s3Uri;
        S3_BUCKET = bucketName;
    }

    private static S3Client s3Client;

    private static S3Presigner s3Presigner;

    /**
     * @description:  获取S3客户端对象
     * @author: bug
     * @date: 2022/6/23 19:45
     * @param  
     * @return software.amazon.awssdk.services.s3.S3Client
     */ 
    public static synchronized S3Client getS3Client() {
        if (null == s3Client) {
            s3Client = S3Client.builder()
                    .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(S3_ACCESS_KEY_ID, S3_SECRET_KEY)))
                    .endpointOverride(URI.create(S3_URI))
                    .serviceConfiguration(item -> item.pathStyleAccessEnabled(true).checksumValidationEnabled(false))
                    .region(Region.AP_SOUTHEAST_1)
                    .build();
        }

        return s3Client;
    }
    
    /**
     * @description:  获取预签名对象
     * @author: bug
     * @date: 2022/6/23 19:46
     * @param  
     * @return software.amazon.awssdk.services.s3.presigner.S3Presigner
     */ 
    public static synchronized S3Presigner getS3PreSigner() {
        if (null == s3Presigner) {
            s3Presigner = S3Presigner.builder()
                    .credentialsProvider(StaticCredentialsProvider.create(AwsBasicCredentials.create(S3_ACCESS_KEY_ID, S3_SECRET_KEY)))
                    .endpointOverride(URI.create(S3_URI))
                    .serviceConfiguration(S3Configuration.builder()
                            .checksumValidationEnabled(false)
                            .pathStyleAccessEnabled(true)
                            .build())
                    .region(Region.AP_SOUTHEAST_1)
                    .build();
        }
        return s3Presigner;
    }


    /**
     * @description:  根据文件地址上传文件
     * @author: bug
     * @date: 2022/6/23 19:39
     * @param filePath 文件绝对地址
     * @param pathName 目标目录: test
     * @return java.lang.String
     */
    public static String uploadPublicFile(String filePath, String pathName) {
        boolean failFlag = true;
        String objectKey = "";
        boolean exists = FileUtils.exists(filePath);
        if (exists) {
            File file = new File(filePath);
            InputStream inputStream = null;
            try {
                inputStream = new FileInputStream(file);
                //获取文件后缀
                String suffix = StrUtil.subAfter(filePath, ".", true);
                objectKey = getFileName(suffix, pathName);
                PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                        .bucket(S3_BUCKET)
                        .key(objectKey)
                        .acl(ObjectCannedACL.PUBLIC_READ)
                        .build();

                S3Client s3Client = getS3Client();
                PutObjectResponse putObjectResponse = s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(inputStream, file.length()));
                failFlag = false;
            } catch (FileNotFoundException e) {
                log.error("上传S3文件对象转流失败,异常:{}", e);
            } catch (Exception e) {
                log.error("上传S3文件失败,异常:{}", e);
            }
        }
        if (failFlag) {
            objectKey = "";
        }
        return objectKey;
    }


    /**
     * @description:  根据文件对象上传文件
     * @author: bug
     * @date: 2022/6/23 19:38
     * @param multipartFile 文件对象
     * @param pathName 目标目录
     * @return java.lang.String
     */
    public static String uploadPublicFile(MultipartFile multipartFile, String pathName) {
        S3Client s3Client = getS3Client();
        String s3FileFullPath = getFileName(multipartFile, pathName);
        try {
            PutObjectRequest putObjectRequest = PutObjectRequest.builder()
                    .bucket(S3_BUCKET)
                    .contentType(multipartFile.getContentType())
                    .contentLength(multipartFile.getSize())
                    .key(s3FileFullPath)
                    .acl(ObjectCannedACL.PUBLIC_READ)
                    .build();
            PutObjectResponse putObjectResponse = s3Client.putObject(putObjectRequest, RequestBody.fromInputStream(multipartFile.getInputStream(), multipartFile.getSize()));
            return s3FileFullPath;
        } catch (Exception e) {
            log.error("上传文件到S3失败 异常:{}", e);
        }
        return null;
    }

    /**
     * @description:  根据文件对象和目标目录生成新的文件地址
     * @author: bug
     * @date: 2022/6/23 19:40
     * @param multipartFile 上传文件
     * @param pathName 目标目录
     * @return java.lang.String
     */
    private static String getFileName(MultipartFile multipartFile, String pathName) {
        String suffix = multipartFile.getOriginalFilename().substring(multipartFile.getOriginalFilename().lastIndexOf(".") + 1);

        return getFileName(suffix, pathName);
    }

    /**
     * @description:  根据文件后缀和目标目录生成新的文件地址
     * @author: bug
     * @date: 2022/6/23 19:41
     * @param suffix 文件后缀
     * @param pathName 目标目录 test
     * @return java.lang.String   test/2022/06
     */
    private static String getFileName(String suffix, String pathName) {
        //生成随机文件名
        String localFileName = UUID.randomUUID() + "." + suffix;
        Date date = new Date();
        SimpleDateFormat formatter_yyyy = new SimpleDateFormat("yyyy");
        SimpleDateFormat formatter_MM = new SimpleDateFormat("MM");
        //在随机名前加上年月
        String s3FileFullPath = pathName + "/" + formatter_yyyy.format(date) + "/" + formatter_MM.format(date) + "/" + localFileName;

        return s3FileFullPath;
    }

    /**
     * @description:  生成预签名URL
     * @author: bug
     * @date: 2022/6/23 19:42
     * @param keyName key名称: test/2022/06/123.pdf
     * @param signatureDurationTime 有效期 单位:秒
     * @return java.lang.String
     */
    public static String getPreSignatureUrl(String keyName, Integer signatureDurationTime) {
        String preSignatureUrl = "";
        try {
            S3Presigner s3PreSigner = FileS3Util.getS3PreSigner();
            GetObjectRequest getObjectRequest =
                    GetObjectRequest.builder()
                            .bucket(S3_BUCKET)
                            .key(keyName)
                            .build();
            //设置预签名URL可访问时间
            signatureDurationTime = Optional.ofNullable(signatureDurationTime)
                    .map(item -> {
                        if (item.intValue() > CommonConstant.Numbers.NUMBER_10080) {
                            item = CommonConstant.Numbers.NUMBER_10080;
                        }
                        return item;
                    })
                    .orElse(CommonConstant.Numbers.NUMBER_10);
            GetObjectPresignRequest getObjectPresignRequest = GetObjectPresignRequest.builder()
                    .signatureDuration(Duration.ofMinutes(signatureDurationTime))
                    .getObjectRequest(getObjectRequest)
                    .build();

            PresignedGetObjectRequest presignedGetObjectRequest =
                    s3PreSigner.presignGetObject(getObjectPresignRequest);

            preSignatureUrl = String.valueOf(presignedGetObjectRequest.url());

        } catch (Exception e) {
            log.error("生成预签名URL失败,异常:{}", e);
        }
        return preSignatureUrl;
    }


    /**
     * 获取S3中对象的信息,最多只能返回1000个
     *
     * @return
     */
    public static List<Map<String, Object>> listObject() {
        ListObjectsRequest listObjects = ListObjectsRequest
                .builder()
                .bucket(S3_BUCKET)
                .build();
        S3Client s3Client = FileS3Util.getS3Client();
        ListObjectsResponse res = s3Client.listObjects(listObjects);
        List<S3Object> objects = res.contents();

        List<Map<String, Object>> result = Lists.newArrayList();
        for (ListIterator iterVals = objects.listIterator(); iterVals.hasNext(); ) {
            S3Object myValue = (S3Object) iterVals.next();
            Map<String, Object> map = Maps.newHashMap();
            map.put("objectKey", myValue.key());
            map.put("objectSize(/KBs)", myValue.size() / 1024);
            map.put("ownerId", myValue.owner().id());
            map.put("ownerDisplayName", myValue.owner().displayName());
            result.add(map);
        }
        return result;
    }

    /**
     * 获取S3中对象的信息,最多只能返回1000个
     *
     * @param delimiter 分隔符号
     * @return
     */
    public static List<Map<String, Object>> listObjectByDelimiter(String delimiter, Integer maxKeys) {
        //限制返回对象信息数量
        maxKeys = Optional.ofNullable(maxKeys)
                .map(item -> {
                    if (item.intValue() > CommonConstant.Numbers.NUMBER_1000) {
                        item = CommonConstant.Numbers.NUMBER_1000;
                    }
                    return item;
                })
                .orElse(CommonConstant.Numbers.NUMBER_1000);

        ListObjectsRequest listObjects = ListObjectsRequest
                .builder()
                .bucket(S3_BUCKET)
                .delimiter(delimiter)
                .maxKeys(maxKeys)
                .build();
        S3Client s3Client = FileS3Util.getS3Client();
        ListObjectsResponse res = s3Client.listObjects(listObjects);
        List<S3Object> objects = res.contents();

        List<Map<String, Object>> result = Lists.newArrayList();
        for (ListIterator iterVals = objects.listIterator(); iterVals.hasNext(); ) {
            S3Object myValue = (S3Object) iterVals.next();
            Map<String, Object> map = Maps.newHashMap();
            map.put("objectKey", myValue.key());
            map.put("objectSize(/KBs)", myValue.size() / 1024);
            map.put("ownerId", myValue.owner().id());
            map.put("ownerDisplayName", myValue.owner().displayName());
            result.add(map);
        }
        return result;
    }


    /**
     * 获取S3中对象的信息,最多只能返回1000个
     *
     * @param prefix 前缀
     * @return
     */
    public static List<Map<String, Object>> listObjectByPrefix(String prefix, Integer maxKeys) {
        //限制返回对象信息数量
        maxKeys = Optional.ofNullable(maxKeys)
                .map(item -> {
                    if (item.intValue() > CommonConstant.Numbers.NUMBER_1000) {
                        item = CommonConstant.Numbers.NUMBER_1000;
                    }
                    return item;
                })
                .orElse(CommonConstant.Numbers.NUMBER_1000);
        ListObjectsRequest listObjects = ListObjectsRequest
                .builder()
                .bucket(S3_BUCKET)
                .prefix(prefix)
                .maxKeys(maxKeys)
                .build();
        S3Client s3Client = FileS3Util.getS3Client();
        ListObjectsResponse res = s3Client.listObjects(listObjects);
        List<S3Object> objects = res.contents();

        List<Map<String, Object>> result = Lists.newArrayList();
        for (ListIterator iterVals = objects.listIterator(); iterVals.hasNext(); ) {
            S3Object myValue = (S3Object) iterVals.next();
            Map<String, Object> map = Maps.newHashMap();
            map.put("objectKey", myValue.key());
            map.put("objectSize(/KBs)", myValue.size() / 1024);
            map.put("ownerId", myValue.owner().id());
            map.put("ownerDisplayName", myValue.owner().displayName());
            result.add(map);
        }
        return result;
    }

    /**
     * 获取S3中对象的信息,最多只能返回1000个
     *
     * @param delimiter 分隔符
     * @param prefix    前缀
     * @param maxKeys   返回最大的对象信息 1000个
     * @return
     */
    public static List<Map<String, Object>> listObjectByDelimiterWithPrefix(String delimiter, String prefix, Integer maxKeys) {
        //限制返回对象信息数量
        maxKeys = Optional.ofNullable(maxKeys)
                .map(item -> {
                    if (item.intValue() > CommonConstant.Numbers.NUMBER_1000) {
                        item = CommonConstant.Numbers.NUMBER_1000;
                    }
                    return item;
                })
                .orElse(CommonConstant.Numbers.NUMBER_1000);

        ListObjectsRequest listObjects = ListObjectsRequest
                .builder()
                .bucket(S3_BUCKET)
                .delimiter(delimiter)
                .prefix(prefix)
                .maxKeys(maxKeys)
                .build();
        S3Client s3Client = FileS3Util.getS3Client();
        ListObjectsResponse res = s3Client.listObjects(listObjects);
        List<S3Object> objects = res.contents();

        List<Map<String, Object>> result = Lists.newArrayList();
        for (ListIterator iterVals = objects.listIterator(); iterVals.hasNext(); ) {
            S3Object myValue = (S3Object) iterVals.next();
            Map<String, Object> map = Maps.newHashMap();
            map.put("objectKey", myValue.key());
            map.put("objectSize(/KBs)", myValue.size() / 1024);
            map.put("ownerId", myValue.owner().id());
            map.put("ownerDisplayName", myValue.owner().displayName());
            result.add(map);
        }
        return result;
    }


}

 

posted @ 2022-06-23 19:49  bug毁灭者  阅读(2289)  评论(1编辑  收藏  举报