使用阿里云OSS完成文件上传

一、开通阿里云OSS功能并创建RAM账号

1、首先必须要了解的几个关于OSS的概念:

https://help.aliyun.com/document_detail/31947.html

中文 英文 说明
存储空间 Bucket 存储空间是您用于存储对象(Object)的容器,所有的对象都必须隶属于某个存储空间。
对象/文件 Object 对象是 OSS 存储数据的基本单元,也被称为OSS的文件。对象由元信息(Object Meta)、用户数据(Data)和文件名(Key)组成。对象由存储空间内部唯一的Key来标识。
地域 Region 地域表示 OSS 的数据中心所在物理位置。您可以根据费用、请求来源等综合选择数据存储的地域。详情请查看OSS已经开通的Region
访问域名 Endpoint Endpoint 表示OSS对外服务的访问域名。OSS以HTTP RESTful API的形式对外提供服务,当访问不同地域的时候,需要不同的域名。通过内网和外网访问同一个地域所需要的域名也是不同的。具体的内容请参见各个Region对应的Endpoint
访问秘钥 AccessKey AccessKey,简称 AK,指的是访问身份验证中用到的AccessKeyId 和AccessKeySecret。OSS通过使用AccessKeyId 和AccessKeySecret对称加密的方法来验证某个请求的发送者身份。AccessKeyId用于标识用户,AccessKeySecret是用户用于加密签名字符串和OSS用来验证签名字符串的密钥,其中AccessKeySecret 必须保密。

2、新增Bucket

14.jpg

创建成功:

15.jpg

Bucket管理界面如下:

16.jpg

3、开通RAM访问控制

https://help.aliyun.com/product/28625.html

17.jpg

创建完成后,必须要记得“添加权限”

18.jpg

之后,这个“AccessKey ID”和“SECRET”对就可以被正常使用了!


二、通过SDK上传文件——简单上传

https://help.aliyun.com/document_detail/32013.html

1、在maven中添加依赖:

<dependency>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-sdk-oss</artifactId>
    <version>3.8.0</version>
</dependency>

2、测试代码如下:

@Test
public void testUpload1() throws FileNotFoundException {
   // Endpoint以杭州为例,其它Region请按实际情况填写。
   String endpoint = "oss-cn-shanghai.aliyuncs.com";
   // 云账号AccessKey有所有API访问权限,建议遵循阿里云安全最佳实践,创建并使用RAM子账号进行API访问或日常运维。
   String accessKeyId = "LTAI4GG4TR1dMsFQU";
   String accessKeySecret = "eJb8sWZUSk1ONpftVN";

   // 创建OSSClient实例。
   OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);

   // 上传文件流。
   InputStream inputStream = new FileInputStream("C:\\Users\\jigq\\Desktop\\子丹商城\\2\\2.jpg");
   ossClient.putObject("zidanmall", "2.jpg", inputStream);

   // 关闭OSSClient。
   ossClient.shutdown();
   System.out.println("上传成功。。。");
}

3、测试结果:

简单上传成功!


三、SpringCloud Alibaba-OSS 服务上传

https://github.com/alibaba/spring-cloud-alibaba/blob/master/README-zh.md

1、引入springcloud alibaba oss的maven依赖

<!-- https://mvnrepository.com/artifact/com.alibaba.cloud/spring-cloud-starter-alicloud-oss -->
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
    <version>2.1.0.RELEASE</version>
</dependency>

2、在application.yml中增加配置信息:

spring:
  cloud:
    alicloud:
      access-key: LTAI4GG4TR1dMsFQU226sb6h
      secret-key: eJb8sWZUSk1ONpftVNa287jns8KZGp
      oss:
        endpoint: oss-cn-shanghai.aliyuncs.com

3、测试代码将变得更加简单:

@Test
public void testUpload2() throws FileNotFoundException {
   // 上传文件流。
   InputStream inputStream = new FileInputStream("C:\\Users\\jigq\\Desktop\\子丹商城\\2\\3.jpg");
   ossClient.putObject("zidanmall", "3.jpg", inputStream);

   // 关闭OSSClient。
   ossClient.shutdown();
   System.out.println("上传成功。。。");
}

测试成功!


四、最佳实践——服务端签名后直传

实际应用中,Web端向服务端请求签名,然后直接上传,不会对服务端产生压力,而且安全可靠;

时序图

结合zidanmall,我们将所有的第三方服务,做成一个 zidanmall-third-party 模块:

