Compare commits

..

237 Commits
0.2.1 ... 2.7

Author SHA1 Message Date
zhaojun1998
4585f22817 🔖 发布 2.7 版 2020-05-24 15:46:10 +08:00
zhaojun1998
b523453588 💄 更新页面 2020-05-24 15:45:38 +08:00
zhaojun1998
a8cc03c911 🔨 优化代码 2020-05-24 15:45:25 +08:00
zhaojun1998
949c437653 新增缓存管理功能, 支持手动/自动刷新缓存, 查看、清理缓存。 2020-05-24 15:41:33 +08:00
zhaojun1998
84e9cce60f 🔖 发布 2.6 版 2020-05-13 21:52:46 +08:00
zhaojun1998
5720bd93ec 💄 更新页面 2020-05-13 21:51:52 +08:00
zhaojun1998
bcae9713bc 🐛 修复自定义 JS, CSS 超出数据库长度无法保存的 BUG. 2020-05-13 21:51:27 +08:00
zhaojun1998
04e3023071 🔖 发布 2.5 版 2020-05-04 21:00:33 +08:00
zhaojun1998
a09ef84629 💄 更新页面 2020-05-04 21:00:13 +08:00
zhaojun1998
1d29395191 🐛 修复 OneDrive 某些情况下 Access Token 过长, 因超出数据库长度无法保存的 BUG. 2020-05-04 20:59:48 +08:00
zhaojun1998
3720dc6aa9 🔖 发布 2.4 版 2020-04-20 22:40:06 +08:00
zhaojun1998
3ada172be2 💄 更新页面 2020-04-20 22:39:42 +08:00
zhaojun1998
15f8fbb49b 🐛 修复阿里云腾讯云私有空间时, 密码文件无法加载的 BUG 2020-04-20 22:37:12 +08:00
zhaojun1998
547e688d38 🏗️ 增强系统校验 2020-04-20 21:58:32 +08:00
zhaojun1998
708eb33d0e 🐛 修复多盘中是否多个 OneDrive 导致无法正常加载的 BUG 2020-04-20 21:57:25 +08:00
zhaojun1998
e954b725b1 📝 更新文档 2020-04-19 15:26:04 +08:00
zhaojun1998
c89cb4e495 📝 更新文档 2020-04-19 15:24:36 +08:00
zhaojun1998
286e9775f6 🔧 更新配置文件, 升级后切换默认数据库路径 2020-04-19 14:35:53 +08:00
zhaojun1998
60513abe6a 💄 更新页面, 删除缓存管理模块 2020-04-19 14:35:21 +08:00
zhaojun1998
f7a8c9faa2 🔖 发布 2.3 版 2020-04-19 12:14:27 +08:00
zhaojun1998
55e0d32ef8 🏗️ 架构调整, 支持多个驱动器. 2020-04-19 12:13:12 +08:00
zhaojun1998
4c0bacba31 🔨 重构代码, 将每个存储策略的表单设置改为 Java 配置 2020-04-04 19:57:09 +08:00
zhaojun1998
61128f2677 🎨 移除无用代码 2020-04-04 15:58:33 +08:00
zhaojun1998
3866526b95 📝 补充注释 2020-04-04 15:57:22 +08:00
zhaojun1998
250955fac9 📝 更新文档 2020-04-04 09:50:06 +08:00
zhaojun1998
3249266cd1 🔖 发布 2.2 版 2020-03-08 11:48:48 +08:00
zhaojun1998
1a6235df73 🔨 重构代码, 去除无效引用。 2020-03-08 11:46:31 +08:00
zhaojun1998
430aee2b7f 🔨 重构代码, 去除无效引用。 2020-03-08 11:43:42 +08:00
zhaojun1998
de2f7e4b80 🔨 重构代码, 优化目录结构 2020-03-08 11:11:12 +08:00
zhaojun1998
6dfcc409ac 更新页面 2020-03-08 11:07:01 +08:00
zhaojun1998
78f795e1cb 🔖 发布 2.1 版 2020-03-07 18:39:33 +08:00
zhaojun1998
c69ee0f356 🐛 修复 S3 协议对象存储, 在私有空间下, 无法下载的 BUG. 2020-03-07 13:10:42 +08:00
zhaojun1998
39475de789 🐛 修复 S3 协议对象存储, 在私有空间下, 无法下载的 BUG. 2020-03-07 13:10:21 +08:00
zhaojun1998
bd71712765 🐛 修复无法刷新单个缓存的 BUG 2020-03-07 13:08:42 +08:00
赵俊
8698686a47 Update application.yml 2020-03-01 14:04:14 +08:00
zhaojun1998
762c67ee37 更新文档 2020-02-29 16:04:19 +08:00
zhaojun1998
7bf3a29c17 🔖 发布 2.0 版 2020-02-29 15:48:57 +08:00
zhaojun1998
6ee5002f0c 🔒 修复任意用户名均可登陆后台的安全问题. 2020-02-29 15:47:24 +08:00
zhaojun1998
fadc64add4 💄 更新页面, 修复滚动分页 BUG. 2020-02-29 15:46:56 +08:00
zhaojun1998
234f43846f 优化分页功能 2020-02-29 15:45:34 +08:00
zhaojun1998
67e42d9753 🐛 修复 OneDrive 获取文档区或文件夹密码时, 链接超时导致异常的 BUG. 2020-02-29 15:45:11 +08:00
zhaojun1998
04f94b4bf5 🏗️ 缓存架构调整, 增强稳定性 2020-02-29 15:43:56 +08:00
zhaojun1998
d29c498457 更新配置自描述文件 2020-02-27 23:01:38 +08:00
zhaojun1998
5aa45b44b2 🔖 发布 1.9 版 2020-02-26 21:18:55 +08:00
zhaojun1998
8273a645f2 📝 更新文档 2020-02-26 21:16:49 +08:00
zhaojun1998
46f292cc9b 🔧 更新配置文件, 增加是否开启缓存自动刷新控制 2020-02-26 21:15:45 +08:00
zhaojun1998
261d48059e 增强 FTP 功能, 提高稳定性 2020-02-26 21:14:26 +08:00
zhaojun1998
79f931c51b 增强 OneDrive 调用, 如调用失败, 尝试重新获取 token 后, 再次请求. 2020-02-26 21:14:07 +08:00
zhaojun1998
399e961a65 🏗️ 缓存架构调整, 改为自实现缓存, 移除第三方依赖. 2020-02-26 21:13:08 +08:00
zhaojun1998
3e61d7d146 增加 UFILE 支持 2020-02-26 21:09:42 +08:00
zhaojun1998
ace95d9071 💄 更新页面 2020-02-26 21:09:02 +08:00
zhaojun1998
60d2a2b986 添加 github issue template 2020-02-23 12:07:16 +08:00
zhaojun1998
69d5661e06 添加 github issue template 2020-02-23 12:06:28 +08:00
zhaojun1998
01d11dfc23 移除无用依赖 2020-02-22 15:23:39 +08:00
zhaojun1998
d35e3ecd93 🔖 发布 1.8 版 2020-02-22 15:21:39 +08:00
zhaojun1998
9e5a3e5385 💄 更新页面 2020-02-22 15:18:15 +08:00
zhaojun1998
b62163b4e8 ⬆️ 升级 hutool 依赖版本 2020-02-22 15:16:39 +08:00
zhaojun1998
595a00f067 🐛 修复 FTP 加载 BUG 2020-02-22 15:16:11 +08:00
zhaojun1998
a759d9fe44 增加系统监控及日志下载功能 2020-02-22 12:53:35 +08:00
zhaojun1998
7a24fd10e0 ✏️ 修复拼写错误 2020-02-22 09:35:51 +08:00
zhaojun1998
7e04a817d7 🔖 发布 1.7 版 2020-02-19 21:45:48 +08:00
zhaojun1998
791967f45e 💄 更新页面 2020-02-19 21:43:17 +08:00
zhaojun1998
d789436a16 ✏️ 修复拼写错误 2020-02-19 21:23:09 +08:00
zhaojun1998
96ab8ff7dd 🔖 发布 1.6 版 2020-02-18 21:10:25 +08:00
zhaojun1998
8809aca170 📝 更新页面 2020-02-18 21:08:53 +08:00
zhaojun1998
97106383b6 🐛 修复使用本地存储时, 文件名中包含 + 引发的无法下载的 BUG. 2020-02-18 20:10:20 +08:00
zhaojun1998
208da95234 🐛 修复不同操作系统, 可能出现的编码问题, 导致导入的数据库文件乱码. 2020-02-18 20:09:32 +08:00
zhaojun1998
d4c843f5f5 🐛 修复 OneDrive 文件夹中包含 + 号, 且文件夹中的内容大于 200 个时, 请求出错的 BUG. 2020-02-18 20:02:37 +08:00
zhaojun1998
d273fc9f12 📝 更新文档 2020-02-15 18:39:56 +08:00
zhaojun1998
0b4a38218c 🔖 发布 1.5 版 2020-02-15 18:25:41 +08:00
zhaojun1998
2f57c5b5cc 新增功能: 自定义表格大小, 显示操作按钮, 显示文档, 公告信息 2020-02-15 18:22:37 +08:00
zhaojun1998
610f68295f 📝 更新页面 2020-02-15 18:22:01 +08:00
zhaojun1998
39ced8eb84 📝 更新页面 2020-02-15 18:05:43 +08:00
zhaojun1998
368b7a1df2 优化排序方式为自然排序 2020-02-14 20:22:22 +08:00
zhaojun1998
8e2107cd46 📝 更新开发计划 2020-02-11 18:27:34 +08:00
zhaojun1998
fa32a33371 📝 更新页面 2020-02-09 21:49:27 +08:00
zhaojun1998
59116a9414 🔖 发布 1.4.1 版 2020-02-09 21:47:27 +08:00
zhaojun1998
b2c732a389 🐛 修复 URL 中包含特殊字符, 返回 400 错误的 BUG. 2020-02-09 21:35:25 +08:00
zhaojun1998
0e1ffef92b 🔖 发布 1.4 版 2020-02-09 18:06:50 +08:00
zhaojun1998
a5b19d3577 新增获取直链下载功能. 2020-02-09 18:06:42 +08:00
zhaojun1998
185c84dd79 新增获取直链下载功能. 2020-02-09 18:05:56 +08:00
zhaojun1998
d554dd298c 优化 OneDrive 相关代码结构. 2020-02-09 18:05:01 +08:00
zhaojun1998
aa6ecf0aaa 优化 OneDrive 相关代码结构. 2020-02-09 18:04:33 +08:00
zhaojun1998
83692718e3 📝 更新页面 2020-02-09 18:01:57 +08:00
zhaojun1998
030bd95941 🔖 发布 1.3 版 2020-02-08 17:47:37 +08:00
zhaojun1998
8722d11ac3 📝 更新页面 2020-02-08 17:46:33 +08:00
zhaojun1998
0131ff02c0 🐛 修复头部文件和密码文件, 在开启缓存的状态下, 仅第一次生效的 BUG. 2020-02-08 17:43:02 +08:00
zhaojun1998
2d115bf1c6 更改本地存储, 文件下载时, 文件不存在的响应状态码为 404. 2020-02-08 17:14:01 +08:00
zhaojun1998
946113216d 🔖 发布 1.2.1 版 2020-02-03 20:57:07 +08:00
zhaojun1998
77b05c6dac 🐛 修复 OneDrive 的 Token 某些情况下, 可能超出 2000 字符的 BUG 2020-02-03 20:52:49 +08:00
zhaojun1998
07c9fca210 🔖 发布 1.2 版 2020-02-01 21:54:32 +08:00
zhaojun1998
27cf61693a 更新前端页面, 修复搜索模式下无法进入文件夹和滚动加载的 BUG 2020-02-01 21:54:20 +08:00
zhaojun1998
37e1aa1fec 🐛 修复 OneDrive 文件夹包含特殊符号时, 获取下一页数据 URL 中重复进行了 URL 编码的 BUG. 2020-02-01 21:51:15 +08:00
zhaojun1998
31b54a3c05 调整 OneDrive Token 自动刷新时间为 15 分钟. 2020-02-01 21:50:08 +08:00
zhaojun1998
589f07c103 🔖 发布 1.1 版 2020-01-31 11:52:27 +08:00
zhaojun1998
fe8b60d873 调整日志级别 2020-01-31 11:52:21 +08:00
zhaojun1998
1734619eac 📝 更新页面 2020-01-31 11:50:55 +08:00
zhaojun1998
f5724dc9ab OneDrive 基础路径支持 2020-01-31 11:21:36 +08:00
zhaojun1998
f7bb147b71 📝 更新文档 2020-01-30 19:31:50 +08:00
zhaojun1998
47fc1bc2df 🔖 发布 1.0 版 2020-01-30 18:06:09 +08:00
zhaojun1998
45172f69ba 📝 更新文档 2020-01-30 18:05:56 +08:00
zhaojun1998
9566b138ff 📝 更新页面 2020-01-30 17:58:26 +08:00
zhaojun1998
e15b6c2242 更新配置文件, 增加 h2 console, 便与调试. 2020-01-30 16:52:20 +08:00
zhaojun1998
acc41511e0 S3 协议新增是否为私有空间支持 2020-01-30 16:51:05 +08:00
zhaojun1998
b882b87405 数据库文件初始化更新, 新增 S3 通用协议支持 2020-01-30 16:50:37 +08:00
zhaojun1998
518b5170ae 优化代码 2020-01-30 16:48:37 +08:00
zhaojun1998
8bfac6d9ac 新增 S3 协议通用支持 2020-01-30 16:47:58 +08:00
zhaojun1998
3ffdb4f1b2 清洁代码 2020-01-30 16:47:03 +08:00
zhaojun1998
47509450a0 📝 更新文档, 修改 Debian/Ubuntu 安装命令. 2020-01-29 18:47:38 +08:00
zhaojun1998
812fd18aac 🐛 修复 OneDrive 世纪互联版自动刷新 REFRESH_TOKEN 失败的 BUG 2020-01-29 16:24:00 +08:00
zhaojun1998
77a13cf8ad 📝 更新文档, 新增预览图片 2020-01-29 13:56:20 +08:00
zhaojun1998
4c914793b0 📝 更新文档 2020-01-29 13:43:19 +08:00
zhaojun1998
5698cfb2d3 🔖 发布 0.9 版 2020-01-29 13:41:42 +08:00
zhaojun1998
3cd5f8f9a7 调整显示顺序 2020-01-29 12:58:03 +08:00
zhaojun1998
76747771de OneDrive 世纪互联支持 2020-01-29 12:53:38 +08:00
zhaojun1998
cfacd39210 优化代码, 增强健壮性 2020-01-29 12:52:07 +08:00
zhaojun1998
90cd13f2c3 🔖 发布 0.8 版 2020-01-28 15:19:04 +08:00
zhaojun1998
018a68246e 💄 更新页面 2020-01-28 15:16:27 +08:00
zhaojun1998
b6a2e3ccb8 添加获取指定路径文件信息的 API 2020-01-28 14:55:06 +08:00
zhaojun1998
38b811f8e6 🐛 新增 '搜索包含加密文件' 支持. 2020-01-28 13:25:28 +08:00
zhaojun1998
6922fa2195 添加自定义 JS, CSS 支持 2020-01-28 13:14:23 +08:00
zhaojun1998
4bca6cf7a5 移除尾部说明文件支持 2020-01-28 13:13:52 +08:00
zhaojun1998
c3484426ab 🐛 修复 OneDrive 教育版和部分国际版无法正常获取文件的 BUG 2020-01-28 10:18:36 +08:00
zhaojun1998
0455bd366c 🔖 发布 0.7.1 版 2020-01-26 13:42:19 +08:00
zhaojun1998
bbe3c053f8 OneDrive 回调页面友好提示 2020-01-26 13:41:15 +08:00
zhaojun1998
f47708f45d Merge remote-tracking branch 'origin/master' 2020-01-26 13:38:24 +08:00
zhaojun1998
2e7a7b8cec 🐛 修复文件夹包含特殊字符编码 BUG 2020-01-26 13:35:50 +08:00
zhaojun1998
9e067dbce9 🐛 修复国际版 OneDrive, 无法获取子目录的 BUG 2020-01-26 13:35:27 +08:00
zhaojun1998
a4a236e488 🐛 修复 OneDrive 列目录, 文件数超出 200 个无法显示的 BUG. 2020-01-26 13:21:49 +08:00
赵俊
7d5b0431f5 Update README.md 2020-01-25 18:10:22 +08:00
zhaojun1998
a758c8cc6d 📝 更新文档 2020-01-25 18:06:13 +08:00
zhaojun1998
21a64ec0f3 🐛 修复循环依赖 BUG 2020-01-25 18:00:38 +08:00
zhaojun1998
3f241d129a 📝 更新文档 2020-01-25 18:00:14 +08:00
zhaojun1998
fa5f16c61f 🔖 发布 0.7 版 2020-01-24 19:00:56 +08:00
zhaojun1998
492b22506d 🐛 修复切换存储策略时没有重新缓存的 BUG 2020-01-24 18:51:20 +08:00
zhaojun1998
a12f685340 🐛 修复 FTP 初始化显示错误 2020-01-24 18:44:59 +08:00
zhaojun1998
2ee3f3dd66 💄 更新页面 2020-01-24 18:39:20 +08:00
zhaojun1998
245937e773 搜索忽略大小写支持 2020-01-24 18:37:58 +08:00
zhaojun1998
aef34facbd 🐛 修复更改系统设置时, 误清理缓存的 BUG 2020-01-24 18:37:32 +08:00
zhaojun1998
14bb5e15e3 替换 onedrive 授权重定向地址, 配置文件添加元数据描述 2020-01-24 17:40:01 +08:00
zhaojun1998
12371f06dd 🐛 修复 S3 协议中, 某些情况下出现了空文件名的 BUG 2020-01-24 17:28:48 +08:00
zhaojun1998
28e43e968f 添加分页, 修复本地存储下载错误 2020-01-24 17:27:12 +08:00
zhaojun1998
669b413ff0 优化存储策略功能, 添加是否初始化成功标识 2020-01-24 17:13:49 +08:00
zhaojun1998
f32e5e8f9e 🐛 修复切换存储引擎时, 没有清空原引擎缓存的 BUG. 2020-01-24 10:46:00 +08:00
zhaojun1998
3719378614 ✏️ 修复拼写错误 2020-01-24 10:28:21 +08:00
zhaojun1998
40c759078e 🐛 MINIO 修改 URL 路径风格指定为 path-style, 防止配置域名情况下, 找不到域名的 BUG. 2020-01-24 10:27:53 +08:00
zhaojun1998
e37e778e1a 优化日志输出 2020-01-23 10:53:16 +08:00
zhaojun1998
031607402a 本地存储, 文件不存在时, 给与友好提示 2020-01-20 22:48:04 +08:00
zhaojun1998
6c9150466c 优化日志配置 2020-01-20 21:36:58 +08:00
zhaojun1998
be633ebe1a OneDrive 支持 2020-01-20 21:36:13 +08:00
zhaojun1998
9715cf922a 优化日志输出 2020-01-20 21:35:41 +08:00
zhaojun1998
f6163c7e19 优化代码结构 2020-01-20 21:35:20 +08:00
zhaojun1998
dcc4cb19ad OneDrive 支持 2020-01-19 21:58:02 +08:00
zhaojun1998
ad0ad12c08 搜索功能支持分页 2020-01-18 22:57:29 +08:00
zhaojun1998
74c935cdf0 抽取通用代码 2020-01-17 23:28:23 +08:00
zhaojun1998
1876e692f2 💄 更改默认排序器 2020-01-16 22:24:46 +08:00
zhaojun1998
f198b34324 🔖 升级版本为 0.6 2020-01-12 11:18:50 +08:00
zhaojun1998
3095e0c8d9 💄 更新页面, 优化缓存页面展示 2020-01-12 11:15:01 +08:00
zhaojun1998
594246127d 🐛 修复更改策略时, 未正确启用和关闭缓存的 BUG 2020-01-12 11:14:20 +08:00
zhaojun1998
f6c5f7a91b 🔧 修改配置配置文件, 将日志改为单独配置 2020-01-12 11:13:02 +08:00
zhaojun1998
2a765fff7e 🐛 获取缓存是否开启时的 NPE 问题 2020-01-11 23:20:12 +08:00
zhaojun1998
28f958878b 🔊 更新日志级别 2020-01-11 23:02:19 +08:00
zhaojun1998
368f3a90eb 移除无用依赖 2020-01-11 22:53:19 +08:00
zhaojun1998
98b14abbfc 🔧 修改配置文件, 去除默认缓存时间. 2020-01-11 22:49:55 +08:00
zhaojun1998
7c04c3d6b8 优化代码结构 2020-01-11 22:48:28 +08:00
zhaojun1998
921cb1a115 通过反射优化代码 2020-01-08 22:34:15 +08:00
zhaojun1998
9371968c3b 增强根据 value 获取枚举的功能 2020-01-08 22:33:30 +08:00
zhaojun1998
47e88849ac 🐛 修复当前存储引擎为空时, 与新设置的存储引擎比较出现的 NPE 2020-01-08 22:32:47 +08:00
zhaojun1998
2f0f41f413 去除无效输出 2020-01-08 21:31:24 +08:00
zhaojun1998
7667765abc 🐛 修复本地存储的文件名, 包含 &?=[] 等特殊字符时出现的问题 2020-01-08 21:28:05 +08:00
zhaojun1998
b2a2e69af5 🔒 关闭 URL 部分校验, 允许中文文件名 2020-01-08 21:22:03 +08:00
zhaojun1998
7c729a72e2 🐛 本地存储, 获取文件不存在返回状态码 404 2020-01-07 22:57:59 +08:00
zhaojun1998
5495abc881 更新未知歌曲默认封面 2020-01-06 23:00:07 +08:00
zhaojun1998
797cd4fc06 💄 更新页面 2020-01-05 16:11:02 +08:00
zhaojun1998
8148d182cf 更新缓存策略刷新时间 2020-01-05 16:01:50 +08:00
zhaojun1998
7e8cab90d0 🔖 升级版本为 0.5 2020-01-05 15:58:46 +08:00
zhaojun1998
4d5743dc0b 💄 更新页面 2020-01-05 15:56:51 +08:00
zhaojun1998
1a326cc17d 💄 更新页面 2020-01-05 15:56:38 +08:00
zhaojun1998
cc993d8e65 优化缓存策略, 开启/关闭缓存后同步控制自动刷新策略 2020-01-05 15:56:17 +08:00
zhaojun1998
f128882034 添加文件获取和判断是否存在接口 2020-01-05 15:54:59 +08:00
zhaojun1998
31dbb902c3 添加文件获取和判断是否存在接口 2020-01-05 15:54:42 +08:00
zhaojun1998
c849057aaa 💄 更新页面 2020-01-03 17:00:15 +08:00
zhaojun1998
7b288b795c 🐛 修复切换缓存时, 出现的异常 BUG 2020-01-03 16:24:53 +08:00
zhaojun1998
316566d479 📝 更新文档, 修复拼写错误 2020-01-03 16:16:05 +08:00
zhaojun1998
e01ce28eb8 💄 更新页面 2020-01-03 15:59:41 +08:00
zhaojun1998
9b7528b61c 💄 更新页面 2020-01-03 15:49:22 +08:00
zhaojun1998
bd22cfd34c 添加检测缓存管理功能 2020-01-03 15:48:42 +08:00
zhaojun1998
4aa9839c6b 🔖 升级版本为 0.4 2020-01-03 15:28:58 +08:00
zhaojun1998
5eeea23703 缓存功能优化, 更高效的管理缓存. 2020-01-03 15:27:45 +08:00
zhaojun1998
6997b15dd0 修复系统设置缓存读取到远程的 BUG 2020-01-02 18:45:19 +08:00
zhaojun1998
326c954c36 💄 更新页面 2020-01-02 18:44:36 +08:00
zhaojun1998
ba5801bea2 🔖 升级版本为 0.3.1 2020-01-02 18:27:30 +08:00
zhaojun1998
e2b0c29e2d 更改日志级别 2020-01-02 18:23:24 +08:00
zhaojun1998
845a380a7e 未开启缓存, 不允许搜索. 2020-01-02 18:22:54 +08:00
zhaojun1998
87229f225e 系统配置添加缓存, 优化性能 2020-01-02 18:20:06 +08:00
zhaojun1998
de947e510c 缓存功能优化, 修改设置后自动修改缓存, 且缓存未完成, 搜索功能暂时禁用. 2020-01-02 18:17:11 +08:00
zhaojun1998
2a367afc37 优化代码, 参数不完整时, 不进行初始化 2020-01-02 18:15:05 +08:00
zhaojun1998
5fb945cebc 🔖 升级版本为 0.3 2020-01-02 14:51:22 +08:00
zhaojun1998
7acedfef38 🎨 修改名称 2020-01-02 14:48:56 +08:00
zhaojun1998
5e198b7ce7 开启 gzip 压缩 2020-01-02 14:48:05 +08:00
zhaojun1998
c3e7e622e2 🎨 缓存修改使用本地 caffeine 2020-01-02 14:46:55 +08:00
zhaojun1998
aec73f5cc7 💄 更新页面 2020-01-02 14:45:21 +08:00
zhaojun1998
9236f11044 优化生产环境配置 2020-01-02 14:40:36 +08:00
zhaojun1998
02973a3c21 更新页面, 支持全局搜索功能 2020-01-01 23:20:12 +08:00
zhaojun1998
e60c64c8fc 📝 更新文档 2019-12-30 22:23:52 +08:00
zhaojun1998
52db0c1515 💄 更新页面 2019-12-29 19:59:48 +08:00
zhaojun1998
0ab2f3b015 移除依赖 2019-12-29 19:58:56 +08:00
zhaojun1998
dd588fe218 🐛 修复某些 S3 协议的存储策略, 生成对象下载地址时, 因重复 encode 造成的 BUG 2019-12-29 19:51:04 +08:00
zhaojun1998
dce1b42e8e 💄 更新页面 2019-12-29 19:14:35 +08:00
zhaojun1998
0e9dd7d5a8 💄 更新页面 2019-12-29 19:14:08 +08:00
zhaojun1998
f5bebd2500 所有存储引擎都支持基路径 2019-12-29 19:10:37 +08:00
zhaojun1998
6a54150868 🏗️ 将缓存框架由 Spring Boot Cache 改为 Alibaba JetCache, 支持缓存自动刷新 2019-12-29 19:09:50 +08:00
zhaojun1998
099c09b625 🎨 抽象基于 S3 API 的存储 2019-12-28 23:49:16 +08:00
zhaojun1998
45e117a05a 腾讯云和七牛云支持基路径 2019-12-28 23:20:56 +08:00
zhaojun1998
14ba1027ae 🎨 修改获取当前存储策略为获取抽象类, 而不是接口 2019-12-28 23:20:26 +08:00
zhaojun1998
04a2ff9542 🐛 修复获取文本内容时的 BUG 2019-12-28 23:20:15 +08:00
zhaojun1998
040e92a433 🎨 抽取 S3 通用 API 2019-12-28 23:19:53 +08:00
zhaojun1998
c739878890 🎨 修改获取当前存储策略为获取抽象类, 而不是接口 2019-12-28 23:19:31 +08:00
zhaojun1998
65616e045b 🎨 优化代码, 将通用方法抽取为抽象类 2019-12-28 23:17:56 +08:00
zhaojun1998
9aaf1494b1 🎨 抽取通用变量 2019-12-28 23:15:34 +08:00
zhaojun1998
74eaaad72d 🐛 修复音乐文件获取封面时包含特殊字符异常的 BUG 2019-12-26 20:19:39 +08:00
zhaojun1998
b65ccc95e2 初始化存储引擎后, 增加测试连接机制 2019-12-25 21:57:22 +08:00
zhaojun1998
e334acd508 🎨 增加启动时显示项目访问地址的功能 2019-12-24 22:11:45 +08:00
zhaojun1998
844cbcc03a 📝 更新文档 2019-12-23 22:11:23 +08:00
zhaojun1998
debaa72938 📝 更新文档 2019-12-21 13:44:05 +08:00
zhaojun1998
d293105521 💩 改善代码, 通过 codacy 校验 2019-12-21 12:31:53 +08:00
zhaojun1998
8e7d4432a3 💩 改善代码, 通过 P3C 校验 2019-12-21 12:08:24 +08:00
zhaojun1998
0e6bcbfa11 接口缓存降级为实现类缓存 2019-12-21 11:06:29 +08:00
zhaojun1998
e8122b4ed0 🗃️ 更新数据库脚本 2019-12-21 11:03:05 +08:00
zhaojun1998
b3a0f4585b 代码优化 2019-12-21 11:01:49 +08:00
zhaojun1998
12bae1ef53 MINIO 添加基路径支持 2019-12-21 11:00:47 +08:00
zhaojun1998
4d9357b11f 🎨 修改文件头, 文件尾, 密码文件的名称为可配置 2019-12-14 22:21:53 +08:00
zhaojun1998
2aa9ccc389 🎨 修改文件头, 文件尾, 密码文件的名称为可配置 2019-12-14 22:01:04 +08:00
zhaojun1998
d81d795095 Merge remote-tracking branch 'origin/master' 2019-12-11 22:40:09 +08:00
zhaojun1998
9af89ecd8c 📝 更新文档 2019-12-11 22:39:30 +08:00
赵俊
bb381a98b9 Create LICENSE 2019-12-10 21:22:32 +08:00
zhaojun1998
14828e7f34 🗃️ 更新数据库文档 2019-12-10 21:11:53 +08:00
185 changed files with 6356 additions and 2751 deletions

