关于微服务项目的文件存储(其一)
在之前普通的 SpringBoot 项目中,我们上传的文件大部分选择存储在那个单一的服务器上,因为整个项目只有一个服务,不涉及微服务的多服务。
但是当进入到了微服务项目阶段,我们的一个微服务中,可能要部署多台服务器,服务器不止一个,那现在,服务就不能单纯的上传到某一台服务器上面了,这样就会导致其他的服务器没有这个资源而导致不同步。那这样怎么解决呢?非常简单,我们有两个选择:
自建服务器
自己在建立一个服务器,专门用于存储要长传的文件。但是缺点是搭建复杂、维护成本高。
云存储
租用第三方,比如阿里云这样的云存储,不是自己的服务器。好处是即开即用,无需维护,按量收费。因此,大部分都会选择云存储。
接下来就以使用 阿里云 云存储服务来开始讲解。我们具体使用的是阿里云的对象存储(OSS)。首先要了解一下对象存储的一些专业术语。
存储空间(Bucket)
存储空间是存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。我们一般一个项目创建一个 Bucket。
对象/文件(Object)
对象是 OSS 存储数据的基本单元,也被称为 OSS 的文件。对象由以下几部分组成:
元信息(Object Meta)
用户数据(Data)
文件名(Key)
对象由存储空间内部唯一的 Key 来标识。
地域(Region)
地域表示 OSS 的数据中心所在的物理位置,可根据费用、请求来源等综合选择数据存储的地域。
访问域名(Endpoint)
访问域名表示 OSS 对外服务的访问域名。OSS 以 HTTP RESTful API 的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。
访问密钥(AccessKey)
访问密钥,即 AccessKey ,简称 AK,指的是访问身份验证中用到的 AccessKeyId 和 AccessKeySecret。OSS 通过使用 AccessKeyId 和 AccessKeySecret 对称加密的方法来验证某个请求的发送者身份。AccessKeyId 用于标识用户,AccessKeySecret 是用户用于加密前面字符串和 OSS 用来
创建我们的 Bucket 步骤:
开通阿里云的OSS服务(免费)
在创建自己的 Bucket

如上图所示,为自己的 Bucket 创建一个名字,选择标准存储(正式上线阶段使用)或者低频存储(测试、学习阶段使用),然后就可创建自己的 Bucket 了。
直接上传文件
直接按照网址的提示,手动上传文件,即可将文件进行云存储
访问文件
直接复制对应文件的访问 url ,即可进行浏览。
当然了,我们今后上传文件,肯定不是手动上传文件的,而是通过后台项目,自动上传的,并且得到文件对应的 url 。
今后我们自动上传主要有两种方式:
用户提交图片后,将上传请求,提交到网关,然后,交给具体处理的微服务,这个微服务拿到这个文件的图片流,将这个图片流数据,传给 OSS 并拿到对应 url。
让服务端签名后直传。即用户提交图片后,将上传请求,提交到网关,然后,交给具体处理的微服务,但是这个微服务不直接提交这个文件流,而是生成一个 Policy,这个 Policy 包含了加密后的账号密码,而阿里云端可以验证这个 Policy。微服务生成的这个 Policy 再传给前端,前端直接将 Policy 及文件,上传给 OSS 并返回对应 url。
但我们一般都是使用第二种方法。虽然第一种方法中,可以在通过在我们的服务器中,用自己的账号密码上传,更加安全,但上传图片还要过一遍我们自己的服务器,完全没有必要,在大量用户下会带来瓶颈。而第二种方法中,文件就不需要在我们的服务中过一遍了。
下面就来详细说一下如何自动上传,以及它的详细步骤。里详细说明了如何上传,具体可查阅官方文档,我就简单介绍下流程步骤。
添加依赖
<dependency>
<groupId>com.aliyun.ossgroupId>
<artifactId>aliyun-sdk-ossartifactId>
<version>3.18.3version>
dependency>配置访问凭证
首先要在中,创建使用永久 AccessKey 访问的 RAM 用户,保存 AccessKey,然后为该用户授予
AliyunOSSFullAccess权限,如下边两张图。

