当前位置: 首页 > news >正文

这才是企业级的oss-spring-boot-starter,属实好用!

来源:juejin.cn/post/7211828279430021180

👉 欢迎加入小哈的星球,你将获得:专属的项目实战(多个项目) / 1v1 提问 /Java 学习路线 /学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《Spring AI 项目实战》正在更新中..., 基于 Spring AI + Spring Boot 3.x + JDK 21;

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍;演示地址:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》2期已完结,演示链接:http://116.62.199.48/;

  • 专栏阅读地址:https://www.quanxiaoha.com/column

截止目前,累计输出 100w+ 字,讲解图 4013+ 张,还在持续爆肝中..后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有4200+小伙伴加入

  • 什么是OSS?

  • OSS在项目中的使用

  • 什么是AmazonS3

  • 找到我们需要的依赖

  • 编写OssProperties

  • 创建一个接口OssTemplate

  • 创建OssTemplate的实现类

  • 创建OssAutoConfiguration

  • 创建我们的spring.factories

  • 执行install打包到我们的本地仓库

  • 测试

  • 后记

  • 项目源码地址


本文主要讲解企业级OSS对象存储服务Spring Boot Starter制作,开箱即用,为项目进行赋能。基于AmazonS3协议,适配市面上的对象存储服务如:阿里云OSS、腾讯COS、七牛云OSS、MInio等等

什么是OSS?

OSS(Object Storage Service),对象存储服务,对象存储服务是一种使用HTTP API存储和检索对象的工具。就是将系统所要用的文件上传到云硬盘上,该云硬盘提供了文件下载、上传、预览等一系列服务,具备版本,权限控制能力,具备数据生命周期管理能力这样的服务以及技术可以统称为OSS

OSS在项目中的使用

OSS对象存储在目前大部分项目中必不可少的存在,如下图所示。

img
  1. 一般项目使用OSS对象存储服务,主要是对图片、文件、音频等对象集中式管理权限控制,管理数据生命周期等等,提供上传,下载,预览,删除等功能。

  2. 通过OSS部署前端项目。

什么是AmazonS3

Amazon Simple Storage Service(Amazon S3,Amazon简便存储服务)是 AWS 最早推出的云服务之一,经过多年的发展,S3 协议在对象存储行业事实上已经成为标准。

  1. 提供了统一的接口 REST/SOAP 来统一访问任何数据

  2. 对 S3 来说,存在里面的数据就是对象名(键),和数据(值)

  3. 不限量,单个文件最高可达 5TB,可动态扩容。

  4. 高速。每个 bucket 下每秒可达 3500 PUT/COPY/POST/DELETE 或 5500 GET/HEAD 请求。

  5. 具备版本,权限控制能力

  6. 具备数据生命周期管理能力

作为一个对象存储服务,S3 功能真的很完备,行业的标杆,目前市面上大部分OSS对象存储服务都支持AmazonS3,本文主要讲解的就是基于AmazonS3实现我们自己的****Spring Boot Starter。

阿里云OSS兼容S3
img
七牛云对象存储兼容S3
img
腾讯云COS兼容S3
img
Minio兼容S3
img
我们为什么要基于AmazonS3实现Spring Boot Starter

原因:市面上OSS对象存储服务基本都支持AmazonS3,我们封装我们的自己的starter那么就必须考虑适配,迁移,可扩展。比喻说我们今天使用的是阿里云OSS对接阿里云OSS的SDK,后天我们使用的是腾讯COS对接是腾讯云COS,我们何不直接对接AmazonS3实现呢,这样后续不需要调整代码,只需要去各个云服务商配置就好了。

创建一个SpringBoot项目

如下图所示:创建一个SpringBoot项目。

我们取名为oss-spring-boot-starter。

img

如下图所示,创建成功,让我们进入制作的过程吧。

img

找到我们需要的依赖

打开maven仓库,搜索minio

地址

  • https://mvnrepository.com/

img

这里我们选择第一个,点进去后我们选择1.12.423版本,做演示。

img
<dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-s3</artifactId> <version>1.12.423</version> </dependency>
本项目的Pom文件
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>2.7.9</version> <relativePath/><!-- lookup parent from repository --> </parent> <groupId>com.qing</groupId> <artifactId>oss-spring-boot-starter</artifactId> <version>0.0.1-SNAPSHOT</version> <name>oss-spring-boot-starter</name> <description>Demo oss-spring-boot-starter</description> <properties> <java.version>1.8</java.version> <aws.version>1.12.423</aws.version> <hutool.version>5.8.5</hutool.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter</artifactId> </dependency> <dependency> <groupId>com.amazonaws</groupId> <artifactId>aws-java-sdk-s3</artifactId> <version>${aws.version}</version> </dependency> <dependency> <groupId>cn.hutool</groupId> <artifactId>hutool-core</artifactId> <version>${hutool.version}</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>org.projectlombok</groupId> <artifactId>lombok</artifactId> <version>RELEASE</version> <scope>compile</scope> </dependency> </dependencies> </project>

