Spring File Storage的详细文档
快速入门
配置
pom.xml引入依赖
<dependencies><!-- spring-file-storage 必须要引入 --><dependency><groupId>cn.xuyanwu</groupId><artifactId>spring-file-storage</artifactId><version>0.7.0</version></dependency><!-- 华为云 OBS 不使用的情况下可以不引入 --><dependency><groupId>com.huaweicloud</groupId><artifactId>esdk-obs-java</artifactId><version>3.22.3.1</version></dependency><!-- 阿里云 OSS 不使用的情况下可以不引入 --><dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.15.1</version></dependency><!-- 七牛云 Kodo 不使用的情况下可以不引入 --><dependency><groupId>com.qiniu</groupId><artifactId>qiniu-java-sdk</artifactId><version>7.11.0</version></dependency><!-- 腾讯云 COS 不使用的情况下可以不引入 --><dependency><groupId>com.qcloud</groupId><artifactId>cos_api</artifactId><version>5.6.98</version></dependency><!-- 百度云 BOS 不使用的情况下可以不引入 --><dependency><groupId>com.baidubce</groupId><artifactId>bce-java-sdk</artifactId><version>0.10.218</version></dependency><!-- 又拍云 USS 不使用的情况下可以不引入 --><dependency><groupId>com.upyun</groupId><artifactId>java-sdk</artifactId><version>4.2.3</version></dependency><!-- MinIO 不使用的情况下可以不引入 --><dependency><groupId>io.minio</groupId><artifactId>minio</artifactId><version>8.4.3</version></dependency><!-- AWS S3 不使用的情况下可以不引入 --><dependency><groupId>com.amazonaws</groupId><artifactId>aws-java-sdk-s3</artifactId><version>1.12.272</version></dependency><!-- FTP 不使用的情况下可以不引入 --><dependency><groupId>commons-net</groupId><artifactId>commons-net</artifactId><version>3.8.0</version></dependency><!-- SFTP 不使用的情况下可以不引入 --><dependency><groupId>com.jcraft</groupId><artifactId>jsch</artifactId><version>0.1.55</version></dependency><!--糊涂工具类扩展,如果要使用 FTP、SFTP 则必须引入,否则不用引入--><dependency><groupId>cn.hutool</groupId><artifactId>hutool-extra</artifactId><version>5.8.5</version></dependency><!-- WebDAV 不使用的情况下可以不引入 --><dependency><groupId>com.github.lookfirst</groupId><artifactId>sardine</artifactId><version>5.10</version></dependency><!-- 谷歌云 Google Cloud Storage--><dependency><groupId>com.google.cloud</groupId><artifactId>google-cloud-storage</artifactId><version>2.14.0</version></dependency><!--因 guava 存在较多冲突版本导致谷歌云存储无法使用,故引入独立版本--><dependency><groupId>com.google.guava</groupId><artifactId>guava</artifactId><version>31.1-jre</version></dependency></dependencies>
application.yml配置文件中添加以下相关配置(不使用的平台可以不配置)
spring:file-storage: #文件存储配置default-platform: local-1 #默认使用的存储平台thumbnail-suffix: ".min.jpg" #缩略图后缀,例如【.min.jpg】【.png】local: # 本地存储(不推荐使用),不使用的情况下可以不写- platform: local-1 # 存储平台标识enable-storage: true #启用存储enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)domain: "" # 访问域名,例如:“http://127.0.0.1:8030/test/file/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名base-path: D:/Temp/test/ # 存储地址path-patterns: /test/file/** # 访问路径,开启 enable-access 后,通过此路径可以访问到上传的文件local-plus: # 本地存储升级版,不使用的情况下可以不写- platform: local-plus-1 # 存储平台标识enable-storage: true #启用存储enable-access: true #启用访问(线上请使用 Nginx 配置,效率更高)domain: "" # 访问域名,例如:“http://127.0.0.1:8030/”,注意后面要和 path-patterns 保持一致,“/”结尾,本地存储建议使用相对路径,方便后期更换域名base-path: local-plus/ # 基础路径path-patterns: /** # 访问路径storage-path: D:/Temp/ # 存储路径huawei-obs: # 华为云 OBS ,不使用的情况下可以不写- platform: huawei-obs-1 # 存储平台标识enable-storage: false # 启用存储access-key: ??secret-key: ??end-point: ??bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.obs.com/base-path: hy/ # 基础路径aliyun-oss: # 阿里云 OSS ,不使用的情况下可以不写- platform: aliyun-oss-1 # 存储平台标识enable-storage: false # 启用存储access-key: ??secret-key: ??end-point: ??bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.oss-cn-shanghai.aliyuncs.com/base-path: hy/ # 基础路径qiniu-kodo: # 七牛云 kodo ,不使用的情况下可以不写- platform: qiniu-kodo-1 # 存储平台标识enable-storage: false # 启用存储access-key: ??secret-key: ??bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.hn-bkt.clouddn.com/base-path: base/ # 基础路径tencent-cos: # 腾讯云 COS- platform: tencent-cos-1 # 存储平台标识enable-storage: true # 启用存储secret-id: ??secret-key: ??region: ?? #存仓库所在地域bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.cos.ap-nanjing.myqcloud.com/base-path: hy/ # 基础路径baidu-bos: # 百度云 BOS- platform: baidu-bos-1 # 存储平台标识enable-storage: true # 启用存储access-key: ??secret-key: ??end-point: ?? # 例如 abc.fsh.bcebos.combucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.fsh.bcebos.com/abc/base-path: hy/ # 基础路径upyun-uss: # 又拍云 USS- platform: upyun-uss-1 # 存储平台标识enable-storage: true # 启用存储username: ??password: ??bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:http://abc.test.upcdn.net/base-path: hy/ # 基础路径minio: # MinIO,由于 MinIO SDK 支持 AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里- platform: minio-1 # 存储平台标识enable-storage: true # 启用存储access-key: ??secret-key: ??end-point: ??bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:http://minio.abc.com/abc/base-path: hy/ # 基础路径aws-s3: # AWS S3,其它兼容 AWS S3 协议的存储平台也都可配置在这里- platform: aws-s3-1 # 存储平台标识enable-storage: true # 启用存储access-key: ??secret-key: ??region: ?? # 与 end-point 参数至少填一个end-point: ?? # 与 region 参数至少填一个bucket-name: ??domain: ?? # 访问域名,注意“/”结尾,例如:https://abc.hn-bkt.clouddn.com/base-path: s3/ # 基础路径ftp: # FTP- platform: ftp-1 # 存储平台标识enable-storage: true # 启用存储host: ?? # 主机,例如:192.168.1.105port: 21 # 端口,默认21user: anonymous # 用户名,默认 anonymous(匿名)password: "" # 密码,默认空domain: ?? # 访问域名,注意“/”结尾,例如:ftp://192.168.1.105/base-path: ftp/ # 基础路径storage-path: /www/wwwroot/file.abc.com/ # 存储路径,可以配合 Nginx 实现访问,注意“/”结尾,默认“/”sftp: # SFTP- platform: sftp-1 # 存储平台标识enable-storage: true # 启用存储host: ?? # 主机,例如:192.168.1.105port: 22 # 端口,默认22user: root # 用户名password: ?? # 密码或私钥密码private-key-path: ?? # 私钥路径,兼容Spring的ClassPath路径、文件路径、HTTP路径等,例如:classpath:id_rsa_2048domain: ?? # 访问域名,注意“/”结尾,例如:https://file.abc.com/base-path: sftp/ # 基础路径storage-path: /www/wwwroot/file.abc.com/ # 存储路径,可以配合 Nginx 实现访问,注意“/”结尾,默认“/”webdav: # WebDAV- platform: webdav-1 # 存储平台标识enable-storage: true # 启用存储server: ?? # 服务器地址,例如:http://192.168.1.105:8405/user: ?? # 用户名password: ?? # 密码domain: ?? # 访问域名,注意“/”结尾,例如:https://file.abc.com/base-path: webdav/ # 基础路径storage-path: / # 存储路径,可以配合 Nginx 实现访问,注意“/”结尾,默认“/”google-cloud: # 谷歌云存储- platform: google-1 # 存储平台标识enable-storage: true # 启用存储project-id: ?? # 项目 idbucket-name: ??credentials-path: file:/deploy/example-key.json # 授权 key json 路径,兼容Spring的ClassPath路径、文件路径、HTTP路径等domain: ?? # 访问域名,注意“/”结尾,例如:https://storage.googleapis.com/test-bucket/base-path: hy/ # 基础路径
注意配置每个平台前面都有个-号,通过以下方式可以配置多个
local:- platform: local-1 # 存储平台标识enable-storage: trueenable-access: truedomain: ""base-path: D:/Temp/test/path-patterns: /test/file/**- platform: local-2 # 存储平台标识,注意这里不能重复enable-storage: trueenable-access: truedomain: ""base-path: D:/Temp/test2/path-patterns: /test2/file/**
2、编码
在启动类上加上@EnableFileStorage注解
@EnableFileStorage
@SpringBootApplication
public class SpringFileStorageTestApplication {public static void main(String[] args) {SpringApplication.run(SpringFileStorageTestApplication.class, args);}}
3、开始使用
@RestController
public class FileDetailController {@Autowiredprivate FileStorageService fileStorageService;//注入实列/*** 上传文件,成功返回文件 url*/@PostMapping("/upload")public String upload(MultipartFile file) {FileInfo fileInfo = fileStorageService.of(file).setPath("upload/") //保存到相对路径下,为了方便管理,不需要可以不写.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();}
}
如果想使用删除、下载等功能,请阅读 保存上传记录 章节
基础功能
上传
多种上传方式
of方法有很多个重载方法,支持 File、MultipartFile、byte[]、InputStream、URL、URI、String
// 直接上传
fileStorageService.of(file).upload();// 如果要用 InputStream、URL、URI、String 等方式上传,暂时无法获取 originalFilename 属性,最好手动设置
fileStorageService.of(inputStream).setOriginalFilename("a.jpg").upload();// 上传到指定路径下
fileStorageService.of(file).setPath("upload/") // 保存到相对路径下,为了方便管理,不需要可以不写.upload();// 关联文件参数并上传
fileStorageService.of(file).setObjectId("0") // 关联对象id,为了方便管理,不需要可以不写.setObjectType("0") // 关联对象类型,为了方便管理,不需要可以不写.putAttr("role","admin") //保存一些属性,可以在切面、保存上传记录、自定义存储平台等地方获取使用,不需要可以不写.putAttr("username","007").upload();// 上传到指定的存储平台
fileStorageService.of(file).setPlatform("aliyun-oss-1") // 使用指定的存储平台.upload();// 对图片进行处理并上传,有多个重载方法。图片处理使用的是 https://github.com/coobird/thumbnailator
fileStorageService.of(file).setThumbnailSuffix(".jpg") //指定缩略图后缀,必须是 thumbnailator 支持的图片格式,默认使用全局的.setSaveThFilename("thabc") //指定缩略图的保存文件名,注意此文件名不含后缀,默认自动生成.image(img -> img.size(1000,1000)) // 将图片大小调整到 1000*1000.thumbnail(th -> th.size(200,200)) // 再生成一张 200*200 的缩略图.upload();// 其它更多方法以实际 API 为准
保存上传记录
如果还想使用除了保存文件之外的其它功能,例如删除、下载文件,还需要实现 FileRecorder 这个接口,把文件信息保存到数据库中。
/*** 用来将文件上传记录保存到数据库,这里使用了 MyBatis-Plus 和 Hutool 工具类*/
@Service
public class FileDetailService extends ServiceImpl<FileDetailMapper, FileDetail> implements FileRecorder {/*** 保存文件信息到数据库*/@SneakyThrows@Overridepublic boolean record(FileInfo info) {FileDetail detail = BeanUtil.copyProperties(info,FileDetail.class,"attr");//这是手动获 取附加属性字典 并转成 json 字符串,方便存储在数据库中if (info.getAttr() != null) {detail.setAttr(new ObjectMapper().writeValueAsString(info.getAttr()));}boolean b = save(detail);if (b) {info.setId(detail.getId());}return b;}/*** 根据 url 查询文件信息*/@SneakyThrows@Overridepublic FileInfo getByUrl(String url) {FileDetail detail = getOne(new QueryWrapper<FileDetail>().eq(FileDetail.COL_URL,url));FileInfo info = BeanUtil.copyProperties(detail,FileInfo.class,"attr");//这是手动获取数据库中的 json 字符串 并转成 附加属性字典,方便使用if (StrUtil.isNotBlank(detail.getAttr())) {info.setAttr(new ObjectMapper().readValue(detail.getAttr(),Dict.class));}return info;}/*** 根据 url 删除文件信息*/@Overridepublic boolean delete(String url) {return remove(new QueryWrapper<FileDetail>().eq(FileDetail.COL_URL,url));}
}
数据库表结构推荐如下,你也可以根据自己喜好在这里自己扩展
-- 这里使用的是 mysql
CREATE TABLE `file_detail`
(`id` varchar(32) NOT NULL COMMENT '文件id',`url` varchar(512) NOT NULL COMMENT '文件访问地址',`size` bigint(20) DEFAULT NULL COMMENT '文件大小,单位字节',`filename` varchar(256) DEFAULT NULL COMMENT '文件名称',`original_filename` varchar(256) DEFAULT NULL COMMENT '原始文件名',`base_path` varchar(256) DEFAULT NULL COMMENT '基础存储路径',`path` varchar(256) DEFAULT NULL COMMENT '存储路径',`ext` varchar(32) DEFAULT NULL COMMENT '文件扩展名',`content_type` varchar(32) DEFAULT NULL COMMENT 'MIME类型',`platform` varchar(32) DEFAULT NULL COMMENT '存储平台',`th_url` varchar(512) DEFAULT NULL COMMENT '缩略图访问路径',`th_filename` varchar(256) DEFAULT NULL COMMENT '缩略图名称',`th_size` bigint(20) DEFAULT NULL COMMENT '缩略图大小,单位字节',`th_content_type` varchar(32) DEFAULT NULL COMMENT '缩略图MIME类型',`object_id` varchar(32) DEFAULT NULL COMMENT '文件所属对象id',`object_type` varchar(32) DEFAULT NULL COMMENT '文件所属对象类型,例如用户头像,评价图片',`attr` text COMMENT '附加属性',`create_time` datetime DEFAULT NULL COMMENT '创建时间',PRIMARY KEY (`id`) USING BTREE
) ENGINE = InnoDBDEFAULT CHARSET = utf8ROW_FORMAT = DYNAMIC COMMENT ='文件记录表';
下载
多种下载方式
// 获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("http://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("http://file.abc.com/test/a.jpg").file("C:\\a.jpg");// 下载缩略图
fileStorageService.downloadTh(fileInfo).file("C:\\th.jpg");
监听下载进度
// 方式一
fileStorageService.download(fileInfo).setProgressMonitor(progressSize ->System.out.println("已下载:" + progressSize)
).file("C:\\a.jpg");// 方式二
fileStorageService.download(fileInfo).setProgressMonitor((progressSize,allSize) ->System.out.println("已下载 " + progressSize + " 总大小" + allSize)
).file("C:\\a.jpg");// 方式三
fileStorageService.download(fileInfo).setProgressMonitor(new ProgressListener() {@Overridepublic void start() {System.out.println("下载开始");}@Overridepublic void progress(long progressSize,long allSize) {System.out.println("已下载 " + progressSize + " 总大小" + allSize);}@Overridepublic void finish() {System.out.println("下载结束");}
}).file("C:\\a.jpg");
删除
//获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("http://file.abc.com/test/a.jpg");//直接删除
fileStorageService.delete(fileInfo);//条件删除
fileStorageService.delete(fileInfo,info -> {//TODO 检查是否满足删除条件return true;
});//直接通过文件信息中的 url 删除,省去手动查询文件信息记录的过程
fileStorageService.delete("http://file.abc.com/test/a.jpg");
判断文件是否存在
//获取文件信息
FileInfo fileInfo = fileStorageService.getFileInfoByUrl("http://file.abc.com/test/a.jpg");//判断文件是否存在
boolean exists = fileStorageService.exists(fileInfo);//直接通过文件信息中的 url 判断文件是否存在,省去手动查询文件信息记录的过程
boolean exists2 = fileStorageService.exists("http://file.abc.com/test/a.jpg");
存储平台
目前支持多种存储平台,你也可以根据需要自行扩展
支持的存储平台
平台 | 支持 |
本地 | √ |
FTP | √ |
SFTP | √ |
WebDAV | √ |
平台 | 官方 SDK | AWS S3 SDK | S3 兼容说明 |
AWS S3 | √ | √ | - |
MinIO | √ | √ | 查看 |
阿里云 OSS | √ | √ | 查看 |
华为云 OBS | √ | √ | 查看 |
七牛云 Kodo | √ | √ | 查看 |
腾讯云 COS | √ | √ | 查看 |
百度云 BOS | √ | √ | 查看 |
又拍云 USS | √ | × | - |
金山云 KS3 | × | √ | 查看 |
美团云 MSS | × | √ | 查看 |
京东云 OSS | × | √ | 查看 |
天翼云 OOS | × | √ | 查看 |
移动云 EOS | × | √ | 查看 |
沃云 OSS | × | √ | 查看 |
网易数帆 NOS | × | √ | 查看 |
Ucloud US3 | × | √ | 查看 |
青云 QingStor | × | √ | 查看 |
平安云 OBS | × | √ | 查看 |
首云 OSS | × | √ | 查看 |
IBM COS | × | √ | 查看 |
谷歌云存储 | √ | × | - |
其它兼容 S3 协议的平台 | × | √ | - |
自定义存储平台
想要自定义存储平台就要实现 FileStorage 这个接口,并进行实例化,注意返回的 bean 是个 list
这里拿 LocalFileStorage 举例
/*** 实现 FileStorage 接口,这里使用了 Lombok 和 Hutool 工具类*/
@Getter
@Setter
public class LocalFileStorage implements FileStorage {/* 本地存储路径*/private String basePath;/* 存储平台 */private String platform;/* 访问域名 */private String domain;/*** 释放资源*/@Overridepublic void close() {}/*** 保存文件*/@Overridepublic boolean save(FileInfo fileInfo,UploadPretreatment pre) {String path = fileInfo.getPath();File newFile = FileUtil.touch(basePath + path,fileInfo.getFilename());fileInfo.setBasePath(basePath);fileInfo.setUrl(domain + path + fileInfo.getFilename());try {pre.getFileWrapper().transferTo(newFile);byte[] thumbnailBytes = pre.getThumbnailBytes();if (thumbnailBytes != null) { //上传缩略图fileInfo.setThUrl(fileInfo.getUrl() + pre.getThumbnailSuffix());FileUtil.writeBytes(thumbnailBytes,newFile.getPath() + pre.getThumbnailSuffix());}return true;} catch (IOException e) {FileUtil.del(newFile);throw new FileStorageRuntimeException("文件上传失败!platform:" + platform + ",filename:" + fileInfo.getOriginalFilename(),e);}}/*** 删除文件*/@Overridepublic boolean delete(FileInfo fileInfo) {if (fileInfo.getThFilename() != null) { //删除缩略图FileUtil.del(new File(fileInfo.getBasePath() + fileInfo.getPath(),fileInfo.getThFilename()));}return FileUtil.del(new File(fileInfo.getBasePath() + fileInfo.getPath(),fileInfo.getFilename()));}/*** 文件是否存在*/@Overridepublic boolean exists(FileInfo fileInfo) {return new File(fileInfo.getBasePath() + fileInfo.getPath(),fileInfo.getFilename()).exists();}/*** 下载文件*/@Overridepublic void download(FileInfo fileInfo,Consumer<InputStream> consumer) {try (InputStream in = FileUtil.getInputStream(fileInfo.getBasePath() + fileInfo.getPath() + fileInfo.getFilename())) {consumer.accept(in);} catch (IOException e) {throw new FileStorageRuntimeException("文件下载失败!platform:" + fileInfo,e);}}/*** 下载缩略图文件*/@Overridepublic void downloadTh(FileInfo fileInfo,Consumer<InputStream> consumer) {if (StrUtil.isBlank(fileInfo.getThFilename())) {throw new FileStorageRuntimeException("缩略图文件下载失败,文件不存在!fileInfo:" + fileInfo);}try (InputStream in = FileUtil.getInputStream(fileInfo.getBasePath() + fileInfo.getPath() + fileInfo.getThFilename())) {consumer.accept(in);} catch (IOException e) {throw new FileStorageRuntimeException("缩略图文件下载失败!fileInfo:" + fileInfo,e);}}
}/*** 初始化*/
@Configuration
public class LocalFileStorageAutoConfiguration {/*** 这里拿本地存储做个演示,注意返回的是个List*/@Beanpublic List<LocalFileStorage> localFileStorageList() {ArrayList<LocalFileStorage> list = new ArrayList<>();LocalFileStorage localFileStorage = new LocalFileStorage();localFileStorage.setPlatform("my-local-1");//平台名称localFileStorage.setBasePath("");localFileStorage.setDomain("");list.add(localFileStorage);return list;}
}
动态增减存储平台
//获得存储平台 List
CopyOnWriteArrayList<FileStorage> list = fileStorageService.getFileStorageList();//增加
LocalFileStorage storage = new LocalFileStorage();
storage.setPlatform("my-local-1");//平台名称
storage.setBasePath("");
storage.setDomain("");
list.add(storage);//删除
FileStorage myLocal = fileStorageService.getFileStorage("my-local-1");
list.remove(myLocal);
myLocal.close();//释放资源
获取对应存储平台
AliyunOssFileStorage storage = (AliyunOssFileStorage) fileStorageService.getFileStorage("aliyun-oss-1");
OSS client = storage.getClient();
//获取到对应SDK的原生客户端对象,可以进行更多高级操作
切面
通过切面,可以对文件的上传和删除等进行干预
自定义切面
只需要实现FileStorageAspect接口
不需要的方法可以不用实现,此接口里的方法全部都有默认实现
/*** 使用切面打印文件上传和删除的日志*/
@Slf4j
@Component
public class LogFileStorageAspect implements FileStorageAspect {/*** 上传,成功返回文件信息,失败返回 null*/@Overridepublic FileInfo uploadAround(UploadAspectChain chain,FileInfo fileInfo,UploadPretreatment pre,FileStorage fileStorage,FileRecorder fileRecorder) {log.info("上传文件 before -> {}",fileInfo);fileInfo = chain.next(fileInfo,pre,fileStorage,fileRecorder);log.info("上传文件 after -> {}",fileInfo);return fileInfo;}/*** 删除文件,成功返回 true*/@Overridepublic boolean deleteAround(DeleteAspectChain chain,FileInfo fileInfo,FileStorage fileStorage,FileRecorder fileRecorder) {log.info("删除文件 before -> {}",fileInfo);boolean res = chain.next(fileInfo,fileStorage,fileRecorder);log.info("删除文件 after -> {}",res);return res;}/*** 文件是否存在*/@Overridepublic boolean existsAround(ExistsAspectChain chain,FileInfo fileInfo,FileStorage fileStorage) {log.info("文件是否存在 before -> {}",fileInfo);boolean res = chain.next(fileInfo,fileStorage);log.info("文件是否存在 after -> {}",res);return res;}/*** 下载文件*/@Overridepublic void downloadAround(DownloadAspectChain chain,FileInfo fileInfo,FileStorage fileStorage,Consumer<InputStream> consumer) {log.info("下载文件 before -> {}",fileInfo);chain.next(fileInfo,fileStorage,consumer);log.info("下载文件 after -> {}",fileInfo);}/*** 下载缩略图文件*/@Overridepublic void downloadThAround(DownloadThAspectChain chain,FileInfo fileInfo,FileStorage fileStorage,Consumer<InputStream> consumer) {log.info("下载缩略图文件 before -> {}",fileInfo);chain.next(fileInfo,fileStorage,consumer);log.info("下载缩略图文件 after -> {}",fileInfo);}
}
动态增减切面
//获得切面 List
CopyOnWriteArrayList<FileStorageAspect> list = fileStorageService.getAspectList();//增加
FileStorageAspect aspect = new LogFileStorageAspect();
list.add(aspect);//删除
list.remove(aspect);//条件删除
list.removeIf(item -> item instanceof LogFileStorageAspect);
常见问题
为什么我在application.yml 中已经添加对应的存储平台配置,上传时却提示我“没有找到对应的存储平台!”
检查pom.xml,是否引入对应平台的依赖,例如阿里云
<!-- 阿里云 OSS 不使用的情况下可以不引入 -->
<dependency><groupId>com.aliyun.oss</groupId><artifactId>aliyun-sdk-oss</artifactId><version>3.6.0</version>
</dependency>
如何根据数据库配置加载存储平台?
参考 动态增减存储平台
如何自定义缩略图后缀?
参考 多种上传方式 中的缩略图上传方式,可以自己调整缩略图后缀