SpringBoot接入华为云OBS

This article was last updated on <span id="expire-date"></span> days ago, the information described in the article may be outdated.

项目数据直线增长,自建存储服务器存在诸多劣势,选择一个数据稳定、业务可靠的数据存储服务器

OBS基本概念

    桶OBS中存储对象的容器。桶中的所有对象都处于同一逻辑层级。每个桶都有自己的访问权限、所属区域等属性,可以在不同区域创建不同访问权限的桶,并配置更多高级属性来满足不同场景的存储诉求。

    桶名必须是全局唯一的且不能修改,即用户创建的桶不能与自己已创建的 其他桶名称相同,也不能与其他用户创建的桶名称相同。桶所属的区域在创建后也不能修改。每个桶在创建时都会生成默认的桶ACL(Access Control List,访问控制列 表),桶ACL的每项包含了对被授权用户授予什么样的权限,如读取权限、写入权限 等。用户只有对桶有相应的权限,才可以对桶进行操作,如创建、删除、显示、设置 桶ACL等。

对象

    对象是OBS中数据存储的基本单位,一个对象实际是一个文件的数据与其相关属性信息的集合体。用户上传至OBS的数据都以对象的形式保存在桶中。

    对象包括了Key,Metadata,Data三部分:

​     ● Key:键值,即对象的名称,一个桶里的每个对象必须拥有唯一的对象键值。

​     ● Metadata:元数据,对象的描述信息,包括系统元数据和用户元数据,这些元数据以键值对(Key-Value)的形式被上传到OBS中,系统元数据由OBS

​     ● Data:数据,即文件的数据内容。

访问密钥(AK/SK)

    OBS支持通过AK/SK认证方式进行认证鉴权,即使用Access Key ID(AK)/Secret Access Key(SK)加密的方法来验证某个请求发送者身份。当您使用OBS提供的API进行二次开发并通过AK/SK认证方式完成认证鉴权时,需要按照OBS定义的签名算法来计 算签名并s添加到请求中。

​     ● Access Key Id(AK):访问密ID。与私有访问密钥关联的唯一标识符;访问密钥ID和私有访问密钥一起使用,对请求进行加密签名。

​      ● Secret Access Key(SK):与访问密钥ID结合使用的私有访问密钥,对请求进行加密签名,可标识发送方,并防止请求被修改。

终端节点(Endpoint)和访问域名

      终端节点(Endpoint):OBS为每个区域提供一个终端节点,终端节点可以理解为OBS在不同区域的区域域名,用于处理各自区域的访问请求。

注:连接OBS时需要访问密钥(AK/SK)以及终端节点(Endpoint)进行认证连接,可查看我提供的代码了解基本格式

开发环境准备

引入JDK依赖

1
2
3
4
5
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java</artifactId>
<version>3.22.12</version>
</dependency>

因版本问题可能遇到的错误

1
2
3
4
5
6
7
Exception in thread "main" java.lang.NoSuchMethodError: 'okhttp3.RequestBody 
okhttp3.RequestBody.create(java.lang.String, okhttp3.MediaType)'
at com.obs.services.internal.RestConnectionService.createRequestBuilder(RestConnectionService.java:157)
at com.obs.services.internal.RestConnectionService.setupConnection(RestConnectionService.java:148)
at com.obs.services.internal.RestConnectionService.setupConnection(RestConnectionService.java:124)
at com.obs.services.internal.RestStorageService.performRequest(RestStorageService.java:395)
at com.obs.services.internal.RestStorageService.performRequest(RestStorageService.java:388)

如果遇到 okhttp 报错问题,报错是因为升级SDK后okhttp使用了老版本的原因,尝试升级okhttp,版本按个人情况修改

1
2
3
4
5
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>

  在我默认提供的esdk-obs-java与okhttp3版本使用是正常,如有版本引发的意外问题可交流讨论

对象的上传与下载

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
package com.example.demo2dateobs;