48
.github/ISSUE_TEMPLATE/bug_report.md vendored Normal file
View File

@@ -0,0 +1,48 @@
---
name: BUG 反馈
about: 事情不像预期的那样工作吗?
title: ''
labels: 'bug'
assignees: ''
---
<!--
你好!感谢你正在考虑为 ZFile 提交一个 bug。请花一点点时间尽量详细地回答以下基础问题。
谢谢!
-->
<!--
请确认你已经做了下面这些事情,若 bug 还是未解决,那么请尽可详细地描述你的问题。
- 我已经安装了最新版的 ZFile
- 我已经阅读了 ZFile 的文档http://docs.zhaojun.im/zfile
- 我已经搜索了已有的 Issues 列表中有关的信息
- 我已经清理过浏览器缓存并重试
-->
## 我的环境
<!--
请登录到管理后台,点击左侧系统监控, 复制或截图此页内容.
-->
## 错误日志
<!--
请登录到管理后台,点击左侧系统监控, 点击右上角诊断日志下载, 然后上传到此 Issue 中.
-->
## 期望行为
<!--
你期望会发生什么?
-->
## 当前行为
<!--
描述 bug 细节,确认出现此问题的复现步骤,例如点击了哪里,发生了什么情况?
你可以粘贴截图或附件。
-->

View File

@@ -0,0 +1,34 @@
---
name: 功能建议
about: 想让我们为 ZFile 增加什么功能吗?
title: 'feat: '
labels: 'Feature Request'
assignees: ''
---
<!--
你好!感谢你愿意考虑希望 ZFile 增加某个新功能。请花一点点时间尽量详细地回答以下基础问题。
谢谢!
-->
## 概述
<!--
对这个新功能的一段描述
-->
## 动机
<!--
为什么你希望在 ZFile 中使用这个功能?
-->
## 详细解释
<!--
详细描述这个新功能。
如果这是一个小功能,你可以忽略这部分。
-->

14
.github/ISSUE_TEMPLATE/question.md vendored Normal file
View File

@@ -0,0 +1,14 @@
---
name: Question
about: 对 ZFile 有任何问题吗?
title: ''
labels: 'question'
assignees: ''
---
<!--
如果你有任何问题也可以通过此渠道来向我们反馈。
谢谢!
-->

164
API.md Normal file
View File

@@ -0,0 +1,164 @@
## API 标准
所有 API 均返回 `msg`, `code`, `data` 三个属性.
| code | 描述 |
| :---: | :------------: |
| 0 | 请求成功 |
| -1 | 请求失败 |
| -2 | 文件夹需要密码 |
`code == 0` 时, `data` 中为请求所需数据.
`code != 0` 时, 应当将 `msg` 中的属性作为参考值.
## 获取文件列表
### 请求 URL
`/api/list` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :------: | :--------: | :------: | :--------------------------: |
| path | 路径 | 是 | `/`, `/文件夹名称` |
| password | 文件夹密码 | 否 | 当文件夹需要密码时, |
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": [
{
"name": "密码文件夹",
"time": "2020-01-28 13:17",
"size": 4096,
"type": "FOLDER",
"path": "/",
"url": null
},
{
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "/",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
]
}
```
## 搜索
### 请求 URL
`/api/search` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :----: | :------: | :--------------------------: |
| name | 搜索值 | 是 | 模糊匹配 |
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": [
{
"name": "密码文件夹",
"time": "2020-01-28 13:17",
"size": 4096,
"type": "FOLDER",
"path": "/",
"url": null
},
{
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "/",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
]
}
```
## 获取单个文件信息
### 请求 URL
`/api/directlink` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :--------: | :------: | :------------------: |
| path | 文件全路径 | 是 | `/新建 文本文档.txt` |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": {
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "d:/test",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
}
```
## 获取系统配置
### 请求 URL
`/api/config` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :--------: | :------: | :-----------: |
| path | 文件夹名称 | 是 | `/文件夹名称` |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": {
"readme": null, # 文档文件名称
"viewConfig": {
"siteName": "站点名称", # 站点名称
"infoEnable": false, # 是否开启右侧信息框
"searchEnable": false, # 是否开启搜索
"searchIgnoreCase": true, # 搜索是否忽略大小写
"storageStrategy": "local", # 当前启用存储引擎
"username": "2", # 用户名
"domain": "http://127.0.0.1:8080", # 域名
"enableCache": false, # 是否开启缓存
"searchContainEncryptedFile": false, # 搜索是否包含加密文件夹
"customJs": "", # 自定义 js 片段
"customCss": "" # 自定义 css 片段
}
}
}
```

21
LICENSE Normal file
View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 ZhaoJun
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

139
README.md
View File

