AWS S3文件存储工具类

news2025/1/5 19:26:40

pom依赖

 <!--aws-s3-->
<dependency>
     <groupId>com.amazonaws</groupId>
     <artifactId>aws-java-sdk-s3</artifactId>
     <version>1.12.95</version>
 </dependency>

S3Utils

import cn.hutool.core.util.ZipUtil;
import com.amazonaws.ClientConfiguration;
import com.amazonaws.auth.AWSStaticCredentialsProvider;
import com.amazonaws.auth.BasicAWSCredentials;
import com.amazonaws.client.builder.AwsClientBuilder;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
import com.amazonaws.services.s3.model.*;
import com.crm.common.config.S3Config;
import com.crm.common.enums.ConflictPolicy;
import com.crm.common.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.PostConstruct;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.util.LinkedList;
import java.util.List;

@Component
public class S3Utils {
    private BasicAWSCredentials awsCreds = null;
    private AmazonS3 s3 = null;

    @Autowired
    S3Config s3Config;


    @PostConstruct
    public void init() {
        /**
         * 创建s3对象
         */
        if (StringUtils.isNotBlank(s3Config.getAccessKey()) && StringUtils.isNotBlank(s3Config.getSecretKey())) {
            ClientConfiguration config = new ClientConfiguration();
            AwsClientBuilder.EndpointConfiguration endpointConfig =
                    new AwsClientBuilder.EndpointConfiguration(s3Config.getEndpoint(), "cn-north-1");

            awsCreds = new BasicAWSCredentials(s3Config.getAccessKey(), s3Config.getSecretKey());
            s3 = AmazonS3ClientBuilder.standard()
                    .withEndpointConfiguration(endpointConfig)
                    .withClientConfiguration(config)
                    .withCredentials(new AWSStaticCredentialsProvider(awsCreds))
                    .build();
        }
    }

    /**
     * 上传文件
     *
     * @param file 文件
     */
    public String uploadFile(MultipartFile file, String moduleName) {
        return uploadFile(file, ConflictPolicy.NEW, moduleName);
    }

    /**
     * @param file
     * @param policy     冲突策略,当同一路径下有同名文件时可选。默认是替换同名文件
     * @param moduleName 项目内的模块名
     * @return
     */
    public String uploadFile(MultipartFile file, ConflictPolicy policy, String moduleName) {
        if (isEmpty(file)) {
            return null;
        }
        // 生成临时文件
        File localFile = null;
        try {
            //先从s3服务器上查找是否有同名文件
            String key = s3Config.getProject() + "/" + moduleName + "/" + file.getOriginalFilename();
            localFile = File.createTempFile("temp", null);
            file.transferTo(localFile);
            String prefix = key.substring(0, key.lastIndexOf("."));
            String suffix = key.substring(key.indexOf("."));
            //取出同名文件的最大number
            int maxNum = getMaxVersionNum(s3Config.getBucketName(), prefix, suffix);
            if (maxNum != -1) {
                switch (policy) {
                    case NEW:
                        key = prefix + "(" + (++maxNum) + ")" + suffix;
                        break;
                    case RETAIN:
                        return "文件已存在,根据冲突策略,文件不予替换";
                    case REPLACE:
                    default:
                        break;
                }
            }
            PutObjectRequest request = new PutObjectRequest(s3Config.getBucketName(), key, localFile);
            // 上传文件 如果没抛异常则可认为上传成功
            PutObjectResult putObjectResult = s3.putObject(request);
            if (StringUtils.isNotEmpty(putObjectResult.getETag())) {
                return key;
            }
            return null;
        } catch (IOException e) {
            e.printStackTrace();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (localFile != null) {
                localFile.delete();
            }
        }
        return null;
    }

    private int getMaxVersionNum(String bucketName, String prefix, String suffix) {
        ListObjectsRequest listRequest = new ListObjectsRequest().withBucketName(bucketName).withPrefix(prefix).withMaxKeys(100);
        ObjectListing objectListing = s3.listObjects(listRequest);
        int value = -1;
        for (S3ObjectSummary inst : objectListing.getObjectSummaries()) {
            String indexStr = inst.getKey().replace(prefix, "").replace("(", "").replace(")", "").replace(suffix, "");
            if (indexStr.length() == 0) {
                indexStr = "0";
            }
            value = Math.max(value, Integer.parseInt(indexStr));
        }
        return value;
    }

    /**
     * 删除单个文件
     *
     * @param key 根据key删除文件
     * @return
     */
    public void deleteObject(String key) {
        if (StringUtils.isBlank(key)) {
            throw new IllegalArgumentException("key can not be null");
        }
        s3.deleteObject(s3Config.getBucketName(), key);
    }