import com.obs.services.ObsClient;
import com.obs.services.model.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;

import java.io.*;
import java.util.HashMap;
import java.util.Map;


@Controller
@RequestMapping("/test")
public class DateObsController {

private final static Logger logger = LoggerFactory.getLogger(DateObsController.class);

//定义OBS的endPoint、Access Key Id与 Secret Access Key用于进行远程OBS连接

private final static String endPoint = "";
private final static String ak = "";
private final static String sk = "";


// 流式上传
/**
* 上传文件--上传字符串(byte 数组)
*/
@GetMapping("/uploadByte")
public boolean uploadFile() {
ObsClient obsClient = null;
try {
obsClient = new ObsClient(ak, sk, endPoint);
String content = "Hello OBS";

HeaderResponse response = obsClient.putObject("bucketName","objectKey",new ByteArrayInputStream(content.getBytes()));

// 可选:调用成功后,记录调用成功的HTTP状态码和服务端请求ID
int statusCode = response.getStatusCode();
if (200 == statusCode) {
return true;
}
obsClient.close();
} catch (IOException e) {
logger.info("文件上传失败:{}", e.getMessage(), e);
}
return false;
}

// 流式上传
/**
* 上传文件--上传文件流
*/
@GetMapping("/uploadFile")
public boolean uploadFileByte() {
ObsClient obsClient = null;
try {
obsClient = new ObsClient(ak, sk, endPoint);
File file = new File("File Path");
FileInputStream fileStream = new FileInputStream(file);
HeaderResponse response = obsClient.putObject("bucketName","objectKey",fileStream);

// 可选:调用成功后,记录调用成功的HTTP状态码和服务端请求ID
int statusCode = response.getStatusCode();
if (200 == statusCode) {
return true;
}
obsClient.close();
} catch (IOException e) {
logger.info("文件上传失败:{}", e.getMessage(), e);
}
return false;
}
/**
* 下载文件--流下载
*/
@GetMapping("/downloadFile")
public boolean downloadFile() {
ObsClient obsClient = null;
try {

obsClient = new ObsClient(ak, sk, endPoint);
ObsObject obsObject = obsClient.getObject();

需要下载的桶名称以及对象名
String objectKey = obsObject.getObjectKey("bucketName","objectKey");

String filePath = "Q:\\Files\\" + objectKey;

InputStream objectContent = obsObject.getObjectContent();
byte[] b = new byte[1024];
OutputStream outputStream = new FileOutputStream(filePath);
int len;
while ((len= objectContent.read(b)) != -1){
outputStream.write(b, 0, len);
}
outputStream.close();
obsClient.close();

} catch (IOException e) {
logger.info("文件上传失败:{}", e.getMessage(), e);
}
return false;
}


/**
* 获取上传地址
* @return
*/
@GetMapping("/getUploadUrl")
public String getUploadUrl() {
ObsClient obsClient = null;
try {
// 创建ObsClient实例
obsClient = new ObsClient(ak, sk, endPoint);
// URL有效期,3600秒
long expireSeconds = 3600L;
Map<String, String> headers = new HashMap<String, String>();
headers.put("Content-Type", "application/octet-stream");
TemporarySignatureRequest request = new TemporarySignatureRequest(HttpMethodEnum.PUT, expireSeconds);
request.setBucketName("bucketName");
request.setObjectKey("objectKey");
request.setHeaders(headers);
TemporarySignatureResponse response = obsClient.createTemporarySignature(request);
System.out.println(response.getSignedUrl());
return response.getSignedUrl();
} catch (Exception e) {
logger.error("获取上传地址异常:{}", e.getMessage(), e);
}
return null;
}

}
Tip

    putObject(String bucketName, String objectKey, InputStream input)传递参数

代码依次为bucketName–桶名称,objectKey–上传/下载时对象名,input上传内容

更多内容参加OBS的Java SDK

Author: oGnok

Permalink: http://lovelypanda.top/2024/02/26/HuaweiOBS/