这个步骤完成后,会获取三个值:
AccessKey ID
一串字符串,要自己记住
AccessKey Secret
一串字符串,要自己记住
用户登录名称
刚刚注册的名称,即为:sanguimall@1109771891991402.onaliyun.com
接着就是为 AccessKey 配置环境变量(Windows):
setx OSS_ACCESS_KEY_ID "这里写你的 AccessKey ID"
setx OSS_ACCESS_KEY_SECRET "这里写你的 AccessKey Secret"此时,主要最好重启一下你的 idea,不然可能识别不了最新的环境变量。
编写原生程序
按照自己的实际信息填写。
/**
* 测试初始化
*/
public void testInitOss(){
// 从环境变量获取访问凭证
String accessKeyId = System.getenv("OSS_ACCESS_KEY_ID");
System.out.println(accessKeyId);
String accessKeySecret = System.getenv("OSS_ACCESS_KEY_SECRET");
System.out.println(accessKeySecret);
// 设置OSS地域和Endpoint
String region = "cn-beijing";
String endpoint = "oss-cn-beijing.aliyuncs.com";
// 创建凭证提供者
DefaultCredentialProvider provider = new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 配置客户端参数
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 显式声明使用V4签名算法
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 初始化OSS客户端
OSS ossClient = OSSClientBuilder.create()
.credentialsProvider(provider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.endpoint(endpoint)
.build();
// 列出当前用户的所有Bucket
List<Bucket> buckets = ossClient.listBuckets();
System.out.println("成功连接到 OSS 服务,当前账号下的 Bucket 列表:");
if (buckets.isEmpty()) {
System.out.println("当前账号下暂无 Bucket");
} else {
for (Bucket bucket : buckets) {
System.out.println("- " + bucket.getName());
}
}
// 释放资源
ossClient.shutdown();
System.out.println("OSS 客户端已关闭");
}
/**
* 测试上传功能
*/
public void testUpload() throws Exception {
// Endpoint 外网域名
String endpoint = "oss-cn-beijing.aliyuncs.com";
// 从环境变量中获取访问凭证。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写 Bucket 名称
String bucketName = "sanguimall-test";
// 填写 Object 完整路径,完整路径中不能包含 Bucket 名称
String objectName = "test/testImage.jpg";
// 填写本地文件的完整路径,
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "D:\\01-TempFiles\\2025-11-07-upload\\testImag.jpg";
// 填写 Bucket 所在地域
String region = "cn-beijing";
// 创建 OSSClient 实例。
// 当 OSSClient 实例不再使用时,调用 shutdown 方法以释放资源。
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
OSS ossClient = OSSClientBuilder.create()
.endpoint(endpoint)
.credentialsProvider(credentialsProvider)
.clientConfiguration(clientBuilderConfiguration)
.region(region)
.build();
try {
InputStream inputStream = new FileInputStream(filePath);
// 创建 PutObjectRequest 对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 创建 PutObject 请求。
PutObjectResult result = ossClient.putObject(putObjectRequest);
} catch (OSSException oe) {
System.out.println("Caught an OSSException, which means your request made it to OSS, "
+ "but was rejected with an error response for some reason.");
System.out.println("Error Message:" + oe.getErrorMessage());
System.out.println("Error Code:" + oe.getErrorCode());
System.out.println("Request ID:" + oe.getRequestId());
System.out.println("Host ID:" + oe.getHostId());
} catch (ClientException ce) {
System.out.println("Caught an ClientException, which means the client encountered "
+ "a serious internal problem while trying to communicate with OSS, "
+ "such as not being able to access the network.");
System.out.println("Error Message:" + ce.getMessage());
} finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}编写基于SpringCloud Alibaba 的 OSS 代码
之前的原生代码,类似于使用 JDBC 来连接数据库,今后会使用 中框架的继承代码来使用。当然使用框架也需要先执行之前的置访问凭证。
添加依赖
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>aliyun-oss-spring-boot-starterartifactId>
dependency>注意:若 Maven 显示该依赖爆红,则可以在
标签同级处,在下方添加如下版本空值的内容即可: <dependencyManagement>
<dependencies>
<dependency>
<groupId>com.alibaba.cloudgroupId>
<artifactId>aliyun-spring-boot-dependenciesartifactId>
<version>1.0.0version>
<type>pomtype>
<scope>importscope>
dependency>
dependencies>
dependencyManagement>
修改 yaml 文件
alibaba
cloud
oss
endpoint你自己的 endpoint
access-key$OSS_ACCESS_KEY_ID
secret-key$OSS_ACCESS_KEY_SECRET注意两个 key 是配置在本机的用户变量里的
添加配置文件
package com.sangui.sanguimall.product.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @Author: sangui
* @CreateTime: 2025-11-08
* @Description:
* @Version: 1.0
*/
public class OssConfig {
public com.aliyun.oss.OSS oss(
("${alibaba.cloud.oss.endpoint}") String endpoint,
("${alibaba.cloud.access-key}") String ak,
("${alibaba.cloud.secret-key}") String sk) {
// 注意:使用 OSSClientBuilder(适用于新版 SDK)
return new com.aliyun.oss.OSSClientBuilder().build(endpoint, ak, sk);
}
}测试程序
public class OssTest {
private OSSClient ossClient;
public void testPutObjectByResourceInject() throws FileNotFoundException {
String bucketName = "sanguimall-test";
String objectName = "test4/testImage2.jpg";
FileInputStream fileInputStream = new FileInputStream("D:\\01-TempFiles\\2025-11-07-upload\\testImag.jpg");
ossClient.putObject(bucketName,objectName,fileInputStream);
}
}
至此,程序流程就结束了,这种方式就是我们之前说的,将图片文件传给微服务端,再进行上传。但是,这种方式其实是不被推荐的,上传的人一多,就会有瓶颈。我们应该直接使用浏览器将图片文件提交给 OSS,而微服务端只需要提供签名数据(Policy)就行了。
- 微信
- 赶快加我聊天吧

- 赶快加我聊天吧
