SpringBoot整合阿里云OSS对象存储

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」。

前言

附件上传相信大家都了解的,整合阿里云OSS对象存储时踩了点小坑。这里记录正确整合步骤,方便以后快速整合。官方文档,感兴趣大家可以自行阅读,这里不赘述了。

附件上传

常见的上传逻辑应该是,Web端上传文件到应用服务器,应用服务器再把文件上传到OSS。具体流程如下图所示。

image.png

但是这种方案存在以下缺点:

  • 速度慢,经过两道传输,时间起码增加一倍
  • 浪费性能,万一用户群体变大,服务器将成为我们的瓶颈

最佳方案 客户端签名直传

由于OSS上行流量是免费的,如果数据直传到OSS,速度会大幅缩减,并且节约了服务器资源,缓解了服务端压力。
image.png

  1. 用户向应用服务器请求上传Policy
  2. 应用服务器返回上传Policy和签名给用户。
  3. 用户直接向OSS发送文件上传请求。

整合步骤

1. 开通阿里云OSS对象存储服务

这个就不介绍了,登录阿里云平台,跟着引导操作就行

2. 获取以下四个参数信息

  • endpoint
  • accessKeyId
  • accessKeySecret
  • bucketName
  • endpoint*
    点击Bucket列表 –> 新建Bucket –> 填好bucket名称 –> 选择地域 –> 根据地域不同会给出不同的endpoint
    image.png
    到这里我们已经有了bucketNameendpoint

如果忘记了可以在以下路径查找
image.png

accessKeyId和accessKeySecret

点击右上角账户头像 –> 点击AccessKey管理

image.png

通过创建子账号的方式创建一个只有OSS相关权限的用户

image.png

创建用户

image.png

创建accesskey,生成完一定要记录下来,页面关掉就只能重新生成了
image.png

给用户添加权限

image.png

添加读写权限
image.png

到这里所有准备工作就完成了,接下来代码整合

SpringBoot代码整合

1. 引入依赖

1
2
3
4
5
6
xml复制代码<!--   阿里云oss存储     -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.13.2</version>
</dependency>

2. 配置文件定义属性值

application.yml中添加配置属性

1
2
3
4
5
6
7
yml复制代码# 阿里云oss
aliyun:
oss:
endpoint: oss-cn-shanghai.aliyuncs.com
accessKeyId: LTAI5tH********Cr88dn
accessKeySecret: ayKgKy4BY********0gLaUI9
bucketName: yourname

3. 添加配置对象

自动配置OSSClient对象

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
java复制代码@Component
public class OssClient {

@Value("${aliyun.oss.endpoint}")
private String endpoint;

@Value("${aliyun.oss.bucketName}")
private String bucketName;

@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;

@Value("${aliyun.oss.accessKeySecret}")
private String accessKeySecret;

@Bean
public OSS getOSSClient() {
return new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
}
}

4. 编写获取policy接口

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
java复制代码@RestController
@RequestMapping("/oss")
public class OSSController {

@Autowired
OSS ossClient;

@Value("${aliyun.oss.endpoint}")
private String endpoint;

@Value("${aliyun.oss.bucketName}")
private String bucketName;

@Value("${aliyun.oss.accessKeyId}")
private String accessKeyId;

@ApiOperation("获取签名policy")
@GetMapping("/policy")
public Map<String, String> policy() {
// host的格式为 bucketname.endpoint
String host = "https://" + bucketName + "." + endpoint;
// callbackUrl为上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
// String callbackUrl = "http://88.88.88.88:8888";
String today = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
// 按日期分文件夹存储
String dir = today + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
// PostObject请求最大可支持的文件大小为5 GB,即CONTENT_LENGTH_RANGE为5*1024*1024*1024。
PolicyConditions policyConds = new PolicyConditions();
policyConds.addConditionItem(PolicyConditions.COND_CONTENT_LENGTH_RANGE, 0, 1048576000);
policyConds.addConditionItem(MatchMode.StartWith, PolicyConditions.COND_KEY, dir);

String postPolicy = ossClient.generatePostPolicy(expiration, policyConds);
byte[] binaryData = postPolicy.getBytes(StandardCharsets.UTF_8);
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);

respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessKeyId);
respMap.put("policy", encodedPolicy);
respMap.put("signature", postSignature);
respMap.put("dir", dir);
respMap.put("host", host);
respMap.put("expire", String.valueOf(expireEndTime / 1000));
// respMap.put("expire", formatISO8601Date(expiration));
} catch (Exception e) {
// Assert.fail(e.getMessage());
System.out.println(e.getMessage());
} finally {
ossClient.shutdown();
}
return respMap;
}
}

到这里服务端的工作就完成了

5. 测试

调用获取policy接口返回

1
2
3
4
5
6
7
8
json复制代码{
"accessid": "LTAI5tHZ1ro3zUUuZmCr88dn",
"policy": "eyJleHBpcmF0aW9uIj1iMjAyMS0xMS0xNVQwOTozODowOS4zOThaIiwiY29uZGl0aW9ucyI6W1siY29udGVudC1sZW5ndGgtcmFuZ2UiLDAsMTA0ODU3NjAwMF0sWyJzdGFydHMtd2l0aCIsIiRrZXkiLCIyMDIxLTExLTE1LyJdXX0=",
"signature": "3K/6hXZPCYCNBwUFBaec7CmAa70=",
"dir": "2021-11-15/",
"host": "https://thinkfon-member.oss-cn-shanghai.aliyuncs.com",
"expire": "1636969089"
}
字段 描述
accessid 用户请求的AccessKey ID。
host 用户发送上传请求的域名。
policy 用户表单上传的策略(Policy),Policy为经过Base64编码过的字符串。详情请参见Post Policy
signature 对Policy签名后的字符串。详情请参见Post Signature
expire 由服务器端指定的Policy过期时间,格式为Unix时间戳(自UTC时间1970年01月01号开始的秒数)。
dir 限制上传的文件前缀。

本文转载自: 掘金

开发者博客 – 和开发相关的 这里全都有

0%