【三方服务集成】最新版 | 阿里云OSS对象存储服务使用教程(包含OSS工具类优化、自定义阿里云OSS服务starter)

本文涉及的产品
对象存储 OSS,20GB 3个月
对象存储 OSS,内容安全 1000次 1年
对象存储 OSS,恶意文件检测 1000次 1年
简介: 阿里云OSS(Object Storage Service)是一种安全、可靠且成本低廉的云存储服务,支持海量数据存储。用户可通过网络轻松存储和访问各类文件,如文本、图片、音频和视频等。使用OSS后,项目中的文件上传业务无需在服务器本地磁盘存储文件,而是直接上传至OSS,由其管理和保障数据安全。此外,介绍了OSS服务的开通流程、Bucket创建、AccessKey配置及环境变量设置,并提供了Java SDK示例代码,帮助用户快速上手。最后,展示了如何通过自定义starter简化工具类集成,实现便捷的文件上传功能。

一、阿里云OSS对象存储服务介绍

阿里云对象存储OSS(Object Storage Service),是一款海量、安全、低成本、高可靠的云存储服务。使用OSS,您可以通过网络随时存储和调用包括文本、图片、音频和视频等在内的各种文件。

相当于一个云储存服务器,可以把我们的文件存储到阿里云的服务器中。 在我们使用了阿里云OSS对象存储服务之后,我们的项目当中如果涉及到文件上传这样的业务,在前端进行文件上传并请求到服务端时,在服务器本地磁盘当中就不需要再来存储文件了。我们直接将接收到的文件上传到oss,由oss帮我们存储和管理,同时阿里云的oss存储服务还保障了我们所存储内容的安全可靠。

第三方服务使用的通用思路,我们做一个简单介绍之后,接下来我们就来介绍一下我们当前要使用的阿里云oss对象存储服务具体的使用步骤。

Bucket:存储空间是用户用于存储对象(Object,就是文件)的容器,所有的对象都必须隶属于某个存储空间。 SDK:Software Development Kit 的缩写,软件开发工具包,包括辅助软件开发的依赖(jar包)、代码示例等,都可以叫做SDK。 简单说,sdk中包含了我们使用第三方云服务时所需要的依赖,以及一些示例代码。我们可以参照sdk所提供的示例代码就可以完成入门程序。

二、服务开通与使用准备

1、准备工作

注册阿里云账户(注册完成后需要实名认证),注册完账号之后登录阿里云https://www.aliyun.com/

产品搜索OSS,点击进入对象存储OSS。

2、开通OSS云服务(新用户免费使用三个月)

进入后点击免费试用。(如果不是新用户,之前已开通过OSS服务,请使用充值渠道获取该服务)

找到对象存储OSS,点击立即试用。

3、创建存储空间bucket

存储空间(Bucket)是用于存储对象(Object)的容器。在上传任意类型的Object前,您需要先创建Bucket。

在阿里云工作台中搜搜OSS,进入对象存储OSS的管理控制台:https://oss.console.aliyun.com/overview

在左侧导航栏中,点击Bucket列表,然后点击创建Bucket。

填写bucket名称,名字唯一不能与其他用户的bucket重复。

Bucket 命名规范

命名长度为 3~63 个字符

只允许小写字母、数字、短横线(-),且不能以短横线开头或结尾

Bucket 名称在 OSS 范围内必须全局唯一

注意读写权限这里要选择公共读!如果选择私有,只是自己能上传,其他用户无法访问。其他选项保持默认即可。

点击确认创建。

创建成功,点击进入bucket。

这里可以看到bucket的概览信息,记住自己的bucketName和Endpoint,后面代码中调用第三方服务会用到。

4、创建并保存Accesskey

在阿里云网站上的个人中心配置Accesskey,查询AccessKeyld和AccesskeySecret。

点击继续使用AccessKey。

点击创建AccessKey。

注意:通过安全验证后可以看到生成的accessKeyld和accessKeySecret,大家下载csv文件或者复制下来,因为accessKeySecret只显示一次,点击确定后将不再显示!