@@ -1,59 +1,89 @@
# Z-File
![https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square](https://img.shields.io/badge/license-MIT-blue.svg?longCache=true&style=flat-square)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/70b793267f7941d58cbd93f50c9a8e0a)](https://www.codacy.com/manual/zhaojun1998/zfile?utm_source=github.com&amp;utm_medium=referral&amp;utm_content=zhaojun1998/zfile&amp;utm_campaign=Badge_Grade)
![https://img.shields.io/badge/springboot-2.0.6-orange.svg?style=flat-square](https://img.shields.io/badge/springboot-2.0.6-yellow.svg?longCache=true&style=popout-square)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/zhaojun1998/zfile.svg?style=flat-square)
此项目是一个在线文件目录的程序, 支持各种对象存储和本地存储, 使用定位是个人放常用工具下载, 或做公共的文件库. 不会向多账户方向开发.
前端基于 [h5ai](https://larsjung.de/h5ai/) 的原有功能使用 Vue 重新开发了一遍. 后端采用 SpringBoot, 数据库采用内嵌数据库.
预览地址: [http://zfile.jun6.net](http://zfile.jun6.net)
预览地址: [https://zfile.jun6.net](https://zfile.jun6.net)
文档地址: [http://docs.zhaojun.im/zfile](http://docs.zhaojun.im/zfile)
## 系统特色
* 内存缓存 (免安装)
* 内存数据库 (免安装)
* 个性化配置
* 自定义目录的 header 和 footer 说明文件
* 自定义目录的 readme 说明文件
* 自定义 JS, CSS
* 文件夹密码
* 支持在线浏览文本文件, 视频, 图片, 音乐.
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
* 文件/目录二维码
* 缓存动态开启, ~~缓存自动刷新 (v2.2 及以前版本支持)~~
* ~~全局搜索 (v2.2 及以前版本支持)~~
* 同时挂载多个存储策略
* 支持 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版, OneDrive 世纪互联版, 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
## 快速开始
安装 JDK 1.8 :
安装依赖环境:
```bash
yum instal -y java # 适用于 Centos 7.x
# CentOS系统
yum install -y java-1.8.0-openjdk unzip
```
```bash
# Debian 9 / Ubuntu 14+
apt update
apt install -y openjdk-8-jre-headless unzip
```
```bash
# Debian 10 (Buster) 系统
apt update && apt install -y apt-transport-https software-properties-common ca-certificates dirmngr gnupg
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add -
add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
apt update && apt install -y adoptopenjdk-8-hotspot-jre
```
> 如为更新程序, 则请先执行 `~/zfile/bin/stop.sh && rm -rf ~/zfile` 清理旧程序. 首次安装请忽略此选项.
下载项目:
```bash
wget https://github.com/zhaojun1998/zfile/releases/download/0.2.1/zfile-0.2.1.jar
cd ~
wget https://c.jun6.net/ZFILE/zfile-release.war
mkdir zfile && unzip zfile-release.war -d zfile && rm -rf zfile-release.war
chmod +x zfile/bin/*.sh
```
> 下载指定版本可以将 `zfile-release.war` 改为 `zfile-x.x.war`,如 `zfile-2.2.war`。
程序的目录结构为:
```
├── zfile
├── META-INF
├── WEB-INF
└── bin
├── start.sh # 启动脚本
└── stop.sh # 停止脚本
├── restart.sh # 重启脚本
```
启动项目:
```bash
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.2.1.jar
## 高级启动
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.2.1.jar --server.port=18777
~/zfile/bin/start.sh
```
> 系统使用的是内置配置文件, 默认配置请参考: [application.yml](https://github.com/zhaojun1998/zfile/blob/master/src/main/resources/application.yml)
> **可下载此文件放置与 jar 包同目录, 此时会以外部配置文件为准, 推荐适用此方式!.**
> 所有参数都可在命令行启动时, 以类似 `--server.port=18777` 的方式强制执行, 此方式的优先级最高.
> *指定 `-Djava.security.egd=file:/dev/./urandom` 是为了防止在 Linux 环境中, 生成首次登陆生成 sessionId 取系统随机数过慢的问题.*
重要参数:
- `server.port` 为指定端口, 默认为 `8080`
- `logging.path` 为日志文件存放路径, 默认为 `${user.home}/.zfile/logs`
- `spring.datasource` 下配置了 `h2``mysql` 两种数据库的支持, 默认采用 `h2`.
- `spring.cache.type` 为指定缓存方式, 默认为 `caffeine`, 即内存缓存, 无需安装, 支持切换为 `redis`, 但需配置 `spring.redis.host``spring.redis.password` 参数后才可使用.
篇幅有限, 更详细的安装教程及介绍请参考: [ZFile 文档](http://zhaojun.im/zfile-install)
访问地址:
@@ -64,40 +94,51 @@ java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.2.1.jar --server.port=
管理后台: http://127.0.0.1:8080/#/admin
## 预览
## 运行环境
* JDK: `1.8`
* 缓存: `caffeine/redis`
* 数据库: `h2/mysql`
![前台首页](https://cdn.jun6.net/2020/04/19/d590d2bde13bb.png)
![后台设置-驱动器设置](https://cdn.jun6.net/2020/04/19/d58fc2debcce8.png)
![后台设置-驱动器设置](https://cdn.jun6.net/2020/04/19/0f321e47fc18c.png)
![后台设置-显示设置](https://cdn.jun6.net/2020/04/19/6d7c300b89671.png)
## 常见问题
### 缓存
缓存默认支持 `caffeine``redis`, 前者为内存缓存, 无需安装, 但后者相对性能更好.
### 数据库
缓存默认支持 `h2``mysql`, 前者为嵌入式数据库, 无需安装, 但后者相对性能更好.
### 默认路径
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录, windows 为 `C:/Users/用户名/`, linux 为 `/home/用户名/`, root 用户为 `/root/`
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录
windows 为 `C:/Users/用户名/`
### 头尾文件和加密文件
linux 为 `/home/用户名/`, root 用户为 `/root/`
- 目录头部显示文件名为 `header.md`
- 目录底部显示文件名为 `footer.md`
> 2.3 及以后版本路径为 `~/.zfile-new/db/`
### 文档文件和加密文件
- 目录文档显示文件名为 `readme.md`
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
## TODO
## 开发计划
- 全局搜索功能
- 文本预览更换更好用的编辑器
- 后台支持上传、编辑、删除等操作
- API 支持
- 更方便的部署方式
- [x] API 支持 [点击查看文档](https://github.com/zhaojun1998/zfile/blob/master/API.md)
- [x] 更方便的部署方式
- [x] 布局优化 - 自定义操作按钮 (现为右键实现)
- [x] 后台优化 - 设置按照其功能进行分离
- [x] 体验优化 - 支持前后端分离部署
- [x] 体验优化 - 文本预览更换 vscode 同款编辑器 monaco editor
- [x] 新功能 - Docker 支持
- [x] 架构调整 - 支持多存储策略
- [ ] 新功能 - 后台支持上传、编辑、删除等操作
- [ ] 新功能 - WebDav 支持
- [ ] 新功能 - 离线下载 (aria2)
- [ ] 体验优化 - 忽略文件列表 (正则表达式)
- [ ] 体验优化 - 自定义支持预览的文件后缀 (正则表达式)
- [ ] 体验优化 - 一键安装脚本
## 支持作者
如果本项目对你有帮助,请作者喝杯咖啡吧。
<img src="http://cdn.jun6.net/alipay.png" width="200" height="312">
<img src="http://cdn.jun6.net/wechat.png" width="222" height="300">

165
pom.xml
View File

@@ -12,8 +12,9 @@
<groupId>im.zhaojun</groupId>
<artifactId>zfile</artifactId>
<version>0.2.1</version>
<version>2.7</version>
<name>zfile</name>
<packaging>war</packaging>
<description>一个在线的文件浏览系统</description>
<properties>
@@ -21,10 +22,8 @@
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- spring boot 官方相关 -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
@@ -43,96 +42,65 @@
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>3.0.10</version>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>4.5.11</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-cache</artifactId>
</dependency>
<dependency>
<groupId>com.github.ben-manes.caffeine</groupId>
<artifactId>caffeine</artifactId>
<version>2.7.0</version>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<!-- 对象存储 API -->
<!-- 数据库驱动-->
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 工具类 -->
<dependency>
<groupId>cn.hutool</groupId>
<artifactId>hutool-all</artifactId>
<version>5.1.3</version>
</dependency>
<!-- 存储策略相关 API, 对象存储、FTP、 Rest API-->
<dependency>
<groupId>com.upyun</groupId>
<artifactId>java-sdk</artifactId>
<version>4.1.3</version>
</dependency>
<dependency>
<groupId>com.qiniu</groupId>
<artifactId>qiniu-java-sdk</artifactId>
<version>7.2.23</version>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3</artifactId>
<version>1.11.699</version>
</dependency>
<dependency>
<groupId>com.huaweicloud</groupId>
<artifactId>esdk-obs-java</artifactId>
<version>3.19.5</version>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.8</version>
</dependency>
<dependency>
<groupId>com.aliyun.oss</groupId>
<artifactId>aliyun-sdk-oss</artifactId>
<version>3.5.0</version>
</dependency>
<!-- <dependency>-->
<!-- <groupId>org.nuxeo.onedrive</groupId>-->
<!-- <artifactId>onedrive-java-client</artifactId>-->
<!-- <version>1.0</version>-->
<!-- </dependency>-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-configuration-processor</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>commons-net</groupId>
<artifactId>commons-net</artifactId>
<version>3.6</version>
</dependency>
<dependency>
<groupId>com.qcloud</groupId>
<artifactId>cos_api</artifactId>
<version>5.6.3</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<!-- 其他工具类 -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</dependency>
<dependency>
<groupId>org</groupId>
<artifactId>jaudiotagger</artifactId>
<version>2.0.3</version>
<scope>provided</scope>
</dependency>
<dependency>
@@ -142,55 +110,38 @@
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.61</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<dependency>
<groupId>commons-validator</groupId>
<artifactId>commons-validator</artifactId>
<version>1.6</version>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
<version>28.1-jre</version>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
</dependency>
</dependencies>
<repositories>
<!-- <repository>-->
<!-- <id>nuxeo</id>-->
<!-- <name>nuxeo</name>-->
<!-- <url>http://maven.nuxeo.org/nexus/content/groups/public</url>-->
<!-- </repository>-->
</repositories>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.uyoqu.framework</groupId>
<artifactId>maven-plugin-starter</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>bin</goal>
</goals>
</execution>
</executions>
<configuration>
<jvms>
<jvm>-Djava.security.egd=file:/dev/./urandom</jvm>
<jvm>-Dfile.encoding=utf-8</jvm>
</jvms>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -1,131 +0,0 @@
package im.zhaojun.aliyun.service;
import cn.hutool.core.util.URLUtil;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.model.*;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class AliyunServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(AliyunServiceImpl.class);
@Value("${zfile.cache.timeout}")
private Long timeout;
@Resource
private StorageConfigService storageConfigService;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String ACCESS_KEY = "accessKey";
private static final String SECRET_KEY = "secretKey";
private static final String DOMAIN_KEY = "domain";
private static final String ENDPOINT_KEY = "endPoint";
private OSS ossClient;
private String bucketName;
private String domain;
private boolean isPrivate;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ALIYUN);
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
ossClient = new OSSClientBuilder().build(endPoint, accessKey, secretKey);
AccessControlList bucketAcl = ossClient.getBucketAcl(bucketName);
CannedAccessControlList cannedAcl = bucketAcl.getCannedACL();
isPrivate = "Private".equals(cannedAcl.name());
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.ALIYUN.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
ObjectListing objectListing =
ossClient.listObjects(new ListObjectsRequest(bucketName).withDelimiter("/").withPrefix(path));
for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(s.getKey().substring(path.length()));
fileItemDTO.setSize(s.getSize());
fileItemDTO.setTime(s.getLastModified());
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
fileItemList.add(fileItemDTO);
}
for (String commonPrefix : objectListing.getCommonPrefixes()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(commonPrefix.substring(path.length(), commonPrefix.length() - 1));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
path = StringUtils.removeFirstSeparator(path);
if (isPrivate) {
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
URL url = ossClient.generatePresignedUrl(bucketName, path, expirationDate);
return URLUtil.complateUrl(domain, url.getFile());
} else {
return URLUtil.complateUrl(domain, path);
}
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.ALIYUN;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,14 +0,0 @@
package im.zhaojun.common.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 标记注解, 用于在调用前检查是否已存储策略
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface CheckStorageStrategyInit {
}

View File

@@ -1,25 +0,0 @@
package im.zhaojun.common.aspect;
import im.zhaojun.common.exception.StorageStrategyUninitializedException;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.SystemConfigService;
import im.zhaojun.common.util.SpringContextHolder;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
@Aspect
@Component
public class StorageStrategyInitCheckAspect {
@Before("@annotation(im.zhaojun.common.annotation.CheckStorageStrategyInit)")
public void logStart() {
SystemConfigService systemConfigService = SpringContextHolder.getBean(SystemConfigService.class);
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
if (currentStorageStrategy == null) {
throw new StorageStrategyUninitializedException("存储策略未初始化");
}
}
}

View File

@@ -1,15 +0,0 @@
package im.zhaojun.common.config;
import im.zhaojun.common.model.enums.StorageTypeEnumDeSerializerConvert;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StorageTypeEnumDeSerializerConvert());
}
}

View File

@@ -1,75 +0,0 @@
package im.zhaojun.common.config;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.cache.caffeine.CaffeineCacheManager;
import org.springframework.cache.interceptor.KeyGenerator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import java.util.Collections;
/**
* 缓存配置类, 用于根据配置决定使用 redis 缓存还是 caffeine (内存).
*/
@Configuration
public class ZFileCacheConfiguration {
public static final String CACHE_NAME = "zfile";
/**
* 个性化配置缓存
*/
@Bean
@ConditionalOnProperty(value = "spring.cache.type", havingValue = "caffeine")
public CaffeineCacheManager caffeineCacheManager() {
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
caffeineCacheManager.setCacheNames(Collections.singletonList(CACHE_NAME));
return caffeineCacheManager;
}
@Bean
@ConditionalOnProperty(value = "spring.cache.type", havingValue = "redis")
public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
GenericJackson2JsonRedisSerializer jsonRedisSerializer
= new GenericJackson2JsonRedisSerializer();
RedisSerializationContext.SerializationPair<Object> pair
= RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer);
RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
}
@Bean
public KeyGenerator keyGenerator() {
return (target, method, params) -> {
char separator = ':';
StringBuilder strBuilder = new StringBuilder();
// 类名
strBuilder.append(target.getClass().getSimpleName());
strBuilder.append(separator);
// 方法名
strBuilder.append(method.getName());
strBuilder.append(separator);
// 参数值
for (int i = 0; i < params.length; i++) {
if (i == params.length - 1) {
strBuilder.append(params[i]);
} else {
strBuilder.append(params[i]).append(",");
}
}
return strBuilder.toString();
};
}
}

View File

@@ -1,114 +0,0 @@
package im.zhaojun.common.controller;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.ResultBean;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileAsyncCacheService;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 后台管理
*/
@RestController
@RequestMapping("/admin")
public class AdminController {
private static final Logger log = LoggerFactory.getLogger(AdminController.class);
@Resource
private StorageConfigService storageConfigService;
@Resource
private SystemConfigService systemConfigService;
@Resource
private FileAsyncCacheService fileAsyncCacheService;
/**
* 获取系统配置
*/
@GetMapping("/config")
public ResultBean getConfig() {
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
return ResultBean.success(systemConfigDTO);
}
/**
* 更新系统配置
*/
@PostMapping("/update-pwd")
public ResultBean updatePwd(String username, String password) {
systemConfigService.updateUsernameAndPwd(username, password);
return ResultBean.success();
}
/**
* 更新系统配置
*/
@PostMapping("/config")
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) {
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
systemConfigDTO.setId(1);
systemConfigService.updateSystemConfig(systemConfigDTO);
if (!currentStorageStrategy.equals(systemConfigDTO.getStorageStrategy())) {
refreshStorageStrategy();
}
return ResultBean.success();
}
@GetMapping("/strategy-form")
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageType);
return ResultBean.success(storageConfigList);
}
/**
* 清理当前启用的存储引擎的缓存
*/
@GetMapping("/clear-cache")
public ResultBean clearCache() {
FileService fileService = systemConfigService.getCurrentFileService();
fileService.clearCache();
return ResultBean.success();
}
/**
* 更新存储策略
*/
public void refreshStorageStrategy() {
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
refreshStorageStrategy(storageStrategy);
}
/**
* 更新存储策略
*/
public void refreshStorageStrategy(StorageTypeEnum storageStrategy) {
if (storageStrategy == null) {
log.info("尚未配置存储策略.");
} else {
FileService fileService = systemConfigService.getCurrentFileService();
fileService.init();
log.info("当前启用存储类型: {}", storageStrategy.getDescription());
// if 判断是否开启搜索.
fileAsyncCacheService.cacheGlobalFile();
}
}
}

View File

@@ -1,160 +0,0 @@
package im.zhaojun.common.controller;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.annotation.CheckStorageStrategyInit;
import im.zhaojun.common.exception.SearchDisableException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.ZFileConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.dto.ResultBean;
import im.zhaojun.common.model.dto.SiteConfigDTO;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import im.zhaojun.common.service.SystemService;
import im.zhaojun.common.util.AudioHelper;
import im.zhaojun.common.util.FileComparator;
import im.zhaojun.common.util.HttpUtil;
import im.zhaojun.common.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* 前台文件管理
*/
@RequestMapping("/api")
@RestController
public class FileController {
@Resource
private SystemService systemService;
@Resource
private SystemConfigService systemConfigService;
@Resource
private StorageConfigService storageConfigService;
/**
* 滚动加载每页条数.
*/
private static final Integer PAGE_SIZE = 30;
@CheckStorageStrategyInit
@GetMapping("/list")
public ResultBean list(@RequestParam(defaultValue = "/") String path,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String order,
@RequestParam(required = false) String password,
@RequestParam(defaultValue = "1") Integer page) throws Exception {
FileService fileService = systemConfigService.getCurrentFileService();
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + URLUtil.decode(path) + "/"));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
if (!HttpUtil.getTextContent(fileItemDTO.getUrl()).equals(password)) {
if (password != null && !"".equals(password)) {
return ResultBean.error("密码错误.");
}
return ResultBean.error("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
}
}
}
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
fileItemList.sort(new FileComparator(sortBy, order));
filterFileList(fileItemList);
Integer total = fileItemList.size();
Integer totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
if (page > totalPage) {
return ResultBean.successData(new ArrayList<>());
}
Integer start = (page - 1) * PAGE_SIZE;
Integer end = page * PAGE_SIZE;
end = end > total ? total : end;
List<FileItemDTO> fileSubItem = fileItemList.subList(start, end);
return ResultBean.successData(fileSubItem);
}
/**
* 获取文件类容, 仅限用于, txt, md, ini 等普通文本文件.
* @param url 文件路径
* @return 文件内容
*/
@CheckStorageStrategyInit
@GetMapping("/content")
public ResultBean getContent(String url) {
return ResultBean.successData(HttpUtil.getTextContent(url));
}
/**
* 获取系统配置信息和当前页的标题, 文件头, 文件尾信息
* @param path 路径
*/
@CheckStorageStrategyInit
@GetMapping("/config")
public ResultBean getConfig(String path) throws Exception {
SiteConfigDTO config = systemService.getConfig(URLUtil.decode(StringUtils.removeDuplicateSeparator("/" + path + "/")));
config.setSystemConfigDTO(systemConfigService.getSystemConfig());
return ResultBean.successData(config);
}
@CheckStorageStrategyInit
@GetMapping("/clearCache")
public ResultBean clearCache() {
FileService fileService = systemConfigService.getCurrentFileService();
if (fileService != null) {
fileService.clearCache();
}
return ResultBean.success();
}
@CheckStorageStrategyInit
@GetMapping("/audioInfo")
public ResultBean getAudioInfo(String url) throws Exception {
return ResultBean.success(AudioHelper.getAudioInfo(url));
}
@CheckStorageStrategyInit
@GetMapping("/search")
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name) throws Exception {
FileService fileService = systemConfigService.getCurrentFileService();
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
if (!systemConfigDTO.getSearchEnable()) {
throw new SearchDisableException("搜索功能未开启");
}
return ResultBean.success(fileService.search(URLUtil.decode(name)));
}
@GetMapping("/form")
public ResultBean getFormByStorageType(String storageType) {
StorageTypeEnum storageTypeEnum = StorageTypeEnum.getEnum(storageType);
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageTypeEnum);
storageConfigList.forEach(storageConfig -> storageConfig.setValue(null));
return ResultBean.success(storageConfigList);
}
/**
* 过滤文件列表, 不显示密码, 头部和尾部文件.
*/
private void filterFileList(List<FileItemDTO> fileItemList) {
if (fileItemList == null) {
return;
}
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.FOOTER_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.HEADER_FILE_NAME.equals(fileItem.getName()));
}
}

View File