编写OssProperties

代码如下,注释写的非常清楚了。**@ConfigurationProperties报红不用管后面会解决。**@Data:注解是lombok,生成get set方法的。

  • @ConfigurationProperties(prefix = "oss"):将配置文件中oss开头的属性绑定到此对象中

大概就是如果想要使用我们的jar他的配置文件有这些配置

oss.endpoint=xxx oss.accessKey=xxx oss.secretKey=xxx /** * @Author JiaQIng * @Description Oss配置类 * @ClassName OssProperties * @Date 2023/3/18 17:51 **/ @Data @ConfigurationProperties(prefix = "oss") publicclass OssProperties { /** * 对象存储服务的URL */ private String endpoint; /** * 区域 */ private String region; /** * true path-style nginx 反向代理和S3默认支持 pathStyle模式 {http://endpoint/bucketname} * false supports virtual-hosted-style 阿里云等需要配置为 virtual-hosted-style 模式{http://bucketname.endpoint} * 只是url的显示不一样 */ private Boolean pathStyleAccess = true; /** * Access key */ private String accessKey; /** * Secret key */ private String secretKey; /** * 最大线程数,默认:100 */ private Integer maxConnections = 100; }

创建一个接口OssTemplate

OssTemplate:oss模板接口,此接口主要是对oss操作的方法的一个接口,定义为接口主要是满足可扩展原则,就是其他人使用了我们的jar包,实现此接口可以自定义相关操作。

如下面所示代码:定义了一些对oss操作的方法。

/** * @Author JiaQIng * @Description oss操作模板 * @ClassName OssTemplate * @Date 2023/3/18 18:15 **/ publicinterface OssTemplate { /** * 创建bucket * @param bucketName bucket名称 */ void createBucket(String bucketName); /** * 获取所有的bucket * @return */ List<Bucket> getAllBuckets(); /** * 通过bucket名称删除bucket * @param bucketName */ void removeBucket(String bucketName); /** * 上传文件 * @param bucketName bucket名称 * @param objectName 文件名称 * @param stream 文件流 * @param contextType 文件类型 * @throws Exception */ void putObject(String bucketName, String objectName, InputStream stream, String contextType) throws Exception; /** * 上传文件 * @param bucketName bucket名称 * @param objectName 文件名称 * @param stream 文件流 * @throws Exception */ void putObject(String bucketName, String objectName, InputStream stream) throws Exception; /** * 获取文件 * @param bucketName bucket名称 * @param objectName 文件名称 * @return S3Object */ S3Object getObject(String bucketName, String objectName); /** * 获取对象的url * @param bucketName * @param objectName * @param expires * @return */ String getObjectURL(String bucketName, String objectName, Integer expires); /** * 通过bucketName和objectName删除对象 * @param bucketName * @param objectName * @throws Exception */ void removeObject(String bucketName, String objectName) throws Exception; /** * 根据文件前置查询文件 * @param bucketName bucket名称 * @param prefix 前缀 * @param recursive 是否递归查询 * @return S3ObjectSummary 列表 */ List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive); }

创建OssTemplate的实现类

如下图所示:实现OssTemplate里面的方法,调用AmazonS3JavaSDK的方法实现。

AmazonS3提供了众多的方法,这里就不写全部的了,公司要用到那些就写那些吧,后续扩展就行。

AmazonS3接口地址如下

  • https://docs.aws.amazon.com/AmazonS3/latest/API/API_CreateBucket.html

此类解释:就是实现OssTemplate接口,引入AmazonS3客户端调用对应的接口。

使用的注解解释:

  • @RequiredArgsConstructor:lomnok的注解,替代@Autowired

  • @SneakyThrows:lomnok的注解,抛出异常。