5、配置访问凭证AK & SK(系统环境变量)

目前最新官方SDK要求将AccessKey ID和AccessKey Secret配置到系统环境变量,才能使用阿里云OSS服务。

  • 以Windows配置访问凭证为例(其他系统请参考官方文档)
管理员身份 打开CMD命令行,执行如下命令,配置系统的环境变量。
set ALIBABA_CLOUD_ACCESS_KEY_ID=yourAccessKeyId
set ALIBABA_CLOUD_ACCESS_KEY_SECRET=yourAccessKeySecret

注意:将上述的ACCESS_KEY_ID 与 ACCESS_KEY_SECRET 的值要替换成自己的。

执行如下命令,让更改生效。
setx ALIBABA_CLOUD_ACCESS_KEY_ID "%ALIBABA_CLOUD_ACCESS_KEY_ID%"
setx ALIBABA_CLOUD_ACCESS_KEY_SECRET "%ALIBABA_CLOUD_ACCESS_KEY_SECRET%"
执行如下命令,验证环境变量是否生效。
echo %ALIBABA_CLOUD_ACCESS_KEY_ID%
echo %ALIBABA_CLOUD_ACCESS_KEY_SECRET%

注意:设置完环境变量需要重启IDEA,才能重新读取系统环境变量。


三、阿里云OSS使用步骤

阿里云OSS对象存储服务的准备工作我们已经完成了,接下来我们参照官方所提供的SDK示例来编写入门程序。 首先我们需要来打开 阿里云OSS的官方文档 ,在官方文档中找到 SDK 的示例代码:

1、导入依赖坐标

以Java安装SDK为例,通过Maven引入阿里云OSS的依赖。

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

如果使用的是Java 9及以上的版本,则需要添加JAXB相关依赖。添加JAXB相关依赖示例代码如下:

<!-- Java 9及以上的版本还需引入以下三个依赖 -->
<dependency>
    <groupId>javax.xml.bind</groupId>
    <artifactId>jaxb-api</artifactId>
    <version>2.3.1</version>
</dependency>
<dependency>
    <groupId>javax.activation</groupId>
    <artifactId>activation</artifactId>
    <version>1.1.1</version>
</dependency>
<!-- no more than 2.3.3-->
<dependency>
    <groupId>org.glassfish.jaxb</groupId>
    <artifactId>jaxb-runtime</artifactId>
    <version>2.3.3</version>
</dependency>

2、文件上传Demo快速入门

找到官方SDK文档的上传文件流代码,点击复制。

这里主要修改地域节点endpoint存储空间名称bucketName要上传到存储空间的文件路径objectName要上传的本地文件完整路径filePath,根据自己的配置,修改为自己的。

import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.common.auth.*;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import java.io.FileInputStream;
import java.io.InputStream;

public class Demo {
   

    public static void main(String[] args) throws Exception {
   
        // Endpoint以华东1(杭州)为例,其它Region请按实际情况填写。
        String endpoint = "https://oss-cn-beijing.aliyuncs.com";
        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 填写Bucket名称,例如examplebucket。
        String bucketName = "oss-bucket-web";
        // 填写Object完整路径,完整路径中不能包含Bucket名称,例如exampledir/exampleobject.txt。
        String objectName = "oss-test/略显智慧的表情.jpg";
        // 填写本地文件的完整路径,例如D:\\localpath\\examplefile.txt。
        // 如果未指定本地路径,则默认从示例程序所属项目对应本地路径中上传文件流。
        String filePath= "D:\\图片\\QQ截图\\略显智慧的表情.jpg";

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

        try {
   
            InputStream inputStream = new FileInputStream(filePath);
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);
            // 创建PutObject请求。
            PutObjectResult result = ossClient.putObject(putObjectRequest);
        } catch (OSSException oe) {
   
            System.out.println("Caught an OSSException, which means your request made it to OSS, "
                    + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        } catch (ClientException ce) {
   
            System.out.println("Caught an ClientException, which means the client encountered "
                    + "a serious internal problem while trying to communicate with OSS, "
                    + "such as not being able to access the network.");
            System.out.println("Error Message:" + ce.getMessage());
        } finally {
   
            if (ossClient != null) {
   
                ossClient.shutdown();
            }
        }
    }
}

