目录
- 1.需求分析
- [2.阿里云 OSS 开通与配置](#2.阿里云 OSS 开通与配置)
-
- 2.1.登录阿里云官网
- [2.2.搜索 OSS 服务并开通](#2.2.搜索 OSS 服务并开通)
- [2.3.OSS 配置](#2.3.OSS 配置)
- [3.在项目使用阿里云 OSS](#3.在项目使用阿里云 OSS)
-
- 3.1.项目环境搭建
- 3.2.代码实现
-
- [3.2.1.将本地文件上传到阿里云 OSS](#3.2.1.将本地文件上传到阿里云 OSS)
- [3.2.2.将前端传入的文件上传到阿里云 OSS](#3.2.2.将前端传入的文件上传到阿里云 OSS)
- 3.2.3.下载文件到本地
- 2.3.4.流式下载
- 3.2.4.OSSController.java
- 3.3.测试
-
- [3.3.1.上传本地文件到阿里云 OSS](#3.3.1.上传本地文件到阿里云 OSS)
- [3.3.2.前端上传文件到阿里云 OSS](#3.3.2.前端上传文件到阿里云 OSS)
- 3.3.3.下载文件到本地
- 3.3.4.流式下载
1.需求分析
目前需要在 Spring Boot 项目中通过阿里云 OSS 来实现文件管理,例如文件上传、下载等操作。
阿里云 OSS 指的是阿里云对象存储服务(Object Storage Service,简称 OSS),是阿里云提供的一种高可用、高扩展性的云端存储服务。它允许用户通过网络随时存储和访问大量数据,适用于各种场景,如网站托管、大数据分析、备份与归档等。
2.阿里云 OSS 开通与配置
2.1.登录阿里云官网
进入阿里云官网页面并登录(未注册需要先点击页面右上角进行注册):
2.2.搜索 OSS 服务并开通
(1)在页面上方的搜索框中搜索"OSS"并点击进入:
(2)第一次使用的账户可以免费试用(下面以免费试用为例):
(3)免费试用的页面如下(相比于付费的,少了自定义配置的过程):
付费版的配置如下,大家可以根据自己的实际需求进行配置。
(4)提交成功后,点击管理试用可以查看详细信息。
2.3.OSS 配置
(1)申请试用(或者付费开通之后)回到之前的页面点击管理控制台:
(2)点击"Bucket 列表"进入页面:
(3)创建 Bucket:
根据自己的需求选择相应配置:
查看 Bucket 中的文件:
初始时为空,即没有任何文件:
需要注意的是,上述配置只是为了满足本文的简单需求,因此在配置时并未开启其它功能(例如实时日志查询、定时备份等)。大家在配置时需要根据实际情况来选择。
3.在项目使用阿里云 OSS
更加详细的信息见阿里云 OSS 官方文档。
3.1.项目环境搭建
(1)在 IDEA 中创建一个 Spring Boot 项目,具体可以参考【环境搭建】使用IDEA创建SpringBoot项目详细步骤这篇文章。
(2)pom.xml
中添加如下依赖:
xml
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.17.4</version>
</dependency>
如果使用的是 Java 9 及以上的版本,则需要添加 JAXB 相关依赖。添加 JAXB 相关依赖示例代码如下:
xml
<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>
(3)application.yml
中的配置如下:
yml
aliyun:
OSS:
endpoint: https://oss-cn-beijing.aliyuncs.com # 上面创建 Bucket 过程中出现的域名
accessKeyId: ******************* # 用于标识用户的密钥 ID,类似于用户名,获取方式见下面的介绍
accessKeySecret: ****************** # 用于对请求进行加密签名的密钥,类似于密码,获取方式见下面的介绍
objectName: myDir/ # 存储空间中的文件存放地址,其中的 myDir 是我手动创建的空目录
bucketName: test-oos-bucket # bucket 名称
accessKeyId
和 accessKeySecret
的获取方式:
通过手机验证或者人脸验证后即可得到 accessKeyId
和 accessKeySecret
,
3.2.代码实现
下面在 OSSUtil.java
工具类中封装相关方法:
java
package com.example.oss.util;
import com.aliyun.oss.OSS;
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.File;
@Component
public class OSSUtil {
//读取配置文件中的相关信息
@Value("${aliyun.OSS.endpoint}")
private String endpoint;
@Value("${aliyun.OSS.accessKeyId}")
private String accessKeyId;
@Value("${aliyun.OSS.accessKeySecret}")
private String accessKeySecret;
@Value("${aliyun.OSS.objectName}")
private String objectName;
@Value("${aliyun.OSS.bucketName}")
private String bucketName;
//具体文件操作见下面的代码
}
3.2.1.将本地文件上传到阿里云 OSS
java
/**
* @description 将本地文件上传到阿里云 OSS
* @param filePath 本地的文件路径
* @return 文件下载地址
*/
public String uploadLocalFile(String filePath) {
//创建 OSSClient 实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
File file = new File(filePath);
// Object 完整路径,完整路径中不能包含 Bucket 名称,例如 myDir/output.pdf
String objectNamePath = objectName + file.getName();
try {
//创建 PutObjectRequest 对象
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNamePath, file);
//如果需要上传时设置存储类型和访问权限,请参考以下示例代码。
// ObjectMetadata metadata = new ObjectMetadata();
// metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
// metadata.setObjectAcl(CannedAccessControlList.Private);
// putObjectRequest.setMetadata(metadata);
//上传文件
PutObjectResult result = ossClient.putObject(putObjectRequest);
//设置 URL 过期时间为 1 小时
Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
//生成文件的下载 URL
String url = ossClient.generatePresignedUrl(bucketName, objectNamePath, expiration).toString();
return url;
} 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 "null";
}
3.2.2.将前端传入的文件上传到阿里云 OSS
java
/**
* @description 将前端传入所接收的文件上传到阿里云 OSS
* @param file 前端传入所接收的文件
* @param fileName 文件命名
* @return 文件存储在云端的地址
* @throws Exception
*/
public String uploadFrontFile(MultipartFile file, String fileName) throws Exception {
// myDir\output2.pdf
String objectNamePath = objectName + fileName;
//创建 OSSClient 实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
//创建 PutObjectRequest 对象
PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectNamePath, file.getInputStream());
//设置该属性可以返回 response,如果不设置,则返回的 response 为空
putObjectRequest.setProcess("true");
//创建 PutObject 请求
PutObjectResult result = ossClient.putObject(putObjectRequest);
//设置 URL 过期时间为 1 小时
Date expiration = new Date(System.currentTimeMillis() + 3600 * 1000);
//生成文件的下载 URL
String url = ossClient.generatePresignedUrl(bucketName, objectNamePath, expiration).toString();
return url;
} 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 "null";
}
3.2.3.下载文件到本地
java
/**
* @description 将前端传入所接收的文件上传到阿里云 OSS
* @param fileName 要下载的阿里云 OSS 上的文件名
* @param downFilePath 下载到本地的完整路径
* @return 下载成功标识
*/
public String downloadFileToLocal(String fileName, String downFilePath) {
// myDir\output.pdf
String objectNamePath = objectName + fileName;
//创建 OSSClient 实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
try {
/**
* 下载 Object 到本地文件,并保存到指定的本地路径中:
* 1.如果指定的本地文件存在会覆盖,不存在则新建。
* 2.如果未指定本地路径,则下载后的文件默认保存到示例程序所属项目对应本地路径中。
* */
ossClient.getObject(new GetObjectRequest(bucketName, objectNamePath), new File(downFilePath));
} 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";
}
2.3.4.流式下载
java
/**
* @description 流式下载文件
* @param fileName 要流式下载的文件名称
* @return 文件内容
*/
public String streamingDownload(String fileName) {
// myDir\test.txt
String objectNamePath = objectName + fileName;
//创建 OSSClient 实例
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
StringBuilder builder = new StringBuilder();
try {
// ossObject 包含文件所在的存储空间名称、文件名称、文件元数据以及一个输入流
OSSObject ossObject = ossClient.getObject(bucketName, objectNamePath);
//读取文件内容
System.out.println("Object content:");
BufferedReader reader = new BufferedReader(new InputStreamReader(ossObject.getObjectContent()));
while (true) {
String line = reader.readLine();
if (line == null) {
break;
}
System.out.println("\n" + line);
builder.append("\n").append(line);
}
//数据读取完成后,获取的流必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作
reader.close();
//ossObject 对象使用完毕后必须关闭,否则会造成连接泄漏,导致请求无连接可用,程序无法正常工作
ossObject.close();
} 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 (Throwable 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 builder.toString();
}
3.2.4.OSSController.java
java
package com.example.oss.controller;
import com.example.oss.util.OSSUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;
@RestController
@RequestMapping("/oss")
public class OSSController {
@Autowired
private OSSUtil ossUtil;
//上传本地文件
@PostMapping("/uploadLocalFile")
public String uploadLocalFile() {
String filePath = "output.pdf";
return ossUtil.uploadLocalFile(filePath);
}
//上传前端文件
@PostMapping("/uploadFrontFile")
public String uploadFrontFile(MultipartFile file) throws Exception {
String fileName = "output2.pdf";
return ossUtil.uploadFrontFile(file, fileName);
}
//下载文件到本地
@PostMapping("/downloadFileToLocal")
public String downloadFileToLocal() {
String fileName = "output.pdf";
String downFilePath = "D:\\output.pdf";
return ossUtil.downloadFileToLocal(fileName, downFilePath);
}
//流式下载
@PostMapping("/streamingDownload")
public String streamingDownload() {
String fileName = "test.txt";
return ossUtil.streamingDownload(fileName);
}
}
3.3.测试
3.3.1.上传本地文件到阿里云 OSS
启动项目后,在 Postman 中进行接口测试(注意是 POST 请求),并返回了该文件的下载 URL:
java
http://localhost:8080/oss/uploadLocalFile
此时在 OSS 控制台可以发现已经成功上传了文件 output.pdf
,它在目录 myDir/
下:
3.3.2.前端上传文件到阿里云 OSS
启动项目后,在 Postman 中进行接口测试(注意是 POST 请求),注意设置请求头中的 Content-Type
为 multipart/form-data
:
java
http://localhost:8080/oss/uploadFrontFile
此时在 OSS 控制台可以发现已经成功上传了文件 output2.pdf
,它也在目录 myDir/
下:
3.3.3.下载文件到本地
启动项目后,在 Postman 中进行接口测试(注意是 POST 请求):
java
http://localhost:8080/oss/downloadFileToLocal
此时本地的 D 盘中也有了刚才下载的文件:
3.3.4.流式下载
考虑到 PDF 文件的读取内容可能为乱码,因此我先上传 test.txt
文件到阿里云 OSS ,其内容如下:
java
hello world!
你好!
启动项目后,在 Postman 中进行接口测试(注意是 POST 请求):
java
http://localhost:8080/oss/streamingDownload