    /**
     * @param key 根据key得到文件的输入流
     * @return
     */
    public S3ObjectInputStream getFileInputStream(String key) {
        S3Object object = s3.getObject(new GetObjectRequest(s3Config.getBucketName(), key));
        return object.getObjectContent();
    }

    /**
     * 根据key得到输入流并输出到输出流
     *
     * @param key
     * @param stream
     */
    public void downloadFile(String key, OutputStream stream) {
        InputStream input = getFileInputStream(key);
        byte[] data = null;
        try {
            data = new byte[input.available()];
            int len = 0;
            while ((len = input.read(data)) != -1) {
                stream.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 根据key得到输入流并输出到输出流
     *
     * @param key
     * @param response
     */
    public void downloadFile(String key, HttpServletResponse response) {
        String fileName = key;
        byte[] data = null;
        OutputStream stream = null;
        InputStream input = getFileInputStream(key);
        if (key.contains("/")) {
            String[] path = key.split("/");
            fileName = path[path.length - 1];
        }
        response.setHeader("Content-Disposition", "attachment; filename=" + fileName);
        try {
            stream = response.getOutputStream();
            data = new byte[input.available()];
            int len = 0;
            while ((len = input.read(data)) != -1) {
                stream.write(data, 0, len);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (stream != null) {
                try {
                    stream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (input != null) {
                try {
                    input.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * 删除文件夹
     *
     * @param filePath  文件夹地址[ eg:temp/1 或 temp ]
     * @param deleteAll true-递进删除所有文件(包括子文件夹);false-只删除当前文件夹下的文件,不删除子文件夹内容
     */
    public void deleteFolder(String filePath, boolean deleteAll) {
        ListObjectsV2Request objectsRequest = new ListObjectsV2Request();
        objectsRequest.setBucketName(s3Config.getBucketName());
        objectsRequest.setPrefix(filePath);
        // deliter表示分隔符, 设置为/表示列出当前目录下的object, 设置为空表示列出所有的object
        objectsRequest.setDelimiter(deleteAll ? "" : "/");
        // 设置最大遍历出多少个对象, 一次listobject最大支持1000
        objectsRequest.setMaxKeys(1000);
        ListObjectsV2Result listObjectsRequest = s3.listObjectsV2(objectsRequest);
        List<S3ObjectSummary> objects = listObjectsRequest.getObjectSummaries();
        String[] object_keys = new String[objects.size()];
        for (int i = 0; i < objects.size(); i++) {
            S3ObjectSummary item = objects.get(i);
            object_keys[i] = item.getKey();
        }
        DeleteObjectsRequest dor = new DeleteObjectsRequest(s3Config.getBucketName()).withKeys(object_keys);
        s3.deleteObjects(dor);
    }

    /**
     * 检查文件是否为空
     *
     * @param
     * @return
     */
    public boolean isEmpty(MultipartFile file) {
        if (file == null || file.getSize() <= 0) {
            return true;
        }
        return false;
    }

    /**
     * 得到所有文件的key
     *
     * @return key list
     */
    public List<String> getFileKeys() {
        List<String> keys = new LinkedList<>();
        ListObjectsRequest listRequest = new ListObjectsRequest().withBucketName(s3Config.getBucketName());
        try {
            ObjectListing objects = s3.listObjects(listRequest);
            while (true) {
                List<S3ObjectSummary> summaries = objects.getObjectSummaries();
                for (S3ObjectSummary summary : summaries) {
                    keys.add(summary.getKey());
                }
                if (objects.isTruncated()) {
                    objects = s3.listNextBatchOfObjects(objects);
                } else {
                    break;
                }
            }
        } catch (Exception exception) {
            exception.printStackTrace();
        }
        return keys;
    }



    public void getBizFile(List<String> keys, File targetZipFile) {
        InputStream[] inputStreams = keys.stream().map(this::getFileInputStream).toArray(InputStream[]::new);
        String[] strings = keys.stream().map(key -> key.split("/")[key.split("/").length - 1]).toArray(String[]::new);
        ZipUtil.zip(targetZipFile, strings, inputStreams);
    }


    public void downBizFile(List<String> keys, HttpServletResponse response) {
        File file = new File(System.currentTimeMillis() + ".zip");
        getBizFile(keys, file);
        OutputStream toClient = null;
        try {
            // 以流的形式下载文件。
            BufferedInputStream fis = new BufferedInputStream(new FileInputStream(file.getPath()));
            byte[] buffer = new byte[fis.available()];
            fis.read(buffer);
            fis.close();
            // 清空response
            response.reset();
            toClient = new BufferedOutputStream(response.getOutputStream());
            response.setCharacterEncoding("UTF-8");
            response.setContentType("application/octet-stream");
            response.setHeader("Content-Disposition", "attachment;filename=" + file.getName());
            toClient.write(buffer);
            toClient.flush();
        } catch (Exception e) {
           e.printStackTrace();
        } finally {
            if (toClient != null) {
                try {
                    toClient.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            //删除改临时zip包(此zip包任何时候都不需要保留,因为源文件随时可以再次进行压缩生成zip包)
            file.delete();
        }
    }

}

相关配置类

public enum ConflictPolicy {
    REPLACE, NEW, RETAIN
}


@Component
@ConfigurationProperties(prefix="aws.s3")
public class S3Config {

    private String accessKey;

    private String secretKey;

    private String bucketName;

    private String region;

    private String project;

    private String module;

    private String endpoint;

    public String getEndpoint() {
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
        this.endpoint = endpoint;
    }

    public String getModule() {
        return module;
    }

    public void setModule(String module) {
        this.module = module;
    }

    public String getAccessKey() {
        return accessKey;
    }

    public void setAccessKey(String accessKey) {
        this.accessKey = accessKey;
    }

    public String getSecretKey() {
        return secretKey;
    }

    public void setSecretKey(String secretKey) {
        this.secretKey = secretKey;
    }

    public String getBucketName() {
        return bucketName;
    }

    public void setBucketName(String bucketName) {
        this.bucketName = bucketName;
    }

    public String getRegion() {
        return region;
    }

    public void setRegion(String region) {
        this.region = region;
    }

    public String getProject() {
        return project;
    }

    public void setProject(String project) {
        this.project = project;
    }
}


aws:
  s3:
    endpoint: https://s3-xxxxx.com
    accessKey: xxxxx
    secretKey: xxxx
    bucketName: xxx
    region: cn-north-1
    project: xxx
    module: dev

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2270581.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

使用Xjar给SpringBoot项目jar包加密

1. 新建一个SpringBoot项目 2. 在pom文件添加依赖&#xff0c;github地址&#xff1a;https://github.com/core-lib/xjar <dependencies><!-- 添加 XJar 依赖 --><dependency><groupId>com.github.core-lib</groupId><artifactId>xjar&l…

UNI-APP_i18n国际化引入

官方文档&#xff1a;https://uniapp.dcloud.net.cn/tutorial/i18n.html vue2中使用 1. 新建文件 locale/index.js import en from ./en.json import zhHans from ./zh-Hans.json import zhHant from ./zh-Hant.json const messages {en,zh-Hans: zhHans,zh-Hant: zhHant }…

AI大模型系列之七:Transformer架构讲解

目录 Transformer网络是什么&#xff1f; 输入模块结构&#xff1a; 编码器模块结构&#xff1a; 解码器模块: 输出模块结构&#xff1a; Transformer 具体是如何工作的&#xff1f; Transformer核心思想是什么&#xff1f; Transformer的代码架构 自注意力机制是什么…

【Linux】:多线程(读写锁 自旋锁)

✨ 倘若南方知我意&#xff0c;莫将晚霞落黄昏 &#x1f30f; &#x1f4c3;个人主页&#xff1a;island1314 &#x1f525;个人专栏&#xff1a;Linux—登神长阶 ⛺️ 欢迎关注&#xff1a;&#x1f44d;点赞 &#…

SELECT的使用

目录 1、SQL的查询命令 1.1 SELECT语句 1.2 投影查询 1.3 选择查询 1.4 聚合函数查询 1.5 简单分组查询(GROUP BY) 1.6 内连接查询 1.7 外连接查询 1.8 子查询 1. 无关子查询 2. 相关子查询 带exists的相关子查询&#xff1a; 1.9 集合查询 1. UNION(并) 2. INT…

Vue项目结构推荐(复杂国际化项目与一般项目结构)

Vue项目结构推荐 一、一般项目结构二、复杂国际化项目结构总结/建议 下面结构是基于Vue和TypeScript开发的项目结构下src包下的结构&#xff0c;若只用到vue与js。则去掉typescript部分的包即可。 一、一般项目结构 assets&#xff1a;存放静态资源&#xff0c;如图片、字体、样…

BOC调制信号matlab性能仿真分析,对比功率谱,自相关性以及抗干扰性

目录 1.算法运行效果图预览 2.算法运行软件版本 3.部分核心程序 4.算法理论概述 5.算法完整程序工程 1.算法运行效果图预览 (完整程序运行后无水印) 2.算法运行软件版本 matlab2022a 3.部分核心程序 &#xff08;完整版代码包含详细中文注释和操作步骤视频&#xff09…

电影院售票 - 策略模式(Strategy Pattern)

策略模式&#xff08;Strategy Pattern&#xff09; 策略模式&#xff08;Strategy Pattern&#xff09;策略模式概述策略模式结构图策略模式主要包含的角色 talk is cheap&#xff0c; show you my code总结 策略模式&#xff08;Strategy Pattern&#xff09; 策略模式&…

重学 Android 自定义 View 系列(十):带指针的渐变环形进度条

前言 该篇文章根据前面 重学 Android 自定义 View 系列(六)&#xff1a;环形进度条 拓展而来。 最终效果如下&#xff1a; 1. 扩展功能 支持进度顺时针或逆时针显示在进度条末尾添加自定义指针图片使用线性渐变为进度条添加颜色效果 2. 关键技术点解析 2.1 进度方向控制的…

【北京迅为】iTOP-4412全能版使用手册-第七十章 Linux内核移植

iTOP-4412全能版采用四核Cortex-A9&#xff0c;主频为1.4GHz-1.6GHz&#xff0c;配备S5M8767 电源管理&#xff0c;集成USB HUB,选用高品质板对板连接器稳定可靠&#xff0c;大厂生产&#xff0c;做工精良。接口一应俱全&#xff0c;开发更简单,搭载全网通4G、支持WIFI、蓝牙、…

CG顶会论文阅读|《科技论文写作》硕士课程报告

文章目录 一、基本信息1.1 论文基本信息1.2 课程基本信息1.3 博文基本信息 二、论文评述&#xff08;中英双语&#xff09;2.1 研究问题&#xff08;Research Problem&#xff09;2.2 创新点&#xff08;Innovation/Contribution&#xff09;2.3 优点&#xff08;Why this pape…

.NET周刊【12月第4期 2024-12-22】

国内文章 dotnet 简单使用 ICU 库进行分词和分行 https://www.cnblogs.com/lindexi/p/18622917 本文将和大家介绍如何使用 ICU 库进行文本的分词和分行。 dotnet 简单聊聊 Skia 里的 SKFontMetrics 的各项属性作用 https://www.cnblogs.com/lindexi/p/18621674 本文将和大…

git 问题解决记录

在用git上传文件到仓库中出现了2个问题 第一个问题&#xff1a; 需要修改git的代理端口与电脑自己的代理服务器设置中的端口和VPN的端口保持一致&#xff0c; 比如我的端口是7897&#xff0c;就设置 git config --global http.proxy http://127.0.0.1:7897 git config --glo…

XML结构快捷转JSON结构API集成指南

XML结构快捷转JSON结构API集成指南 引言 在当今的软件开发世界中&#xff0c;数据交换格式的选择对于系统的互操作性和效率至关重要。JSON&#xff08;JavaScript Object Notation&#xff09;和XML&#xff08;eXtensible Markup Language&#xff09;是两种广泛使用的数据表…

Oracle 创建本地用户,授予权限,创建表并插入数据

目录 一. 用户的种类二. 切换session为PDB三. 创建用户并授予权限四. 创建表空间五. 为用户分配默认表空间并指定表空间配额六. 通过创建的用户进行登录七. 创建脚本&#xff0c;简化登录八. 查看用户信息九. 创建表&#xff0c;并插入数据9.1 查看当前用户的schema9.2 插入数据…

系统设计——大文件传输方案设计

摘要 大文件传输是指通过网络将体积较大的文件从一个位置发送到另一个位置的过程。这些文件可能包括高清视频、大型数据库、复杂的软件安装包等&#xff0c;它们的大小通常超过几百兆字节&#xff08;MB&#xff09;甚至达到几个吉字节&#xff08;GB&#xff09;或更大。大文…

【老白学 Java】简单位移动画

简单位移动画 文章来源&#xff1a;《Head First Java》修炼感悟。 上一篇文章中&#xff0c;老白利用内部类的特性完成了多个事件的处理&#xff0c;感觉还不错。 为了更深入理解内部类&#xff0c;本篇文章继续使用内部类创建一个画板&#xff0c;完成简单的位移动画&#x…

彻底解决 Selenium ChromeDriver 不匹配问题:Selenium ChromeDriver 最新版本下载安装教程

在 Python 的 Selenium 自动化测试中&#xff0c;ChromeDriver 是不可或缺的工具。它作为代码与 Chrome 浏览器的桥梁&#xff0c;但如果版本不匹配&#xff0c;就会导致各种报错&#xff0c;尤其是以下常见问题&#xff1a; selenium.common.exceptions.SessionNotCreatedExc…

[CTF/网络安全] 攻防世界 warmup 解题详析

查看页面源代码&#xff0c;发现source.php 得到一串代码&#xff0c;进行代码审计&#xff1a; <?phpclass emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php"];…

基于fMRI数据计算脑脊液(CSF)与全脑BOLD信号的时间耦合分析

一、前言 笔者之前的文章《基于Dpabi和spm12的脑脊液(csf)分割和提取笔记》,介绍了如何从普通的fMRI数据中提取CSF信号。首先是基础的预处理,包括时间层校正、头动校正,再加上0.01-0.1Hz的带通滤波。接着用SPM12分割出CSF区域,设置一个比较严格的0.9阈值,确保提取的真是…