执行main方法,可以发现bucket中已经自动创建文件夹,文件上传成功。

点击上传的文件,这个URL就是文件通过OSS生成的访问下载地址。

3、阿里云OSS工具类

根据官方的文件上传Demo,我们可以抽取成一个文件上传工具类,方便我们上传文件调用。

  • 阿里云OSS文件上传工具类AliOSSUtils,可直接复制粘贴使用(注意修改自己的OSS四项配置信息)。
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.IOException;
import java.io.InputStream;
import java.util.UUID;

/**
 * 阿里云OSS文件上传工具类
 */
@Component
public class AliOSSUtils {
   
    // 将以下四项替换为自己的信息
    private String endpoint = "https://oss-cn-beijing.aliyuncs.com";
    private String accessKeyId = "yourAccessKeyId";
    private String accessKeySecret = "yourAccessKeySecret";
    private String bucketName = "oss-bucket-web";

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * 方法重载,直接以UUID文件名存储,无上传目录
     * @param multipartFile Spring接收前端上传文件的对象
     * @return 对象存储在OSS中的URL
     * @throws IOException
     */
    public String upload(MultipartFile multipartFile) throws IOException {
   
        return upload(multipartFile, ""); // 把上传到oss的路径返回
    }

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * OSS存储文件路径为:uploadDir/UUID.文件后缀名
     * @param multipartFile Spring接收前端上传文件的对象
     * @param uploadDir 上传文件到OSS的目录,不能包含Bucket名称,只能包含目录,不能以“/”开头,目录可传参为空。
     * @return 对象存储在OSS中的URL
     * @throws IOException
     */
    public String upload(MultipartFile multipartFile, String uploadDir) throws IOException {
   
        // 判断上传目录是否为空,不为空则进行目录合法性校验
        if (uploadDir == null || "/".equals(uploadDir)) return upload(multipartFile);
        uploadDir = uploadDir.trim();
        if (uploadDir.startsWith("/")) uploadDir = uploadDir.substring(1);
        if (!"".equals(uploadDir) && !uploadDir.endsWith("/")) uploadDir += "/";
        // 获取上传的文件的输入流
        InputStream inputStream = multipartFile.getInputStream();
        // 获取上传文件的原始文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 为保证文件名唯一,避免文件上传覆盖,使用UUID作为文件名,并拼接文件后缀名
        String fileName = uploadDir + UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));
        // 上传文件到 OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, accessKeyId, accessKeySecret);
        ossClient.putObject(bucketName, fileName, inputStream);
        // 文件访问路径 = https://bucketName.endpoint/fileName,例如https://oss-bucket-web.oss-cn-beijing.aliyuncs.com/uploadDir/UUID.jpg
        String url = endpoint.split("//")[0] + "//" + bucketName + "." + endpoint.split("//")[1] + "/" + fileName;
        // 关闭ossClient
        ossClient.shutdown();
        // 把上传到oss的路径返回
        return url;
    }
}
  • 文件上传控制器UploadController,模拟文件上传服务。
import com.dkd.common.utils.file.AliOSSUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {
   
    @Autowired
    private AliOSSUtils aliOSSUtils;

    @PostMapping("/oss")
    public String upload(@RequestParam("file") MultipartFile file) throws Exception {
   
        if (file.isEmpty()) {
   
            log.warn("上传文件为空");
            return "上传文件为空,未接收到文件";
        }
        // 上传到根目录
        String url = aliOSSUtils.upload(file);
        // 上传到指定目录
        //String url = aliOSSUtils.upload(file, "uploads");
        log.info("文件上传成功,访问地址为:{}", url);
        return url;
    }
}
  • 使用Apifox或Postman发送文件上传的Post请求

