一、现有存储的一般方案
对象存储方案大比拼——本地存储、OSS、MinIO、Ceph、Apache Ozone 与 OpenIO-优快云博客
二、为什么要用百度网盘作代理
1.免费;
2.安全;
3.云部署,不用考虑本地跑和部署后移植文件的问题;
三、适用于
1.个人开发者;
2.不想充钱;
3.本地内存不够的;
4.服务器内存不够的
四、解决什么问题
1.文件如果存储在本地,则部署到服务器上的时候跨系统会出现问题;文件如果存储在后端系统中,则部署到服务器时内存会非常大从而导致系统响应速度慢、内存泄露等问题;
2.百度网盘只允许企业注册应用,不允许个人注册;
3.服务器内存有限,NAS存储要钱;
五、解决方案
通过Alist代理百度网盘,基于Alist开放的文档,撰写一套Java代码。
六、Alist配置百度网盘文档
七、Alist的API文档
八、代码
1.实体类
import lombok.AllArgsConstructor;
import lombok.Data;
@Data
@AllArgsConstructor
public class AlistConfig {
private String alistBaseUrl;
private String alistUsername;
private String alistPassword;
}
2.HTTP请求
import com.google.gson.Gson;
import okhttp3.*;
import java.io.IOException;
import java.util.Map;
public class OkHttpUtils {
private static final MediaType JSON = MediaType.parse("application/json; charset=utf-8");
private static final OkHttpClient client = new OkHttpClient();
/**
* 发送 POST 请求
*
* @param url 请求地址
* @param bodyData 请求体数据,可以是 Map 或 JSON 字符串
* @return 响应结果
*/
public static String doPost(String url, Object bodyData) {
RequestBody requestBody;
if (bodyData instanceof Map) {
requestBody = RequestBody.create(JSON, new Gson().toJson(bodyData));
} else if (bodyData instanceof String) {
requestBody = RequestBody.create(JSON, (String) bodyData);
} else {
throw new IllegalArgumentException("请求参数必须是Map或JSON");
}
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("错误代码:" + response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static String doPostWithHeaders(String url, Object bodyData, Map<String, String> headers) {
RequestBody requestBody;
if (bodyData instanceof Map) {
requestBody = RequestBody.create(JSON, new Gson().toJson(bodyData));
} else if (bodyData instanceof String) {
requestBody = RequestBody.create(JSON, (String) bodyData);
} else {
throw new IllegalArgumentException("请求参数必须是Map或JSON");
}
Request request = new Request.Builder()
.url(url)
.post(requestBody)
.build();
for (Map.Entry<String, String> entry : headers.entrySet()) {
request = request.newBuilder().addHeader(entry.getKey(), entry.getValue()).build();
}
try (Response response = client.newCall(request).execute()) {
if (response.isSuccessful()) {
return response.body().string();
} else {
throw new IOException("错误代码:" + response);
}
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
3.Alist工具类
ram path 路径 eg: /files/test/xxx.txt
* @param password 文件密码,可以传空字符串
* @return
*/
public static String getAlistFileInfo(AlistConfig alistConfig,String path,String password){
String url = alistConfig.getAlistBaseUrl() + "/api/fs/get";
HashMap<String, String> headerData = new HashMap<>();
HashMap<String, String> bodyData = new HashMap<>();
bodyData.put("path", path);
bodyData.put("password", password);
headerData.put("Authorization", getToken(alistConfig));
return OkHttpUtils.doPostWithHeaders(url, bodyData, headerData);
}
/**
* 递归-遍历文件夹下所有文件下载地址
* @param alistConfig alist配置实体类
* @param path 目录 eg:/files/test
* @param password 文件密码,可以传空字符串
* @return {path : rawUrl}
*/
public static ArrayList<HashMap<String, String>> getAlistAllFilesInfo(AlistConfig alistConfig,String path, String password) {
// 获取path目录下信息
String result = getAlistFileList(alistConfig,path);
// 获取所有的信息
JSONObject json_data = JSON.parseObject(JSON.parseObject(result).get("data").toString());
// 将content转为json数组
JSONArray json_array = json_data.getJSONArray("content");
ArrayList<HashMap<String, String>> filesInfoMaps = new ArrayList<>();
processDirectory(alistConfig,filesInfoMaps, path, json_array, password);
return filesInfoMaps;
}
//处理文件夹
private static void processDirectory(AlistConfig alistConfig,ArrayList<HashMap<String, String>> filesInfoMaps, String path, JSONArray json_array, String password) {
//判空处理
if (json_array == null || json_array.isEmpty()) {
return;
}
for (int i = 0; i < json_array.size(); i++) {
HashMap<String, String> filesInfoMap = new HashMap<>();
// 获取当前json对象
JSONObject json_object = json_array.getJSONObject(i);
// 获取当前json对象的name
String name = json_object.getString("name");
// 判断是否为文件夹
String is_dir = json_object.getString("is_dir");
if (!"true".equals(is_dir)) {
String filename = safePathJoin(path, name);
String alistFileInfo = getAlistFileInfo(alistConfig,filename, password);
JSONObject json_file_data = JSON.parseObject(JSON.parseObject(alistFileInfo).get("data").toString());
if (json_file_data.containsKey("content")) {
JSONArray json_file_content = json_file_data.getJSONArray("content");
for (int j = 0; j < json_file_content.size(); j++) {
// 获取当前json对象
JSONObject json_file_object = json_file_content.getJSONObject(j);
// 获取当前json对象的raw_url
String rawUrl = json_file_object.getString("raw_url");
filesInfoMap.put("filePath",filename);
filesInfoMap.put("rawUrl",rawUrl);
filesInfoMaps.add(filesInfoMap);
}
} else {
String rawUrl = json_file_data.getString("raw_url");
filesInfoMap.put("filePath",filename);
filesInfoMap.put("rawUrl",rawUrl);
filesInfoMaps.add(filesInfoMap);
}
} else {
// 处理文件夹
String directoryPath = safePathJoin(path, name);
String directoryResult = getAlistFileList(alistConfig,directoryPath);
JSONObject directoryJsonData = JSON.parseObject(JSON.parseObject(directoryResult).get("data").toString());
JSONArray directoryJsonArray = directoryJsonData.getJSONArray("content");
processDirectory(alistConfig,filesInfoMaps, directoryPath, directoryJsonArray, password);
}
}
}
private static String safePathJoin(String base, String name) {
// 防止路径穿越
return base.endsWith("/") ? base + name : base + "/" + name;
}
/**
* 上传文件
* @param alistConfig alist配置实体类
* @param originalPath 目标文件
* @param targetPath 目的路径
* @param FileName 目的文件名
* @return 文件路径/结果
* @throws IOException
*/
public static String uploadFile(AlistConfig alistConfig,String originalPath,String FileName,String targetPath) throws IOException {
String url = alistConfig.getAlistBaseUrl() + "/api/fs/put";
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("text/plain");
byte[] bytes = Files.readAllBytes(Paths.get(originalPath));
RequestBody body = RequestBody.create(mediaType, bytes);
Request request = new Request.Builder()
.url(url)
.method("PUT", body)
.addHeader("Authorization", getToken(alistConfig))
.addHeader("File-Path", targetPath+"/"+FileName)
.addHeader("As-Task", "true")
.addHeader("Content-Length", "")
.build();
Response response = client.newCall(request).execute();
JSONObject parse = JSON.parseObject(response.body().string());
if (parse.get("code").toString().equals("200")){
return alistConfig.getAlistBaseUrl()+"/d"+targetPath+"/"+FileName;
}else {
return parse.get("message").toString();
}
}
}
4.测试类
import com.mavis.entity.AlistConfig;
import com.mavis.util.AlistUtils;
import java.util.ArrayList;
import java.util.HashMap;
public class Test {
public static void main(String[] args) {
AlistConfig alistConfig = new AlistConfig(
"http://你的服务器地址:5244",
"你的账号名",
"你的密码"
);
ArrayList<HashMap<String, String>> alistAllFilesInfo = AlistUtils.getAlistAllFilesInfo(alistConfig, "/BaiduDisk/AlistStorage/pic", "");
for (HashMap<String, String> map : alistAllFilesInfo) {
System.out.println(map);
}
}
}
九、AlistUtils使用说明
1.初始化AlistConfig对象 (所有方法的前提)
AlistConfig alistConfig = new AlistConfig("http://localhost:5244","admin","123456");
//传入alist地址,用户名,密码即可
2.获取指定目录下列表
String alistFileList = AlistUtils.getAlistFileList(alistConfig, "/files/test");
//传入实例化的AlistConfig对象和路径即可
3.获取指定文件信息
String alistFileInfo = AlistUtils.getAlistFileInfo(alistConfig, "/files/test/test.txt", "");
//传入实例化的AlistConfig对象、路径以及文件密码即可 文件密码若没设置可以为空
4.递归获取指定目录下所有文件的下载直链
ArrayList<HashMap<String, String>> alistAllFilesInfo = AlistUtils.getAlistAllFilesInfo(alistConfig, "/files/test", "");
//传入实例化的AlistConfig对象、路径以及文件密码即可 文件密码若没设置可以为空
//返回的ArrayList集合中会包含所有的文件对应路径以及下载地址的键值对集合
5.上传文件
AlistUtils.uploadFile(alistConfig, "D:/files/test/test.txt", "/files/test/test","test.txt");
//传入实例化的AlistConfig对象、源文件、目标目录、传入后文件名