/** * @Author JiaQIng * @Description OssTemplate的实现类 * @ClassName OssTemplateImpl * @Date 2023/3/18 19:02 **/ @RequiredArgsConstructor publicclass OssTemplateImpl implements OssTemplate { privatefinal AmazonS3 amazonS3; /** * 创建Bucket * @param bucketName bucket名称 */ @Override @SneakyThrows public void createBucket(String bucketName) { if ( !amazonS3.doesBucketExistV2(bucketName) ) { amazonS3.createBucket((bucketName)); } } /** * 获取所有的buckets * @return */ @Override @SneakyThrows public List<Bucket> getAllBuckets() { return amazonS3.listBuckets(); } /** * 通过Bucket名称删除Bucket * @param bucketName */ @Override @SneakyThrows public void removeBucket(String bucketName) { amazonS3.deleteBucket(bucketName); } /** * 上传对象 * @param bucketName bucket名称 * @param objectName 文件名称 * @param stream 文件流 * @param contextType 文件类型 */ @Override @SneakyThrows public void putObject(String bucketName, String objectName, InputStream stream, String contextType) { putObject(bucketName, objectName, stream, stream.available(), contextType); } /** * 上传对象 * @param bucketName bucket名称 * @param objectName 文件名称 * @param stream 文件流 */ @Override @SneakyThrows public void putObject(String bucketName, String objectName, InputStream stream) { putObject(bucketName, objectName, stream, stream.available(), "application/octet-stream"); } /** * 通过bucketName和objectName获取对象 * @param bucketName bucket名称 * @param objectName 文件名称 * @return */ @Override @SneakyThrows public S3Object getObject(String bucketName, String objectName) { return amazonS3.getObject(bucketName, objectName); } /** * 获取对象的url * @param bucketName * @param objectName * @param expires * @return */ @Override @SneakyThrows public String getObjectURL(String bucketName, String objectName, Integer expires) { Date date = new Date(); Calendar calendar = new GregorianCalendar(); calendar.setTime(date); calendar.add(Calendar.DAY_OF_MONTH, expires); URL url = amazonS3.generatePresignedUrl(bucketName, objectName, calendar.getTime()); return url.toString(); } /** * 通过bucketName和objectName删除对象 * @param bucketName * @param objectName */ @Override @SneakyThrows public void removeObject(String bucketName, String objectName) { amazonS3.deleteObject(bucketName, objectName); } /** * 根据bucketName和prefix获取对象集合 * @param bucketName bucket名称 * @param prefix 前缀 * @param recursive 是否递归查询 * @return */ @Override @SneakyThrows public List<S3ObjectSummary> getAllObjectsByPrefix(String bucketName, String prefix, boolean recursive) { ObjectListing objectListing = amazonS3.listObjects(bucketName, prefix); return objectListing.getObjectSummaries(); } /** * * @param bucketName * @param objectName * @param stream * @param size * @param contextType * @return */ @SneakyThrows private PutObjectResult putObject(String bucketName, String objectName, InputStream stream, long size, String contextType) { byte[] bytes = IOUtils.toByteArray(stream); ObjectMetadata objectMetadata = new ObjectMetadata(); objectMetadata.setContentLength(size); objectMetadata.setContentType(contextType); ByteArrayInputStream byteArrayInputStream = new ByteArrayInputStream(bytes); // 上传 return amazonS3.putObject(bucketName, objectName, byteArrayInputStream, objectMetadata); } }

创建OssAutoConfiguration

img
OssAutoConfiguration`:自动装配配置类,自动装配的bean有`AmazonS3`和`OssTemplate

所使用的注解:

  • @RequiredArgsConstructor:lomnok的注解,替代@Autowired。

  • @EnableConfigurationProperties(OssProperties.class):自动装配我们的配置类

  • @Bean:声明式bean。

  • @ConditionalOnMissingBean:修饰bean的一个注解,当你的bean被注册之后,注册相同类型的bean,就不会成功,它会保证你的bean只有一个,即你的实例只有一个。多个会报错。

  • @ConditionalOnBean(AmazonS3.class):当给定的在bean存在时,则实例化当前Bean。

/** * @Author JiaQIng * @Description oss配置bean * @ClassName OssAConfiguration * @Date 2023/3/18 18:23 **/ @Configuration @RequiredArgsConstructor @EnableConfigurationProperties(OssProperties.class) public class OssAutoConfiguration { @Bean @ConditionalOnMissingBean public AmazonS3 ossClient(OssProperties ossProperties) { // 客户端配置,主要是全局的配置信息 ClientConfiguration clientConfiguration = new ClientConfiguration(); clientConfiguration.setMaxConnections(ossProperties.getMaxConnections()); // url以及region配置 AwsClientBuilder.EndpointConfiguration endpointConfiguration = new AwsClientBuilder.EndpointConfiguration( ossProperties.getEndpoint(), ossProperties.getRegion()); // 凭证配置 AWSCredentials awsCredentials = new BasicAWSCredentials(ossProperties.getAccessKey(), ossProperties.getSecretKey()); AWSCredentialsProvider awsCredentialsProvider = new AWSStaticCredentialsProvider(awsCredentials); // build amazonS3Client客户端 return AmazonS3Client.builder().withEndpointConfiguration(endpointConfiguration) .withClientConfiguration(clientConfiguration).withCredentials(awsCredentialsProvider) .disableChunkedEncoding().withPathStyleAccessEnabled(ossProperties.getPathStyleAccess()).build(); } @Bean @ConditionalOnBean(AmazonS3.class) public OssTemplate ossTemplate(AmazonS3 amazonS3){ returnnew OssTemplateImpl(amazonS3); } }
ClientConfiguration对象

客户端配置,主要是全局的配置信息

看下图,有很多的配置,有的指定了默认值有的没有,可以到AmazonS3的官方文档熟悉相关配置,配置你所需要指定的配置信息等。

只有你真正的理解那些配置的作用才能避免线上的bug。有兴趣的同学可以看一下。

img

创建我们的spring.factories

在resources目录下新增META-INF包,下面新建spring.factories文件。

这种形式也是"约定大于配置"的体现。读过spring-boot源码的同学应该知道,这里就不给大家讲解了。

如下图所示:

org.springframework.boot.autoconfigure.EnableAutoConfiguration=\ com.qing.oss.OssAutoConfiguration

执行install打包到我们的本地仓库

把springboot工程的启动类,配置文件干掉,干掉Test包。

最重要的是干掉pom文件的spring-boot-maven-plugin,要不然install报错。

img
<build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build>

这样我们的一个oss-spring-boot-starter就完成了。

img

执行install打包成jar到我们的本地仓库。

img

到我们的本地仓库就能看到我们的oss-spring-boot-starter

img

测试

创建一个spring-boot工程当作我们的测试工程

这里就不演示怎么创建项目了。直接看下图吧

img
pom文件新增我们的oss-spring-boot-starter依赖

新增版本全局配置

<properties> <oss.version>0.0.1-SNAPSHOT</oss.version> </properties>

新增oss-spring-boot-starter依赖

<dependency> <groupId>com.qing</groupId> <artifactId>oss-spring-boot-starter</artifactId> <version>${oss.version}</version> </dependency>

刷新maven后可以看到我们依赖加进来了。

img
解决打包没有注释的问题

可以发现我们的依赖没有注释没有Javadoc注释。

在我们的oss-string-boot-starter的pom文件下加入下面插件,重新install一下就好了。

<build> <plugins> <!-- 在打好的jar包中保留javadoc注释,实际会另外生成一个xxxxx-sources.jar --> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <executions> <execution> <id>attach-sources</id> <goals> <goal>jar</goal> </goals> </execution> </executions> </plugin> </plugins> </build>

在我们的测试项目里面刷新一下maven可以看到已经带注释了。

img
配置文件添加oss-spring-boot-starter所需要的配置

这里填写你的阿里云,腾讯cos,七牛云,minio等等的配置。

下面我给大家演示的是Minio

oss.endpoint=xxx oss.accessKey=xxx oss.secretKey=xxx
编写测试方法

如下图所示,编写测试方法,执行测试方法成功。

@SpringBootTest class TestOssSpringBpptStarterApplicationTests { @Autowired private OssTemplate ossTemplate; @Test void contextLoads() { ossTemplate.createBucket("oss02"); } }
img

到我的Minio中查看发现测试成功。

img

后记

本文主要讲解企业级OSS对象存储服务Spring Boot Starter制作,开箱即用,为项目进行赋能。基于AmazonS3协议,适配市面上的大部分对象存储服务如:阿里云OSS、腾讯COS、七牛云OSS、MInio等等

如何制作spring-boot-starter,看这篇就够了。

项目源码地址

https://github.com/hujiaqing789/test-spring-boot-starter

👉 欢迎加入小哈的星球,你将获得:专属的项目实战(多个项目) / 1v1 提问 /Java 学习路线 /学习打卡 / 每月赠书 / 社群讨论

  • 新项目:《Spring AI 项目实战》正在更新中..., 基于 Spring AI + Spring Boot 3.x + JDK 21;

  • 《从零手撸:仿小红书(微服务架构)》 已完结,基于 Spring Cloud Alibaba + Spring Boot 3.x + JDK 17..., 点击查看项目介绍;演示地址:http://116.62.199.48:7070/

  • 《从零手撸:前后端分离博客项目(全栈开发)》2期已完结,演示链接:http://116.62.199.48/;

  • 专栏阅读地址:https://www.quanxiaoha.com/column

截止目前,累计输出 100w+ 字,讲解图 4013+ 张,还在持续爆肝中..后续还会上新更多项目,目标是将 Java 领域典型的项目都整一波,如秒杀系统, 在线商城, IM 即时通讯,Spring Cloud Alibaba 等等,戳我加入学习,解锁全部项目,已有4200+小伙伴加入

1. 我的私密学习小圈子,从0到1手撸企业实战项目~ 2. MyBatis 批量插入从5分钟缩短到3秒?我的三个关键优化 3. 面试官:String 为什么设计成 final 不可变的? 4. 五大 Java 对象映射工具终极对决:从 Spring、Apache 到 MapStruct 的性能深度评测
最近面试BAT,整理一份面试资料《Java面试BATJ通关手册》,覆盖了Java核心技术、JVM、Java并发、SSM、微服务、数据库、数据结构等等。 获取方式:点“在看”,关注公众号并回复 Java 领取,更多内容陆续奉上。
PS:因公众号平台更改了推送规则,如果不想错过内容,记得读完点一下“在看”,加个“星标”,这样每次新文章推送才会第一时间出现在你的订阅列表里。 点“在看”支持小哈呀,谢谢啦
http://www.jsqmd.com/news/336617/

相关文章:

  • API接口调用操作步骤与公众号内容热度解析指南
  • 15分钟全面掌握:进程/线程、同步/异步、阻塞/非阻塞、并发/并行
  • 收藏备用|告别“小作文”式Prompt:小白也能看懂的Agent Skills构建全指南
  • 一文详解ITIL 4 与 ITILV5之间核心差异、更新及改进
  • 新中式高定服装加盟2026,趋势品牌一网打尽,优质的新中式高定服装加盟哪家好色麦新中式引领行业标杆 - 品牌推荐师
  • <span class=“js_title_inner“>国家标准《网络安全技术 软件产品开源代码安全评价方法》GB/T 43848—2024正式发布</span>
  • 智能多功能AI配音系统源码,支持导出行业标准的MP3格式
  • 重庆银行,国密SM4,自定义算法,C#.NET版
  • 广州时尚天河附近白切鸡餐厅,值得去的有哪些 - myqiye
  • app添加每日自定义任务+已经完成任务+没完成任务
  • 科研提速!AI辅助实验数据拟合与分析:告别手动计算,10分钟出精准结果
  • Go分布式追踪实战:从理论到OpenTelemetry集成|Go语言进阶(15) - 详解
  • leetcode 888. Fair Candy Swap 公平的糖果交换
  • 智泊AI官网:与时俱进!大模型应用开发重磅上线!
  • openshift 4.20.12安装报错 1 waitforceo.go:69] waiting on condition EtcdRunningInCluster in etcd CR /clus
  • yolov8,U-Net++,Transformer
  • 学术导航仪:用书匠策AI解锁期刊论文写作的“超维空间”
  • 论文写作AI工具哪个好?2026年精选8款一键生成论文的软件亲测,AI写作效率与低查重兼得! - 掌桥科研-AI论文写作
  • 石油智能体,让钻头自己“找油”
  • 郑州研究生留学中介前十盘点,口碑好机构详细评测 - 留学机构评审官
  • 时尚必读!圣罗兰YSL六大经典款包,你拥有哪一款?
  • <span class=“js_title_inner“>通过vivado HLS设计一个FIR低通滤波器</span>
  • 定位误差暴降23%!MIT新作VGGT-SLAM 2.0:实时密集前馈场景重建,消除15自由度漂移问题
  • <span class=“js_title_inner“>内存还能涨多久?</span>
  • 2026年本地排名前五GEO优化公司选哪家,小红书推广/百度推广/抖音推广/快手代运营,GEO优化公司推荐排行 - 品牌推荐师
  • 自动驾驶之心春节活动来啦(2.1-2.23)
  • RA-L 2026 南开最新开源!R-VoxelMap:长距离定位不漂移,定位更精准、更稳健!
  • 2026 年热门的陕西保温铝板一体板优质厂家最新推荐榜 - 朴素的承诺
  • 书匠策AI:期刊论文写作的“智能航海图”,带你驶向学术新大陆
  • 2026年泰州、常州好用的非织造布设备分梳辊厂家推荐,哪家靠谱? - 工业推荐榜