OSS文件上传(一):简单上传
在现代 Web 应用中,文件上传是核心功能之一,而当面对大文件(如视频、压缩包等)时,传统的单文件上传方案往往会遇到超时、网络波动失败、效率低下等问题。阿里云 OSS(Object Storage Service)作为稳定可靠的对象存储服务,提供了完善的文件上传解决方案。本文将从基础的简单上传讲起,逐步深入到分片上传,并结合 Redis 实现断点续传功能,深入剖析OSS文件上传功能,帮助你构建高效、稳定的大文件上传系统。
OSS 文件上传基础:简单上传
简单上传适用于小文件场景(通常建议文件大小≤100MB),通过 OSS 的PutObject
接口直接将文件上传到 OSS。这种方式实现简单,适合快速集成。
1. 环境准备
(1)依赖配置(Maven)
首先在pom.xml
中添加 OSS SDK 相关依赖:
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.17.4</version>
</dependency>
如果使用的是Java 9及以上的版本,则需要添加以下JAXB相关依赖:
<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)OSS 配置
在application.yml
中配置 OSS 连接信息:
aliyun:oss:endpoint: oss-cn-beijing.aliyuncs.com # 地域Endpointaccess-key-id: your-access-key-idaccess-key-secret: your-access-key-secretbucket-name: your-bucket-name # 存储桶名称
创建配置类初始化 OSS 客户端:
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClient;
import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;@Data
@Component
@ConfigurationProperties(prefix = "aliyun")
public class AliYunConfig {private String accessKey; // 阿里云AccessKeyIdprivate String accessKeySecret; // 阿里云AccessKeySecretprivate String ossBucket; // 存储桶名称private String ossEndpoint; // OSS地域节点@Beanpublic OSS oSSClient() {return new OSSClient(ossEndpoint, accessKey, accessKeySecret);}
}
创建统一结果返回类:
package com.netflow.utils;import java.io.Serializable;
import java.util.HashMap;
import java.util.Map;/*** 统一结果返回类* @param <T> 返回数据的类型*/public class Msg<T> implements Serializable {private static final long serialVersionUID = 1L;// 状态码private int code;// 消息private String message;// 返回数据private T data;// 时间戳private long timestamp;// 附加数据(可选)private Map<String, Object> extra;// 构造方法private Msg() {this.timestamp = System.currentTimeMillis();}private Msg(int code, String message) {this();this.code = code;this.message = message;}private Msg(int code, String message, T data) {this(code, message);this.data = data;}// 成功静态工厂方法public static <T> Msg<T> success() {return new Msg<>(200, "操作成功");}public static <T> Msg<T> success(String message) {return new Msg<>(200, message);}public static <T> Msg<T> success(T data) {return new Msg<>(200, "操作成功", data);}public static <T> Msg<T> success(String message, T data) {return new Msg<>(200, message, data);}// 失败静态工厂方法public static <T> Msg<T> fail() {return new Msg<>(500, "操作失败");}public static <T> Msg<T> fail(String message) {return new Msg<>(500, message);}public static <T> Msg<T> fail(int code, String message) {return new Msg<>(code, message);}// 链式调用方法public Msg<T> code(int code) {this.code = code;return this;}public Msg<T> message(String message) {this.message = message;return this;}public Msg<T> data(T data) {this.data = data;return this;}public Msg<T> extra(String key, Object value) {if (this.extra == null) {this.extra = new HashMap<>();}this.extra.put(key, value);return this;}// Getter方法public int getCode() {return code;}public String getMessage() {return message;}public T getData() {return data;}public long getTimestamp() {return timestamp;}public Map<String, Object> getExtra() {return extra;}@Overridepublic String toString() {return "Msg{" +"code=" + code +", message='" + message + '\'' +", data=" + data +", timestamp=" + timestamp +", extra=" + extra +'}';}
}
2. 简单上传实现
简单上传的核心是通过 OSS 客户端的putObject
方法直接上传文件流,代码如下:
import com.aliyun.oss.ClientException;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.model.ObjectMetadata;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyun.oss.model.PutObjectResult;
import com.netflow.config.AliYunConfig;
import com.netflow.utils.Msg;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;import java.io.File;
import java.io.IOException;
import java.util.UUID;@RestController
@Slf4j
public class OSScontroller {@AutowiredOSS ossClient;@AutowiredAliYunConfig aliYunConfig;@PostMapping("/upload")public Msg<String> uploadFile(@RequestParam("file") MultipartFile file) {try {//获取初始文件名String fileName = file.getOriginalFilename();//获取文件后缀String suffixName = fileName.substring(fileName.lastIndexOf("."));//UUID作为文件名String newFileName = UUID.randomUUID().toString()+ "-"+ fileName + suffixName;// 创建PutObjectRequest对象。PutObjectRequest putObjectRequest = new PutObjectRequest(aliYunConfig.getOssBucket(), newFileName, file.getInputStream());// 上传文件。PutObjectResult result = ossClient.putObject(putObjectRequest);return Msg.success("上传成功");} 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 | IOException 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();}}return Msg.fail("上传失败");}}
3. 简单上传的局限性
简单上传虽然实现简单,但存在明显短板:
- 文件大小限制:单次上传最大支持 5GB(OSS 限制),但实际网络中 1GB 以上文件易失败;
- 无断点续传:网络中断后需重新上传整个文件;
- 效率低:单线程上传,无法利用带宽资源。
因此,对于大文件(建议>100MB),需采用分片上传方案。想要了解分片上传内容的小伙伴可以参考我的另一篇文章
OSS文件上传(二):分片上传-CSDN博客