「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战」。
前言
附件上传相信大家都了解的,整合阿里云OSS对象存储时踩了点小坑。这里记录正确整合步骤,方便以后快速整合。官方文档,感兴趣大家可以自行阅读,这里不赘述了。
附件上传
常见的上传逻辑应该是,Web端上传文件到应用服务器,应用服务器再把文件上传到OSS。具体流程如下图所示。
但是这种方案存在以下缺点:
- 速度慢,经过两道传输,时间起码增加一倍
- 浪费性能,万一用户群体变大,服务器将成为我们的瓶颈
最佳方案 客户端签名直传
由于OSS上行流量是免费的,如果数据直传到OSS,速度会大幅缩减,并且节约了服务器资源,缓解了服务端压力。
- 用户向应用服务器请求上传Policy。
- 应用服务器返回上传Policy和签名给用户。
- 用户直接向OSS发送文件上传请求。
整合步骤
1. 开通阿里云OSS对象存储服务
这个就不介绍了,登录阿里云平台,跟着引导操作就行
2. 获取以下四个参数信息
- endpoint
- accessKeyId
- accessKeySecret
- bucketName endpoint 点击Bucket列表 --> 新建Bucket --> 填好bucket名称 --> 选择地域 --> 根据地域不同会给出不同的endpoint
到这里我们已经有了bucketName、 endpoint
如果忘记了可以在以下路径查找
accessKeyId和accessKeySecret
点击右上角账户头像 --> 点击AccessKey管理
通过创建子账号的方式创建一个只有
OSS相关权限的用户
创建用户
创建accesskey,生成完一定要记录下来,页面关掉就只能重新生成了
给用户添加权限
添加读写权限
到这里所有准备工作就完成了,接下来代码整合
SpringBoot代码整合
1. 引入依赖
<!-- 阿里云oss存储 -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.13.2</version>
</dependency>
2. 配置文件定义属性值
application.yml中添加配置属性
# 阿里云oss
aliyun:
oss:
endpoint: oss-cn-shanghai.aliyuncs.com
accessKeyId: LTAI5tH********Cr88dn
accessKeySecret: ayKgKy4BY********0gLaUI9
bucketName: yourname
3. 添加配置对象
自动配置OSSClient对象
@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接口
@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接口返回
{
"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 | 限制上传的文件前缀。 |