SpringBoot对接123云盘API:实现文件上传与直链获取完整指南
前言
在开发Web应用时,文件存储和管理是一个常见需求。123云盘提供了开放的API接口,允许开发者将文件上传到其云存储平台。本文将详细介绍如何在Spring Boot项目中对接123云盘API,实现文件上传并获取文件直链的功能。
本文将详细介绍如何在SpringBoot项目中对接123云盘开放平台API,实现文件上传和获取文件直链的功能。我们将基于123云盘的官方文档和提供的Java代码示例,逐步讲解实现过程。
一、准备工作
1. 注册123云盘开发者账号
首先需要访问123云盘开放平台注册开发者账号,获取client_id
和client_secret
。
2. 添加项目依赖
在SpringBoot项目中,我们需要添加OkHttp依赖用于HTTP请求:
xml
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>okhttp</artifactId>
<version>4.9.3</version>
</dependency>
二、核心代码实现
1. 配置属性类
首先创建一个配置类来存储123云盘的客户端凭证:
java
@Data
@Component
@ConfigurationProperties(prefix = "yunpan")
public class YunpanProperties {
private String clientId;
private String clientSecret;
}
在application.yml
中配置:
yaml
yunpan:
client_id: xxxxxxxxxxxx
client_secret: xxxxxxxxxxxx
2. AccessToken服务
123云盘的API需要通过AccessToken进行鉴权,我们需要实现一个服务来获取和管理AccessToken:
java
public interface AccessTokenService {
String getAccessToken() throws IOException;
}
@Component
public class AccessTokenServiceImpl implements AccessTokenService {
@Autowired
private YunpanProperties yunpanProperties;
private String accessToken;
private LocalDateTime expiredAt;
public synchronized String getAccessToken() throws IOException {
// 如果token不存在或已过期,则刷新token
if (expiredAt == null || LocalDateTime.now().isAfter(expiredAt)) {
refreshAccessToken();
}
return accessToken;
}
private void refreshAccessToken() throws IOException {
OkHttpClient client = new OkHttpClient();
// 构建请求体
JSONObject jsonObject = new JSONObject();
jsonObject.put("clientID", yunpanProperties.getClientId());
jsonObject.put("clientSecret", yunpanProperties.getClientSecret());
RequestBody body = RequestBody.create(jsonObject.toString(), MediaType.get("application/json"));
// 构建请求
Request request = new Request.Builder()
.url("https://open-api.123pan.com/api/v1/access_token")
.post(body)
.addHeader("Platform", "open_platform")
.addHeader("Content-Type", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) {
throw new IOException("获取AccessToken失败: " + response);
}
String jsonResponse = response.body().string();
JSONObject data = JSON.parseObject(jsonResponse).getJSONObject("data");
this.accessToken = data.getString("accessToken");
String expiredAtStr = data.getString("expiredAt");
this.expiredAt = OffsetDateTime.parse(expiredAtStr).toLocalDateTime();
System.out.println("✅ 刷新 accessToken 成功: " + this.accessToken);
}
}
}
3. 123云盘操作类
这是核心的操作类,封装了与123云盘API交互的所有方法:
java
@Slf4j
@Component
public class YunpanOperator {
@Autowired
private AccessTokenService accessTokenService;
/**
* 计算文件的MD5值
* @param file 要计算的文件
* @return MD5字符串
*/
private String getFileMD5(MultipartFile file) throws NoSuchAlgorithmException, IOException {
MessageDigest md5 = MessageDigest.getInstance("MD5");
byte[] digest = md5.digest(file.getBytes());
BigInteger bigInt = new BigInteger(1, digest);
StringBuilder md5Str = new StringBuilder(bigInt.toString(16));
// 补齐32位
while (md5Str.length() < 32) {
md5Str.insert(0, "0");
}
return md5Str.toString();
}
/**
* 获取上传域名
* @return 上传域名
*/
private String getDomain() throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder()
.url("https://open-api.123pan.com/upload/v2/file/domain")
.get()
.addHeader("Authorization", accessTokenService.getAccessToken())
.addHeader("Platform", "open_platform")
.build();
try (Response response = client.newCall(request).execute()) {
String jsonResponse = response.body().string();
log.info("获取上传域名响应: {}", jsonResponse);
return JSONObject.parseObject(jsonResponse).getJSONArray("data").getString(0);
}
}
/**
* 单步上传文件到123云盘
* @param file 要上传的文件
* @return 文件ID
*/
public String uploadSingleFile(MultipartFile file) throws IOException, NoSuchAlgorithmException {
// 生成随机文件名,避免重名
String originalFilename = file.getOriginalFilename();
String extensionName = originalFilename.substring(originalFilename.lastIndexOf("."));
String filename = UUID.randomUUID().toString() + extensionName;
// 上传参数
String parentFileID = "0"; // 上传到根目录
String etag = getFileMD5(file);
String size = String.valueOf(file.getSize());
// 构建多部分请求体
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
.addFormDataPart("file", filename,
RequestBody.create(MediaType.parse("application/octet-stream"),
file.getBytes()))
.addFormDataPart("parentFileID", parentFileID)
.addFormDataPart("filename", filename)
.addFormDataPart("etag", etag)
.addFormDataPart("size", size)
.build();
// 构建请求
Request request = new Request.Builder()
.url(getDomain() + "/upload/v2/file/single/create")
.method("POST", body)
.addHeader("Authorization", "Bearer " + accessTokenService.getAccessToken())
.addHeader("Platform", "open_platform")
.build();
// 执行请求并处理响应
try (Response response = client.newCall(request).execute()) {
String json = response.body().string();
log.info("文件上传响应: {}", json);
return JSON.parseObject(json).getJSONObject("data").getString("fileID");
}
}
/**
* 获取文件直链
* @param fileID 文件ID
* @return 文件直链URL
*/
public String getDirectLink(String fileID) throws IOException {
OkHttpClient client = new OkHttpClient().newBuilder().build();
Request request = new Request.Builder()
.url("https://open-api.123pan.com/api/v1/direct-link/url?fileID=" + fileID)
.get()
.addHeader("Content-Type", "application/json")
.addHeader("Platform", "open_platform")
.addHeader("Authorization", "Bearer " + accessTokenService.getAccessToken())
.build();
try (Response response = client.newCall(request).execute()) {
String jsonResponse = response.body().string();
log.info("获取直链响应: {}", jsonResponse);
return JSON.parseObject(jsonResponse).getJSONObject("data").getString("url");
}
}
}
4. 上传服务接口与实现
定义上传服务接口和实现:
java
public interface UploadService {
String upload(MultipartFile file) throws Exception;
}
@Service
public class YunpanUploadServiceImpl implements UploadService {
@Autowired
private YunpanOperator yunpanOperator;
@Override
public String upload(MultipartFile file) throws Exception {
// 1. 上传文件到123云盘
String fileID = yunpanOperator.uploadSingleFile(file);
// 2. 获取文件直链
return yunpanOperator.getDirectLink(fileID);
}
}
5. 控制器
最后创建控制器处理文件上传请求:
java
@RestController
@RequestMapping("/upload")
@Slf4j
public class UploadController {
@Resource(name = "yunpanUploadServiceImpl")
private UploadService uploadService;
@PostMapping
public Result upload(MultipartFile file) {
log.info("上传文件:{}", file.getOriginalFilename());
try {
String url = uploadService.upload(file);
return Result.success(url);
} catch (Exception e) {
log.error("上传失败", e);
return Result.error("上传失败: " + e.getMessage());
}
}
}
三、实现流程解析
获取AccessToken:
使用client_id和client_secret调用
/api/v1/access_token
接口获取AccessTokenAccessToken有有效期,需要在过期前刷新
获取上传域名:
调用
/upload/v2/file/domain
接口获取可用的上传域名123云盘可能提供多个域名用于负载均衡
文件上传:
计算文件的MD5值
构建multipart/form-data请求,包含文件流和元数据
调用
/upload/v2/file/single/create
接口上传文件如果文件MD5已存在,会触发秒传机制
获取直链:
使用文件ID调用
/api/v1/direct-link/url
接口获取文件直链直链可用于直接下载文件
四、注意事项
文件命名限制:
文件名要小于256个字符
不能包含以下字符:
"\/:*?|><
不能全部是空格
文件大小限制:
单步上传接口限制文件大小为1GB
大文件需要使用分片上传接口
重名处理:
可以通过
duplicate
参数设置重名处理策略1: 保留两者(新文件自动添加后缀)
2: 覆盖原文件
错误处理:
所有API调用都需要进行错误处理
检查HTTP响应状态码和返回的JSON中的code字段
性能优化:
可以复用OkHttpClient实例
对大文件可以考虑使用分片上传
五、扩展功能
文件管理:
可以实现文件列表查询、删除、移动等功能
对应API:
/api/v2/file/list
、/api/v1/file/delete
等
目录管理:
可以创建、删除目录
对应API:
/api/v1/dir/create
、/api/v1/dir/delete
等
分片上传:
对于大文件,可以实现分片上传
流程:初始化上传 -> 上传分片 -> 完成上传
通过以上实现,我们成功在SpringBoot项目中集成了123云盘的文件上传功能,并能够获取文件直链供用户下载。这种方案适用于需要将文件存储到第三方云服务的应用场景。