工具类成功返回文件上传到OSS可供访问下载的URL。

4、工具类解耦优化

  • 优化一:用@Value注解配置常量抽取到properties或yml文件中,防止在程序中硬编码,降低耦合度。
  • 优化二:使用官方推荐的EnvironmentVariableCredentialsProvider对象来创建OSS对象,accessKeyId和accessKeySecret从系统环境变量中获取,提升安全性。
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.web.multipart.MultipartFile;
import java.io.InputStream;
import java.util.UUID;

/**
 * 阿里云OSS文件上传工具类
 */
@Component
public class AliOSSUtils {
   
    @Value("${aliyun.oss.endpoint}")
    private String endpoint;
    @Value("${aliyun.oss.bucketName}")
    private String bucketName;

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * 方法重载,直接以UUID文件名存储,无上传目录
     * @param multipartFile Spring接收前端上传文件的对象
     * @return 对象存储在OSS中的URL
     * @throws Exception
     */
    public String upload(MultipartFile multipartFile) throws Exception {
   
        return upload(multipartFile, ""); // 把上传到oss的路径返回
    }

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * OSS存储文件路径为:uploadDir/UUID.文件后缀名
     * @param multipartFile Spring接收前端上传文件的对象
     * @param uploadDir 上传文件到OSS的目录,不能包含Bucket名称,只能包含目录,不能以“/”开头,目录可传参为空。
     * @return 对象存储在OSS中的URL
     * @throws Exception
     */
    public String upload(MultipartFile multipartFile, String uploadDir) throws Exception {
   
        // 判断上传目录是否为空,不为空则进行目录合法性校验
        if (uploadDir == null || "/".equals(uploadDir)) return upload(multipartFile);
        uploadDir = uploadDir.trim();
        if (uploadDir.startsWith("/")) uploadDir = uploadDir.substring(1);
        if (!"".equals(uploadDir) && !uploadDir.endsWith("/")) uploadDir += "/";

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 获取上传的文件的输入流
        InputStream inputStream = multipartFile.getInputStream();
        // 获取上传文件的原始文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 为保证文件名唯一,避免文件上传覆盖,使用UUID作为文件名,并拼接文件后缀名
        String fileName = uploadDir + UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        // 创建OSSClient实例,上传文件到OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        ossClient.putObject(bucketName, fileName, inputStream);

        // 文件访问路径 = https://bucketName.endpoint/fileName,例如https://oss-bucket-web.oss-cn-beijing.aliyuncs.com/uploadDir/UUID.jpg
        if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
        String[] endpointPart = endpoint.split("//");
        StringBuilder url = new StringBuilder(endpointPart[0]);   // https:
        url.append("//")
                .append(bucketName)
                .append(".")
                .append(endpointPart[1])
                .append("/")
                .append(fileName);
        // 关闭ossClient
        ossClient.shutdown();
        // 把上传到oss的路径返回
        return url.toString();
    }
}
  • application.properties 或 application.yml中的配置:
# application.properties
aliyun.oss.endpoint=https://oss-cn-beijing.aliyuncs.com
aliyun.oss.bucketName=oss-bucket-web

# application.yaml
# 阿里云OSS配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: oss-bucket-web
  • 将测试的Controller中的上传代码,改为上传到uploads文件夹下(第二个参数为上传到OSS的存储文件夹)。
// 上传到指定目录
String url = aliOSSUtils.upload(file, "uploads");
  • 通过Apifox发送Post请求,注意请求参数名称指定为file,提交类型指定为form-data。

  • 阿里云OSS控制台成功存储,并自动创建了uploads文件夹,文件上传成功!


四、阿里云OSS自定义starter

1、需求说明

背景:假设项目组里不止一人用到阿里云OSS工具类,开发团队想要引入依赖就能使用工具类,后期工具类有新增功能时,方便统一修改管理。