@@ -1,99 +0,0 @@
package im.zhaojun.common.controller;
import cn.hutool.crypto.SecureUtil;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.InstallModelDTO;
import im.zhaojun.common.model.dto.ResultBean;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;
/**
* 系统安装初始化
*/
@Controller
public class InstallController {
@Resource
private SystemConfigService systemConfigService;
@Resource
private StorageConfigService storageConfigService;
@Resource
private AdminController adminController;
@GetMapping("/is-installed")
@ResponseBody
public ResultBean isInstall() {
if (systemConfigService.getCurrentStorageStrategy() == null) {
return ResultBean.success();
}
return ResultBean.error("请勿重复初始化");
}
@PostMapping("/install")
@ResponseBody
public ResultBean install(InstallModelDTO installModelDTO) {
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
if (systemConfigDTO.getStorageStrategy() != null) {
return ResultBean.error("请勿重复初始化.");
}
systemConfigDTO.setSiteName(installModelDTO.getSiteName());
StorageTypeEnum storageTypeEnum = installModelDTO.getStorageStrategy();
systemConfigDTO.setStorageStrategy(storageTypeEnum);
systemConfigDTO.setUsername(installModelDTO.getUsername());
systemConfigDTO.setPassword(SecureUtil.md5(installModelDTO.getPassword()));
systemConfigDTO.setDomain(installModelDTO.getDomain());
systemConfigService.updateSystemConfig(systemConfigDTO);
Map<String, String> storageStrategyConfig = installModelDTO.getStorageStrategyConfig();
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageTypeEnum);
for (StorageConfig storageConfig : storageConfigList) {
String key = storageConfig.getKey();
String value = storageStrategyConfig.get(key);
storageConfig.setValue(value);
}
storageConfigService.updateStorageConfig(storageConfigList);
adminController.refreshStorageStrategy();
return ResultBean.success();
}
@PostMapping("/storage-strategy")
@ResponseBody
public ResultBean save(@RequestParam Map<String, String> storageStrategyConfig, StorageTypeEnum storageStrategy) {
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageStrategy);
for (StorageConfig storageConfig : storageConfigList) {
String key = storageConfig.getKey();
String value = storageStrategyConfig.get(key);
storageConfig.setValue(value);
}
storageConfigService.updateStorageConfig(storageConfigList);
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
if (Objects.equals(storageStrategy, currentStorageStrategy)) {
FileService fileService = systemConfigService.getCurrentFileService();
fileService.clearCache();
fileService.init();
}
return ResultBean.success();
}
}

View File

@@ -1,24 +0,0 @@
package im.zhaojun.common.model.constant;
public class ZFileConstant {
public final static String USER_HOME = System.getProperty("user.home");
public static final String AUDIO_TMP_PATH = "/.zfile/tmp/audio/";
/**
* 页面头部文件
*/
public static final String HEADER_FILE_NAME = "header.md";
/**
* 页面尾部文件
*/
public static final String FOOTER_FILE_NAME = "footer.md";
/**
* 密码文件
*/
public static final String PASSWORD_FILE_NAME = "password.txt";
}

View File

@@ -1,50 +0,0 @@
package im.zhaojun.common.model.dto;
public class AudioInfoDTO {
private String title;
private String artist;
private String cover;
private String src;
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getArtist() {
return artist;
}
public void setArtist(String artist) {
this.artist = artist;
}
public String getCover() {
return cover;
}
public void setCover(String cover) {
this.cover = cover;
}
public String getSrc() {
return src;
}
public void setSrc(String src) {
this.src = src;
}
@Override
public String toString() {
return "AudioInfoDTO{" +
"title='" + title + '\'' +
", artist='" + artist + '\'' +
", cover='" + cover + '\'' +
", src='" + src + '\'' +
'}';
}
}

View File

@@ -1,50 +0,0 @@
package im.zhaojun.common.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
public class SiteConfigDTO implements Serializable {
private static final long serialVersionUID = 8811196207046121740L;
private String header;
private String footer;
@JsonProperty("viewConfig")
private SystemConfigDTO systemConfigDTO;
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getFooter() {
return footer;
}
public void setFooter(String footer) {
this.footer = footer;
}
public SystemConfigDTO getSystemConfigDTO() {
return systemConfigDTO;
}
public void setSystemConfigDTO(SystemConfigDTO systemConfigDTO) {
this.systemConfigDTO = systemConfigDTO;
}
@Override
public String toString() {
return "SiteConfigDTO{" +
"header='" + header + '\'' +
", footer='" + footer + '\'' +
", systemConfig=" + systemConfigDTO +
'}';
}
}

View File

@@ -1,102 +0,0 @@
package im.zhaojun.common.model.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnumSerializerConvert;
public class SystemConfigDTO {
@JsonIgnore
private Integer id;
private String siteName;
private Boolean infoEnable;
private Boolean searchEnable;
private Boolean searchIgnoreCase;
@JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
private StorageTypeEnum storageStrategy;
private String username;
@JsonIgnore
private String password;
private String domain;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSiteName() {
return siteName;
}
public void setSiteName(String siteName) {
this.siteName = siteName;
}
public Boolean getInfoEnable() {
return infoEnable;
}
public void setInfoEnable(Boolean infoEnable) {
this.infoEnable = infoEnable;
}
public Boolean getSearchEnable() {
return searchEnable;
}
public void setSearchEnable(Boolean searchEnable) {
this.searchEnable = searchEnable;
}
public Boolean getSearchIgnoreCase() {
return searchIgnoreCase;
}
public void setSearchIgnoreCase(Boolean searchIgnoreCase) {
this.searchIgnoreCase = searchIgnoreCase;
}
public StorageTypeEnum getStorageStrategy() {
return storageStrategy;
}
public void setStorageStrategy(StorageTypeEnum storageStrategy) {
this.storageStrategy = storageStrategy;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
}

View File

@@ -1,15 +0,0 @@
package im.zhaojun.common.repository;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
@Repository
public interface StorageConfigRepository extends JpaRepository<StorageConfig, Integer> {
List<StorageConfig> findByTypeOrderById(StorageTypeEnum type);
}

View File

@@ -1,11 +0,0 @@
package im.zhaojun.common.repository;
import im.zhaojun.common.model.SystemConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
@Repository
public interface SystemConfigRepository extends JpaRepository<SystemConfig, Integer> {
SystemConfig findByKey(String key);
}

View File

@@ -1,43 +0,0 @@
package im.zhaojun.common.service;
import im.zhaojun.common.config.StorageTypeFactory;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
@Service
public class FileAsyncCacheService {
private static final Logger log = LoggerFactory.getLogger(FileAsyncCacheService.class);
@Resource
private SystemConfigService systemConfigService;
@Async
public void cacheGlobalFile() {
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
if (storageStrategy == null) {
log.info("尚未配置存储策略. 跳过启动缓存.");
return;
}
FileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
log.info("缓存 {} 所有文件开始", storageStrategy.getDescription());
long startTime = System.currentTimeMillis();
try {
if (fileService.getIsInitialized()) {
fileService.selectAllFileList();
}
} catch (Exception e) {
log.error("缓存所有文件失败", e);
e.printStackTrace();
}
long endTime = System.currentTimeMillis();
log.info("缓存 {} 所有文件结束, 用时: {} 秒", storageStrategy.getDescription(), ( (endTime - startTime) / 1000 ));
}
}

View File

@@ -1,73 +0,0 @@
package im.zhaojun.common.service;
import im.zhaojun.common.config.ZFileCacheConfiguration;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.util.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.cache.annotation.CacheConfig;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import javax.annotation.PostConstruct;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.List;
@CacheConfig(cacheNames = ZFileCacheConfiguration.CACHE_NAME, keyGenerator = "keyGenerator")
public interface FileService {
@Cacheable(condition = "#root.targetClass.simpleName != 'LocalServiceImpl'")
List<FileItemDTO> fileList(String path) throws Exception;
@Cacheable
String getDownloadUrl(String path) throws Exception;
@PostConstruct
default void init() {}
/**
* 清除缓存.
*/
@CacheEvict(allEntries = true)
default void clearCache() {}
default List<FileItemDTO> search(String name) throws Exception {
List<FileItemDTO> result = new ArrayList<>();
List<FileItemDTO> fileItemList = selectAllFileList();
for (FileItemDTO fileItemDTO : fileItemList) {
if (fileItemDTO.getName().contains(name)) {
result.add(fileItemDTO);
}
}
return result;
}
default List<FileItemDTO> selectAllFileList() throws Exception {
List<FileItemDTO> result = new ArrayList<>();
String path = "/";
FileService currentFileService = (FileService) AopContext.currentProxy();
List<FileItemDTO> fileItemList = currentFileService.fileList(path);
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
while (!queue.isEmpty()) {
FileItemDTO fileItemDTO = queue.pop();
result.add(fileItemDTO);
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
queue.addAll(currentFileService.fileList(filePath));
}
}
return result;
}
StorageTypeEnum getStorageTypeEnum();
boolean getIsInitialized();
}

View File

@@ -1,126 +0,0 @@
package im.zhaojun.common.service;
import cn.hutool.crypto.SecureUtil;
import im.zhaojun.common.config.StorageTypeFactory;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.SystemConfigConstant;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.repository.SystemConfigRepository;
import im.zhaojun.common.util.StringUtils;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
@Service
public class SystemConfigService {
@Resource
private SystemConfigRepository systemConfigRepository;
public SystemConfigDTO getSystemConfig() {
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
List<SystemConfig> systemConfigList = systemConfigRepository.findAll();
for (SystemConfig systemConfig : systemConfigList) {
switch (systemConfig.getKey()) {
case SystemConfigConstant.SITE_NAME:
systemConfigDTO.setSiteName(systemConfig.getValue());
break;
case SystemConfigConstant.INFO_ENABLE:
systemConfigDTO.setInfoEnable("true".equals(systemConfig.getValue()));
break;
case SystemConfigConstant.SEARCH_ENABLE:
systemConfigDTO.setSearchEnable("true".equals(systemConfig.getValue()));
break;
case SystemConfigConstant.SEARCH_IGNORE_CASE:
systemConfigDTO.setSearchIgnoreCase("true".equals(systemConfig.getValue()));
break;
case SystemConfigConstant.STORAGE_STRATEGY:
String value = systemConfig.getValue();
systemConfigDTO.setStorageStrategy(StorageTypeEnum.getEnum(value));
break;
case SystemConfigConstant.USERNAME:
systemConfigDTO.setUsername(systemConfig.getValue());
break;
case SystemConfigConstant.PASSWORD:
systemConfigDTO.setPassword(systemConfig.getValue());
break;
case SystemConfigConstant.DOMAIN:
systemConfigDTO.setDomain(systemConfig.getValue());
break;
default:break;
}
}
return systemConfigDTO;
}
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) {
List<SystemConfig> systemConfigList = new ArrayList<>();
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SITE_NAME);
systemConfig.setValue(systemConfigDTO.getSiteName());
systemConfigList.add(systemConfig);
SystemConfig domainConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
domainConfig.setValue(systemConfigDTO.getDomain());
systemConfigList.add(domainConfig);
SystemConfig infoEnableSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.INFO_ENABLE);
infoEnableSystemConfig.setValue(systemConfigDTO.getInfoEnable() ? "true" : "false");
systemConfigList.add(infoEnableSystemConfig);
SystemConfig searchEnableSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SEARCH_ENABLE);
searchEnableSystemConfig.setValue(systemConfigDTO.getSearchEnable() ? "true" : "false");
systemConfigList.add(searchEnableSystemConfig);
SystemConfig searchIgnoreCaseSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SEARCH_IGNORE_CASE);
searchIgnoreCaseSystemConfig.setValue(systemConfigDTO.getSearchIgnoreCase() ? "true" : "false");
systemConfigList.add(searchIgnoreCaseSystemConfig);
SystemConfig storageStrategySystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.STORAGE_STRATEGY);
storageStrategySystemConfig.setValue(systemConfigDTO.getStorageStrategy().getKey());
systemConfigList.add(storageStrategySystemConfig);
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getUsername())) {
SystemConfig usernameSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
usernameSystemConfig.setValue(systemConfigDTO.getUsername());
systemConfigList.add(usernameSystemConfig);
}
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getPassword())) {
SystemConfig passwordSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
passwordSystemConfig.setValue(systemConfigDTO.getPassword());
systemConfigList.add(passwordSystemConfig);
}
systemConfigRepository.saveAll(systemConfigList);
}
public void updateUsernameAndPwd(String username, String password) {
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
usernameConfig.setValue(username);
systemConfigRepository.save(usernameConfig);
password = SecureUtil.md5(password);;
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
systemConfig.setValue(password);
systemConfigRepository.save(systemConfig);
}
public FileService getCurrentFileService() {
StorageTypeEnum storageStrategy = getCurrentStorageStrategy();
return StorageTypeFactory.getStorageTypeService(storageStrategy);
}
public StorageTypeEnum getCurrentStorageStrategy() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return systemConfigDTO.getStorageStrategy();
}
}

View File

@@ -1,38 +0,0 @@
package im.zhaojun.common.service;
import im.zhaojun.common.model.constant.ZFileConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.dto.SiteConfigDTO;
import im.zhaojun.common.util.HttpUtil;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.List;
@Service
public class SystemService {
@Resource
private SystemConfigService systemConfigService;
/**
* 构建指定路径下标题, 页头, 页尾
* @param path 路径
*/
public synchronized SiteConfigDTO getConfig(String path) throws Exception {
SiteConfigDTO siteConfigDTO = new SiteConfigDTO();
FileService fileService = systemConfigService.getCurrentFileService();
List<FileItemDTO> fileItemList = fileService.fileList(path);
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.FOOTER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setFooter(HttpUtil.getTextContent(fileItemDTO.getUrl()));
} else if (ZFileConstant.HEADER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setHeader(HttpUtil.getTextContent(fileItemDTO.getUrl()));
}
}
return siteConfigDTO;
}
}

View File

@@ -1,14 +0,0 @@
package im.zhaojun.common.util;
import cn.hutool.core.util.URLUtil;
import org.springframework.web.client.RestTemplate;
public class HttpUtil {
public static String getTextContent(String url) {
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
String result = restTemplate.getForObject(URLUtil.decode(url), String.class);
return result == null ? "" : result;
}
}

View File

@@ -1,32 +0,0 @@
package im.zhaojun.common.util;
import im.zhaojun.common.service.FileAsyncCacheService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.ApplicationListener;
import org.springframework.context.event.ContextRefreshedEvent;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
/**
* 项目启动监听器, 当项目启动时, 遍历当前对象存储的所有内容, 添加到缓存中.
*/
@Component
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
private static final Logger log = LoggerFactory.getLogger(StartupListener.class);
@Resource
private FileAsyncCacheService fileAsyncCacheService;
@Override
public void onApplicationEvent(ContextRefreshedEvent event) {
try {
fileAsyncCacheService.cacheGlobalFile();
} catch (Exception e) {
throw new RuntimeException("缓存异常.", e);
}
}
}

View File

