【三方服务集成】最新版 | 阿里云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文件上传成功!


相关文章
|
15天前
|
弹性计算 人工智能 架构师
阿里云携手Altair共拓云上工业仿真新机遇
2024年9月12日,「2024 Altair 技术大会杭州站」成功召开,阿里云弹性计算产品运营与生态负责人何川,与Altair中国技术总监赵阳在会上联合发布了最新的“云上CAE一体机”。
阿里云携手Altair共拓云上工业仿真新机遇
|
11天前
|
机器学习/深度学习 算法 大数据
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
2024“华为杯”数学建模竞赛,对ABCDEF每个题进行详细的分析,涵盖风电场功率优化、WLAN网络吞吐量、磁性元件损耗建模、地理环境问题、高速公路应急车道启用和X射线脉冲星建模等多领域问题,解析了问题类型、专业和技能的需要。
2539 19
【BetterBench博士】2024 “华为杯”第二十一届中国研究生数学建模竞赛 选题分析
|
11天前
|
机器学习/深度学习 算法 数据可视化
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
2024年中国研究生数学建模竞赛C题聚焦磁性元件磁芯损耗建模。题目背景介绍了电能变换技术的发展与应用,强调磁性元件在功率变换器中的重要性。磁芯损耗受多种因素影响,现有模型难以精确预测。题目要求通过数据分析建立高精度磁芯损耗模型。具体任务包括励磁波形分类、修正斯坦麦茨方程、分析影响因素、构建预测模型及优化设计条件。涉及数据预处理、特征提取、机器学习及优化算法等技术。适合电气、材料、计算机等多个专业学生参与。
1532 16
【BetterBench博士】2024年中国研究生数学建模竞赛 C题:数据驱动下磁性元件的磁芯损耗建模 问题分析、数学模型、python 代码
|
7天前
|
存储 关系型数据库 分布式数据库
GraphRAG:基于PolarDB+通义千问+LangChain的知识图谱+大模型最佳实践
本文介绍了如何使用PolarDB、通义千问和LangChain搭建GraphRAG系统,结合知识图谱和向量检索提升问答质量。通过实例展示了单独使用向量检索和图检索的局限性,并通过图+向量联合搜索增强了问答准确性。PolarDB支持AGE图引擎和pgvector插件,实现图数据和向量数据的统一存储与检索,提升了RAG系统的性能和效果。
|
13天前
|
编解码 JSON 自然语言处理
通义千问重磅开源Qwen2.5,性能超越Llama
击败Meta,阿里Qwen2.5再登全球开源大模型王座
665 14
|
8天前
|
人工智能 开发框架 Java
重磅发布!AI 驱动的 Java 开发框架:Spring AI Alibaba
随着生成式 AI 的快速发展,基于 AI 开发框架构建 AI 应用的诉求迅速增长,涌现出了包括 LangChain、LlamaIndex 等开发框架,但大部分框架只提供了 Python 语言的实现。但这些开发框架对于国内习惯了 Spring 开发范式的 Java 开发者而言,并非十分友好和丝滑。因此,我们基于 Spring AI 发布并快速演进 Spring AI Alibaba,通过提供一种方便的 API 抽象,帮助 Java 开发者简化 AI 应用的开发。同时,提供了完整的开源配套,包括可观测、网关、消息队列、配置中心等。
511 5
|
9天前
|
人工智能 IDE 程序员
期盼已久!通义灵码 AI 程序员开启邀测,全流程开发仅用几分钟
在云栖大会上,阿里云云原生应用平台负责人丁宇宣布,「通义灵码」完成全面升级,并正式发布 AI 程序员。
|
1天前
|
Docker 容器
Docker操作 (五)
Docker操作 (五)
130 68
|
1天前
|
Docker 容器
Docker操作 (三)
Docker操作 (三)
125 69
|
13天前
|
人工智能 自动驾驶 机器人
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界
过去22个月,AI发展速度超过任何历史时期,但我们依然还处于AGI变革的早期。生成式AI最大的想象力,绝不是在手机屏幕上做一两个新的超级app,而是接管数字世界,改变物理世界。
544 49
吴泳铭:AI最大的想象力不在手机屏幕,而是改变物理世界