weblog/doc/8、对象存储服务搭建与开发/8.5 文件上传到阿里云 OSS 功能开发.md
2025-02-17 10:05:44 +08:00

13 KiB
Raw Blame History

上小节 中,我们已经将 Minio 文件策略类的上传文件逻辑编写好了,本小节中,把剩下的上传文件到阿里云 OSS 的功能也敲一下。

开通服务

首先,咱们需要登录阿里云官网,并访问对象存储 OSS 产品首页:https://www.aliyun.com/product/oss ,如下图所示,点击立即开通按钮,开通服务:

开通成功后,进入到对象存储 OSS 控制台, 点击 Bucket 列表

在 Bucket 列表中,点击上方的创建 Bucket 按钮,准备创建桶:

填写 Bucket 相关配置项,如下:

  • 模式选择:勾选自定义创建;
  • Bucket 名称:这里填写 xiaohashu
  • 地域:推荐选择离你产品使用者较近的地方,有助于提升访问速度。
  • 阻止公共访问:关闭掉,并将读写权限修改为公共读

配置填写完毕后,点击完成创建按钮,并确认要创建

Bucket 创建成功后,在列表页中就可以看到新创建的 xiaohashu 桶了,如上图所示。

获取 AccessKey 接入凭证

通过代码上传文件到 Bucket ,阿里云需要校验你的身份,还需要获取一下接入凭证。点击回到阿里云首页,将鼠标移动到登录用户的头像上,即可看到 AccessKey 选项,点击即可查看:

imgimg

Tip

: 记得给你的账号充值一点钱,比如 1 块钱,因为图片的访问会产生流量费用。

将你的 AccessKeyID 以及 AccessKey Secret 复制出来:

imgimg

修改配置格式

编辑 xiaohashu-oss-biz 模块的 application-dev.yml 开发环境配置,修改一下 minio 配置项的结构,统一放置到 storage 节点下,方便统一维护。再额外加一下阿里云 OSS 需要用到的配置项,如下:

#=================================================================
# 对象存储配置
#=================================================================
storage:
  minio:
    endpoint: http://127.0.0.1:9000
    accessKey: quanxiaoha
    secretKey: quanxiaoha
  aliyun-oss:
    endpoint: oss-cn-hangzhou.aliyuncs.com # 改成你自己的
    accessKey: xxx # 改成你自己的
    secretKey: xxx # 改成你自己的

因为配置文件中 minio 配置项的结构变动了,对应的,MinioProperties 配置类的 @ConfigurationProperties 注解的值也需要修正一下,修改为 storage.minio, 代码如下:

package com.quanxiaoha.xiaohashu.oss.biz.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author: 犬小哈
 * @url: www.quanxiaoha.com
 * @date: 2023-05-11 8:49
 * @description: Minio 配置项
 **/
@ConfigurationProperties(prefix = "storage.minio")
@Component
@Data
public class MinioProperties {
    private String endpoint;
    private String accessKey;
    private String secretKey;
}

添加阿里云 OSS 配置类

顺便把阿里云 OSS 配置项对应的配置类也创建一下,代码如下:

package com.quanxiaoha.xiaohashu.oss.biz.config;

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

/**
 * @author: 犬小哈
 * @url: www.quanxiaoha.com
 * @date: 2023-05-11 8:49
 * @description: 阿里云 OSS 配置项
 **/
@ConfigurationProperties(prefix = "storage.aliyun-oss")
@Component
@Data
public class AliyunOSSProperties {
    private String endpoint;
    private String accessKey;
    private String secretKey;
}

添加依赖

前置工作完成后,开始添加阿里云 OSS 对象存储的 SDK 依赖,可访问官方文档:https://help.aliyun.com/zh/oss/ 查看详细内容。这里直接演示如何操作,编辑项目最外层的 pom.xml 文件,声明相关版本号与依赖,代码如下:

    <properties>
		// 省略...
        <minio.version>8.2.1</minio.version>
        <aliyun-sdk-oss.version>3.17.4</aliyun-sdk-oss.version>
        <jaxb-api.version>2.3.1</jaxb-api.version>
        <activation.version>1.1.1</activation.version>
        <jaxb-runtime.version>2.3.3</jaxb-runtime.version>
    </properties>

    <!-- 统一依赖管理 -->
    <dependencyManagement>
        <dependencies>
			// 省略...

            <!-- 阿里云 OSS -->
            <dependency>
                <groupId>com.aliyun.oss</groupId>
                <artifactId>aliyun-sdk-oss</artifactId>
                <version>${aliyun-sdk-oss.version}</version>
            </dependency>

            <dependency>
                <groupId>javax.xml.bind</groupId>
                <artifactId>jaxb-api</artifactId>
                <version>${jaxb-api.version}</version>
            </dependency>
            <dependency>
                <groupId>javax.activation</groupId>
                <artifactId>activation</artifactId>
                <version>${activation.version}</version>
            </dependency>
            <!-- no more than 2.3.3-->
            <dependency>
                <groupId>org.glassfish.jaxb</groupId>
                <artifactId>jaxb-runtime</artifactId>
                <version>${jaxb-runtime.version}</version>
            </dependency>
        </dependencies>
    </dependencyManagement>

接着,编辑 xiaohashu-oss-biz 模块的 pom.xml 文件,引入上述依赖:

    <dependencies>
		// 省略...

        <!-- 阿里云 OSS -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
        </dependency>

        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
        </dependency>
        <!-- no more than 2.3.3-->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
        </dependency>
    </dependencies>