@@ -1,100 +0,0 @@
package im.zhaojun.ftp.service;
import cn.hutool.core.util.URLUtil;
import cn.hutool.extra.ftp.Ftp;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.apache.commons.net.ftp.FTPFile;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class FtpServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(FtpServiceImpl.class);
@Resource
private StorageConfigService storageConfigService;
private static final String HOST_KEY = "host";
private static final String PORT_KEY = "port";
private static final String USERNAME_KEY = "username";
private static final String PASSWORD_KEY = "password";
private static final String DOMAIN_KEY = "domain";
private Ftp ftp;
private String domain;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.FTP);
String host = stringStorageConfigMap.get(HOST_KEY).getValue();
String port = stringStorageConfigMap.get(PORT_KEY).getValue();
String username = stringStorageConfigMap.get(USERNAME_KEY).getValue();
String password = stringStorageConfigMap.get(PASSWORD_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
ftp = new Ftp(host, Integer.parseInt(port), username, password);
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.FTP.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
FTPFile[] ftpFiles = ftp.lsFiles(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
for (FTPFile ftpFile : ftpFiles) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(ftpFile.getName());
fileItemDTO.setSize(ftpFile.getSize());
fileItemDTO.setTime(ftpFile.getTimestamp().getTime());
fileItemDTO.setType(ftpFile.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE);
fileItemDTO.setPath(path);
if (ftpFile.isFile()) {
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
}
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
return URLUtil.complateUrl(domain, path);
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.FTP;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,132 +0,0 @@
package im.zhaojun.huawei.service;
import cn.hutool.core.util.URLUtil;
import com.obs.services.ObsClient;
import com.obs.services.model.*;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class HuaweiServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(HuaweiServiceImpl.class);
private String bucketName;
private String domain;
@Value("${zfile.cache.timeout}")
private Long timeout;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String ACCESS_KEY = "accessKey";
private static final String SECRET_KEY = "secretKey";
private static final String DOMAIN_KEY = "domain";
private static final String ENDPOINT_KEY = "endPoint";
@Resource
private StorageConfigService storageConfigService;
private ObsClient obsClient;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.HUAWEI);
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
obsClient = new ObsClient(accessKey, secretKey, endPoint);
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.HUAWEI.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) throws Exception {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
listObjectsRequest.setBucketName(bucketName);
listObjectsRequest.setDelimiter("/");
listObjectsRequest.setPrefix(path);
ObjectListing objectListing = obsClient.listObjects(listObjectsRequest);
List<ObsObject> objects = objectListing.getObjects();
for (ObsObject object : objects) {
String fileName = object.getObjectKey();
ObjectMetadata metadata = object.getMetadata();
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(fileName.substring(path.length()));
fileItemDTO.setSize(metadata.getContentLength());
fileItemDTO.setTime(metadata.getLastModified());
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
fileItemList.add(fileItemDTO);
}
for (String commonPrefix : objectListing.getCommonPrefixes()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(commonPrefix.substring(0, commonPrefix.length() - 1));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) throws Exception {
path = StringUtils.removeFirstSeparator(path);
TemporarySignatureRequest req = new TemporarySignatureRequest(HttpMethodEnum.GET, timeout);
req.setBucketName(bucketName);
req.setObjectKey(path);
TemporarySignatureResponse res = obsClient.createTemporarySignature(req);
URL url = new URL(res.getSignedUrl());
return URLUtil.complateUrl(domain, url.getFile());
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.HUAWEI;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,60 +0,0 @@
package im.zhaojun.local.controller;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.util.StringUtils;
import im.zhaojun.local.service.LocalServiceImpl;
import org.springframework.core.io.FileSystemResource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.util.Date;
@Controller
public class LocalController {
@Resource
private LocalServiceImpl localServiceImpl;
@GetMapping("/file/**")
@ResponseBody
public ResponseEntity<FileSystemResource> downAttachment(final HttpServletRequest request) throws IOException {
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String ) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
AntPathMatcher apm = new AntPathMatcher();
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
return export(new File(StringUtils.concatPath(localServiceImpl.getFilePath(), URLUtil.decode(filePath))));
}
private ResponseEntity<FileSystemResource> export(File file) throws IOException {
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.setContentDispositionFormData("attachment", URLUtil.encode(file.getName()));
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.add("Last-Modified", new Date().toString());
headers.add("ETag", String.valueOf(System.currentTimeMillis()));
return ResponseEntity
.ok()
.headers(headers)
.contentLength(file.length())
.contentType(mediaType)
.body(new FileSystemResource(file));
}
}

View File

@@ -1,106 +0,0 @@
package im.zhaojun.local.service;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.SystemConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.repository.SystemConfigRepository;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class LocalServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(LocalServiceImpl.class);
private static final String FILE_PATH_KEY = "filePath";
@Resource
private StorageConfigService storageConfigService;
@Resource
private SystemConfigRepository systemConfigRepository;
private String filePath;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.LOCAL);
filePath = stringStorageConfigMap.get(FILE_PATH_KEY).getValue();
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.LOCAL.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) throws Exception {
List<FileItemDTO> fileItemList = new ArrayList<>();
String fullPath = StringUtils.concatPath(filePath, path);
File file = new File(fullPath);
File[] files = file.listFiles();
if (files == null) {
return fileItemList;
}
for (File f : files) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setType(f.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE);
fileItemDTO.setTime(new Date(f.lastModified()));
fileItemDTO.setSize(f.length());
fileItemDTO.setName(f.getName());
fileItemDTO.setPath(path);
if (f.isFile()) {
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, f.getName())));
}
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) throws Exception {
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
return StringUtils.removeDuplicateSeparator(usernameConfig.getValue() + "/file/" + path);
}
public String getFilePath() {
return filePath;
}
public void setFilePath(String filePath) {
this.filePath = filePath;
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.LOCAL;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,109 +0,0 @@
package im.zhaojun.minio;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import io.minio.MinioClient;
import io.minio.Result;
import io.minio.messages.Item;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
@Service
public class MinIOServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(MinIOServiceImpl.class);
private String bucketName;
@Value("${zfile.cache.timeout}")
private Long timeout;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String ACCESS_KEY = "accessKey";
private static final String SECRET_KEY = "secretKey";
private static final String ENDPOINT_KEY = "endPoint";
@Resource
private StorageConfigService storageConfigService;
private MinioClient minioClient;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.MINIO);
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
minioClient = new MinioClient(endPoint, accessKey, secretKey);
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.MINIO.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) throws Exception {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
Iterable<Result<Item>> iterable = minioClient.listObjects(bucketName, path, false);
for (Result<Item> itemResult : iterable) {
Item item = itemResult.get();
FileItemDTO fileItemDTO = new FileItemDTO();
if (item.isDir()) {
fileItemDTO.setName(StringUtils.removeLastSeparator(item.objectName().replaceFirst(path, "")));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
} else {
fileItemDTO.setName(item.objectName().replaceFirst(path, ""));
fileItemDTO.setSize(item.objectSize());
fileItemDTO.setTime(item.lastModified());
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
}
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) throws Exception {
return minioClient.presignedGetObject(bucketName, path, timeout.intValue());
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.MINIO;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,35 +0,0 @@
// package im.zhaojun.onedrive.config;
//
// import org.nuxeo.onedrive.client.*;
// import org.springframework.context.annotation.Configuration;
//
// @Configuration
// public class OneDriveConfig {
//
//
// public void a () {
// OneDriveAPI api = new OneDriveBasicAPI("YOUR_ACCESS_TOKEN");
//
// OneDriveFolder folder = new OneDriveFolder(api, "FOLDER_ID");
// OneDriveFile file = new OneDriveFile(api, "FILE_ID");
// }
//
// public static void main(String[] args) throws OneDriveAPIException {
// OneDriveBasicAPI api = new OneDriveBasicAPI("EwAgA61DBAAUcSSzoTJJsy+XrnQXgAKO5cj4yc8AAQ0ZknDUY8YnwB9aJv7vA9YjiRAVMnKc+rG11fSXLZRAA8Q/CgJaz+OkRN60vaLDfp6KxbmVlob6kxeD/peOUI2eHtk0055Q2+n057tlyVAvGIFl9dvqkItoAthjmybcSkKBZS5h1meWxQ5IOvzSVrdgCKL0NOtTxfh33ZUDsYjvSid6NOX4Bs+pRjvZhQkvqEfGt8KlOL+JoIowmv2I+u09iDmS60BMwSoeK2K3CCLIXxLaiiPYUMsrNk65j4PWEBwBEfyHb6j3lrM/YvwFLq7Y8KJVjrXjFENC7ruja6Ko/cfTMX90yLkUEckpsZ30E6RJHWEHt7jXtNwndDZVknYDZgAACL5pnk17FJfb8AGGxJL1Y0CnAzgkTM2gw+WkFRRDDNzujuW1LQofwZ119HdeANhPrBZ14x32VaPGL1l0RvtR9LCeAN+EogcV5xhVpmCExitaXQB6OkZ6BnXaxLj5TNvFRNeZq0ZfJ3T08clLA1vXHkZhNKgiFDI8xUbahy4r6QpzgoF+0+dz+MA1NzQCQCsRGieS63OD1BKrzRsNxzls5Z9rKzBT6CpWpiaiOg4mmW0yeino/L9zz9Gf5kAJr813bpNr+rH/E8MPd0pZf+6hv37FaVCM7RN1V7CkkCDnRAxwxEK8pDgZhRjZOw7gKutPOiOoTO9ptjh2Jcrds714HitX2HI3RsRY+yyAOcb8XI27m4daSEGCJCuu/TJwXTE4ul54MWsi8MrcDlZN9DOjckiJIqVI8IbvhM+OUAP4FUIfZJJrIVa8WFwxcsMmjlLTxp/I7+JfdvZjJSk3j1yYvbWFviyoSkpQgw2hIDhZxCg083Z6qS467g5H9Uz3fQc+Ss0K0Mud6RcZTU9RqCcp+h92tUc8+gDxQ2NwJsG5vcmSRwf5KHKvsWjt6yK4OHxCpkLYi31eJZtv2EjQGXX1gYyhc/2wQ+cHPvbgBzIfhXetbZKpSxoowAQO/J1i5oRs90h24kjTd4qJd3qspxk1lhZcEC8IkfZXjNgjEQI=");
//
// OneDriveFolder folder = new OneDriveFolder(api, "PDF");
//
// for (OneDriveItem.Metadata metadata : OneDriveFolder.getRoot(api)) {
// System.out.println(metadata.getName());
// if (metadata.isFile()) {
// }
// }
//
// // for (OneDriveItem.Metadata search : OneDriveFolder.getRoot(api).search("index.html")) {
// // System.out.println(search.getName());
// // }
//
// // OneDriveFile file = new OneDriveFile(api, "key.txt");
// // System.out.println(file);
// }
// }

View File

@@ -1,42 +0,0 @@
package im.zhaojun.onedrive.controller;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
@Controller
public class OneDriveController {
@Resource
private RestTemplate restTemplate;
@GetMapping("/onedirve/callback")
@ResponseBody
public String onedriveCallback(String code, HttpServletRequest request) {
RestTemplate restTemplate = new RestTemplate();
HttpHeaders headers = new HttpHeaders();
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
headers.setContentType(type);
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
String json = "client_id=04a73532-6c16-4fe4-92e5-f2cd125ed553&redirect_uri=http://localhost:8080/onedirve/callback&client_secret=2gY/t?*Eff6i36TgKTtiG*08/k]@.I4[&code=" + code + "&grant_type=authorization_code";
HttpRequest post = HttpUtil.createPost("https://login.microsoftonline.com/common/oauth2/v2.0/token");
post.body(json, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
System.out.println(response.body());
return response.body();
}
}

View File

@@ -1,141 +0,0 @@
package im.zhaojun.qiniu.service;
import cn.hutool.core.util.URLUtil;
import com.qiniu.common.Zone;
import com.qiniu.storage.BucketManager;
import com.qiniu.storage.Configuration;
import com.qiniu.storage.model.FileInfo;
import com.qiniu.storage.model.FileListing;
import com.qiniu.util.Auth;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class QiniuServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(QiniuServiceImpl.class);
@Value("${zfile.cache.timeout}")
private Long timeout;
@Resource
private StorageConfigService storageConfigService;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String ACCESS_KEY = "accessKey";
private static final String SECRET_KEY = "secretKey";
private static final String DOMAIN_KEY = "domain";
private BucketManager bucketManager;
private Auth auth;
private String bucketName;
private String domain;
private boolean isPrivate;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.QINIU);
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
Configuration cfg = new Configuration(Zone.autoZone());
auth = Auth.create(accessKey, secretKey);
bucketManager = new BucketManager(auth, cfg);
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
isPrivate = bucketManager.getBucketInfo(bucketName).getPrivate() == 1;
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.QINIU.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) throws Exception {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
// 每次迭代的长度限制, 最大1000, 推荐值 1000
int limit = 1000;
// 指定目录分隔符, 列出所有公共前缀(模拟列出目录效果). 缺省值为空字符串
String delimiter = "/";
// 列举空间文件列表
FileListing fileListing = bucketManager.listFilesV2(bucketName, path, "", limit, delimiter);
for (FileInfo item : fileListing.items) {
String fileKey = item.key;
String fileName = fileKey.substring(path.length());
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(fileName);
fileItemDTO.setSize(item.fsize);
fileItemDTO.setTime(new Date(item.putTime / 1000));
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
fileItemList.add(fileItemDTO);
}
String[] commonPrefixes = fileListing.commonPrefixes;
for (String commonPrefix : commonPrefixes) {
if ("/".equals(commonPrefix)) {
continue;
}
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(commonPrefix.substring(0, commonPrefix.length() - 1));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
String url = URLUtil.complateUrl(domain, path);
if (isPrivate) {
url = auth.privateDownloadUrl(url, timeout);
}
return url;
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.QINIU;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,128 +0,0 @@
package im.zhaojun.tencent;
import cn.hutool.core.util.URLUtil;
import com.qcloud.cos.COSClient;
import com.qcloud.cos.ClientConfig;
import com.qcloud.cos.auth.BasicCOSCredentials;
import com.qcloud.cos.auth.COSCredentials;
import com.qcloud.cos.model.COSObjectSummary;
import com.qcloud.cos.model.ListObjectsRequest;
import com.qcloud.cos.model.ObjectListing;
import com.qcloud.cos.region.Region;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Service
public class TencentServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(TencentServiceImpl.class);
@Resource
private StorageConfigService storageConfigService;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String SECRET_ID_KEY = "secretId";
private static final String SECRET_KEY = "secretKey";
private static final String DOMAIN_KEY = "domain";
private static final String ENDPOINT_KEY = "endPoint";
@Value("${zfile.cache.timeout}")
private Long timeout;
private String bucketName;
private String domain;
private COSClient cosClient;
private boolean isInitialized;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.TENCENT);
String secretId = stringStorageConfigMap.get(SECRET_ID_KEY).getValue();
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
String regionName = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
Region region = new Region(regionName);
ClientConfig clientConfig = new ClientConfig(region);
cosClient = new COSClient(cred, clientConfig);
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.TENCENT.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
ObjectListing objectListing = cosClient.listObjects(new ListObjectsRequest().withBucketName(bucketName).withDelimiter("/").withPrefix(path));
for (COSObjectSummary s : objectListing.getObjectSummaries()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(s.getKey().substring(path.length()));
fileItemDTO.setSize(s.getSize());
fileItemDTO.setTime(s.getLastModified());
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
fileItemList.add(fileItemDTO);
}
for (String commonPrefix : objectListing.getCommonPrefixes()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(commonPrefix.substring(path.length(), commonPrefix.length() - 1));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
URL url = cosClient.generatePresignedUrl(bucketName, path, expirationDate);
return URLUtil.complateUrl(domain, url.getFile());
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.TENCENT;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,115 +0,0 @@
package im.zhaojun.upyun.service;
import cn.hutool.core.util.URLUtil;
import com.UpYun;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@Service
public class UpYunServiceImpl implements FileService {
private static final Logger log = LoggerFactory.getLogger(UpYunServiceImpl.class);
@Resource
private StorageConfigService storageConfigService;
private static final String BUCKET_NAME_KEY = "bucket-name";
private static final String USERNAME_KEY = "username";
private static final String PASSWORD_KEY = "password";
private static final String DOMAIN_KEY = "domain";
private static final String BASE_PATH = "base-path";
private String domain;
private UpYun upYun;
private boolean isInitialized;
private String basePath;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.UPYUN);
String bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
String username = stringStorageConfigMap.get(USERNAME_KEY).getValue();
String password = stringStorageConfigMap.get(PASSWORD_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
basePath = stringStorageConfigMap.get(BASE_PATH).getValue();
upYun = new UpYun(bucketName, username, password);
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.UPYUN.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) throws Exception {
ArrayList<FileItemDTO> fileItemList = new ArrayList<>();
String nextMark = null;
do {
HashMap<String, String> hashMap = new HashMap<>(24);
hashMap.put("x-list-iter", nextMark);
hashMap.put("x-list-limit", "100");
UpYun.FolderItemIter folderItemIter = upYun.readDirIter(URLUtil.encode(basePath + path), hashMap);
nextMark = folderItemIter.iter;
ArrayList<UpYun.FolderItem> folderItems = folderItemIter.files;
if (folderItems != null) {
for (UpYun.FolderItem folderItem : folderItems) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(folderItem.name);
fileItemDTO.setSize(folderItem.size);
fileItemDTO.setTime(folderItem.date);
fileItemDTO.setPath(path);
if ("folder".equals(folderItem.type)) {
fileItemDTO.setType(FileTypeEnum.FOLDER);
} else {
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(basePath + path, fileItemDTO.getName())));
}
fileItemList.add(fileItemDTO);
}
}
} while (!"g2gCZAAEbmV4dGQAA2VvZg".equals(nextMark));
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
return URLUtil.complateUrl(domain, path);
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.UPYUN;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,14 +1,15 @@
package im.zhaojun;
package im.zhaojun.zfile;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
import org.springframework.scheduling.annotation.EnableAsync;
/**
* @author zhaojun
*/
@EnableAsync
@SpringBootApplication
@EnableCaching
@EnableAspectJAutoProxy(exposeProxy = true)
public class ZfileApplication {

View File

@@ -0,0 +1,65 @@
package im.zhaojun.zfile.aspect;
import im.zhaojun.zfile.cache.ZFileCache;
import im.zhaojun.zfile.model.dto.FileItemDTO;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.service.DriveConfigService;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.List;
/**
* @author zhaojun
* 缓存切面类, 用于访问文件夹时, 缓存文件列表内容.
*/
@Aspect
@Component
public class FileListCacheAop {
@Resource
private ZFileCache zFileCache;
@Resource
private DriveConfigService driveConfigService;
/**
* 缓存切面, 如果此驱动器开启了缓存, 则从缓存中取数据, 没有开启, 则直接调用方法.
*/
@Around(value = "execution(public * im.zhaojun.zfile.service.base.AbstractBaseFileService.fileList(..))")
public Object around(ProceedingJoinPoint point) throws Throwable {
List<FileItemDTO> result;
// 获取请求路径
Object[] args = point.getArgs();
String path = String.valueOf(args[0]);
// 获取当前驱动器
AbstractBaseFileService fileService = ((AbstractBaseFileService) point.getTarget());
Integer driveId = fileService.driveId;
// 判断驱动器是否开启了缓存
DriveConfig driveConfig = driveConfigService.findById(driveId);
boolean enableCache = driveConfig.getEnableCache();
if (enableCache) {
List<FileItemDTO> cacheFileList = zFileCache.get(driveId, path);
if (cacheFileList == null) {
result = (List<FileItemDTO>) point.proceed();
zFileCache.put(driveId, path, result);
} else {
result = cacheFileList;
}
} else {
result = (List<FileItemDTO>) point.proceed();
}
return result;
}
}

View File

@@ -0,0 +1,19 @@
package im.zhaojun.zfile.cache;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author zhaojun
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class DriveCacheKey {
private Integer driveId;
private String key;
}

View File

@@ -0,0 +1,43 @@
package im.zhaojun.zfile.cache;
import cn.hutool.cache.impl.CacheObj;
import cn.hutool.cache.impl.TimedCache;
import im.zhaojun.zfile.context.DriveContext;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.util.SpringContextHolder;
import lombok.extern.slf4j.Slf4j;
import java.util.Map;
/**
* @author zhaojun
*/
@Slf4j
public class MyTimedCache<K, V> extends TimedCache<K, V> {
private DriveContext driveContext;
public MyTimedCache(long timeout) {
super(timeout);
}
public MyTimedCache(long timeout, Map<K, CacheObj<K, V>> map) {
super(timeout, map);
}
@Override
protected void onRemove(K key, V cachedObject) {
log.debug("尝试刷新缓存: " + key);
if (driveContext == null) {
driveContext = SpringContextHolder.getBean(DriveContext.class);
}
DriveCacheKey cacheKey = (DriveCacheKey) key;
AbstractBaseFileService baseFileService = driveContext.getDriveService(cacheKey.getDriveId());
try {
baseFileService.fileList(cacheKey.getKey());
} catch (Exception e) {
log.error("尝试刷新驱动器 {} 的 {} 失败, ", cacheKey.getDriveId(), cacheKey.getKey());
e.printStackTrace();
}
}
}

View File

@@ -0,0 +1,315 @@
package im.zhaojun.zfile.cache;
import cn.hutool.cache.impl.CacheObj;
import cn.hutool.core.util.StrUtil;
import im.zhaojun.zfile.model.constant.ZFileConstant;
import im.zhaojun.zfile.model.dto.FileItemDTO;
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.repository.DriverConfigRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
/**
* ZFile 缓存类
*
* @author zhaojun
*/
@Component
public class ZFileCache {
@Value("${zfile.cache.timeout}")
private long timeout;
@Value("${zfile.cache.auto-refresh.interval}")
private long autoRefreshInterval;
/**
* 缓存 map 对象.
*
* ConcurrentMap<Integer, ConcurrentHashMap<String, List<FileItemDTO>>>
* ConcurrentMap<driveId, ConcurrentHashMap<key, value>>
*
* driveId: 驱动器 ID
* key: 文件夹路径
* value: 文件夹中内容
*/
private ConcurrentMap<Integer, MyTimedCache<DriveCacheKey, List<FileItemDTO>>> drivesCache = new ConcurrentHashMap<>();
/**
* 系统设置缓存
*/
private SystemConfigDTO systemConfigCache;
@Resource
private DriverConfigRepository driverConfigRepository;
/**
* 写入缓存
*
* @param driveId
* 驱动器 ID
*
* @param key
* 文件夹路径
*
* @param value
* 文件夹中列表
*/
public synchronized void put(Integer driveId, String key, List<FileItemDTO> value) {
getCacheByDriveId(driveId).put(new DriveCacheKey(driveId, key), value);
}
/**
* 获取指定驱动器, 某个文件夹的名称
*
* @param driveId
* 驱动器 ID
*
* @param key
* 文件夹路径
*
* @return 驱动器中文件夹的内容
*/
public List<FileItemDTO> get(Integer driveId, String key) {
return getCacheByDriveId(driveId).get(new DriveCacheKey(driveId, key), false);
}
/**
* 清空指定驱动器的缓存.
*
* @param driveId
* 驱动器 ID
*/
public void clear(Integer driveId) {
getCacheByDriveId(driveId).clear();
}
/**
* 获取指定驱动器中已缓存文件夹数量
*
* @param driveId
* 驱动器 ID
*
* @return 已缓存文件夹数量
*/
public int cacheCount(Integer driveId) {
return getCacheByDriveId(driveId).size();
}
/**
* 指定驱动器, 根据文件及文件名查找相关的文件
*
* @param driveId
* 驱动器 ID
*
* @param key
* 搜索键, 可匹配文件夹名称和文件名称.
*
* @return 搜索结果, 包含文件夹和文件.
*/
public List<FileItemDTO> find(Integer driveId, String key) {
List<FileItemDTO> result = new ArrayList<>();
DriveConfig driveConfig = driverConfigRepository.getOne(driveId);
boolean searchContainEncryptedFile = driveConfig.getSearchContainEncryptedFile();
boolean ignoreCase = driveConfig.getSearchIgnoreCase();
for (List<FileItemDTO> fileItemList : getCacheByDriveId(driveId)) {
// 过滤加密文件
if (!searchContainEncryptedFile && isEncryptedFolder(fileItemList)) {
continue;
}
for (FileItemDTO fileItemDTO : fileItemList) {
boolean testResult;
// 根据是否需要忽略大小写来匹配文件(夹)名
if (ignoreCase) {
testResult = StrUtil.containsIgnoreCase(fileItemDTO.getName(), key);
} else {
testResult = fileItemDTO.getName().contains(key);
}
if (testResult) {
result.add(fileItemDTO);
}
}
}
return result;
}
/**
* 获取所有缓存 key (文件夹名称)
*
* @return 所有缓存 key
*/
public Set<String> keySet(Integer driveId) {
Iterator<CacheObj<DriveCacheKey, List<FileItemDTO>>> cacheObjIterator = getCacheByDriveId(driveId).cacheObjIterator();
Set<String> keys = new HashSet<>();
while (cacheObjIterator.hasNext()) {
keys.add(cacheObjIterator.next().getKey().getKey());
}
return keys;
}
/**
* 从缓存中删除指定存储器的某个路径的缓存
*
* @param driveId
* 驱动器 ID
*
* @param key
* 文件夹路径
*/
public void remove(Integer driveId, String key) {
getCacheByDriveId(driveId).remove(new DriveCacheKey(driveId, key));
}
/**
* 更新缓存中的系统设置
*
* @param systemConfigCache
* 系统设置
*/
public void updateConfig(SystemConfigDTO systemConfigCache) {
this.systemConfigCache = systemConfigCache;
}
/**
* 从缓存中获取系统设置
*
* @return 系统设置
*/
public SystemConfigDTO getConfig() {
return this.systemConfigCache;
}
/**
* 清空系统设置缓存
*/
public void removeConfig() {
this.systemConfigCache = null;
}
/**
* 判断此文件夹是否为加密文件夹 (包含)
*
* @param list
* 文件夹中的内容
*
* @return 返回此文件夹是否是加密的 ().
*/
private boolean isEncryptedFolder(List<FileItemDTO> list) {
// 遍历文件判断是否包含
for (FileItemDTO fileItemDTO : list) {
if (Objects.equals(ZFileConstant.PASSWORD_FILE_NAME, fileItemDTO.getName())) {
return true;
}
}
return false;
}
/**
* 获取指定驱动器对应的缓存
*
* @param driveId
* 驱动器 ID
*
* @return 驱动器对应的缓存
*/
private synchronized MyTimedCache<DriveCacheKey, List<FileItemDTO>> getCacheByDriveId(Integer driveId) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache == null) {
driveCache = new MyTimedCache<>(timeout * 1000);
drivesCache.put(driveId, driveCache);
startAutoCacheRefresh(driveId);
}
return driveCache;
}
/**
* 获取指定驱动器的缓存命中数
*
* @param driveId
* 驱动器 ID
*
* @return 缓存命中数
*/
public int getHitCount(Integer driveId) {
return getCacheByDriveId(driveId).getHitCount();
}
/**
* 获取指定驱动器的缓存未命中数
*
* @param driveId
* 驱动器 ID
*
* @return 缓存未命中数
*/
public int getMissCount(Integer driveId) {
return getCacheByDriveId(driveId).getMissCount();
}
/**
* 开启缓存自动刷新, 仅当数据库设置为开启时, 才会真正开启缓存自动刷新.
*
* @param driveId
* 驱动器 ID
*/
public void startAutoCacheRefresh(Integer driveId) {
DriveConfig driveConfig = driverConfigRepository.findById(driveId).get();
Boolean autoRefreshCache = driveConfig.getAutoRefreshCache();
if (autoRefreshCache != null && autoRefreshCache) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache == null) {
driveCache = new MyTimedCache<>(timeout * 1000);
drivesCache.put(driveId, driveCache);
}
driveCache.schedulePrune(autoRefreshInterval * 1000);
}
}
/**
* 停止缓存自动刷新
*
* @param driveId
* 驱动器 ID
*/
public void stopAutoCacheRefresh(Integer driveId) {
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
if (driveCache != null) {
driveCache.cancelPruneSchedule();
}
}
}

