大家好,我是可乐。
基于电商项目,往往会有很多图片交互,比如海量的商品图片,卖家和买家的聊天图片,用户个人信息图片等等
假如你作为公司电商项目技术负责人,你会如何去实现图片交互逻辑呢?
1、菜鸟版实现-本机存储
我们先看下菜鸟小A的实现:
如上图所示,我们在服务内部实现好文件上传的代码,然后上传的文件直接存储到我们服务内部。
这听上去很美好,实现也很简单,但是存在很多问题:
①、单点问题:图片都是存在服务器内部,如果是分布式服务,也就是浏览器将图片上传到A服务器,但是某用户访问是从B服务器发起的,这时候如何访问?
另外,如果一个服务器发生故障,那该服务器存储的图片不就无法访问了?
②、流量问题:文件上传往往需要比较大的带宽,随着图片的上传访问增多,如果我们不扩大带宽,就会影响到其它正常操作。
2、进阶版实现-自建服务器
基于菜鸟版实现存在的问题,工作两年的小A升级了一下处理方式:
原来图片是存储在服务器本身,现在我们自己搭建了一个图片服务器。
浏览器发现图片上传请求,经过我们的电商服务,然后服务将图片存储到我们的图片服务器。
这样我们解决了上面的单点问题,但是又引进了新的问题:自己搭建一个图片服务器,服务器成本是比较高的,而且搭建复杂,另外,我们引进了一个新的系统,那么也需要专人去维护这个图片服务器。
3、高手版实现-OSS
老板看到高昂的服务器费用,眉头一皱。
公司一高手小C微微一笑,给出了新的方案:
我们将自建的图片服务器换成对象存储 OSS。
使用 OSS(Object Storage Service) 有如下几个好处:
①、高可靠:OSS 一般都是副本冗余的,能够保证服务的高可用性。
②、低成本:前期无需大量投入,能够按需计费。
③、易扩展:对象存储,存储空间无上限限制,也无需担心扩容问题。
④、存储加速:依托服务提供商的加速能力,比如CDN。
4、大神版实现-服务端签名
大家发现没,上面的每种方案,图片或者文件进行上传的时候,都要经过我们自己的服务器,都要占用我们自己本身服务的带宽,这在并发高的情况下,对其它操作是有很大影响的,所以有了如下方案:
①、服务端签名后直传是通过用户(浏览器)发起请求到我们自已的服务器中进行验证;
②、验证通过后服务器会根据OSS服务提供商的账号密码生成一段policy
(防伪签名) 返回给我们用户(浏览器),policy中包含了访问服务提供商的授权令牌,以及要上传给服务提供商OSS哪个地址哪个位置等相关信息, 需要注意的是这段签名中并没有账号密码;
③、用户(浏览器)拿到签名后可以直接通过我们浏览器将文件上传至OSS服务提供商(服务提供商可以验证签名是否正确)。
这样通过服务端签名后直传的方式多大的并发都不会对服务端产生压力,而且安全可靠。
讲完了原理,那么我们怎么在实际开发中实现呢?
现在市面上的云厂商都提供了OSS服务(比如阿里云、腾讯云、七牛云、青云等等),下面我们以阿里云OSS,从零教大家如何实现文件上传。
5、开通阿里云OSS
第一步:点击立即开通
https://www.aliyun.com/product/oss
第二步:进入管理控制台
第三步:查看API帮助文档
https://help.aliyun.com/document_detail/31947.html?spm=5176.8465980.help.dexternal.41231450z6Cv3R
6、创建 bucket
存储类型:低频访问存储
读写权限:公共读
7、创建子账户
https://ram.console.aliyun.com/users
第一步:点击创建用户
第二步:填写相关信息,然后点击确定
开通完成之后,就会有个 AccessKey ID 和 AccessKey Secret。
PS:创建账户后,开通了 Open API 调用访问,要及时保存 AccessKey,否则关闭后无法再次获取。
8、给子账户分配OSS管理权限
添加OSS权限
9、整合SDK-OSS
9.1 引入依赖 liyun-oss-spring-boot-starter
在 gulimall-common 模块中引入:
PS:这里和官方引入的依赖不一样。
<dependency>
<groupId>com.alibaba.cloud</groupId>
<artifactId>spring-cloud-starter-alicloud-oss</artifactId>
<version>2.2.0.RELEASE</version>
</dependency>
9.2 在配置文件中配置 OSS 服务对应的 accessKey、secretKey 和 endpoint。
spring:
cloud:
alicloud:
oss:
endpoint:
access-key:
secret-key:
9.3 测试
package com.itcoke.product;
import com.aliyun.oss.OSSClient;
import com.aliyun.oss.model.GetObjectRequest;
import com.atguigu.gulimall.product.entity.BrandEntity;
import com.atguigu.gulimall.product.service.BrandService;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
@SpringBootTest
class GulimallProductApplicationTests {
@Autowired
OSSClient ossClient;
@Test
public void testUpload() throws FileNotFoundException {
//上传文件流。
InputStream inputStream = new FileInputStream("/Users/yushuai/Downloads/idea.jpeg");
ossClient.putObject("itcoke", "test.jpeg", inputStream);
// 关闭OSSClient。
ossClient.shutdown();
System.out.println("上传成功.");
}
}
至此,大功告成!!!你也成为了一个大神。