本项目我们使用阿里云对象存储。
阿里云对象存储OSS(Object Storage Service) 。

开通

登录进入阿里云官网,找到对象存储OSS:
image.png
进入后,点击立即开通,来开通阿里云对象存储服务:
image.png
进入页面后,同意协议,点击立即开通:
image.png
开通成功后,点击进入管理控制台:
image.png
进入后,如下:
image.png
我们可以在这里找到OSS的API文档:
文档地址 https://help.aliyun.com/document_detail/31947.html?spm=5176.8465980.help.dexternal.54a11450e2q5ZE
以下图片摘自OSS的API文档:
image.png

使用

第一步:
在OSS的管理控制台,创建一个新的存储空间Bucket,一般会为一个项目创建一个自己的Bucket:
image.png
image.png

  • 这里Bucket名称可能会与别人的重复,要设定为不重复的;
  • 地域可以根据自己的实际情况选择就近的区域;
  • 存储类型,我们这里自己学习、联系,是使用低频访问存储即可;实际项目、专业的来说会使用标准存储;
  • 读写权限,我们选择公共读。 如果是私有,那么所有的文件的读和写,都需要携带账号密码进行身份认证;公共读的话,则读取文件不需要认证,写入需要;公共读写则是读取与写入都不需要身份认证;

进入我们创建的bucket:
image.png

上传方式选择及流程

第一种:
普通上传方式:
用户先上传给应用服务器,应用服务器再上传给OSS。
这种方式虽然保证了文件数据的安全,但是效率太低,不采用这种方式。
第二种:
1.用户向应用服务器请求上传Policy
2.应用服务器返回上传Policy和签名给用户
3.用户根据签名直接上传到OSS
这种方式既保证了安全性,效率也高,我们采用这种方式。

OSS整合测试及相关设置

这些都可以参考阿里云官网文档。
一:
在gulimall-product中,导入阿里云存储的依赖:

  1. <!-- 阿里云OSS -->
  2. <dependency>
  3. <groupId>com.aliyun.oss</groupId>
  4. <artifactId>aliyun-sdk-oss</artifactId>
  5. <version>3.5.0</version>
  6. </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是我们为了安全起见,在阿里云官网申请的。
申请步骤:
image.png
image.png

image.png
image.png
image.png
这里,选中账户, 为账户分配权限:
image.png
image.png
image.png

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也配置到里面:
image.png
代码:

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 -> 概览 -> 基础设置 -> 跨域访问
设置为:
image.png
image.png