View File

@@ -0,0 +1,56 @@
package im.zhaojun.zfile.config;
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
import im.zhaojun.zfile.model.entity.StorageConfig;
import im.zhaojun.zfile.service.StorageConfigService;
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.Collections;
import java.util.LinkedList;
/**
* @author zhaojun
*/
@Configuration
public class OneDriveConfig {
@Resource
private StorageConfigService storageConfigService;
@Resource
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
/**
* OneDrive 请求 RestTemplate, 会在请求头中添加 Bearer: Authorization {token} 信息, 用于 API 认证.
*/
@Bean
public RestTemplate oneDriveRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
ClientHttpRequestInterceptor interceptor = (httpRequest, bytes, clientHttpRequestExecution) -> {
HttpHeaders headers = httpRequest.getHeaders();
Integer driveId = Integer.valueOf(((LinkedList)headers.get("driveId")).get(0).toString());
StorageConfig accessTokenConfig =
storageConfigService.findByDriveIdAndKey(driveId, StorageConfigConstant.ACCESS_TOKEN_KEY);
String tokenValue = String.format("%s %s", "Bearer", accessTokenConfig.getValue());
httpRequest.getHeaders().add("Authorization", tokenValue);
return clientHttpRequestExecution.execute(httpRequest, bytes);
};
restTemplate.setInterceptors(Collections.singletonList(interceptor));
return restTemplate;
}
}

View File

@@ -0,0 +1,34 @@
package im.zhaojun.zfile.config;
import im.zhaojun.zfile.model.enums.StorageTypeEnumDeSerializerConvert;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.format.FormatterRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
/**
* @author zhaojun
*/
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {
@Override
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StorageTypeEnumDeSerializerConvert());
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory();
// 添加对 URL 中特殊符号的支持.
webServerFactory.addConnectorCustomizers(connector -> {
connector.setAttribute("relaxedPathChars", "<>[\\]^`{|}");
connector.setAttribute("relaxedQueryChars", "<>[\\]^`{|}");
});
return webServerFactory;
}
}

View File

@@ -1,12 +1,18 @@
package im.zhaojun.common.config;
package im.zhaojun.zfile.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpHeaders;
import org.springframework.http.client.ClientHttpResponse;
import org.springframework.http.converter.StringHttpMessageConverter;
import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
import java.util.Collections;
/**
* @author zhaojun
*/
@Configuration
public class ZFileConfiguration {
@@ -14,6 +20,14 @@ public class ZFileConfiguration {
public RestTemplate restTemplate(){
RestTemplate restTemplate = new RestTemplate();
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
restTemplate.setInterceptors(Collections.singletonList((request, body, execution) -> {
ClientHttpResponse response = execution.execute(request, body);
HttpHeaders headers = response.getHeaders();
headers.put("Content-Type", Collections.singletonList("application/text"));
return response;
}));
return restTemplate;
}

View File

@@ -0,0 +1,107 @@
package im.zhaojun.zfile.context;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.service.DriveConfigService;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.util.SpringContextHolder;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;
/**
* 驱动器上下文环境
* @author zhaojun
*/
@Component
@DependsOn("springContextHolder")
public class DriveContext implements ApplicationContextAware {
private static Map<Integer, AbstractBaseFileService> drivesServiceMap = new ConcurrentHashMap<>();
private static Map<StorageTypeEnum, Class<AbstractBaseFileService>> storageTypeEnumClassMap = new ConcurrentHashMap<>();
@Resource
private DriveConfigService driveConfigService;
/**
* 初始化指定驱动器的 Service, 添加到上下文环境中.
*
* @param driveId
* 驱动器 ID.
*/
public void initDrive(Integer driveId) {
AbstractBaseFileService baseFileService = getBeanByDriveId(driveId);
if (baseFileService != null) {
baseFileService.init(driveId);
drivesServiceMap.put(driveId, baseFileService);
}
}
/**
* 获取指定驱动器的 Service.
*
* @param driveId
* 驱动器 ID
*
* @return 驱动器对应的 Service
*/
public AbstractBaseFileService getDriveService(Integer driveId) {
return drivesServiceMap.get(driveId);
}
/**
* 销毁指定驱动器的 Service.
*
* @param driveId
* 驱动器 ID
*/
public void destroyDrive(Integer driveId) {
drivesServiceMap.remove(driveId);
}
/**
* 获取指定驱动器对应的 Service, 状态为未初始化
*
* @param driveId
* 驱动器 ID
*
* @return 驱动器对应未初始化的 Service
*/
private AbstractBaseFileService getBeanByDriveId(Integer driveId) {
StorageTypeEnum storageTypeEnum = driveConfigService.findStorageTypeById(driveId);
Map<String, AbstractBaseFileService> beansOfType = SpringContextHolder.getBeansOfType(AbstractBaseFileService.class);
for (AbstractBaseFileService value : beansOfType.values()) {
if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) {
return SpringContextHolder.getBean(value.getClass());
}
}
return null;
}
/**
* 项目启动时, 自动调用所有驱动器进行初始化.
*/
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
List<DriveConfig> list = driveConfigService.list();
for (DriveConfig driveConfig : list) {
initDrive(driveConfig.getId());
}
}
}

View File

@@ -1,21 +1,26 @@
package im.zhaojun.common.config;
package im.zhaojun.zfile.context;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.stereotype.Component;
import java.util.Map;
@Component
public class StorageTypeFactory implements ApplicationContextAware {
private static Map<String, FileService> storageTypeEnumFileServiceMap;
/**
* 存储类型工厂类
* @author zhaojun
*/
@Component
public class StorageTypeContext implements ApplicationContextAware {
private static Map<String, AbstractBaseFileService> storageTypeEnumFileServiceMap;
private static ApplicationContext applicationContext;
/**
* 项目启动时执行
*/
@@ -24,15 +29,16 @@ public class StorageTypeFactory implements ApplicationContextAware {
applicationContext = act;
// 获取 Spring 容器中所有 FileService 类型的类
storageTypeEnumFileServiceMap = act.getBeansOfType(FileService.class);
storageTypeEnumFileServiceMap = act.getBeansOfType(AbstractBaseFileService.class);
}
/**
* 获取指定存储类型 Service
*/
public static FileService getStorageTypeService(StorageTypeEnum type) {
FileService result = null;
for (FileService fileService : storageTypeEnumFileServiceMap.values()) {
public static AbstractBaseFileService getStorageTypeService(StorageTypeEnum type) {
AbstractBaseFileService result = null;
for (AbstractBaseFileService fileService : storageTypeEnumFileServiceMap.values()) {
if (fileService.getStorageTypeEnum() == type) {
result = fileService;
break;
@@ -41,7 +47,9 @@ public class StorageTypeFactory implements ApplicationContextAware {
return result;
}
public static ApplicationContext getApplicationContext() {
return applicationContext;
}
}

View File

@@ -0,0 +1,58 @@
package im.zhaojun.zfile.controller;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.util.AudioHelper;
import im.zhaojun.zfile.util.HttpUtil;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
/**
* 公共 Controller
* @author zhaojun
*/
@RestController
@RequestMapping("/common")
public class CommonController {
/**
* 返回系统支持的所有存储策略
*
* @return 存储策略
*/
@GetMapping("/support-strategy")
public ResultBean supportStrategy() {
return ResultBean.successData(StorageTypeEnum.values());
}
/**
* 获取文件内容, 仅限用于 txt, md, ini 等普通文本文件.
*
* @param url
* 文件路径
*
* @return 文件内容
*/
@GetMapping("/content")
public ResultBean getContent(String url) {
return ResultBean.successData(HttpUtil.getTextContent(url));
}
/**
* 获取音频文件信息
*
* @param url
* 文件 URL
*
* @return 音频信息, 标题封面等信息
*/
@GetMapping("/audio-info")
public ResultBean getAudioInfo(String url) throws Exception {
return ResultBean.success(AudioHelper.getAudioInfo(url));
}
}

View File

@@ -0,0 +1,220 @@
package im.zhaojun.zfile.controller;
import im.zhaojun.zfile.model.constant.ZFileConstant;
import im.zhaojun.zfile.model.dto.FileItemDTO;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.model.dto.SystemFrontConfigDTO;
import im.zhaojun.zfile.model.support.FilePageModel;
import im.zhaojun.zfile.service.DriveConfigService;
import im.zhaojun.zfile.service.SystemConfigService;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.context.DriveContext;
import im.zhaojun.zfile.util.FileComparator;
import im.zhaojun.zfile.util.HttpUtil;
import im.zhaojun.zfile.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.HttpClientErrorException;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
/**
* 前台文件管理
* @author zhaojun
*/
@Slf4j
@RequestMapping("/api")
@RestController
public class FileController {
@Resource
private SystemConfigService systemConfigService;
@Resource
private DriveContext driveContext;
@Resource
private DriveConfigService driveConfigService;
/**
* 滚动加载每页条数.
*/
private static final Integer PAGE_SIZE = 30;
/**
* 获取所有驱动器
*
* @return 所有驱动器
*/
@GetMapping("/drive/list")
public ResultBean drives() {
return ResultBean.success(driveConfigService.list());
}
/**
* 获取某个驱动器下, 指定路径的数据, 每页固定 {@link #PAGE_SIZE} 条数据.
*
* @param driveId
* 驱动器 ID
*
* @param path
* 路径
*
* @param password
* 文件夹密码, 某些文件夹需要密码才能访问, 当不需要密码时, 此参数可以为空
*
* @param page
* 页数
*
* @return 当前路径下所有文件及文件夹
*/
@GetMapping("/list/{driveId}")
public ResultBean list(@PathVariable(name = "driveId") Integer driveId,
@RequestParam(defaultValue = "/") String path,
@RequestParam(required = false) String password,
@RequestParam(defaultValue = "1") Integer page) throws Exception {
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + path + "/"));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
String expectedPasswordContent;
try {
expectedPasswordContent = HttpUtil.getTextContent(fileItemDTO.getUrl());
} catch (HttpClientErrorException httpClientErrorException) {
log.debug("尝试重新获取密码文件缓存中链接后仍失败", httpClientErrorException);
try {
String fullPath = StringUtils.removeDuplicateSeparator(fileItemDTO.getPath() + "/" + fileItemDTO.getName());
FileItemDTO fileItem = fileService.getFileItem(fullPath);
expectedPasswordContent = HttpUtil.getTextContent(fileItem.getUrl());
} catch (Exception e) {
log.debug("尝试重新获取密码文件链接后仍失败, 已暂时取消密码", e);
break;
}
}
if (Objects.equals(expectedPasswordContent, password)) {
break;
}
if (password != null && !"".equals(password)) {
return ResultBean.error("密码错误.", ResultBean.INVALID_PASSWORD);
}
return ResultBean.error("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
}
}
return ResultBean.successData(getSortedPagingData(fileItemList, page));
}
/**
* 获取系统配置信息和当前页的标题, 页面文档信息
*
* @param driveId
* 驱动器 ID
*
* @return 返回指定存储器的系统配置信息
*/
@GetMapping("/config/{driveId}")
public ResultBean getConfig(@PathVariable(name = "driveId") Integer driveId, String path) {
SystemFrontConfigDTO systemConfig = systemConfigService.getSystemFrontConfig(driveId);
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
String fullPath = StringUtils.removeDuplicateSeparator(path + "/" + ZFileConstant.README_FILE_NAME);
try {
FileItemDTO fileItem = fileService.getFileItem(fullPath);
String readme = HttpUtil.getTextContent(fileItem.getUrl());
systemConfig.setReadme(readme);
} catch (Exception e) {
// ignore
}
return ResultBean.successData(systemConfig);
}
@GetMapping("/search/{driveId}")
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String order,
@RequestParam(defaultValue = "1") Integer page,
@PathVariable("driveId") Integer driveId) {
return ResultBean.error("暂不支持搜索功能");
}
/**
* 过滤文件列表, 去除密码, 文档文件.
*
* @param fileItemList
* 文件列表
*/
private void filterFileList(List<FileItemDTO> fileItemList) {
if (fileItemList == null) {
return;
}
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.README_FILE_NAME.equals(fileItem.getName()));
}
/**
* 对传入的文件列表, 按照文件名进行排序, 然后取相应页数的文件
*
* @param fileItemList
* 文件列表
*
* @param page
* 要取的页数
*
* @return 排序及分页后的那段数据
*/
private FilePageModel getSortedPagingData(List<FileItemDTO> fileItemList, Integer page) {
ArrayList<FileItemDTO> copy = new ArrayList<>(Arrays.asList(new FileItemDTO[fileItemList.size()]));
Collections.copy(copy, fileItemList);
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
copy.sort(new FileComparator());
filterFileList(copy);
int total = copy.size();
int totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
if (page > totalPage) {
return new FilePageModel(totalPage, Collections.emptyList());
}
int start = (page - 1) * PAGE_SIZE;
int end = page * PAGE_SIZE;
end = Math.min(end, total);
return new FilePageModel(totalPage, copy.subList(start, end));
}
/**
* 获取指定路径下的文件信息内容
*
* @param driveId
* 驱动器 ID
*
* @param path
* 文件全路径
*
* @return 该文件的名称, 路径, 大小, 下载地址等信息.
*/
@GetMapping("/directlink/{driveId}")
public ResultBean directlink(@PathVariable(name = "driveId") Integer driveId, String path) {
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
return ResultBean.successData(fileService.getFileItem(path));
}
}

View File

@@ -0,0 +1,53 @@
package im.zhaojun.zfile.controller;
import cn.hutool.crypto.SecureUtil;
import im.zhaojun.zfile.controller.admin.AdminController;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
import im.zhaojun.zfile.service.StorageConfigService;
import im.zhaojun.zfile.service.SystemConfigService;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 系统安装初始化
* @author zhaojun
*/
@RestController
public class InstallController {
@Resource
private SystemConfigService systemConfigService;
@Resource
private StorageConfigService storageConfigService;
@Resource
private AdminController adminController;
@GetMapping("/is-installed")
public ResultBean isInstall() {
if (!StringUtils.isEmpty(systemConfigService.getAdminUsername())) {
return ResultBean.error("请勿重复初始化");
}
return ResultBean.success();
}
@PostMapping("/install")
public ResultBean install(SystemConfigDTO systemConfigDTO) {
if (!StringUtils.isEmpty(systemConfigService.getAdminUsername())) {
return ResultBean.error("请勿重复初始化.");
}
systemConfigDTO.setPassword(SecureUtil.md5(systemConfigDTO.getPassword()));
systemConfigService.updateSystemConfig(systemConfigDTO);
return ResultBean.success();
}
}

View File

@@ -0,0 +1,49 @@
package im.zhaojun.zfile.controller;
import im.zhaojun.zfile.service.impl.LocalServiceImpl;
import im.zhaojun.zfile.context.DriveContext;
import im.zhaojun.zfile.util.FileUtil;
import im.zhaojun.zfile.util.StringUtils;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.HandlerMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
/**
* 本地存储 Controller
* @author zhaojun
*/
@Controller
public class LocalController {
@Resource
private DriveContext driveContext;
/**
* 本地存储下载指定文件
*
* @param driveId
* 驱动器 ID
*
* @return 文件
*/
@GetMapping("/file/{driveId}/**")
@ResponseBody
public ResponseEntity<Object> downAttachment(@PathVariable("driveId") Integer driveId, final HttpServletRequest request) {
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
AntPathMatcher apm = new AntPathMatcher();
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
LocalServiceImpl localService = (LocalServiceImpl) driveContext.getDriveService(driveId);
return FileUtil.export(new File(StringUtils.concatPath(localService.getFilePath(), filePath)));
}
}

View File

@@ -0,0 +1,43 @@
package im.zhaojun.zfile.controller;
import im.zhaojun.zfile.model.support.OneDriveToken;
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import javax.annotation.Resource;
/**
* @author zhaojun
*/
@Controller
@RequestMapping("/onedrive")
public class OneDriveController {
@Resource
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
@GetMapping("/callback")
public String oneDriveCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveServiceImpl.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";
}
@GetMapping("/china-callback")
public String oneDriveChinaCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveChinaServiceImpl.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";
}
}

