一、介绍
云存储是一种通过互联网连接的服务,允许用户将数据存储在远程的云服务器上,而不是存储在本地设备上。这些数据可以包括文件、数据库、备份等各种类型的信息。云存储服务提供商通常会管理和维护这些存储设施,并提供用户可以访问、管理和共享数据的工具和接口。
国内有名的大公司都有提供专门的存储服务,我们自需要进行购买就可以使用了。
阿里云的对象存储服务(Object Storage Service,简称OSS)、腾讯云的对象存储服务(Cloud Object Storage,简称COS)、华为云的对象存储服务(Object Storage Service,简称OBS)、百度云的对象存储服务(Baidu Object Storage,简称BOS)这国内的四大互联网巨头都有提供相应的存储服务,我本次使用阿里云的对象存储服务OSS来进行演示;
二、进行购买服务
我是阿里云的新用户所以可以白嫖一次3个月,20GB的存储服务。如果你不是新用户的话就只能进行购买了;
直接登录阿里云之后,在搜索框中进行OSS存储服务的搜索:
点击立即购买:
选择要购买的存储类型和大小
进行购买之后,可以点击“控制台”来查看自己购买的服务
点击对象存储就可以进入到购买的服务中
你可以选择创建一个Bucket来进行数据的存放,Bucket的作用是将不同的数据分隔开,类似于MySQL中一个个的数据库。
Bucket的名称是不可重复的,另外在设置Bucket的时候还可以相应的设置一些属性:
三、在项目中进行实际的代码实现
新建一个spring boot项目,来实现文件的上传(也可以直接在阿里云的控制器中进行文件的上传)
版本:spring boot3.1.11,jdk17
我们在购买完这个OSS服务之后,要进行代码的实现是非常简单的。(毕竟我们掏了钱的,是甲方爸爸)阿里已经帮我们封装好了一些API,我们只需要进行一些简单的修改就可以直接使用了;
在Bucket列表页面,点击“帮助文档”,选择“文档中心打开”:
点击“开发参考”、“SDK参考”、选择Java语言。基本上就是傻瓜式的文档,我们自需要修改几个特定的位置就可以实现相应的功能。
首先导入相应的maven坐标来集成OSS对象存储
我本次使用spring boot框架来进行对象的上传和下载功能,使用knife4j来进行代码的测试;
相应的maven依赖如下:
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.github.xiaoymin</groupId>
<artifactId>knife4j-openapi3-jakarta-spring-boot-starter</artifactId>
<version>4.3.0</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.15.1</version>
</dependency>
<dependency>
<groupId>javax.xml.bind</groupId>
<artifactId>jaxb-api</artifactId>
<version>2.3.1</version>
</dependency>
<dependency>
<groupId>javax.activation</groupId>
<artifactId>activation</artifactId>
<version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
<groupId>org.glassfish.jaxb</groupId>
<artifactId>jaxb-runtime</artifactId>
<version>2.3.3</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
3.1文件上传:
直接复制阿里给我们写好的实例代码:
public class Demo {
public static void main(String[] args) throws Exception {
// Endpoint以北京为例,其它Region请按实际情况填写。
String endpoint = "https://oss-cn-beijing.aliyuncs.com";
// 访问密钥AccessKey ID和AccessKey Secret。
String accessKeyId = "你自己的AccessKey";
String accessKeySecret = "你自己的AccessKeySecret";
// 使用代码嵌入的STS临时访问密钥和安全令牌配置访问凭证。
CredentialsProvider credentialsProvider =
new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 填写Bucket名称,例如examplebucket。
String bucketName = "zhangqiaobucket";
// 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
String objectName = "test/30.jpg";
// 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
// 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
String filePath= "D:\\idea代码存放\\sso-demo\\30.jpg";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
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();
}
}
}
}
这个代码是阿里给出的上传文件的代码,更加具体的你可以在官网中进行查看:
我们需要修改一些地方,换成我们本地的信息;
1、创建Bucket的所属地址:
2、访问访问密钥AccessKey ID和AccessKey Secret。
这个可以在账号的“AccessKey”中进行查看和设置:
3、填写Bucket名称,例如examplebucket。
4、填写Object完整路径,完整路径中不能包含Bucket名称,一个“/”号就会创建一个文件夹
5、填写本地文件的完整路径
我们需要修改的就只有这5处地方,现在运行这个main方法,就可以看到我们成功上传的图片了;
我们可以点击“详情”来查看这个文件的具体信息和响应的url;
在网站中查看这个url:
至此,就完成了我们使用OSS来上传文件。但是,我们在开发中是一定不会这样做的,我们会暴露出一个个的接口来实现文件的上传、下载和删除等。
新建一个FileController,在这个Controller中来完成我们对文件的一系列操作,新建一个FileUtil来进行方法的具体实现,最终用knife4j来进行测试。
@RestController
@RequestMapping("/file")
@Tag(name = "文件上传下载", description = "文件上传下载接口")
public class FileController {
@Autowired
private FileUtil fileUtil;
// 上传文件
@Schema(description = "上传文件")
@PostMapping("/upload")
public Result<String> upload(MultipartFile file) {
String url = fileUtil.upload(file);
return Result.successData(url);
}
}
工具类FileUtil:
@Component
@Slf4j
public class FileUtil {
@Value("${sso.endpoint}")
private String endpoint;
@Value("${sso.accessKeyId}")
private String accessKeyId;
@Value("${sso.accessKeySecret}")
private String accessKeySecret;
@Value("${sso.bucketName}")
private String bucketName;
// 文件上传方法
public String upload(MultipartFile file){
CredentialsProvider credentialsProvider =
new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
// 获取上传文件的输入流
InputStream inputStream=null;
try {
inputStream = file.getInputStream();
// 避免文件覆盖,使用当前时间作为文件夹,并设置UUID作为文件名
String fileName= LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd"))+"/"+ UUID.randomUUID() +file.getOriginalFilename();
// 正式上传文件
ossClient.putObject(bucketName, fileName, inputStream);
// 文件访问路径
String url="https://"+bucketName+"."+endpoint.split("//")[1]+"/"+fileName;
return url;
} catch (IOException e) {
log.error("文件上传失败=======>"+e.getMessage());
throw new RuntimeException(e);
}finally {
if (ossClient != null) {
ossClient.shutdown();
}
}
}
}
我将需要获取的属性放在yml配置文件中了,文件上传的时候以当前日期作为文件夹,以UUID加上文件的名字作为前缀,这样可以避免文件的覆盖。现在,让我们运行我们的项目来进行相应的测试:(使用knife4j进行测试)
点击上传文件:
可以看到上传成功,并且返回了这个图片的url地址,我们现在就可以访问这个地址,来查看我们上传的图片了;
3.2下载文件:
// 下载文件,需要传入文件的url地址
public void download(String url) {
CredentialsProvider credentialsProvider =
new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
try {
// 下载Object到本地文件,并保存到指定的本地路径中。如果指定的本地文件存在会覆盖,不存在则新建。
// 如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
String objectName = url.split("com/")[1];
String pathName = "D:\\logs\\"+objectName.split("/")[1];
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();
}
}
}
这个方法需要传入文件的url地址,并且指定下载的具体路径:
本地的下载路径为:
可以看到相应的文件已经下载到了本地
3.3删除文件:
// 删除文件:
public void deletedFile(String url){
CredentialsProvider credentialsProvider =
new DefaultCredentialProvider(accessKeyId, accessKeySecret);
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
// 填写文件完整路径。文件完整路径中不能包含Bucket名称。
String objectName = url.split("com/")[1];
try {
// 删除文件或目录。如果要删除目录,目录必须为空。
ossClient.deleteObject(bucketName, objectName);
} 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();
}
}
}
这个方法同样的传入一个url地址,并进行删除;
我们在控制台查看会发现文件已经安全删除了;
总结
使用云存储是未来的大趋势,能熟练掌握云存储还是很有必要的。最简单高效的方法是直接购买大厂推出的存储服务。我本次只是演示了文件操作的最基本部分,阿里云的官方SDK中还有非常多的操作部署,读者可以根据自己的需要去阅读官方的SDK官网。
当然,现在也有一些开源的文件存储工具,如minio、OwnCloud、Seafile等等,如果有需要的话也可以使用这些开源的存储工具;
我之前也写过minio的快速上手和实战:
springboot整合minio(实现文件的上传和下载超详细入门)_minio 下载文件-CSDN博客