需求:自定义aliyun-oss-spring-boot-starter,完成阿里云OSS操作工具类 AliOSSUtils 的自动配置。

目标:引入起步依赖引入之后,要想使用阿里云OSS,注入AliOSSUtils直接使用即可。

2、步骤分析

(1)创建 aliyun-oss-spring-boot-starter 模块。

(2)创建 aliyun-oss-spring-boot-autoconfigure 模块,在starter中到引入该模块。

(3)在 aliyun-oss-spring-boot-autoconfigure 模块中的定义自动配置功能,并定义自动配置文件 META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports。

3、自定义starter实现

(1)创建starter模块

将starter模块中多余的文件全部删掉。

(2)创建autoconfigure模块

(3)在starter的pom中引入autoconfigure的依赖

配置starter的pom文件:

  • 引入spring-boot-starter核心起步依赖,用于实现SpringBoot自动配置。
  • 引入阿里云OSS的自动配置类aliyun-oss-spring-boot-autoconfigure,用于完成AliOSSUtils的自动装配。
<?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>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-starter</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <!-- springboot核心起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- 阿里云OSS的自动配置类 -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>
</project>

(4)配置autoconfigure的pom

配置autoconfigure的pom文件:

  • 引入spring-boot-starter核心起步依赖,用于实现SpringBoot自动配置。
  • 引入spring-web,接收上传文件的MultipartFile类需要用到。
  • 引入阿里云OSS的相关依赖。
<?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>3.3.3</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aliyun.oss</groupId>
    <artifactId>aliyun-oss-spring-boot-autoconfigure</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

    <dependencies>
        <!-- springboot核心起步依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter</artifactId>
        </dependency>
        <!-- spring-web MultipartFile需要 -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
        </dependency>

        <!-- 阿里云OSS -->
        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-sdk-oss</artifactId>
            <version>3.17.4</version>
        </dependency>
        <!-- Java 9及以上的版本还需引入以下三个依赖 -->
        <dependency>
            <groupId>javax.xml.bind</groupId>
            <artifactId>jaxb-api</artifactId>
            <version>2.3.1</version>
        </dependency>
        <dependency>
            <groupId>javax.activation</groupId>
            <artifactId>activation</artifactId>
            <version>1.1.1</version>
        </dependency>
        <!-- no more than 2.3.3-->
        <dependency>
            <groupId>org.glassfish.jaxb</groupId>
            <artifactId>jaxb-runtime</artifactId>
            <version>2.3.3</version>
        </dependency>
    </dependencies>
</project>

(5)创建AliOSSUtils、AliOSSProperties、AliOSSAutoConfiguration类

  • 文件上传工具类AliOSSUtils,将工具类再次升级改造为从AliOSSProperties中读取配置信息。同时去掉@Component注解,因为我们的启动类不会去扫描com.aliyun.oss包。
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import org.springframework.web.multipart.MultipartFile;

import java.io.InputStream;
import java.util.UUID;

/**
 * 阿里云OSS文件上传工具类
 */
public class AliOSSUtils {
   
    private AliOSSProperties aliOSSProperties;

    public AliOSSProperties getAliOSSProperties() {
   
        return aliOSSProperties;
    }

    public void setAliOSSProperties(AliOSSProperties aliOSSProperties) {
   
        this.aliOSSProperties = aliOSSProperties;
    }

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * 方法重载,直接以UUID文件名存储,无上传目录
     * @param multipartFile Spring接收前端上传文件的对象
     * @return 对象存储在OSS中的URL
     * @throws Exception
     */
    public String upload(MultipartFile multipartFile) throws Exception {
   
        return upload(multipartFile, ""); // 把上传到oss的路径返回
    }