View File

@@ -0,0 +1,70 @@
package im.zhaojun.zfile.controller;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.zfile.model.constant.ZFileConstant;
import im.zhaojun.zfile.model.dto.FileItemDTO;
import im.zhaojun.zfile.model.enums.FileTypeEnum;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.context.DriveContext;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.servlet.HandlerMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Objects;
/**
* @author Zhao Jun
*/
@Controller
public class PageController {
@Resource
private DriveContext driveContext;
/**
* 获取指定驱动器, 某个文件的直链, 然后重定向过去.
* @param driveId
* 驱动器 ID
*
* @return 重定向至文件直链
*/
@GetMapping("/directlink/{driveId}/**")
public String directlink(@PathVariable("driveId") Integer driveId, final HttpServletRequest request) {
String path = (String) request.getAttribute(
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
AntPathMatcher apm = new AntPathMatcher();
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
if (filePath.length() > 0 && filePath.charAt(0) != ZFileConstant.PATH_SEPARATOR_CHAR) {
filePath = "/" + filePath;
}
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
FileItemDTO fileItem = fileService.getFileItem(filePath);
String url = fileItem.getUrl();
int queryIndex = url.indexOf('?');
if (queryIndex != -1) {
String origin = url.substring(0, queryIndex);
String queryString = url.substring(queryIndex + 1);
url = URLUtil.encode(origin) + "?" + URLUtil.encode(queryString);
} else {
url = URLUtil.encode(url);
}
if (Objects.equals(fileItem.getType(), FileTypeEnum.FOLDER)) {
return "redirect:" + fileItem.getUrl();
} else {
return "redirect:" + url;
}
}
}

View File

@@ -0,0 +1,119 @@
package im.zhaojun.zfile.controller.admin;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.ZipUtil;
import im.zhaojun.zfile.context.StorageTypeContext;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.model.dto.StorageStrategyDTO;
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
import im.zhaojun.zfile.model.entity.StorageConfig;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.model.support.SystemMonitorInfo;
import im.zhaojun.zfile.service.SystemConfigService;
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
import im.zhaojun.zfile.util.FileUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
* 管理后台接口
* @author zhaojun
*/
@RestController
@RequestMapping("/admin")
@Slf4j
public class AdminController {
@Resource
private SystemConfigService systemConfigService;
/**
* 获取系统配置
*/
@GetMapping("/config")
public ResultBean getConfig() {
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
return ResultBean.success(systemConfigDTO);
}
/**
* 更新系统配置
*/
@PostMapping("/config")
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) throws Exception {
systemConfigDTO.setId(1);
systemConfigService.updateSystemConfig(systemConfigDTO);
return ResultBean.success();
}
/**
* 修改管理员登陆密码
*/
@PostMapping("/update-pwd")
public ResultBean updatePwd(String username, String password) {
systemConfigService.updateUsernameAndPwd(username, password);
return ResultBean.success();
}
/**
* 获取指定存储策略的表单域
*
* @param storageType
* 存储策略
*
* @return 所有表单域
*/
@GetMapping("/strategy-form")
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
AbstractBaseFileService storageTypeService = StorageTypeContext.getStorageTypeService(storageType);
List<StorageConfig> storageConfigList = storageTypeService.storageStrategyConfigList();
return ResultBean.success(storageConfigList);
}
/**
* 返回支持的存储引擎.
*/
@GetMapping("/support-strategy")
public ResultBean supportStrategy() {
List<StorageStrategyDTO> result = new ArrayList<>();
StorageTypeEnum[] values = StorageTypeEnum.values();
return ResultBean.successData(values);
}
/**
* 系统日志下载
*/
@GetMapping("/log")
public ResponseEntity<Object> downloadLog(HttpServletResponse response) {
String userHome = System.getProperty("user.home");
File fileZip = ZipUtil.zip(userHome + "/.zfile/logs");
String currentDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
return FileUtil.export(fileZip, "ZFile 诊断日志 - " + currentDate + ".zip");
}
/**
* 获取系统监控信息
*/
@GetMapping("monitor")
public ResultBean monitor() {
return ResultBean.success(new SystemMonitorInfo());
}
}

View File

@@ -0,0 +1,72 @@
package im.zhaojun.zfile.controller.admin;
import im.zhaojun.zfile.model.dto.CacheInfoDTO;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.service.DriveConfigService;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
/**
* 缓存 Controller
*
* @author zhaojun
*/
@RestController
@RequestMapping("/admin/cache")
public class CacheController {
@Resource
private DriveConfigService driveConfigService;
@PostMapping("/{driveId}/enable")
public ResultBean enableCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.updateCacheStatus(driveId, true);
return ResultBean.success();
}
@PostMapping("/{driveId}/disable")
public ResultBean disableCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.updateCacheStatus(driveId, false);
return ResultBean.success();
}
@GetMapping("/{driveId}/info")
public ResultBean cacheInfo(@PathVariable("driveId") Integer driveId) {
CacheInfoDTO cacheInfo = driveConfigService.findCacheInfo(driveId);
return ResultBean.success(cacheInfo);
}
@PostMapping("/{driveId}/refresh")
public ResultBean refreshCache(@PathVariable("driveId") Integer driveId, String key) throws Exception {
driveConfigService.refreshCache(driveId, key);
return ResultBean.success();
}
@PostMapping("/{driveId}/auto-refresh/start")
public ResultBean enableAutoRefresh(@PathVariable("driveId") Integer driveId) {
driveConfigService.startAutoCacheRefresh(driveId);
return ResultBean.success();
}
@PostMapping("/{driveId}/auto-refresh/stop")
public ResultBean disableAutoRefresh(@PathVariable("driveId") Integer driveId) {
driveConfigService.stopAutoCacheRefresh(driveId);
return ResultBean.success();
}
@PostMapping("/{driveId}/clear")
public ResultBean clearCache(@PathVariable("driveId") Integer driveId) {
driveConfigService.clearCache(driveId);
return ResultBean.success();
}
}

View File

@@ -0,0 +1,81 @@
package im.zhaojun.zfile.controller.admin;
import im.zhaojun.zfile.model.dto.DriveConfigDTO;
import im.zhaojun.zfile.model.dto.ResultBean;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.service.DriveConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.DeleteMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
/**
* 驱动器 Controller
* @author zhaojun
*/
@RestController
@RequestMapping("/admin")
@Slf4j
public class DriveController {
@Resource
private DriveConfigService driveConfigService;
/**
* 获取所有驱动器列表
*
* @return 驱动器列表
*/
@GetMapping("drives")
public ResultBean driveList() {
List<DriveConfig> list = driveConfigService.list();
return ResultBean.success(list);
}
/**
* 获取指定驱动器基本信息及其参数
*
* @param id
* 驱动器 ID
*
* @return 驱动器基本信息信息
*/
@GetMapping("drive/{id}")
public ResultBean driveItem(@PathVariable Integer id) {
DriveConfigDTO driveConfig = driveConfigService.findDriveConfigDTOById(id);
return ResultBean.success(driveConfig);
}
/**
* 保存驱动器设置
*/
@PostMapping("drive")
public ResultBean saveDriveItem(@RequestBody DriveConfigDTO driveConfigDTO) {
driveConfigService.save(driveConfigDTO);
return ResultBean.success();
}
/**
* 删除驱动器设置
*
* @param id
* 驱动器 ID
*/
@DeleteMapping("drive/{id}")
public ResultBean deleteDriveItem(@PathVariable Integer id) {
driveConfigService.deleteById(id);
return ResultBean.success();
}
}

View File