依赖添加完毕后,点击右侧栏 Reload 图标,重新刷新一下 Maven 依赖,将包下载到本地 Maven 仓库中。

初始化客户端

然后,在 /config 包下创建 AliyunOSSConfig 配置类,代码如下,用于初始化 OSS 客户端实体类,并注入到 Spring 容器中:

package com.quanxiaoha.xiaohashu.oss.biz.config;

import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.DefaultCredentialProvider;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @author: 犬小哈
 * @url: www.quanxiaoha.com
 * @date: 2023-05-11 8:49
 * @description: 阿里云 Client 配置
 **/
@Configuration
public class AliyunOSSConfig {

    @Resource
    private AliyunOSSProperties aliyunOSSProperties;

    /**
     * 构建 阿里云 OSS 客户端
     *
     * @return
     */
    @Bean
    public OSS aliyunOSSClient() {
        // 设置访问凭证
        DefaultCredentialProvider credentialsProvider = CredentialsProviderFactory.newDefaultCredentialProvider(
                aliyunOSSProperties.getAccessKey(), aliyunOSSProperties.getSecretKey());

        // 创建 OSSClient 实例
        return new OSSClientBuilder().build(aliyunOSSProperties.getEndpoint(), credentialsProvider);
    }
}

补充阿里云策略实现类

客户端初始化完毕后,编辑 AliyunOSSFileStrategy 阿里云策略实现类,补充上传文件功能,代码如下:

package com.quanxiaoha.xiaohashu.oss.biz.strategy.impl;

import com.aliyun.oss.OSS;
import com.quanxiaoha.xiaohashu.oss.biz.config.AliyunOSSProperties;
import com.quanxiaoha.xiaohashu.oss.biz.strategy.FileStrategy;
import jakarta.annotation.Resource;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.multipart.MultipartFile;

import java.io.ByteArrayInputStream;
import java.util.UUID;

/**
 * @author: 犬小哈
 * @date: 2024/6/27 19:47
 * @version: v1.0.0
 * @description: 阿里云 OSS 文件上传策略
 **/
@Slf4j
public class AliyunOSSFileStrategy implements FileStrategy  {

    @Resource
    private AliyunOSSProperties aliyunOSSProperties;

    @Resource
    private OSS ossClient;

    @Override
    @SneakyThrows
    public String uploadFile(MultipartFile file, String bucketName) {
        log.info("## 上传文件至阿里云 OSS ...");

        // 判断文件是否为空
        if (file == null || file.getSize() == 0) {
            log.error("==> 上传文件异常:文件大小为空 ...");
            throw new RuntimeException("文件大小不能为空");
        }

        // 文件的原始名称
        String originalFileName = file.getOriginalFilename();

        // 生成存储对象的名称(将 UUID 字符串中的 - 替换成空字符串)
        String key = UUID.randomUUID().toString().replace("-", "");
        // 获取文件的后缀,如 .jpg
        String suffix = originalFileName.substring(originalFileName.lastIndexOf("."));

        // 拼接上文件后缀,即为要存储的文件名
        String objectName = String.format("%s%s", key, suffix);

        log.info("==> 开始上传文件至阿里云 OSS, ObjectName: {}", objectName);

        // 上传文件至阿里云 OSS
        ossClient.putObject(bucketName, objectName, new ByteArrayInputStream(file.getInputStream().readAllBytes()));

        // 返回文件的访问链接
        String url = String.format("https://%s.%s/%s", bucketName, aliyunOSSProperties.getEndpoint(), objectName);
        log.info("==> 上传文件至阿里云 OSS 成功,访问路径: {}", url);
        return url;
    }
}

大体上和 minio 差不太多,细节部分需要注意一下,如:

  • 返回文件访问链接:阿里云 OSS 的访问链接有些不一样,小伙伴们可以在控制台中,手动上传一个图片,然后查看详情,观察一下图片 URL 地址格式,如下图标注所示,所以,咱们的访问链接拼接格式,也需要保持一致,否则会无法访问图片。

自测一波

功能敲写完毕后,重启对象存储服务。登录到 Nacos 控制台,将对象存储类型切换到 aliyun , 以便测试对应功能。打开 Apipost 工具,测试一波上传图片接口,如下:

可以看到,成功返回了阿里云 OSS 的图片访问地址。也可以进入到阿里云后台文件列表中,确认一下图片是否真的上传成功了:

关于图片浏览器无法预览的问题

如果你直接将图片链接复制到浏览器中进行访问,会发现图片直接就下载了,而不是预览模式。这个不是代码写的有问题,官方有解释这个问题:

https://help.aliyun.com/zh/oss/user-guide/how-to-ensure-an-object-is-previewed-when-you-access-the-object?spm=a2c6h.13066369.question.9.1346431aVBckWS ,如下图所示:

官方解释如下:

使用OSS默认域名或传输加速域名访问。出于数据传输安全考虑当使用OSS默认域名或传输加速域名访问某个时间点创建的Bucket内的特定类型文件时例如Content-Type为text/html、image/jpeg等OSS会强制在返回头中增加下载Headerx-oss-force-download: trueContent-Disposition: attachment)。标准浏览器检测到Content-Disposition: attachment时,会出现强制下载而不是预览行为。

解决方案是:

您需要使用自定义域名访问。

可以先不用管,不影响到时候前端 <img> 标签图片展示。

本小节源码下载

https://t.zsxq.com/EbPCF