一行代码将文件存储到本地、FTP、SFTP、WebDAV、阿里云 OSS、华为云 OBS、七牛云 Kodo、腾讯云 COS、百度云 BOS、又拍云 USS、MinIO、 Amazon S3、Amazon S3 V2、GoogleCloud Storage、FastDFS、 Azure Blob Storage、Mongo GridFS、Mongo GridFS、go-fastdfs、 火山引擎 TOS、Cloudflare R2、金山云 KS3、美团云 MSS、京东云 OSS、天翼云 OOS、移动 云EOS、沃云 OSS、 网易数帆 NOS、Ucloud US3、青云 QingStor、平安云 OBS、首云 OSS、IBM COS、其它兼容 S3 协议的存储平台。官网
使用阿里云为例
xml<!-- 引入本项目 -->
<dependency>
<groupId>org.dromara.x-file-storage</groupId>
<artifactId>x-file-storage-spring</artifactId>
<version>2.3.0</version>
</dependency>
<!-- 引入 阿里云 OSS SDK,如果使用其它存储平台,就引入对应的 SDK -->
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.16.1</version>
</dependency>
ymldromara:
x-file-storage: #文件存储配置
default-platform: aliyun-oss-1 #默认使用的存储平台
aliyun-oss:
- platform: aliyun-oss-1 # 存储平台标识
enable-storage: true # 启用存储
access-key: ??
secret-key: ??
end-point: ??
bucket-name: ??
domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/
base-path: test/ # 基础路径
java@EnableFileStorage
@SpringBootApplication
public class SpringFileStorageTestApplication {
public static void main(String[] args) {
SpringApplication.run(SpringFileStorageTestApplication.class,args);
}
}
java@RestController
public class FileDetailController {
@Autowired
private FileStorageService fileStorageService;//注入实列
/**
* 上传文件
*/
@PostMapping("/upload")
public FileInfo upload(MultipartFile file) {
//只需要这一行代码即可上传成功
return fileStorageService.of(file).upload();
}
/**
* 上传文件,成功返回文件 url
*/
@PostMapping("/upload2")
public String upload2(MultipartFile file) {
FileInfo fileInfo = fileStorageService.of(file)
.setPath("upload/") //保存到相对路径下,为了方便管理,不需要可以不写
.setSaveFilename("image.jpg") //设置保存的文件名,不需要可以不写,会随机生成
.setObjectId("0") //关联对象id,为了方便管理,不需要可以不写
.setObjectType("0") //关联对象类型,为了方便管理,不需要可以不写
.putAttr("role","admin") //保存一些属性,可以在切面、保存上传记录、自定义存储平台等地方获取使用,不需要可以不写
.upload(); //将文件上传到对应地方
return fileInfo == null ? "上传失败!" : fileInfo.getUrl();
}
/**
* 上传图片,成功返回文件信息
* 图片处理使用的是 https://github.com/coobird/thumbnailator
*/
@PostMapping("/upload-image")
public FileInfo uploadImage(MultipartFile file) {
return fileStorageService.of(file)
.image(img -> img.size(1000,1000)) //将图片大小调整到 1000*1000
.thumbnail(th -> th.size(200,200)) //再生成一张 200*200 的缩略图
.upload();
}
/**
* 上传文件到指定存储平台,成功返回文件信息
*/
@PostMapping("/upload-platform")
public FileInfo uploadPlatform(MultipartFile file) {
return fileStorageService.of(file)
.setPlatform("aliyun-oss-1") //使用指定的存储平台
.upload();
}
/**
* 直接读取 HttpServletRequest 中的文件进行上传,成功返回文件信息
* 使用这种方式有些注意事项,请查看文档 基础功能-上传 章节
*/
@PostMapping("/upload-request")
public FileInfo uploadPlatform(HttpServletRequest request) {
return fileStorageService.of(request).upload();
}
//还有监听上传进度,手动分片上传
}
java//通过 FileInfo 获取文件信息
RemoteFileInfo info = fileStorageService.getFile(fileInfo);
//通过 FileInfo 获取缩略图文件信息
RemoteFileInfo info2 = fileStorageService.getThFile(fileInfo);
//将结果转成 FileInfo 方便进行其它操作
FileInfo fileInfo2 = info.toFileInfo();
//将缩略图文件信息也 set 到 FileInfo 中
info2.toFileInfoTh(fileInfo2);
//自行传入 path 及 filename 获取文件信息
RemoteFileInfo info3 = fileStorageService.getFile().setPath("test/").setFilename("123.jpg").getFile();
Assert.notNull(info3, "文件不存在");
log.info("获取文件结果:{}", info3);
//文件元数据
MapProxy metadata = info3.getKebabCaseInsensitiveMetadata();
//文件用户元数据
MapProxy userMetadata = info3.getKebabCaseInsensitiveUserMetadata();
//获取原始文件信息,这里以阿里云为例
OSSObject ossObject = info3.getOriginalAliyunOssObject();
java//获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("https://file.abc.com/test/a.jpg");
//直接删除
fileStorageService.delete(fileInfo);
//条件删除
fileStorageService.delete(fileInfo,info -> {
//TODO 检查是否满足删除条件
return true;
});
//直接通过文件信息中的 url 删除,省去手动查询文件信息记录的过程
fileStorageService.delete("https://file.abc.com/test/a.jpg");
java//获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("https://file.abc.com/test/a.jpg");
//判断文件是否存在
boolean exists = fileStorageService.exists(fileInfo);
//直接通过文件信息中的 url 判断文件是否存在,省去手动查询文件信息记录的过程
boolean exists2 = fileStorageService.exists("https://file.abc.com/test/a.jpg");
****
java// 上传源文件
FileInfo fileInfo = fileStorageService.of(new File("D:\\Desktop\\a.png")).thumbnail().upload();
// 复制到 copy 这个路径下(同存储平台复制)
FileInfo destFileInfo = fileStorageService.copy(fileInfo)
.setPath("copy/")
.copy();
//复制到同路径下不同文件名(同存储平台复制)
FileInfo destFileInfo = fileStorageService.copy(fileInfo)
.setFilename("aaaCopy." + FileNameUtil.extName(fileInfo.getFilename()))
.setThFilename("aaaCopy.min." + FileNameUtil.extName(fileInfo.getThFilename()))
.copy();
//复制到其它存储平台(跨存储平台复制)
FileInfo destFileInfo = fileStorageService.copy(fileInfo)
.setPlatform("local-plus-1")
.setProgressListener((progressSize, allSize) ->
log.info("文件复制进度:{} {}%", progressSize, progressSize * 100 / allSize))
.copy();
//强制使用跨存储平台复制
FileInfo destFileInfo = fileStorageService.copy(fileInfo)
.setCopyMode(Constant.CopyMode.CROSS)
.setPath("copy/")
.copy();
//是否支持同存储平台复制
boolean supportSameCopy = fileStorageService.isSupportSameCopy("aliyun-oss-1");
java// 上传源文件
FileInfo fileInfo = fileStorageService.of(new File("D:\\Desktop\\a.png")).thumbnail().upload();
// 移动到 move 这个路径下(同存储平台移动)
FileInfo destFileInfo = fileStorageService.move(fileInfo)
.setPath("move/")
.move();
//移动到同路径下不同文件名(同存储平台移动)
FileInfo destFileInfo = fileStorageService.move(fileInfo)
.setFilename("aaaMove." + FileNameUtil.extName(fileInfo.getFilename()))
.setThFilename("aaaMove.min." + FileNameUtil.extName(fileInfo.getThFilename()))
.move();
//移动到其它存储平台(跨存储平台移动)
FileInfo destFileInfo = fileStorageService.move(fileInfo)
.setPlatform("local-plus-1")
.setProgressListener((progressSize, allSize) ->
log.info("文件移动进度:{} {}%", progressSize, progressSize * 100 / allSize))
.move();
//强制使用跨存储平台移动
FileInfo destFileInfo = fileStorageService.move(fileInfo)
.setMoveMode(Constant.MoveMode.CROSS)
.setPath("move/")
.move();
//是否支持同存储平台移动
boolean supportSameMove = fileStorageService.isSupportSameMove("aliyun-oss-1");
java// 获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("https://file.abc.com/test/a.jpg");
// 下载为字节数组
byte[] bytes = fileStorageService.download(fileInfo).bytes();
// 下载到文件
fileStorageService.download(fileInfo).file("C:\\a.jpg");
// 下载到 OutputStream 中
ByteArrayOutputStream out = new ByteArrayOutputStream();
fileStorageService.download(fileInfo).outputStream(out);
// 获取 InputStream 手动处理
fileStorageService.download(fileInfo).inputStream(in -> {
//TODO 读取 InputStream
});
// 直接通过文件信息中的 url 下载,省去手动查询文件信息记录的过程
fileStorageService.download("https://file.abc.com/test/a.jpg").file("C:\\a.jpg");
// 下载缩略图
fileStorageService.downloadTh(fileInfo).file("C:\\th.jpg");
java
@Slf4j
@SpringBootTest
class FileStorageServiceTransferTest {
@Autowired
private FileStorageService fileStorageService;
/**
* 从存储平台读取迁移
*/
@Test
public void transferByPlatform() {
// 源存储平台
String fromPlatform = "cos-1";
// 目标存储平台
String toPlatform = "oss-1";
// 要迁移的路径
String path = "";
// 开始迁移
transfer(fromPlatform, toPlatform, path);
}
/**
* 使用数据库迁移文件
*/
public void transfer(String fromPlatform, String toPlatform, String path) {
// 例举出当前路径下所有目录及文件
ListFilesResult result = fileStorageService
.listFiles()
.setPlatform(fromPlatform)
.setPath(path)
.listFiles();
// 递归迁移所有子目录
for (RemoteDirInfo dir : result.getDirList()) {
transfer(fromPlatform, toPlatform, path + dir.getName() + "/");
}
// 迁移当前路径下所有文件
for (RemoteFileInfo remoteFileInfo : result.getFileList()) {
// 转换成 FileInfo,注意 createTime 、metadata 及 userMetadata 可能需要自行处理,详情查看方法源码注释
// 同时每个存储平台的 ACL 也不一样,也需要自行处理
FileInfo fileInfo = remoteFileInfo.toFileInfo();
// 这里仅保留需要的 metadata ,例如:
Map<String, String> fromMetadata = new KebabCaseInsensitiveMap<>(fileInfo.getMetadata());
Map<String, String> toMetadata = new HashMap<>();
if (fromMetadata.containsKey(Constant.Metadata.CONTENT_TYPE)) {
toMetadata.put(Constant.Metadata.CONTENT_TYPE, fromMetadata.get(Constant.Metadata.CONTENT_TYPE));
}
if (fromMetadata.containsKey(Constant.Metadata.CONTENT_LENGTH)) {
toMetadata.put(Constant.Metadata.CONTENT_LENGTH, fromMetadata.get(Constant.Metadata.CONTENT_LENGTH));
}
if (fromMetadata.containsKey(Constant.Metadata.CONTENT_DISPOSITION)) {
toMetadata.put(
Constant.Metadata.CONTENT_DISPOSITION, fromMetadata.get(Constant.Metadata.CONTENT_DISPOSITION));
}
fileInfo.setMetadata(toMetadata);
// 使用复制文件,会保留旧文件,推荐
fileStorageService
.move(fileInfo)
.setPlatform(toPlatform)
.setNotSupportMetadataThrowException(true) // 不支持元数据时抛出异常
.setNotSupportAclThrowException(true) // 不支持 ACL 时抛出异常
.setProgressListener((progressSize, allSize) -> log.info(
"文件 {}/{} 迁移进度:{} {}%",
fileInfo.getPath(), fileInfo.getFilename(), progressSize, progressSize * 100 / allSize))
.move();
}
}
}
本文作者:Weee
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!