@@ -1,6 +1,6 @@
package im.zhaojun.common.exception;
package im.zhaojun.zfile.exception;
import im.zhaojun.common.model.dto.ResultBean;
import im.zhaojun.zfile.model.dto.ResultBean;
import org.apache.catalina.connector.ClientAbortException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -13,14 +13,15 @@ import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 全局异常处理器
* @author zhaojun
*/
@ControllerAdvice
@ResponseBody
public class GlobleExceptionHandler {
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
@ExceptionHandler(SearchDisableException.class)
@ResponseBody
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
public ResultBean searchDisableExceptionHandler(SearchDisableException e) {
if (log.isDebugEnabled()) {
@@ -31,6 +32,7 @@ public class GlobleExceptionHandler {
@ExceptionHandler
@ResponseBody
@ResponseStatus
public ResultBean searchDisableExceptionHandler(StorageStrategyUninitializedException e) {
if (log.isDebugEnabled()) {
@@ -39,6 +41,16 @@ public class GlobleExceptionHandler {
return ResultBean.error(e.getMessage());
}
/**
* 不存在的文件异常
*/
@ExceptionHandler({NotExistFileException.class})
@ResponseBody
public ResultBean notExistFile(Exception ex) {
return ResultBean.error("文件不存在");
}
/**
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
*/
@@ -51,7 +63,32 @@ public class GlobleExceptionHandler {
// }
}
/**
* 文件预览异常
*/
@ExceptionHandler({PreviewException.class})
@ResponseBody
@ResponseStatus
public ResultBean previewException(PreviewException ex) {
return ResultBean.error(ex.getMessage());
}
/**
* 初始化异常
*/
@ExceptionHandler({InitializeException.class})
@ResponseBody
@ResponseStatus
public ResultBean initializeException(InitializeException ex) {
return ResultBean.error(ex.getMessage());
}
@ExceptionHandler
@ResponseBody
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
public ResultBean searchDisableExceptionHandler(Exception e) {
if (log.isDebugEnabled()) {

View File

@@ -1,7 +1,8 @@
package im.zhaojun.common.exception;
package im.zhaojun.zfile.exception;
/**
* 对象存储初始化异常
* @author zhaojun
*/
public class InitializeException extends RuntimeException {

View File

@@ -0,0 +1,28 @@
package im.zhaojun.zfile.exception;
/**
* @author zhaojun
*/
public class NotExistFileException extends RuntimeException {
public NotExistFileException() {
super();
}
public NotExistFileException(String message) {
super(message);
}
public NotExistFileException(String message, Throwable cause) {
super(message, cause);
}
public NotExistFileException(Throwable cause) {
super(cause);
}
protected NotExistFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -0,0 +1,28 @@
package im.zhaojun.zfile.exception;
/**
* 文件预览异常类
* @author zhaojun
*/
public class PreviewException extends RuntimeException {
public PreviewException() {
}
public PreviewException(String message) {
super(message);
}
public PreviewException(String message, Throwable cause) {
super(message, cause);
}
public PreviewException(Throwable cause) {
super(cause);
}
public PreviewException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}

View File

@@ -1,5 +1,8 @@
package im.zhaojun.common.exception;
package im.zhaojun.zfile.exception;
/**
* @author zhaojun
*/
public class SearchDisableException extends RuntimeException {
public SearchDisableException() {

View File

@@ -1,7 +1,8 @@
package im.zhaojun.common.exception;
package im.zhaojun.zfile.exception;
/**
* 存储策略未初始化异常
* @author zhaojun
*/
public class StorageStrategyUninitializedException extends RuntimeException {

View File

@@ -1,7 +1,8 @@
package im.zhaojun.common.exception;
package im.zhaojun.zfile.exception;
/**
* 未知的存储类型异常
* @author zhaojun
*/
public class UnknownStorageTypeException extends RuntimeException {

View File

@@ -1,4 +1,4 @@
package im.zhaojun.common.config;
package im.zhaojun.zfile.filter;
import org.springframework.http.HttpHeaders;
import org.springframework.web.cors.CorsUtils;
@@ -14,6 +14,7 @@ import java.io.IOException;
/**
* 开启跨域支持. 一般用于开发环境, 或前后端分离部署时开启.
* @author zhaojun
*/
public class CorsFilter extends GenericFilterBean {
@@ -22,7 +23,6 @@ public class CorsFilter extends GenericFilterBean {
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
// Set customized header
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, httpServletRequest.getHeader(HttpHeaders.ORIGIN));
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_HEADERS, "Origin, X-Requested-With, Content-Type, Accept");
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, OPTIONS");
@@ -33,4 +33,5 @@ public class CorsFilter extends GenericFilterBean {
chain.doFilter(httpServletRequest, httpServletResponse);
}
}
}

View File

@@ -1,4 +1,4 @@
package im.zhaojun.common.security;
package im.zhaojun.zfile.filter;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
@@ -6,6 +6,9 @@ import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;
/**
* @author zhaojun
*/
@Configuration
public class MyCorsFilter {

View File

@@ -0,0 +1,40 @@
package im.zhaojun.zfile.model.constant;
/**
* @author zhaojun
*/
public class StorageConfigConstant {
public static final String BUCKET_NAME_KEY = "bucketName";
public static final String SECRET_ID_KEY = "secretId";
public static final String ACCESS_KEY = "accessKey";
public static final String SECRET_KEY = "secretKey";
public static final String ENDPOINT_KEY = "endPoint";
public static final String BASE_PATH = "basePath";
public static final String DOMAIN_KEY = "domain";
public static final String USERNAME_KEY = "username";
public static final String PASSWORD_KEY = "password";
public static final String HOST_KEY = "host";
public static final String PORT_KEY = "port";
public static final String FILE_PATH_KEY = "filePath";
public static final String ACCESS_TOKEN_KEY = "accessToken";
public static final String REFRESH_TOKEN_KEY = "refreshToken";
public static final String PATH_STYLE = "pathStyle";
public static final String IS_PRIVATE = "isPrivate";
}

View File

@@ -1,15 +1,18 @@
package im.zhaojun.common.model.constant;
package im.zhaojun.zfile.model.constant;
/**
* @author zhaojun
*/
public class SystemConfigConstant {
public static final String SITE_NAME = "siteName";
public static final String INFO_ENABLE = "infoEnable";
public static final String SEARCH_ENABLE = "searchEnable";
public static final String SEARCH_IGNORE_CASE = "searchIgnoreCase";
public static final String ENABLE_CACHE = "enableCache";
public static final String STORAGE_STRATEGY = "storageStrategy";
public static final String USERNAME = "username";

View File

@@ -0,0 +1,63 @@
package im.zhaojun.zfile.model.constant;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
/**
* @author zhaojun
*/
@Configuration
public class ZFileConstant {
public final static String USER_HOME = System.getProperty("user.home");
public static final String AUDIO_TMP_PATH = "/.zfile/tmp/audio/";
public static final Character PATH_SEPARATOR_CHAR = '/';
public static final String PATH_SEPARATOR = "/";
/**
* 页面文档文件
*/
public static String README_FILE_NAME = "readme.md";
/**
* 密码文件
*/
public static String PASSWORD_FILE_NAME = "password.txt";
/**
* 最大支持文件大小为 ? MB 的音乐文件解析封面, 歌手等信息.
*/
public static Long AUDIO_MAX_FILE_SIZE_MB = 1L;
/**
* 最大支持文本文件大小为 ? KB 的文件内容.
*/
public static Long TEXT_MAX_FILE_SIZE_KB = 100L;
@Autowired(required = false)
public void setHeaderFileName(@Value("${zfile.constant.readme}") String headerFileName) {
ZFileConstant.README_FILE_NAME = headerFileName;
}
@Autowired(required = false)
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;
}
@Autowired(required = false)
public void setAudioMaxFileSizeMb(@Value("${zfile.preview.audio.maxFileSizeMb}") Long maxFileSizeMb) {
ZFileConstant.AUDIO_MAX_FILE_SIZE_MB = maxFileSizeMb;
}
@Autowired(required = false)
public void setTextMaxFileSizeMb(@Value("${zfile.preview.text.maxFileSizeKb}") Long maxFileSizeKb) {
ZFileConstant.TEXT_MAX_FILE_SIZE_KB = maxFileSizeKb;
}
}

View File

@@ -0,0 +1,27 @@
package im.zhaojun.zfile.model.dto;
import lombok.Data;
/**
* @author zhaojun
*/
@Data
public class AudioInfoDTO {
private String title;
private String artist;
private String cover;
private String src;
public static AudioInfoDTO buildDefaultAudioInfoDTO() {
AudioInfoDTO audioInfoDTO = new AudioInfoDTO();
audioInfoDTO.setTitle("未知歌曲");
audioInfoDTO.setArtist("未知");
audioInfoDTO.setCover("http://c.jun6.net/audio.png");
return audioInfoDTO;
}
}

View File

@@ -0,0 +1,19 @@
package im.zhaojun.zfile.model.dto;
import lombok.Data;
import java.util.Date;
import java.util.Set;
/**
* @author zhaojun
*/
@Data
public class CacheConfigDTO {
private Boolean enableCache;
private Boolean cacheFinish;
private Set<String> cacheKeys;
private Integer cacheDirectoryCount;
private Integer cacheFileCount;
private Date lastCacheAutoRefreshDate;
}

View File

@@ -0,0 +1,23 @@
package im.zhaojun.zfile.model.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.Set;
/**
* @author zhaojun
*/
@Data
@AllArgsConstructor
public class CacheInfoDTO {
private Integer cacheCount;
private Integer hitCount;
private Integer missCount;
private Set<String> cacheKeys;
}

View File

@@ -0,0 +1,33 @@
package im.zhaojun.zfile.model.dto;
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.model.enums.StorageTypeEnumJsonDeSerializerConvert;
import lombok.Data;
/**
* @author zhaojun
*/
@Data
public class DriveConfigDTO {
private Integer id;
private String name;
@JsonDeserialize(using = StorageTypeEnumJsonDeSerializerConvert.class)
private StorageTypeEnum type;
private boolean enableCache;
private boolean autoRefreshCache;
private boolean searchEnable;
private boolean searchIgnoreCase;
private boolean searchContainEncryptedFile;
private StorageStrategyConfig storageStrategyConfig;
}

View File

@@ -1,10 +1,13 @@
package im.zhaojun.common.model.dto;
package im.zhaojun.zfile.model.dto;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.zfile.model.enums.FileTypeEnum;
import java.io.Serializable;
import java.util.Date;
/**
* @author zhaojun
*/
public class FileItemDTO implements Serializable {
private String name;

View File

@@ -1,9 +1,12 @@
package im.zhaojun.common.model.dto;
package im.zhaojun.zfile.model.dto;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import java.util.Map;
/**
* @author zhaojun
*/
public class InstallModelDTO {
private String siteName;
private StorageTypeEnum storageStrategy;

View File

@@ -1,7 +1,10 @@
package im.zhaojun.common.model.dto;
package im.zhaojun.zfile.model.dto;
import java.io.Serializable;
/**
* @author zhaojun
*/
public class ResultBean implements Serializable {
private static final long serialVersionUID = -8276264968757808344L;
@@ -12,6 +15,8 @@ public class ResultBean implements Serializable {
public static final int REQUIRED_PASSWORD = -2;
public static final int INVALID_PASSWORD = -3;
private String msg = "操作成功";
private int code = SUCCESS;
@@ -40,6 +45,10 @@ public class ResultBean implements Serializable {
return success("操作成功", data);
}
public static ResultBean successPage(Object data, Long total) {
return success("操作成功", data);
}
public static ResultBean success(Object data) {
return success("操作成功", data);
}

View File

@@ -0,0 +1,23 @@
// package im.zhaojun.zfile.model.dto;
//
// import com.fasterxml.jackson.annotation.JsonProperty;
// import lombok.Data;
// import lombok.ToString;
//
// import java.io.Serializable;
//
// /**
// * @author zhaojun
// */
// @Data
// @ToString
// public class SiteConfigDTO implements Serializable {
//
// private static final long serialVersionUID = 8811196207046121740L;
//
// private String readme;
//
// @JsonProperty("viewConfig")
// private SystemConfigDTO systemConfigDTO;
//
// }

View File

@@ -0,0 +1,43 @@
package im.zhaojun.zfile.model.dto;
import lombok.Data;
/**
* @author zhaojun
*/
@Data
public class StorageStrategyConfig {
private String endPoint;
private String pathStyle;
private Boolean isPrivate;
private String accessKey;
private String secretKey;
private String bucketName;
private String host;
private String port;
private String accessToken;
private String refreshToken;
private String secretId;
private String filePath;
private String username;
private String password;
private String domain;
private String basePath;
}

View File

@@ -0,0 +1,23 @@
package im.zhaojun.zfile.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
/**
* @author Zhao Jun
*/
@Data
@AllArgsConstructor
@NoArgsConstructor
public class StorageStrategyDTO {
private String key;
private String description;
@JsonProperty(defaultValue = "false")
private Boolean available;
}

View File

@@ -0,0 +1,49 @@
package im.zhaojun.zfile.model.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.model.enums.StorageTypeEnumSerializerConvert;
import lombok.Data;
import lombok.ToString;
/**
* 系统设置传输类
*
* @author zhaojun
*/
@ToString
@Data
public class SystemConfigDTO {
@JsonIgnore
private Integer id;
private String siteName;
private String username;
@JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
private StorageTypeEnum storageStrategy;
@JsonIgnore
private String password;
private String domain;
private String customJs;
private String customCss;
private String tableSize;
private Boolean showOperator;
private Boolean showDocument;
private String announcement;
private Boolean showAnnouncement;
private String layout;
}

View File

@@ -0,0 +1,47 @@
package im.zhaojun.zfile.model.dto;
import com.fasterxml.jackson.annotation.JsonIgnore;
import lombok.Data;
import lombok.ToString;
/**
* 系统设置传输类
* @author zhaojun
*/
@ToString
@Data
public class SystemFrontConfigDTO {
@JsonIgnore
private Integer id;
private String siteName;
private Boolean searchEnable;
// @JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
// private StorageTypeEnum storageStrategy;
private String username;
private String domain;
private String customJs;
private String customCss;
private String tableSize;
private Boolean showOperator;
private Boolean showDocument;
private String announcement;
private Boolean showAnnouncement;
private String layout;
private String readme;
}

View File

@@ -0,0 +1,38 @@
package im.zhaojun.zfile.model.entity;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import lombok.Data;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* 驱动器
*
* @author zhaojun
*/
@Entity(name = "DRIVER_CONFIG")
@Data
public class DriveConfig {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private Integer id;
private String name;
private Boolean enableCache;
private Boolean autoRefreshCache;
private StorageTypeEnum type;
private Boolean searchEnable;
private Boolean searchIgnoreCase;
private Boolean searchContainEncryptedFile;
}

View File

@@ -1,10 +1,18 @@
package im.zhaojun.common.model;
package im.zhaojun.zfile.model.entity;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import lombok.Data;
import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
/**
* @author zhaojun
*/
@Entity(name = "STORAGE_CONFIG")
@Data
public class StorageConfig {
@@ -20,8 +28,16 @@ public class StorageConfig {
private String title;
@Lob
private String value;
private Integer driveId;
public StorageConfig(String key, String title) {
this.key = key;
this.title = title;
}
public Integer getId() {
return id;
}

View File

@@ -1,9 +1,17 @@
package im.zhaojun.common.model;
package im.zhaojun.zfile.model.entity;
import lombok.Data;
import javax.persistence.*;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Lob;
/**
* @author zhaojun
*/
@Entity(name = "SYSTEM_CONFIG")
@Data
public class SystemConfig {
@@ -15,6 +23,7 @@ public class SystemConfig {
@Column(name = "k")
private String key;
@Lob
private String value;
private String remark;

View File

@@ -1,5 +1,8 @@
package im.zhaojun.common.model.enums;
package im.zhaojun.zfile.model.enums;
/**
* @author zhaojun
*/
public enum FileTypeEnum {
/**

View File

@@ -1,21 +1,34 @@
package im.zhaojun.common.model.enums;
package im.zhaojun.zfile.model.enums;
import com.fasterxml.jackson.annotation.JsonFormat;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhaojun
*/
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
public enum StorageTypeEnum {
/**
* 当前系统支持的所有存储策略
*/
UPYUN("upyun", "又拍云 USS"),
QINIU("qiniu", "七牛云 KODO"),
HUAWEI("huawei", "华为云 OBS"),
ALIYUN("aliyun", "阿里云 OSS"),
FTP("ftp", "FTP"),
LOCAL("local", "本地存储"),
ALIYUN("aliyun", "阿里云 OSS"),
TENCENT("tencent", "腾讯云 COS"),
MINIO("minio", "MINIO");
UPYUN("upyun", "又拍云 USS"),
FTP("ftp", "FTP"),
UFILE("ufile", "UFile"),
HUAWEI("huawei", "华为云 OBS"),
MINIO("minio", "MINIO"),
S3("s3", "S3通用协议"),
ONE_DRIVE("onedrive", "OneDrive"),
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
QINIU("qiniu", "七牛云 KODO");
private String key;
private String description;
private static Map<String, StorageTypeEnum> enumMap = new HashMap<>();
@@ -30,9 +43,6 @@ public enum StorageTypeEnum {
this.description = description;
}
private String key;
private String description;
public String getKey() {
return key;
}
@@ -50,7 +60,7 @@ public enum StorageTypeEnum {
}
public static StorageTypeEnum getEnum(String value) {
return enumMap.get(value);
return enumMap.get(value.toLowerCase());
}
}

View File

@@ -1,8 +1,11 @@
package im.zhaojun.common.model.enums;
package im.zhaojun.zfile.model.enums;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* @author zhaojun
*/
@Converter(autoApply = true)
public class StorageTypeEnumConvert implements AttributeConverter<StorageTypeEnum, String> {

View File

@@ -1,11 +1,16 @@
package im.zhaojun.common.model.enums;
package im.zhaojun.zfile.model.enums;
import org.springframework.core.convert.converter.Converter;
import org.springframework.lang.NonNull;
/**
* @author zhaojun
*/
public class StorageTypeEnumDeSerializerConvert implements Converter<String, StorageTypeEnum> {
@Override
public StorageTypeEnum convert(String s) {
public StorageTypeEnum convert(@NonNull String s) {
return StorageTypeEnum.getEnum(s);
}
}
}

View File

@@ -0,0 +1,18 @@
package im.zhaojun.zfile.model.enums;
import com.fasterxml.jackson.core.JsonParser;
import com.fasterxml.jackson.databind.DeserializationContext;
import com.fasterxml.jackson.databind.JsonDeserializer;
import java.io.IOException;
/**
* @author zhaojun
*/
public class StorageTypeEnumJsonDeSerializerConvert extends JsonDeserializer<StorageTypeEnum> {
@Override
public StorageTypeEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
return StorageTypeEnum.getEnum(jsonParser.getText());
}
}

View File

@@ -1,4 +1,4 @@
package im.zhaojun.common.model.enums;
package im.zhaojun.zfile.model.enums;
import com.fasterxml.jackson.core.JsonGenerator;
import com.fasterxml.jackson.databind.JsonSerializer;
@@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* @author zhaojun
*/
public class StorageTypeEnumSerializerConvert extends JsonSerializer<StorageTypeEnum> {
@Override

View File

@@ -0,0 +1,20 @@
package im.zhaojun.zfile.model.support;
import im.zhaojun.zfile.model.dto.FileItemDTO;
import lombok.AllArgsConstructor;
import lombok.Data;
import java.util.List;
/**
* @author zhaojun
*/
@Data
@AllArgsConstructor
public class FilePageModel {
private int totalPage;
private List<FileItemDTO> fileList;
}

View File

@@ -0,0 +1,39 @@
package im.zhaojun.zfile.model.support;
import lombok.Data;
/**
* @author zhaojun
*/
@Data
public class Jvm {
/**
* 当前 JVM 占用的内存总数 (M)
*/
private double total;
/**
* JVM 最大可用内存总数 (M)
*/
private double max;
/**
* JVM 空闲内存 (M)
*/
private double free;
/**
* JDK 版本
*/
private String version;
public Jvm() {
Runtime runtime = Runtime.getRuntime();
this.total = runtime.totalMemory();
this.free = runtime.freeMemory();
this.max = runtime.maxMemory();
this.version = System.getProperty("java.version");
}
}

View File

@@ -0,0 +1,41 @@
package im.zhaojun.zfile.model.support;
import com.sun.management.OperatingSystemMXBean;
import lombok.Data;
import java.lang.management.ManagementFactory;
/**
* @author zhaojun
*/
@Data
public class Mem {
/**
* 内存总量
*/
private double total;
/**
* 已用内存
*/
private double used;
/**
* 剩余内存
*/
private double free;
public Mem() {
OperatingSystemMXBean osb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
// 总的物理内存+虚拟内存
long totalVirtualMemory = osb.getTotalSwapSpaceSize();
// 剩余的物理内存
long freePhysicalMemorySize = osb.getFreePhysicalMemorySize();
this.total = totalVirtualMemory;
this.free = freePhysicalMemorySize;
this.used = totalVirtualMemory - freePhysicalMemorySize;
}
}

View File

@@ -0,0 +1,17 @@
package im.zhaojun.zfile.model.support;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
/**
* @author zhaojun
*/
@Data
public class OneDriveToken {
@JSONField(name = "access_token")
private String accessToken;
@JSONField(name = "refresh_token")
private String refreshToken;
}

View File

@@ -0,0 +1,58 @@
package im.zhaojun.zfile.model.support;
import cn.hutool.core.date.BetweenFormater;
import cn.hutool.core.date.DateUtil;
import lombok.Data;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.IOException;
import java.lang.management.ManagementFactory;
/**
* @author zhaojun
*/
@Data
public class Sys {
/**
* 项目路径
*/
private String projectDir;
/**
* 操作系统
*/
private String osName;
/**
* 系统架构
*/
private String osArch;
/**
* 系统版本
*/
private String osVersion;
/**
* 启动时间
*/
private String upTime;
public Sys() {
this.osName = System.getProperty("os.name");
this.osArch = System.getProperty("os.arch");
this.osVersion = System.getProperty("os.version");
Resource resource = new ClassPathResource("");
try {
this.projectDir = resource.getFile().getAbsolutePath();
} catch (IOException e) {
e.printStackTrace();
}
long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
this.upTime = DateUtil.formatBetween(uptime, BetweenFormater.Level.SECOND);
}
}

View File

@@ -0,0 +1,34 @@
package im.zhaojun.zfile.model.support;
import lombok.Data;
import java.io.Serializable;
/**
* @author zhaojun
*/
@Data
public class SystemMonitorInfo implements Serializable {
/**
* 服务器基本信息
*/
private Sys sys;
/**
* JVM 信息
*/
private Jvm jvm;
/**
* 系统内存
*/
private Mem mem;
public SystemMonitorInfo() {
this.jvm = new Jvm();
this.sys = new Sys();
this.mem = new Mem();
}
}

View File

@@ -0,0 +1,26 @@
package im.zhaojun.zfile.repository;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author zhaojun
*/
@Repository
public interface DriverConfigRepository extends JpaRepository<DriveConfig, Integer> {
/**
* 根据存储策略类型获取所有驱动器
*
* @param type
* 存储类型
*
* @return 指定存储类型的存储器
*/
List<DriveConfig> findByType(StorageTypeEnum type);
}

View File

@@ -0,0 +1,71 @@
package im.zhaojun.zfile.repository;
import im.zhaojun.zfile.model.entity.StorageConfig;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
import java.util.List;
/**
* @author zhaojun
*/
@Repository
public interface StorageConfigRepository extends JpaRepository<StorageConfig, Integer> {
/**
* 根据存储类型找对应的配置信息
*
* @param type
* 存储类型
*
* @return 此类型所有的配置信息
*/
List<StorageConfig> findByTypeOrderById(StorageTypeEnum type);
/**
* 根据存储类型找对应的配置信息
*
* @param driveId
* 驱动器 ID
*
* @return 此驱动器所有的配置信息
*/
List<StorageConfig> findByDriveIdOrderById(Integer driveId);
/**
* 根据驱动器找到对应的配置信息
*
* @param driveId
* 驱动器 ID
*
* @return 此驱动器所有的配置信息
*/
List<StorageConfig> findByDriveId(Integer driveId);
/**
* 删除指定驱动器对应的配置信息
*
* @param driveId
* 驱动器 ID
*/
void deleteByDriveId(Integer driveId);
/**
* 查找某个驱动器的某个 KEY 的值
*
* @param driveId
* 驱动器
*
* @param key
* KEY 值
*
* @return KEY 对应的对象
*/
StorageConfig findByDriveIdAndKey(Integer driveId, String key);
}

View File

@@ -0,0 +1,23 @@
package im.zhaojun.zfile.repository;
import im.zhaojun.zfile.model.entity.SystemConfig;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.stereotype.Repository;
/**
* @author zhaojun
*/
@Repository
public interface SystemConfigRepository extends JpaRepository<SystemConfig, Integer> {
/**
* 查找系统设置中, 某个设置项对应的值
*
* @param key
* 设置项
*
* @return 设置值
*/
SystemConfig findByKey(String key);
}

View File

@@ -0,0 +1,72 @@
package im.zhaojun.zfile.schedule;
import im.zhaojun.zfile.model.entity.DriveConfig;
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
import im.zhaojun.zfile.service.DriveConfigService;
import im.zhaojun.zfile.service.base.AbstractOneDriveServiceBase;
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
import im.zhaojun.zfile.context.DriveContext;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.List;
/**
* 计划任务工具类
* @author zhaojun
*/
@Configuration
@EnableScheduling
@Slf4j
public class OneDriveTokenRefreshSchedule {
@Resource
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
@Resource
private DriveConfigService driveConfigService;
@Resource
private DriveContext driveContext;
/**
* 项目启动 30 秒后, 每 15 分钟执行一次刷新 OneDrive Token 的定时任务.
*/
@Scheduled(fixedRate = 1000 * 60 * 10, initialDelay = 1000 * 30)
public void autoRefreshOneDriveToken() {
try {
log.debug("尝试调用 OneDrive 自动刷新 AccessToken 定时任务");
List<DriveConfig> driveConfigList = driveConfigService.findByType(StorageTypeEnum.ONE_DRIVE);
driveConfigList.addAll(driveConfigService.findByType(StorageTypeEnum.ONE_DRIVE_CHINA));
driveConfigList.forEach(driveConfig -> {
StorageTypeEnum storageType = driveConfig.getType();
String name = driveConfig.getName();
try {
AbstractOneDriveServiceBase driveService = (AbstractOneDriveServiceBase) driveContext.getDriveService(driveConfig.getId());
driveService.refreshOneDriveToken();
log.info("刷新驱动器 {}, {} key 时间: {}", name, storageType.getDescription(), LocalDateTime.now());
} catch (Exception e) {
log.debug("刷新驱动器 " + name + " Token 失败.", e);
}
});
} catch (Throwable e) {
log.debug("尝试调用 OneDrive 自动刷新 AccessToken 定时任务出现未知异常", e);
}
}
}

View File

@@ -1,9 +1,12 @@
package im.zhaojun.common.security;
package im.zhaojun.zfile.security;
import cn.hutool.crypto.SecureUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
public class MD5PasswordEncoder implements PasswordEncoder {
/**
* @author zhaojun
*/
public class Md5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {

Some files were not shown because too many files have changed in this diff Show More