1、pom.xml文件:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
   <modelVersion>4.0.0</modelVersion>
   <parent>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-parent</artifactId>
      <version>2.1.8.RELEASE</version>
      <relativePath/> <!-- lookup parent from repository -->
   </parent>
   <groupId>com.jiguiquan.zidanmall</groupId>
   <artifactId>zidanmall-third-party</artifactId>
   <version>0.0.1-SNAPSHOT</version>
   <name>zidanmall-third-party</name>
   <description>子丹商城-所有的第三方服务继承模块</description>

   <properties>
      <java.version>1.8</java.version>
      <spring-cloud.version>Greenwich.SR3</spring-cloud.version>
   </properties>

   <dependencies>
      <dependency>
         <groupId>com.jiguiquan.zidanmall</groupId>
         <artifactId>zidanmall-common</artifactId>
         <version>1.0-SNAPSHOT</version>
         <exclusions>
            <exclusion>
               <groupId>com.baomidou</groupId>
               <artifactId>mybatis-plus-boot-starter</artifactId>
            </exclusion>
         </exclusions>
      </dependency>

      <dependency>
         <groupId>com.alibaba.cloud</groupId>
         <artifactId>spring-cloud-starter-alicloud-oss</artifactId>
         <version>2.1.0.RELEASE</version>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-web</artifactId>
      </dependency>
      <dependency>
         <groupId>org.springframework.cloud</groupId>
         <artifactId>spring-cloud-starter-openfeign</artifactId>
      </dependency>

      <dependency>
         <groupId>org.springframework.boot</groupId>
         <artifactId>spring-boot-starter-test</artifactId>
         <scope>test</scope>
      </dependency>
   </dependencies>

   <dependencyManagement>
      <dependencies>
         <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-dependencies</artifactId>
            <version>${spring-cloud.version}</version>
            <type>pom</type>
            <scope>import</scope>
         </dependency>
      </dependencies>
   </dependencyManagement>

   <build>
      <plugins>
         <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
         </plugin>
      </plugins>
   </build>

</project>

2、bootstrap.yml:

server:
  port: 30000
spring:
  application:
    name: zidanmall-third-party
  cloud:
    nacos:
      discovery:
        server-addr: localhost:8848
      config:
        server-addr: localhost:8848
        file-extension: yaml
        namespace: f2e98e0e-63ec-44f5-8a9f-fdc797ab22bf
        group: dev
        refresh-enabled: true

3、application.yml:

spring:
  cloud:
    alicloud:
      access-key: LTAI4GG4TR1dMsFQU226sb6h
      secret-key: eJb8sWZUSk1ONpftVNa287jns8KZGp
      oss:
        endpoint: oss-cn-shanghai.aliyuncs.com
        bucket: zidanmall

4、返回签名的核心代码:

https://help.aliyun.com/document_detail/91868.html

@RestController
public class OssController {
    @Autowired
    private OSS ossClient;

    @Value("${spring.cloud.alicloud.oss.bucket}")
    private String bucket;

    @Value("${spring.cloud.alicloud.oss.endpoint}")
    private String endpoint;

    @Value("${spring.cloud.alicloud.access-key}")
    private String accessId;

    /**
     *
     * @return
     */
    @GetMapping("/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 + "/"; // 用户上传文件时自定义的目录文件夹。

        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("utf-8");
            String encodedPolicy = BinaryUtil.toBase64String(binaryData);
            String postSignature = ossClient.calculatePostSignature(postPolicy);

            Map<String, String> 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));

            return new R().put("data", respMap);

        } catch (Exception e) {
            System.out.println(e.getMessage());
            return null;
        }
    }
}

5、最后,我们使用 Gateway做一下统一的路由转发:

spring:
  cloud:
    gateway:
      routes:
        - id: third_party_route
          uri: lb://zidanmall-third-party
          predicates:
            - Path=/api/thirdparty/**
          filters:
            - RewritePath=/api/thirdparty/(?<segment>/?.*), /$\{segment}

6、都完成后,我们通过网关访问一下此接口,看看是否能正常访问:

21.jpg

显然是OK的,这样我们的OSS服务端签名接口就完成了;


五、最后补充一点

当我们前端从后端获取到签名后,会直接调用阿里云的接口进行文件上传;

但是由于阿里云的接口并没有经过我们的Gateway统一进行跨域允许设置,所以会碰到跨域问题;

所以我们必须要开启阿里云OSS文件上传的跨域支持:创建跨域规则:

image.png

这样,我们整个的OSS最佳实践的文件上传功能就算是实现了后端部分,与前端部分的整合,可以参见:

商品服务-品牌管理-三、使用阿里云OSS服务实现logo文件的上传

http://www.jiguiquan.com/archives/1192

jiguiquan@163.com

文章作者信息...

留下你的评论

*评论支持代码高亮<pre class="prettyprint linenums">代码</pre>

相关推荐