    /**
     * 实现上传文件到OSS,上传的文件对象以UUID命名,并返回文件访问路径
     * OSS存储文件路径为:uploadDir/UUID.文件后缀名
     * @param multipartFile Spring接收前端上传文件的对象
     * @param uploadDir 上传文件到OSS的目录,不能包含Bucket名称,只能包含目录,不能以“/”开头,目录可传参为空。
     * @return 对象存储在OSS中的URL
     * @throws Exception
     */
    public String upload(MultipartFile multipartFile, String uploadDir) throws Exception {
   
        // 判断上传目录是否为空,不为空则进行目录合法性校验
        if (uploadDir == null || "/".equals(uploadDir)) return upload(multipartFile);
        uploadDir = uploadDir.trim();
        if (uploadDir.startsWith("/")) uploadDir = uploadDir.substring(1);
        if (!"".equals(uploadDir) && !uploadDir.endsWith("/")) uploadDir += "/";
        // 获取上传文件的原始文件名
        String originalFilename = multipartFile.getOriginalFilename();
        // 为保证文件名唯一,避免文件上传覆盖,使用UUID作为文件名,并拼接文件后缀名
        String fileName = uploadDir + UUID.randomUUID().toString() + originalFilename.substring(originalFilename.lastIndexOf("."));

        // 从环境变量中获取访问凭证。运行本代码示例之前,请确保已设置环境变量ALIBABA_CLOUD_ACCESS_KEY_ID和ALIBABA_CLOUD_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 获取上传的文件的输入流
        InputStream inputStream = multipartFile.getInputStream();
        // 从AliOSSProperties中获取endpoint和bucketName
        String endpoint = aliOSSProperties.getEndpoint();
        String bucketName = aliOSSProperties.getBucketName();
        // 创建OSSClient实例,上传文件到OSS
        OSS ossClient = new OSSClientBuilder().build(endpoint, credentialsProvider);
        ossClient.putObject(bucketName, fileName, inputStream);

        // 文件访问路径 = https://bucketName.endpoint/fileName,例如https://oss-bucket-web.oss-cn-beijing.aliyuncs.com/uploadDir/UUID.jpg
        if (!endpoint.startsWith("https://")) endpoint = "https://" + endpoint;
        String[] endpointPart = endpoint.split("//");
        StringBuilder url = new StringBuilder(endpointPart[0]);   // https:
        url.append("//")
                .append(bucketName)
                .append(".")
                .append(endpointPart[1])
                .append("/")
                .append(fileName);
        // 关闭ossClient
        ossClient.shutdown();
        // 把上传到oss的路径返回
        return url.toString();
    }
}
  • 阿里云OSS配置类AliOSSProperties,用于从引入该starter的模块下读取配置文件中前缀为aliyun.oss的配置项。注意endpoint和bucketName属性名要与配置文件中前缀下的key保持一致,同时需要提供get和set方法。
import org.springframework.boot.context.properties.ConfigurationProperties;

@ConfigurationProperties(prefix = "aliyun.oss") // 从引入该starter的模块下的配置文件中读取,prefix为配置前缀
public class AliOSSProperties {
   
    // 前缀下的配置项的key要与属性名保持一致
    private String endpoint;
    private String bucketName;

    // 需要添加get和set方法
    public String getEndpoint() {
   
        return endpoint;
    }

    public void setEndpoint(String endpoint) {
   
        this.endpoint = endpoint;
    }

    public String getBucketName() {
   
        return bucketName;
    }

    public void setBucketName(String bucketName) {
   
        this.bucketName = bucketName;
    }
}
@ConfigurationProperties和@Value的区别

相同点:都是用来注入外部配置的属性的。

不同点:

  • @Value注解只能一个一个的进行外部属性的注入(属性多的情况下注入很麻烦)。
  • @ConfigurationProperties可以批量的将外部的属性配置注入到bean对象的属性中(前缀可以复用)。

@ConfigurationProperties使用注意点:

  • 需要创建一个实现类,且实体类中的属性名和配置文件当中key的名字必须要一致。
  • 实体类中的属性还需要提供getter和setter方法。
  • 阿里云OSS自动配置类AliOSSAutoConfiguration,用于将工具类注册为Spring的bean对象,并设置配置类。@EnableConfigurationProperties可以将配置类AliOSSProperties直接注册为bean对象,从而我们可以从Spring的容器中去获取配置好的AliOSSProperties对象。
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
@EnableConfigurationProperties(AliOSSProperties.class)
public class AliOSSAutoConfiguration {
   
