本项目我们使用阿里云对象存储。
阿里云对象存储OSS(Object Storage Service) 。
开通
登录进入阿里云官网,找到对象存储OSS:
进入后,点击立即开通,来开通阿里云对象存储服务:
进入页面后,同意协议,点击立即开通:
开通成功后,点击进入管理控制台:
进入后,如下:
我们可以在这里找到OSS的API文档:
文档地址 https://help.aliyun.com/document_detail/31947.html?spm=5176.8465980.help.dexternal.54a11450e2q5ZE
以下图片摘自OSS的API文档:
使用
第一步:
在OSS的管理控制台,创建一个新的存储空间Bucket,一般会为一个项目创建一个自己的Bucket:
- 这里Bucket名称可能会与别人的重复,要设定为不重复的;
- 地域可以根据自己的实际情况选择就近的区域;
- 存储类型,我们这里自己学习、联系,是使用低频访问存储即可;实际项目、专业的来说会使用标准存储;
- 读写权限,我们选择公共读。 如果是私有,那么所有的文件的读和写,都需要携带账号密码进行身份认证;公共读的话,则读取文件不需要认证,写入需要;公共读写则是读取与写入都不需要身份认证;
上传方式选择及流程
第一种:
普通上传方式:
用户先上传给应用服务器,应用服务器再上传给OSS。
这种方式虽然保证了文件数据的安全,但是效率太低,不采用这种方式。
第二种:
1.用户向应用服务器请求上传Policy
2.应用服务器返回上传Policy和签名给用户
3.用户根据签名直接上传到OSS
这种方式既保证了安全性,效率也高,我们采用这种方式。
OSS整合测试及相关设置
这些都可以参考阿里云官网文档。
一:
在gulimall-product中,导入阿里云存储的依赖:
<!-- 阿里云OSS -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.5.0</version>
</dependency>
二:<br />在单元测试中测试:
@Test
public void testUpload() throws FileNotFoundException {
// Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
String endpoint = "xx";
// 阿里云账号AccessKey拥有所有API的访问权限,风险很高。强烈建议您创建并使用RAM用户进行API访问或日常运维,请登录RAM控制台创建RAM用户。
String accessKeyId = "xx";
String accessKeySecret = "xx";
// 创建OSSClient实例。
OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
// 上传文件流
InputStream inputStream = new FileInputStream("D:\wallPaper\bz3.jpg");
ossClient.putObject("yourBucketName","yourObjectName",inputStream);
// 关闭OSSClient
ossClient.shutdown();
}
这里面,String endpoint = “xxx”;的值,是自己要上传到的bucket自己的地域节点。
yourBucketName是指要上传到的bucket的名字
yourObjectName是给定这个上传到文件一个名称;(这里我实际操作,这个名字要带上后缀名)
accessKeyId和accessKeySecret是我们为了安全起见,在阿里云官网申请的。
申请步骤:
OSS使用之spring-cloud-alibaba整合OSS
上面只是学习一下简单操作,下面我们使用springcloudalibaba封装好的对象存储相关工具。
先把gulimall-product中oss相关依赖注释掉。
然后在gulimall-common中,引入oss的起步依赖:
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
注意:由于版本更新等的原因,可能后面oss的起步依赖不是这种写法和用法了,详情参见官方文档。
配置文件中,配置以下信息:
spring:
cloud:
alicloud:
access-key: xx
secret-key: xx
oss:
endpoint: xx
(属性值根据实际情况配置)
单元测试:
@Autowired
OSSClient ossClient;
@Test
public void testUpload2() throws FileNotFoundException {
InputStream inputStream = new FileInputStream("D:\\wallPaper\\bz7.jpg");
ossClient.putObject("gulimall-yuanhai","bz7.jpg",inputStream);
// 关闭OSSClient
ossClient.shutdown();
System.out.println("上传完成...");
}
放到第三方服务
上面的演示,都是把文件先上传到应用服务器,然后再上传到OSS,这与我们一开始设想的保证安全性的同时效率也高的想法不符。同时,现在的文件上传,与以后的发送短信,查询物流功能,是各个微服务模块都有可能使用的,所以现在创建一个第三方服务,在这个第三方服务中,实现文件上传的功能(后续第三方功能也放到这里),同时,实现上传文件时,获取服务端签名,然后直接上传到OSS服务,不先上传到应用服务器。
创建gulimall-third-party模块,并且将oss起步依赖放在这里,且引入gulimall-common依赖,gulimall-common中的删掉。
并且在gulimall-third-party的配置文件中,配置注册中心,oss相关配置等配置。
bootstrap.propeties:
spring.application.name=gulimall-third-party
spring.cloud.nacos.config.server-addr=127.0.0.1:8848
spring.cloud.nacos.config.namespace=third-party
spring.cloud.nacos.config.ext-config[0].data-id=oss.yml
spring.cloud.nacos.config.ext-config[0].group=DEFAULT_GROUP
spring.cloud.nacos.config.ext-config[0].refresh=true
注册中心新建third-party命名空间,放置gulimall-third-party的配置,并新增如下配置:
spring:
cloud:
alicloud:
access-key: xxx
secret-key: xxx
oss:
endpoint: xxx
新建application.yml文件,配置其他项:
服务端签名后直传
官方文档:https://help.aliyun.com/document_detail/31926.html
上面的演示,都是把文件先上传到应用服务器,然后再上传到OSS,这与我们一开始设想的保证安全性的同时效率也高的想法不符。下面实现服务端签名后直传。
签名直传服务:
上面配置文件中,oss相关配置,配置了access-key、secret-key和endpoint,现在把bucket也配置到里面:
代码:
package com.atguigu.gulimall.thirdparty.controller;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.utils.BinaryUtil;
import com.aliyun.oss.model.MatchMode;
import com.aliyun.oss.model.PolicyConditions;
import com.atguigu.common.utils.R;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map;
/**
* 本类说明:
* 对象存储Controller
* @author yuanhai
* @date 2022年02月13日
*/
@RestController
public class OssController {
@Autowired
OSS ossClient;
@Value("${spring.cloud.alicloud.oss.endpoint}")
private String endpoint;
@Value("${spring.cloud.alicloud.oss.bucket}")
private String bucket;
@Value("${spring.cloud.alicloud.access-key}")
private String accessId;
@RequestMapping("/oss/policy")
public R policy() {
String host = "https://" + bucket + "." + endpoint; // host的格式为 bucketname.endpoint
// callbackUrl为 上传回调服务器的URL,请将下面的IP和Port配置为您自己的真实信息。
// String callbackUrl = "http://88.88.88.88:8888";
String format = new SimpleDateFormat("yyyy-MM-dd").format(new Date());
String dir = format + "/"; // 用户上传文件时指定的前缀。
Map<String, String> respMap = null;
try {
long expireTime = 30;
long expireEndTime = System.currentTimeMillis() + expireTime * 1000;
Date expiration = new Date(expireEndTime);
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("utf-8");
String encodedPolicy = BinaryUtil.toBase64String(binaryData);
String postSignature = ossClient.calculatePostSignature(postPolicy);
respMap = new LinkedHashMap<String, String>();
respMap.put("accessid", accessId);
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());
}
return R.ok().put("data",respMap);
}
}
OSS设置允许跨域:
阿里云控制台 -> 对象存储 -> Bucket列表 -> gulimall-yuanhai -> 概览 -> 基础设置 -> 跨域访问
设置为: