目录
对象存储背景
单节点环境下,文件往往存储在tomcat服务器内,随着业务需求的增多,单节点已不能满足需求,项目架构需要扩展到多节点(见下图),此时文件经过nginx转发存储到某一个节点,在分布式架构下对文件的访问就存在问题(文件存储到节点A,查看文件请求到节点B访问不了文件)。

在分布式环境下,需要引入集中管理文件的节点服务,改进如下:

分布式文件服务解决方案有很多,常见的有:独立搭建文件服务器,如基于开源FastDFS搭建;引入第三方云储存方案,如基于阿里云的OSS;相比独立搭建文件服务器,云存储方案有诸多优势:SDK使用简单、运维成本低、图形化的管理控制台、提供强大的文件处理功能、CDN加速、服务扩展简单等,本文重点讲述基于阿里云的OSS方案。
阿里云OSS
使用步骤如下:
1、【阿里云官网】开通OSS服务
2、【阿里云官网】创建Bucket
重点关注标签有:Bucket 名称、Endpoint,本文新建的Bucket 名称 = gingko-sawyer,Endpoint = oss-cn-beijing.aliyuncs.com

3、【阿里云官网】创建并使用RAM账号进行API访问或日常运维,请登录RAM控制台创建RAM账号,创建AccessKey,并将AccessKeyId和AccessKeySecret设置到本地电脑环境变量中。


4、后台编写代码实现基于阿里云OSS文件上传及下载
4.1、添加aliyun.oss依赖
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
4.2、修改配置,增加对oss的支持
server:
port: 8080
#aliyun oss config
aliyun:
oss:
endpoint: oss-cn-beijing.aliyuncs.com
region: cn-beijing
bucket-name: gingko-sawyer
foler-prefix: oss/
host: https://gingko-sawyer.oss-cn-beijing.aliyuncs.com
4.3 文件上传&下载程序
java
package com.ginko.aliyunoss.controller;
import com.aliyun.oss.*;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.Protocol;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
import java.io.InputStream;
@RestController
@RequestMapping("oss")
@Slf4j
public class OSSController {
@Value("${aliyun.oss.endpoint}")
private String endpoint;
@Value("${aliyun.oss.region}")
private String region;
@Value("${aliyun.oss.bucket-name}")
private String bucketName;
@Value("${aliyun.oss.foler-prefix}")
private String folerPrefix;//上传到oss中具体的文件夹目录
@Value("${aliyun.oss.host}")
private String host;
@PostMapping("/upload")
public String upload(@RequestParam("file") MultipartFile file) throws Exception {
// 创建 ClientBuilderConfiguration 实例,用于配置 OSS 客户端参数
ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
// 设置签名算法版本为 V4
clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
// 设置使用 HTTPS 协议访问 OSS,保证传输安全性
clientBuilderConfiguration.setProtocol(Protocol.HTTPS);
// 创建 OSS 客户端实例
OSS ossClient = OSSClientBuilder.create()
// endpoint
.endpoint(this.endpoint)
// 从环境变量中获取访问凭证(需提前配置 OSS_ACCESS_KEY_ID 和 OSS_ACCESS_KEY_SECRET)
.credentialsProvider(CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider())
// 设置客户端配置
.clientConfiguration(clientBuilderConfiguration)
// 设置region
.region(this.region)
.build();
try {
// 填写Bucket名称
String bucketName = this.bucketName;
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = this.folerPrefix + file.getOriginalFilename();
InputStream inputStream = file.getInputStream();
// 创建PutObjectRequest对象。
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
// 创建PutObject请求。
PutObjectResult result = ossClient.putObject(putObjectRequest);
System.out.println(result);
} finally {
// 当OSSClient实例不再使用时,调用shutdown方法以释放资源
ossClient.shutdown();
}
return "success";
}
@PostMapping("/download")
public String download() throws Exception {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = this.endpoint;
//从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
// 填写Bucket名称,例如examplebucket。
String bucketName = this.bucketName;
// 填写不包含Bucket名称在内的Object完整路径,例如testfolder/exampleobject.txt。
String objectName = this.folerPrefix + "1.png";
// 填写Object下载到本地的完整路径。
String pathName = "D:\\rename.png";
// 填写Bucket所在地域。以华东1(杭州)为例,Region填写为cn-hangzhou。
String region = this.region;
// 创建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 {
// 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
// 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
ObjectMetadata object = ossClient.getObject(new GetObjectRequest(bucketName, objectName), new File(pathName));
} 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();
}
}
return "success";
}
}
5、测试,通过postman模拟上传及下载文件
如下图所示,1.png文件已经被上传到oss中,rename.png是从oss下载到本地的文件