    @Bean
    public AliOSSUtils aliOSSUtils(AliOSSProperties aliOSSProperties) {
   
        AliOSSUtils aliOSSUtils = new AliOSSUtils();
        aliOSSUtils.setAliOSSProperties(aliOSSProperties);
        return aliOSSUtils;
    }
}

(6)创建.imports自动配置文件

在resources资源路径下创建文件夹META-INF/spring,在这个文件夹下创建名为org.springframework.boot.autoconfigure.AutoConfiguration.imports的自动配置文件,供SpringBoot底层的自动配置去扫描读取。文件目录结构如下图所示:

4、测试阿里云OSS的自定义starter

准备一个测试模块

在测试模块的pom中引入阿里云OSS的自定义starter依赖和web依赖:

<?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.7.5</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.aizen</groupId>
    <artifactId>springboot-autoconfiguration-test</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <java.version>17</java.version>
    </properties>

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

        <dependency>
            <groupId>com.aliyun.oss</groupId>
            <artifactId>aliyun-oss-spring-boot-starter</artifactId>
            <version>0.0.1-SNAPSHOT</version>
        </dependency>
    </dependencies>

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

在yaml文件中配置阿里云OSS的配置项:

# 阿里云OSS配置
aliyun:
  oss:
    endpoint: https://oss-cn-beijing.aliyuncs.com
    bucketName: oss-bucket-web

测试文件上传UploadController,AliOSSUtils工具类将通过自动配置后自动注入:

import com.aliyun.oss.AliOSSUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {
   
    @Autowired
    private AliOSSUtils aliOSSUtils;

    @PostMapping("/oss")
    public String upload(@RequestParam("file") MultipartFile file) throws Exception {
   
        if (file.isEmpty()) {
   
            log.warn("上传文件为空");
            return "上传文件为空,未接收到文件";
        }
        // 上传到根目录
        String url = aliOSSUtils.upload(file);
        log.info("文件上传成功,访问地址为:{}", url);
        return url;
    }
}

通过Apifox发送文件上传的Post请求,成功响应存储url。

使用阿里云OSS自定义starter文件上传成功!


