AWS S3文件存储工具类
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;@AutowiredS3Config s3Config;@PostConstructpublic 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("."));//取出同名文件的最大numberint 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, 设置为空表示列出所有的objectobjectsRequest.setDelimiter(deleteAll ? "" : "/");// 设置最大遍历出多少个对象, 一次listobject最大支持1000objectsRequest.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();// 清空responseresponse.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.comaccessKey: xxxxxsecretKey: xxxxbucketName: xxxregion: cn-north-1project: xxxmodule: dev
相关文章:
AWS S3文件存储工具类
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.a…...
【leetcode100】二叉树的中序遍历
1、题目描述 给定一个二叉树的根节点 root ,返回 它的 中序 遍历 。 示例 1: 输入:root [1,null,2,3] 输出:[1,3,2] 2、初始思路 2.1 思路 中序遍历的顺序是左→根→右,定义一个函数进行遍历 # Definition for …...
开源GTKSystem.Windows.Forms框架:C# Winform跨平台运行深度解析
开源GTKSystem.Windows.Forms框架:C# Winform跨平台运行深度解析 一、跨平台框架的崛起 1.1 跨平台技术的现状与需求 在当今快速发展的科技时代,软件开发的需求日益多样化。随着移动设备和操作系统的不断涌现,开发者面临着前所未有的挑战&…...
C++软件设计模式之责任链模式
责任链模式的动机与意图 动机: 在软件开发中,经常会遇到需要处理一系列请求或事件的情况。这些请求可能需要经过多个处理对象,每个对象根据其职责决定是否处理请求或将其传递给下一个对象。责任链模式(Chain of Responsibility P…...
021-spring-springmvc-组件
SpringMVC的handMapping 比较重要的部分 比较重要的部分 比较重要的部分 关于组件的部分 这里以 RequestMappingHandlerMapping 为例子 默认的3个组件是: org.springframework.web.servlet.handler.BeanNameUrlHandlerMapping org.springframework.web.servlet.mvc…...
基于SpringBoot和OAuth2,实现通过Github授权登录应用
基于SpringBoot和OAuth2,实现通过Github授权登录应用 文章目录 基于SpringBoot和OAuth2,实现通过Github授权登录应用0. 引言1. 创建Github应用2. 创建SpringBoot测试项目2.1 初始化项目2.2 设置配置文件信息2.3 创建Controller层2.4 创建Html页面 3. 启动…...
macos 支持外接高分辩率显示器开源控制软件
macos 支持外接高分辩率显示器开源控制软件 软件(app应用)名:BetterDisplay 官方地址: https://github.com/waydabber/BetterDisplay...
C++26 新特性预览(Preview)
文章目录 1. 静态反射 (Static Reflection)示例: 枚举转字符串应用场景 2. 合约 (Contracts)示例: 定义函数合约应用场景 3. 条件中的结构化绑定 (Structured Bindings in Conditions)示例: 改进的错误处理应用场景 4. 包索引 (Pack Indexing)示例: 获取参数包的第一个和最后一…...
MySQL5.7.26-Linux-安装(2024.12)
文章目录 1.下载压缩包1.访问MySQL版本归档2.找到5.7.26并下载3.百度网盘 2.Linux安装1.卸载原来的MySQL8.0.26(如果没有则无需在意)1.查看所有mysql的包2.批量卸载3.删除残留文件**配置文件**(默认路径): 4.**验证卸载…...
2025-1-2-sklearn学习(30)模型选择与评估-验证曲线: 绘制分数以评估模型 真珠帘卷玉楼空,天淡银河垂地。
文章目录 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型30.1. 验证曲线30.2. 学习曲线 sklearn学习(30) 模型选择与评估-验证曲线: 绘制分数以评估模型 文章参考网站: https://sklearn.apachecn.org/ 和 https://scikit-learn.org/stable/ 每种估…...
【优选算法】查找总价格为目标值的两个商品
链接:LCR 179. 查找总价格为目标值的两个商品 - 力扣(LeetCode) 解法:利用单调性,使用双指针算法解决问题 1.先从小到大排序 2. sum > t : right--; sum < t : left; sum t : return class Solution {public…...
利用 NineData 实现 PostgreSQL 到 Kafka 的高效数据同步
记录一次 PostgreSQL 到 Kafka 的数据迁移实践。前段时间,NineData 的某个客户在一个项目中需要将 PostgreSQL 的数据实时同步到 Kafka。需求明确且普遍: PostgreSQL 中的交易数据,需要实时推送到 Kafka,供下游多个系统消费&#…...
future和CompletableFuture
future 什么是future Future 类是并发编程中一个非常重要的工具。它主要用于表示一个异步计算的结果,允许你在计算完成后获取结果或处理异常。Java 的 Future 也常常与线程池(如 ExecutorService)结合使用,用来执行并行任务&…...
如何通过深度学习提升大分辨率图像预测准确率?
随着科技的不断进步,图像处理在各个领域的应用日益广泛,特别是在医疗影像、卫星遥感、自动驾驶、安防监控等领域中,大分辨率图像的使用已经成为了一项不可或缺的技术。然而,大分辨率图像带来了巨大的计算和存储压力,同…...
【机器学习】机器学习的基本分类-半监督学习-Ladder Networks
Ladder Networks 是一种半监督学习模型,通过将无监督学习与监督学习相结合,在标记数据较少的情况下实现高效的学习。它最初由 A. Rasmus 等人在 2015 年提出,特别适合深度学习任务,如图像分类或自然语言处理。 核心思想 Ladder N…...
[react]小技巧, ts如何声明点击事件的类型
很简单, 鼠标放到事件上面就行了 如果想知道点击的是什么元素 ,打印他的nodename就行了 不过得断言为html元素才行 const handleClick (e: React.MouseEvent<HTMLDivElement, MouseEvent>) > {console.log(current, (e.target as HTMLElement).nodeName);}; 为什么…...
智能工厂的设计软件 应用场景的一个例子:为AI聊天工具添加一个知识系统 之9 重新开始 之2
本文要点 对程序设计而言:前者基于一个自上而下的 分类体系--(生物遗传基因),后者者需要一个收集差异的自下而上的差异继承路径--(系统继承源流) 就是 广义和狭义 分类学。 共性对齐 和 差异收集 正是两者…...
【从零开始】11. LLaMA-Factory 微调 Qwen 模型(番外篇)
书接上回,在完成了 RAGChecker 测试后,离 RAG 应用真正发布还差最后一步 - 基础信息指令微调。考虑到模型还是需要具备一定程度的“自我认知”,因此需要将公司信息“嵌入”到模型里面的。为此,我选择了 LLaMA-Factory(…...
WPF使用ContentControl控件实现区域导航,并使用Prism依赖注入优化
背景:使用ContentControl控件实现区域导航是有Mvvm框架的WPF都能使用的,不限于Prism 主要是将ContenControl控件的Content内容在ViewModel中切换成不同的用户控件 下面是MainViewModel: private object body;public object Body {get { retu…...
JavaWeb——MySQL-DML(1/3)-添加数据insert(DML 操作概述、INSERT 语句插入数据、语句演示、总结)
目录 DML 操作概述 INSERT 语句插入数据 INSERT 语句基础语法 INSERT 语句演示 注意事项 总结 DML 操作概述 DML 简介 DML(Data Manipulation Language)即数据操作语言,用于对数据库表中的数据进行增删改操作,包括添加数据&…...
iOS 26 携众系统重磅更新,但“苹果智能”仍与国行无缘
美国西海岸的夏天,再次被苹果点燃。一年一度的全球开发者大会 WWDC25 如期而至,这不仅是开发者的盛宴,更是全球数亿苹果用户翘首以盼的科技春晚。今年,苹果依旧为我们带来了全家桶式的系统更新,包括 iOS 26、iPadOS 26…...
PHP和Node.js哪个更爽?
先说结论,rust完胜。 php:laravel,swoole,webman,最开始在苏宁的时候写了几年php,当时觉得php真的是世界上最好的语言,因为当初活在舒适圈里,不愿意跳出来,就好比当初活在…...
1688商品列表API与其他数据源的对接思路
将1688商品列表API与其他数据源对接时,需结合业务场景设计数据流转链路,重点关注数据格式兼容性、接口调用频率控制及数据一致性维护。以下是具体对接思路及关键技术点: 一、核心对接场景与目标 商品数据同步 场景:将1688商品信息…...
STM32F4基本定时器使用和原理详解
STM32F4基本定时器使用和原理详解 前言如何确定定时器挂载在哪条时钟线上配置及使用方法参数配置PrescalerCounter ModeCounter Periodauto-reload preloadTrigger Event Selection 中断配置生成的代码及使用方法初始化代码基本定时器触发DCA或者ADC的代码讲解中断代码定时启动…...
基于Docker Compose部署Java微服务项目
一. 创建根项目 根项目(父项目)主要用于依赖管理 一些需要注意的点: 打包方式需要为 pom<modules>里需要注册子模块不要引入maven的打包插件,否则打包时会出问题 <?xml version"1.0" encoding"UTF-8…...
【Java_EE】Spring MVC
目录 Spring Web MVC 编辑注解 RestController RequestMapping RequestParam RequestParam RequestBody PathVariable RequestPart 参数传递 注意事项 编辑参数重命名 RequestParam 编辑编辑传递集合 RequestParam 传递JSON数据 编辑RequestBody …...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
IP如何挑?2025年海外专线IP如何购买?
你花了时间和预算买了IP,结果IP质量不佳,项目效率低下不说,还可能带来莫名的网络问题,是不是太闹心了?尤其是在面对海外专线IP时,到底怎么才能买到适合自己的呢?所以,挑IP绝对是个技…...
招商蛇口 | 执笔CID,启幕低密生活新境
作为中国城市生长的力量,招商蛇口以“美好生活承载者”为使命,深耕全球111座城市,以央企担当匠造时代理想人居。从深圳湾的开拓基因到西安高新CID的战略落子,招商蛇口始终与城市发展同频共振,以建筑诠释对土地与生活的…...
【Nginx】使用 Nginx+Lua 实现基于 IP 的访问频率限制
使用 NginxLua 实现基于 IP 的访问频率限制 在高并发场景下,限制某个 IP 的访问频率是非常重要的,可以有效防止恶意攻击或错误配置导致的服务宕机。以下是一个详细的实现方案,使用 Nginx 和 Lua 脚本结合 Redis 来实现基于 IP 的访问频率限制…...