相关实践学习
借助OSS搭建在线教育视频课程分享网站
本教程介绍如何基于云服务器ECS和对象存储OSS,搭建一个在线教育视频课程分享网站。
相关文章
|
3月前
|
Java API 对象存储
微服务魔法启动!Spring Cloud与Netflix OSS联手,零基础也能创造服务奇迹!
这段内容介绍了如何使用Spring Cloud和Netflix OSS构建微服务架构。首先,基于Spring Boot创建项目并添加Spring Cloud依赖项。接着配置Eureka服务器实现服务发现,然后创建REST控制器作为API入口。为提高服务稳定性,利用Hystrix实现断路器模式。最后,在启动类中启用Eureka客户端功能。此外,还可集成其他Netflix OSS组件以增强系统功能。通过这些步骤,开发者可以更高效地构建稳定且可扩展的微服务系统。
60 1
|
4月前
|
机器学习/深度学习 存储 前端开发
实战揭秘:如何借助TensorFlow.js的强大力量,轻松将高效能的机器学习模型无缝集成到Web浏览器中,从而打造智能化的前端应用并优化用户体验
【8月更文挑战第31天】将机器学习模型集成到Web应用中,可让用户在浏览器内体验智能化功能。TensorFlow.js作为在客户端浏览器中运行的库,提供了强大支持。本文通过问答形式详细介绍如何使用TensorFlow.js将机器学习模型带入Web浏览器,并通过具体示例代码展示最佳实践。首先,需在HTML文件中引入TensorFlow.js库;接着,可通过加载预训练模型如MobileNet实现图像分类;然后,编写代码处理图像识别并显示结果;此外,还介绍了如何训练自定义模型及优化模型性能的方法,包括模型量化、剪枝和压缩等。
59 1
|
4月前
|
域名解析 网络协议 API
【API管理 APIM】APIM集成内部VNet时,常遇见的关于自定义DNS服务问题。
【API管理 APIM】APIM集成内部VNet时,常遇见的关于自定义DNS服务问题。
|
4月前
|
搜索推荐
实现CRM与ERP系统无缝集成,优化客户关系管理
在当今竞争激烈的市场环境中,企业要想保持领先地位,必须高效地管理客户关系并优化内部资源。CRM(客户关系管理)系统与ERP(企业资源规划)系统的无缝集成,为企业提供了一种强大的工具,以实现这一目标
74 2
|
4月前
|
JavaScript jenkins 持续交付
自动化部署与持续集成:使用Jenkins和Docker优化开发流程
【8月更文挑战第31天】在软件开发的世界里,时间就是一切。本文将引导你通过Jenkins和Docker的强大组合,实现自动化部署和持续集成,让你的开发流程如丝般顺滑。我们将从基础设置开始,逐步深入到构建管道,最终实现一键部署的梦想。准备好让你的开发效率飞跃,一起探索这个令人兴奋的旅程吧!
|
4月前
|
API UED 开发者
如何在Uno Platform中轻松实现流畅动画效果——从基础到优化,全方位打造用户友好的动态交互体验!
【8月更文挑战第31天】在开发跨平台应用时,确保用户界面流畅且具吸引力至关重要。Uno Platform 作为多端统一的开发框架,不仅支持跨系统应用开发,还能通过优化实现流畅动画,增强用户体验。本文探讨了Uno Platform中实现流畅动画的多个方面,包括动画基础、性能优化、实践技巧及问题排查,帮助开发者掌握具体优化策略,提升应用质量与用户满意度。通过合理利用故事板、减少布局复杂性、使用硬件加速等技术,结合异步方法与预设缓存技巧,开发者能够创建美观且流畅的动画效果。
89 0
|
4月前
|
SQL 网络协议 安全
【Azure API 管理】APIM集成内网虚拟网络后,启用自定义路由管理外出流量经过防火墙(Firewall),遇见APIs加载不出来问题
【Azure API 管理】APIM集成内网虚拟网络后,启用自定义路由管理外出流量经过防火墙(Firewall),遇见APIs加载不出来问题
|
5月前
|
机器学习/深度学习 人工智能 专有云
人工智能平台PAI使用问题之怎么将DLC的数据写入到另一个阿里云主账号的OSS中
阿里云人工智能平台PAI是一个功能强大、易于使用的AI开发平台,旨在降低AI开发门槛,加速创新,助力企业和开发者高效构建、部署和管理人工智能应用。其中包含了一系列相互协同的产品与服务,共同构成一个完整的人工智能开发与应用生态系统。以下是对PAI产品使用合集的概述,涵盖数据处理、模型开发、训练加速、模型部署及管理等多个环节。
|
1月前
|
分布式计算 Java 开发工具
阿里云MaxCompute-XGBoost on Spark 极限梯度提升算法的分布式训练与模型持久化oss的实现与代码浅析
本文介绍了XGBoost在MaxCompute+OSS架构下模型持久化遇到的问题及其解决方案。首先简要介绍了XGBoost的特点和应用场景,随后详细描述了客户在将XGBoost on Spark任务从HDFS迁移到OSS时遇到的异常情况。通过分析异常堆栈和源代码,发现使用的`nativeBooster.saveModel`方法不支持OSS路径,而使用`write.overwrite().save`方法则能成功保存模型。最后提供了完整的Scala代码示例、Maven配置和提交命令,帮助用户顺利迁移模型存储路径。
|
4月前
|
存储 机器学习/深度学习 弹性计算
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决
阿里云EMR数据湖文件系统问题之OSS-HDFS全托管服务的问题如何解决

相关产品

  • 对象存储