mirror of
https://github.com/zfile-dev/zfile.git
synced 2025-04-19 05:34:52 +00:00
Compare commits
399 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2ec8a5df1f | ||
|
|
47b5f6ac12 | ||
|
|
c64c8465f2 | ||
|
|
f636681dd8 | ||
|
|
eadd2434e0 | ||
|
|
b84c0bff42 | ||
|
|
4cb5b84bfe | ||
|
|
0351b4401c | ||
|
|
48cb14be8a | ||
|
|
eea2ff11f9 | ||
|
|
325ec1a348 | ||
|
|
93205266d3 | ||
|
|
6849a4347f | ||
|
|
cb5c6a5945 | ||
|
|
5ed45c3bb3 | ||
|
|
4442ec3165 | ||
|
|
b268a24333 | ||
|
|
84f9354d4e | ||
|
|
8dfc4f8004 | ||
|
|
1158f5c2b9 | ||
|
|
c5f0e15207 | ||
|
|
68a842ce75 | ||
|
|
3bd4f74dae | ||
|
|
4a0bdc3baf | ||
|
|
603c1b4654 | ||
|
|
1136d582df | ||
|
|
187544fc06 | ||
|
|
aa3cde8f59 | ||
|
|
e29a702b6e | ||
|
|
e4f663c9f0 | ||
|
|
fb08ef6e78 | ||
|
|
10c465d159 | ||
|
|
d15d1203b7 | ||
|
|
de48ed3b61 | ||
|
|
d22e2e872a | ||
|
|
7da1b454dc | ||
|
|
463f311dd3 | ||
|
|
73b42cf654 | ||
|
|
1fac59c4cd | ||
|
|
6ed6b4a019 | ||
|
|
7bd02437f0 | ||
|
|
57aeb5771c | ||
|
|
695c03a530 | ||
|
|
6ebc403572 | ||
|
|
7ff6fe43b5 | ||
|
|
b34f141181 | ||
|
|
87dd7b58d1 | ||
|
|
2a949db5d2 | ||
|
|
b889e91fb5 | ||
|
|
b5c757f9f0 | ||
|
|
a465f48b94 | ||
|
|
797a0a0e4c | ||
|
|
e7ff159b6d | ||
|
|
a9fbf54bb2 | ||
|
|
81f9e262f5 | ||
|
|
23bb3960ab | ||
|
|
c4a17985a4 | ||
|
|
75ddcd47f4 | ||
|
|
2dd03ae490 | ||
|
|
5b383c8741 | ||
|
|
73198d7852 | ||
|
|
fb0d9721aa | ||
|
|
b24c663fd6 | ||
|
|
6e62cfc84d | ||
|
|
eee22e9dc9 | ||
|
|
5109c51ffc | ||
|
|
66d6d311ea | ||
|
|
ef7cbdcbd7 | ||
|
|
63bcbebb4b | ||
|
|
50ce1bb6db | ||
|
|
3c88659679 | ||
|
|
d79a993eea | ||
|
|
afafb311b8 | ||
|
|
2e280e4931 | ||
|
|
ed6efac8b7 | ||
|
|
7409df85d7 | ||
|
|
4d42529c4d | ||
|
|
65224685c8 | ||
|
|
080a84986e | ||
|
|
3f8beb2f0b | ||
|
|
410a87c426 | ||
|
|
c14b8343d2 | ||
|
|
bea440f6c3 | ||
|
|
6a5fe15121 | ||
|
|
e920ab0ec0 | ||
|
|
537e3e0563 | ||
|
|
e208dc7c4c | ||
|
|
ed64910a53 | ||
|
|
5b075c3505 | ||
|
|
a8e6d9af6a | ||
|
|
2b21d8a73c | ||
|
|
e30289d21b | ||
|
|
3b6e2be7fe | ||
|
|
43c12aa8a7 | ||
|
|
c03a7710c0 | ||
|
|
1833b23d84 | ||
|
|
f3e393972d | ||
|
|
4f46c13369 | ||
|
|
f181959218 | ||
|
|
11effc0ae7 | ||
|
|
c8397e17bf | ||
|
|
ed32b9f1d4 | ||
|
|
4e184936db | ||
|
|
fe6aebfdee | ||
|
|
d65e1a442d | ||
|
|
34647793c8 | ||
|
|
e8c249b9ea | ||
|
|
d1e613dc10 | ||
|
|
1adcfee96f | ||
|
|
75f5de6b9a | ||
|
|
499942ef70 | ||
|
|
e11277ce26 | ||
|
|
5edd9e38a7 | ||
|
|
f4ffee706b | ||
|
|
bb65750278 | ||
|
|
e09167c0d0 | ||
|
|
ee6c04fa11 | ||
|
|
b31982b788 | ||
|
|
544a3d3eb2 | ||
|
|
1987bc97a9 | ||
|
|
7e878af06c | ||
|
|
766a047ee1 | ||
|
|
c1d29a46f5 | ||
|
|
08e39b3d15 | ||
|
|
e7790ac256 | ||
|
|
499f3e108c | ||
|
|
19144b653e | ||
|
|
17a87648fa | ||
|
|
ac4cef0980 | ||
|
|
71978f8003 | ||
|
|
0b3a67ec6e | ||
|
|
ee5fb54ebb | ||
|
|
4585f22817 | ||
|
|
b523453588 | ||
|
|
a8cc03c911 | ||
|
|
949c437653 | ||
|
|
84e9cce60f | ||
|
|
5720bd93ec | ||
|
|
bcae9713bc | ||
|
|
04e3023071 | ||
|
|
a09ef84629 | ||
|
|
1d29395191 | ||
|
|
3720dc6aa9 | ||
|
|
3ada172be2 | ||
|
|
15f8fbb49b | ||
|
|
547e688d38 | ||
|
|
708eb33d0e | ||
|
|
e954b725b1 | ||
|
|
c89cb4e495 | ||
|
|
286e9775f6 | ||
|
|
60513abe6a | ||
|
|
f7a8c9faa2 | ||
|
|
55e0d32ef8 | ||
|
|
4c0bacba31 | ||
|
|
61128f2677 | ||
|
|
3866526b95 | ||
|
|
250955fac9 | ||
|
|
3249266cd1 | ||
|
|
1a6235df73 | ||
|
|
430aee2b7f | ||
|
|
de2f7e4b80 | ||
|
|
6dfcc409ac | ||
|
|
78f795e1cb | ||
|
|
c69ee0f356 | ||
|
|
39475de789 | ||
|
|
bd71712765 | ||
|
|
8698686a47 | ||
|
|
762c67ee37 | ||
|
|
7bf3a29c17 | ||
|
|
6ee5002f0c | ||
|
|
fadc64add4 | ||
|
|
234f43846f | ||
|
|
67e42d9753 | ||
|
|
04f94b4bf5 | ||
|
|
d29c498457 | ||
|
|
5aa45b44b2 | ||
|
|
8273a645f2 | ||
|
|
46f292cc9b | ||
|
|
261d48059e | ||
|
|
79f931c51b | ||
|
|
399e961a65 | ||
|
|
3e61d7d146 | ||
|
|
ace95d9071 | ||
|
|
60d2a2b986 | ||
|
|
69d5661e06 | ||
|
|
01d11dfc23 | ||
|
|
d35e3ecd93 | ||
|
|
9e5a3e5385 | ||
|
|
b62163b4e8 | ||
|
|
595a00f067 | ||
|
|
a759d9fe44 | ||
|
|
7a24fd10e0 | ||
|
|
7e04a817d7 | ||
|
|
791967f45e | ||
|
|
d789436a16 | ||
|
|
96ab8ff7dd | ||
|
|
8809aca170 | ||
|
|
97106383b6 | ||
|
|
208da95234 | ||
|
|
d4c843f5f5 | ||
|
|
d273fc9f12 | ||
|
|
0b4a38218c | ||
|
|
2f57c5b5cc | ||
|
|
610f68295f | ||
|
|
39ced8eb84 | ||
|
|
368b7a1df2 | ||
|
|
8e2107cd46 | ||
|
|
fa32a33371 | ||
|
|
59116a9414 | ||
|
|
b2c732a389 | ||
|
|
0e1ffef92b | ||
|
|
a5b19d3577 | ||
|
|
185c84dd79 | ||
|
|
d554dd298c | ||
|
|
aa6ecf0aaa | ||
|
|
83692718e3 | ||
|
|
030bd95941 | ||
|
|
8722d11ac3 | ||
|
|
0131ff02c0 | ||
|
|
2d115bf1c6 | ||
|
|
946113216d | ||
|
|
77b05c6dac | ||
|
|
07c9fca210 | ||
|
|
27cf61693a | ||
|
|
37e1aa1fec | ||
|
|
31b54a3c05 | ||
|
|
589f07c103 | ||
|
|
fe8b60d873 | ||
|
|
1734619eac | ||
|
|
f5724dc9ab | ||
|
|
f7bb147b71 | ||
|
|
47fc1bc2df | ||
|
|
45172f69ba | ||
|
|
9566b138ff | ||
|
|
e15b6c2242 | ||
|
|
acc41511e0 | ||
|
|
b882b87405 | ||
|
|
518b5170ae | ||
|
|
8bfac6d9ac | ||
|
|
3ffdb4f1b2 | ||
|
|
47509450a0 | ||
|
|
812fd18aac | ||
|
|
77a13cf8ad | ||
|
|
4c914793b0 | ||
|
|
5698cfb2d3 | ||
|
|
3cd5f8f9a7 | ||
|
|
76747771de | ||
|
|
cfacd39210 | ||
|
|
90cd13f2c3 | ||
|
|
018a68246e | ||
|
|
b6a2e3ccb8 | ||
|
|
38b811f8e6 | ||
|
|
6922fa2195 | ||
|
|
4bca6cf7a5 | ||
|
|
c3484426ab | ||
|
|
0455bd366c | ||
|
|
bbe3c053f8 | ||
|
|
f47708f45d | ||
|
|
2e7a7b8cec | ||
|
|
9e067dbce9 | ||
|
|
a4a236e488 | ||
|
|
7d5b0431f5 | ||
|
|
a758c8cc6d | ||
|
|
21a64ec0f3 | ||
|
|
3f241d129a | ||
|
|
fa5f16c61f | ||
|
|
492b22506d | ||
|
|
a12f685340 | ||
|
|
2ee3f3dd66 | ||
|
|
245937e773 | ||
|
|
aef34facbd | ||
|
|
14bb5e15e3 | ||
|
|
12371f06dd | ||
|
|
28e43e968f | ||
|
|
669b413ff0 | ||
|
|
f32e5e8f9e | ||
|
|
3719378614 | ||
|
|
40c759078e | ||
|
|
e37e778e1a | ||
|
|
031607402a | ||
|
|
6c9150466c | ||
|
|
be633ebe1a | ||
|
|
9715cf922a | ||
|
|
f6163c7e19 | ||
|
|
dcc4cb19ad | ||
|
|
ad0ad12c08 | ||
|
|
74c935cdf0 | ||
|
|
1876e692f2 | ||
|
|
f198b34324 | ||
|
|
3095e0c8d9 | ||
|
|
594246127d | ||
|
|
f6c5f7a91b | ||
|
|
2a765fff7e | ||
|
|
28f958878b | ||
|
|
368f3a90eb | ||
|
|
98b14abbfc | ||
|
|
7c04c3d6b8 | ||
|
|
921cb1a115 | ||
|
|
9371968c3b | ||
|
|
47e88849ac | ||
|
|
2f0f41f413 | ||
|
|
7667765abc | ||
|
|
b2a2e69af5 | ||
|
|
7c729a72e2 | ||
|
|
5495abc881 | ||
|
|
797cd4fc06 | ||
|
|
8148d182cf | ||
|
|
7e8cab90d0 | ||
|
|
4d5743dc0b | ||
|
|
1a326cc17d | ||
|
|
cc993d8e65 | ||
|
|
f128882034 | ||
|
|
31dbb902c3 | ||
|
|
c849057aaa | ||
|
|
7b288b795c | ||
|
|
316566d479 | ||
|
|
e01ce28eb8 | ||
|
|
9b7528b61c | ||
|
|
bd22cfd34c | ||
|
|
4aa9839c6b | ||
|
|
5eeea23703 | ||
|
|
6997b15dd0 | ||
|
|
326c954c36 | ||
|
|
ba5801bea2 | ||
|
|
e2b0c29e2d | ||
|
|
845a380a7e | ||
|
|
87229f225e | ||
|
|
de947e510c | ||
|
|
2a367afc37 | ||
|
|
5fb945cebc | ||
|
|
7acedfef38 | ||
|
|
5e198b7ce7 | ||
|
|
c3e7e622e2 | ||
|
|
aec73f5cc7 | ||
|
|
9236f11044 | ||
|
|
02973a3c21 | ||
|
|
e60c64c8fc | ||
|
|
52db0c1515 | ||
|
|
0ab2f3b015 | ||
|
|
dd588fe218 | ||
|
|
dce1b42e8e | ||
|
|
0e9dd7d5a8 | ||
|
|
f5bebd2500 | ||
|
|
6a54150868 | ||
|
|
099c09b625 | ||
|
|
45e117a05a | ||
|
|
14ba1027ae | ||
|
|
04a2ff9542 | ||
|
|
040e92a433 | ||
|
|
c739878890 | ||
|
|
65616e045b | ||
|
|
9aaf1494b1 | ||
|
|
74eaaad72d | ||
|
|
b65ccc95e2 | ||
|
|
e334acd508 | ||
|
|
844cbcc03a | ||
|
|
debaa72938 | ||
|
|
d293105521 | ||
|
|
8e7d4432a3 | ||
|
|
0e6bcbfa11 | ||
|
|
e8122b4ed0 | ||
|
|
b3a0f4585b | ||
|
|
12bae1ef53 | ||
|
|
4d9357b11f | ||
|
|
2aa9ccc389 | ||
|
|
d81d795095 | ||
|
|
9af89ecd8c | ||
|
|
bb381a98b9 | ||
|
|
14828e7f34 | ||
|
|
13c091bcf4 | ||
|
|
6842a31402 | ||
|
|
eb99a3e340 | ||
|
|
403dd4f2e1 | ||
|
|
ff7feedb2f | ||
|
|
2861faeacd | ||
|
|
8532e91386 | ||
|
|
83cb080f35 | ||
|
|
682da819a8 | ||
|
|
0c58869158 | ||
|
|
92396c3631 | ||
|
|
6285633ad4 | ||
|
|
7dadb24727 | ||
|
|
3c278cf176 | ||
|
|
7033fc3fb1 | ||
|
|
8758bd8225 | ||
|
|
94290af50c | ||
|
|
0200483e22 | ||
|
|
8aa497b13b | ||
|
|
1d60395161 | ||
|
|
d4978b0903 | ||
|
|
495da58af0 | ||
|
|
57f012482c | ||
|
|
22a5e5cfeb | ||
|
|
fa332df4cf | ||
|
|
86885c880a | ||
|
|
9ef217c33c | ||
|
|
efbd2b441f | ||
|
|
de7d276825 | ||
|
|
428d04d478 |
48
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
48
.github/ISSUE_TEMPLATE/bug_report.md
vendored
Normal file
@@ -0,0 +1,48 @@
|
||||
---
|
||||
name: BUG 反馈
|
||||
about: 事情不像预期的那样工作吗?
|
||||
title: ''
|
||||
labels: 'bug'
|
||||
assignees: ''
|
||||
---
|
||||
|
||||
<!--
|
||||
你好!感谢你正在考虑为 ZFile 提交一个 bug。请花一点点时间尽量详细地回答以下基础问题。
|
||||
|
||||
谢谢!
|
||||
-->
|
||||
|
||||
<!--
|
||||
请确认你已经做了下面这些事情,若 bug 还是未解决,那么请尽可详细地描述你的问题。
|
||||
|
||||
- 我已经安装了最新版的 ZFile
|
||||
- 我已经阅读了 ZFile 的文档:https://docs.zfile.vip
|
||||
- 我已经搜索了已有的 Issues 列表中有关的信息
|
||||
- 我已经清理过浏览器缓存并重试
|
||||
-->
|
||||
|
||||
## 我的环境
|
||||
|
||||
<!--
|
||||
请登录到管理后台,点击左侧系统监控, 复制或截图此页内容.
|
||||
-->
|
||||
|
||||
## 错误日志
|
||||
|
||||
<!--
|
||||
请登录到管理后台,点击左侧系统监控, 点击右上角诊断日志下载, 然后上传到此 Issue 中.
|
||||
-->
|
||||
|
||||
## 期望行为
|
||||
|
||||
<!--
|
||||
你期望会发生什么?
|
||||
-->
|
||||
|
||||
## 当前行为
|
||||
|
||||
<!--
|
||||
描述 bug 细节,确认出现此问题的复现步骤,例如点击了哪里,发生了什么情况?
|
||||
|
||||
你可以粘贴截图或附件。
|
||||
-->
|
||||
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal file
34
.github/ISSUE_TEMPLATE/feature_request.md
vendored
Normal 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
14
.github/ISSUE_TEMPLATE/question.md
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
---
|
||||
name: Question
|
||||
about: 对 ZFile 有任何问题吗?
|
||||
title: ''
|
||||
labels: 'question'
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
<!--
|
||||
如果你有任何问题也可以通过此渠道来向我们反馈。
|
||||
|
||||
谢谢!
|
||||
-->
|
||||
181
API.md
Normal file
181
API.md
Normal file
@@ -0,0 +1,181 @@
|
||||
## API 标准
|
||||
|
||||
所有 API 均返回 `msg`, `code`, `data` 三个属性.
|
||||
|
||||
| code | 描述 |
|
||||
| :---: | :------------: |
|
||||
| 0 | 请求成功 |
|
||||
| -1 | 请求失败 |
|
||||
| -2 | 文件夹需要密码 |
|
||||
|
||||
当 `code == 0` 时, `data` 中为请求所需数据.
|
||||
|
||||
当 `code != 0` 时, 应当将 `msg` 中的内容作为参考值.
|
||||
|
||||
|
||||
## 驱动器列表
|
||||
|
||||
### 请求 URL
|
||||
|
||||
`/api/drive/list` `GET`
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "操作成功",
|
||||
"code": 0,
|
||||
"data": [
|
||||
{
|
||||
"id": 3, --- 此 ID 是驱动器 ID, 用来唯一区分驱动器
|
||||
"name": "演示 A 盘", --- 驱动器名称
|
||||
"enableCache": true, --- 是否开启了缓存
|
||||
"autoRefreshCache": false, --- 是否开启了缓存自动刷新
|
||||
"type": { --- 存储源类型
|
||||
"key": "upyun",
|
||||
"description": "又拍云 USS"
|
||||
},
|
||||
"searchEnable": false, --- 是否开启搜索
|
||||
"searchIgnoreCase": false, --- 搜索是否忽略大小写
|
||||
"searchContainEncryptedFile": false --- 搜索是否包含加密文件夹
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
|
||||
## 获取文件列表
|
||||
|
||||
### 请求 URL
|
||||
|
||||
`/api/list/{driveId}` `GET`
|
||||
|
||||
|
||||
### URL 参数
|
||||
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :-----: | :-------------------: | :------: | :------------------------------------: |
|
||||
| driveId | 驱动器 ID | 是 | 参考 `获取驱动器列表` 接口返回的 id 值 |
|
||||
|
||||
|
||||
### 请求参数
|
||||
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :------: | :--------: | :------: | :--------------------------: |
|
||||
| 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/directlink/{driveId}` `GET`
|
||||
|
||||
|
||||
### URL 参数
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :-----: | :-------------------: | :------: | :------------------------------------: |
|
||||
| driveId | 驱动器 ID | 是 | 参考 `获取驱动器列表` 接口返回的 id 值 |
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :----: | :--------: | :------: | :------------------: |
|
||||
| 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/{driveId}` `GET`
|
||||
|
||||
|
||||
### URL 参数
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :-----: | :-------------------: | :------: | :------------------------------------: |
|
||||
| driveId | 驱动器 ID | 是 | 参考 `获取驱动器列表` 接口返回的 id 值 |
|
||||
|
||||
|
||||
### 参数
|
||||
|
||||
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||
| :----: | :--------: | :------: | :-----------: |
|
||||
| path | 文件夹名称 | 是 | `/文件夹名称` |
|
||||
|
||||
### 响应
|
||||
|
||||
```json
|
||||
{
|
||||
"msg": "操作成功",
|
||||
"code": 0,
|
||||
"data": {
|
||||
"siteName": "ZFile 演示站",
|
||||
"searchEnable": false,
|
||||
"username": "zhao",
|
||||
"domain": "https://zfile.jun6.net",
|
||||
"customJs": "",
|
||||
"customCss": "",
|
||||
"tableSize": "small",
|
||||
"showOperator": true,
|
||||
"showDocument": true,
|
||||
"announcement": "本站是 ZFile 演示站,交流反馈群 180605017",
|
||||
"showAnnouncement": true,
|
||||
"layout": "full",
|
||||
"readme": null
|
||||
}
|
||||
}
|
||||
```
|
||||
21
LICENSE
Normal file
21
LICENSE
Normal 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.
|
||||
145
README.md
145
README.md
@@ -1,54 +1,137 @@
|
||||
# Z-File
|
||||
<p align = "center">
|
||||
<img alt="ZFile" src="https://cdn.jun6.net/2021/04/21/69a89344e2a84.png" height="150px">
|
||||
<br><br>
|
||||
基于 Java 的在线网盘程序,支持对接 S3、OneDrive、SharePoint、又拍云、本地存储、FTP 等存储源,支持在线浏览图片、播放音视频,文本文件等文件类型。
|
||||
<br><br>
|
||||
<img src="https://img.shields.io/badge/license-MIT-blue.svg?longCache=true&style=flat-square">
|
||||
<img src="https://api.codacy.com/project/badge/Grade/70b793267f7941d58cbd93f50c9a8e0a">
|
||||
<img src="https://img.shields.io/github/last-commit/zhaojun1998/zfile.svg?style=flat-square">
|
||||
<img src="https://img.shields.io/github/downloads/zhaojun1998/zfile/total?style=flat-square">
|
||||
<img src="https://img.shields.io/github/v/release/zhaojun1998/zfile?style=flat-square">
|
||||
<img src="https://img.shields.io/github/commit-activity/y/zhaojun1998/zfile?style=flat-square">
|
||||
<br>
|
||||
<img src="https://img.shields.io/github/issues/zhaojun1998/zfile?style=flat-square">
|
||||
<img src="https://img.shields.io/github/issues-closed-raw/zhaojun1998/zfile?style=flat-square">
|
||||
<img src="https://img.shields.io/github/forks/zhaojun1998/zfile?style=flat-square">
|
||||
<img src="https://img.shields.io/github/stars/zhaojun1998/zfile?style=flat-square">
|
||||
<img src="https://img.shields.io/github/watchers/zhaojun1998/zfile?style=flat-square">
|
||||
</p>
|
||||
|
||||
此项目是一个在线文件目录的程序, 支持各种对象存储和本地存储, 使用定位是个人放常用工具下载, 或做公共的文件库. 不会向多账户方向开发.
|
||||
## 相关地址
|
||||
|
||||
前端基于 [h5ai](https://larsjung.de/h5ai/) 的原有功能使用 Vue 重新开发了一遍. 后端采用 SpringBoot, 数据库采用内嵌数据库.
|
||||
预览地址: [https://zfile.vip](https://zfile.vip)
|
||||
|
||||
预览地址: [http://zfile.jun6.net](http://zfile.jun6.net)
|
||||
文档地址: [https://docs.zfile.vip](https://docs.zfile.vip)
|
||||
|
||||
社区地址: [https://bbs.zfile.vip](https://bbs.zfile.vip)
|
||||
|
||||
项目源码: [https://github.com/zhaojun1998/zfile](https://github.com/zhaojun1998/zfile)
|
||||
|
||||
前端源码: [https://github.com/zhaojun1998/zfile-vue](https://github.com/zhaojun1998/zfile-vue)
|
||||
|
||||
## 系统特色
|
||||
|
||||
* 内存缓存 (免安装)
|
||||
* 内存数据库 (免安装)
|
||||
* 个性化配置
|
||||
* 自定义目录的 header 和 footer 说明文件
|
||||
* 文件夹密码
|
||||
* 支持在线浏览文本文件, 视频, 图片, 音乐.
|
||||
* 文件/目录二维码
|
||||
* 目录 README 说明
|
||||
* 文件直链(短链,永久直链,二维码)
|
||||
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
|
||||
* 图片模式
|
||||
* Docker 支持
|
||||
* 隐藏指定文件夹(通配符支持)
|
||||
* 自定义 JS, CSS
|
||||
* 自定义目录 README 说明文件和密码文件名称
|
||||
* 同时挂载多个存储策略
|
||||
* 缓存动态开启, ~~缓存自动刷新 (v2.2 及以前版本支持)~~
|
||||
* ~~全局搜索 (v2.2 及以前版本支持)~~
|
||||
* 支持 S3 协议, 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版/世纪互联版/SharePoint, , 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
|
||||
|
||||
## 运行环境
|
||||
## 快速开始
|
||||
|
||||
* JDK: `1.8`
|
||||
* 缓存: `caffeine/redis`
|
||||
* 数据库: `h2/mysql`
|
||||
安装依赖环境:
|
||||
|
||||
```bash
|
||||
# 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` 清理旧程序. 首次安装请忽略此选项.
|
||||
|
||||
### 缓存
|
||||
下载项目:
|
||||
|
||||
缓存默认支持 `caffeine` 和 `redis`, 前者为内存缓存, 无需安装, 但后者相对性能更好.
|
||||
```bash
|
||||
export ZFILE_INSTALL_PATH=~/zfile
|
||||
mkdir -p $ZFILE_INSTALL_PATH && cd $ZFILE_INSTALL_PATH
|
||||
wget https://c.jun6.net/ZFILE/zfile-release.war
|
||||
unzip zfile-release.war && rm -rf zfile-release.war
|
||||
chmod +x $ZFILE_INSTALL_PATH/bin/*.sh
|
||||
```
|
||||
|
||||
### 数据库
|
||||
> 下载指定版本可以将 `zfile-release.war` 改为 `zfile-x.x.war`,如 `zfile-2.2.war`。
|
||||
|
||||
缓存默认支持 `h2` 和 `mysql`, 前者为嵌入式数据库, 无需安装, 但后者相对性能更好.
|
||||
程序的目录结构为:
|
||||
```
|
||||
├── zfile
|
||||
├── META-INF
|
||||
├── WEB-INF
|
||||
└── bin
|
||||
├── start.sh # 启动脚本
|
||||
└── stop.sh # 停止脚本
|
||||
├── restart.sh # 重启脚本
|
||||
```
|
||||
|
||||
启动项目:
|
||||
|
||||
```bash
|
||||
~/zfile/bin/start.sh
|
||||
```
|
||||
|
||||
篇幅有限, 更详细的安装教程及介绍请参考: [ZFile 文档](https://docs.zfile.vip)
|
||||
|
||||
访问地址:
|
||||
|
||||
用户前台: http://127.0.0.1:8080/main
|
||||
|
||||
初始安装: http://127.0.0.1:8080/install
|
||||
|
||||
管理后台: http://127.0.0.1:8080/admin
|
||||
|
||||
|
||||
### 默认路径
|
||||
## 预览
|
||||
|
||||
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录, windows 为 `C:/Users/用户名/`, linux 为 `/home/用户名/`, root 用户为 `/root/`
|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||

|
||||
|
||||
## 支持作者
|
||||
|
||||
### 头尾文件和加密文件
|
||||
如果本项目对你有帮助,请作者喝杯咖啡吧。
|
||||
|
||||
- 目录头部显示文件名为 `header.md`
|
||||
- 目录底部显示文件名为 `footer.md`
|
||||
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
|
||||
<img src="https://cdn.jun6.net/2021/03/27/152704e91f13d.png" width="400" alt="赞助我">
|
||||
|
||||
## TODO
|
||||
## Stargazers over time
|
||||
|
||||
- 全局搜索功能
|
||||
- 文本预览更换更好用的编辑器
|
||||
- 后台支持上传、编辑、删除等操作
|
||||
- API 支持
|
||||
- 更方便的部署方式
|
||||
[](https://starchart.cc/zhaojun1998/zfile.svg)
|
||||
|
||||
## 开发工具赞助
|
||||
|
||||
<a href="https://www.jetbrains.com/?from=zfile"><img src="https://cdn.jun6.net/2021/04/21/26e410d60b0b0.png?1=1" width="100px"></a>
|
||||
|
||||
172
pom.xml
172
pom.xml
@@ -6,25 +6,25 @@
|
||||
<parent>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-parent</artifactId>
|
||||
<version>2.0.6.RELEASE</version>
|
||||
<version>2.5.4</version>
|
||||
<relativePath/>
|
||||
</parent>
|
||||
|
||||
<groupId>im.zhaojun</groupId>
|
||||
<artifactId>zfile</artifactId>
|
||||
<version>0.1</version>
|
||||
<version>3.2.1</version>
|
||||
<name>zfile</name>
|
||||
<packaging>war</packaging>
|
||||
<description>一个在线的文件浏览系统</description>
|
||||
|
||||
<properties>
|
||||
<java.version>1.8</java.version>
|
||||
<log4j2.version>2.17.1</log4j2.version>
|
||||
</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>
|
||||
@@ -33,101 +33,72 @@
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-aop</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-jpa</artifactId>
|
||||
</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>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>
|
||||
<version>1.4.197</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
<version>8.0.27</version>
|
||||
</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>
|
||||
</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>
|
||||
@@ -137,56 +108,47 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<groupId>com.alibaba</groupId>
|
||||
<artifactId>fastjson</artifactId>
|
||||
<version>1.2.69</version>
|
||||
</dependency>
|
||||
|
||||
|
||||
<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
<groupId>cn.dev33</groupId>
|
||||
<artifactId>sa-token-spring-boot-starter</artifactId>
|
||||
<version>1.26.0</version>
|
||||
</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>
|
||||
|
||||
</project>
|
||||
</project>
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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 {
|
||||
}
|
||||
@@ -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("存储策略未初始化");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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());
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package im.zhaojun.common.config;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
@Configuration
|
||||
public class ZFileConfiguration {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(){
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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 = 20;
|
||||
|
||||
@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()));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,99 +0,0 @@
|
||||
package im.zhaojun.common.controller;
|
||||
|
||||
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.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
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(new BCryptPasswordEncoder().encode(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();
|
||||
}
|
||||
}
|
||||
@@ -1,63 +0,0 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@ResponseBody
|
||||
public class GlobleExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
|
||||
|
||||
@ExceptionHandler(SearchDisableException.class)
|
||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ResultBean searchDisableExceptionHandler(SearchDisableException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(e.getMessage(), e);
|
||||
}
|
||||
return ResultBean.error(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
@ExceptionHandler
|
||||
@ResponseStatus
|
||||
public ResultBean searchDisableExceptionHandler(StorageStrategyUninitializedException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(e.getMessage(), e);
|
||||
}
|
||||
return ResultBean.error(e.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
|
||||
*/
|
||||
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public void clientAbortException(Exception ex) {
|
||||
// if (log.isDebugEnabled()) {
|
||||
// log.debug("出现了断开异常:", ex);
|
||||
// }
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ResultBean searchDisableExceptionHandler(Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug(e.getMessage(), e);
|
||||
}
|
||||
return ResultBean.error("系统异常, 请联系管理员");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* 对象存储初始化异常
|
||||
*/
|
||||
public class InitializeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -1920550904063819880L;
|
||||
|
||||
public InitializeException() {
|
||||
}
|
||||
|
||||
public InitializeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InitializeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InitializeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InitializeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
public class SearchDisableException extends RuntimeException {
|
||||
|
||||
public SearchDisableException() {
|
||||
}
|
||||
|
||||
public SearchDisableException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public SearchDisableException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public SearchDisableException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public SearchDisableException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* 未知的存储类型异常
|
||||
*/
|
||||
public class UnknownStorageTypeException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -4853756482605773655L;
|
||||
|
||||
public UnknownStorageTypeException() {
|
||||
}
|
||||
|
||||
public UnknownStorageTypeException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public UnknownStorageTypeException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public UnknownStorageTypeException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public UnknownStorageTypeException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -1,64 +0,0 @@
|
||||
package im.zhaojun.common.model;
|
||||
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity(name = "STORAGE_CONFIG")
|
||||
@Data
|
||||
public class StorageConfig {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
private StorageTypeEnum type;
|
||||
|
||||
@Column(name = "k")
|
||||
private String key;
|
||||
|
||||
private String title;
|
||||
|
||||
private String value;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public StorageTypeEnum getType() {
|
||||
return type;
|
||||
}
|
||||
|
||||
public void setType(StorageTypeEnum type) {
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getTitle() {
|
||||
return title;
|
||||
}
|
||||
|
||||
public void setTitle(String title) {
|
||||
this.title = title;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
}
|
||||
@@ -1,53 +0,0 @@
|
||||
package im.zhaojun.common.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
|
||||
@Entity(name = "SYSTEM_CONFIG")
|
||||
@Data
|
||||
public class SystemConfig {
|
||||
|
||||
@Id
|
||||
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||
private Integer id;
|
||||
|
||||
@Column(name = "k")
|
||||
private String key;
|
||||
|
||||
private String value;
|
||||
|
||||
private String remark;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public void setKey(String key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public String getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
public void setValue(String value) {
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
public String getRemark() {
|
||||
return remark;
|
||||
}
|
||||
|
||||
public void setRemark(String remark) {
|
||||
this.remark = remark;
|
||||
}
|
||||
}
|
||||
@@ -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";
|
||||
|
||||
}
|
||||
@@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,74 +0,0 @@
|
||||
package im.zhaojun.common.model.dto;
|
||||
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class InstallModelDTO {
|
||||
private String siteName;
|
||||
private StorageTypeEnum storageStrategy;
|
||||
private String username;
|
||||
private String password;
|
||||
private String domain;
|
||||
private Map<String, String> storageStrategyConfig;
|
||||
|
||||
public String getSiteName() {
|
||||
return siteName;
|
||||
}
|
||||
|
||||
public void setSiteName(String siteName) {
|
||||
this.siteName = siteName;
|
||||
}
|
||||
|
||||
public StorageTypeEnum getStorageStrategy() {
|
||||
return storageStrategy;
|
||||
}
|
||||
|
||||
public void setStorageStrategy(StorageTypeEnum storageStrategy) {
|
||||
this.storageStrategy = storageStrategy;
|
||||
}
|
||||
|
||||
public Map<String, String> getStorageStrategyConfig() {
|
||||
return storageStrategyConfig;
|
||||
}
|
||||
|
||||
public void setStorageStrategyConfig(Map<String, String> storageStrategyConfig) {
|
||||
this.storageStrategyConfig = storageStrategyConfig;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString() {
|
||||
return "InstallModelDTO{" +
|
||||
"siteName='" + siteName + '\'' +
|
||||
", storageStrategy=" + storageStrategy +
|
||||
", username='" + username + '\'' +
|
||||
", password='" + password + '\'' +
|
||||
", domain='" + domain + '\'' +
|
||||
", storageStrategyConfig=" + storageStrategyConfig +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -1,47 +0,0 @@
|
||||
package im.zhaojun.common.model.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
public class SiteConfigDTO implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = 8811196207046121740L;
|
||||
|
||||
private String header;
|
||||
|
||||
private String footer;
|
||||
|
||||
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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
@@ -1,23 +0,0 @@
|
||||
package im.zhaojun.common.security;
|
||||
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
@Configuration
|
||||
public class MyCorsFilter {
|
||||
|
||||
@Bean
|
||||
public CorsFilter corsFilter() {
|
||||
final UrlBasedCorsConfigurationSource urlBasedCorsConfigurationSource = new UrlBasedCorsConfigurationSource();
|
||||
final CorsConfiguration corsConfiguration = new CorsConfiguration();
|
||||
corsConfiguration.setAllowCredentials(true);
|
||||
corsConfiguration.addAllowedOrigin("*");
|
||||
corsConfiguration.addAllowedHeader("*");
|
||||
corsConfiguration.addAllowedMethod("*");
|
||||
urlBasedCorsConfigurationSource.registerCorsConfiguration("/**", corsConfiguration);
|
||||
return new CorsFilter(urlBasedCorsConfigurationSource);
|
||||
}
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package im.zhaojun.common.security;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.http.HttpMethod;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.builders.WebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* 自定义Security配置类
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
protected void configure(HttpSecurity http) throws Exception {
|
||||
http
|
||||
// .authenticationProvider(authenticationProvider())
|
||||
.exceptionHandling()
|
||||
//未登录时,进行json格式的提示,很喜欢这种写法,不用单独写一个又一个的类
|
||||
.authenticationEntryPoint((request, response, authException) -> {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(objectMapper.writeValueAsString(ResultBean.error("未登录")));
|
||||
out.flush();
|
||||
out.close();
|
||||
})
|
||||
.and()
|
||||
.authorizeRequests()
|
||||
.antMatchers("/").permitAll()
|
||||
.antMatchers("/admin/**").authenticated()
|
||||
.and()
|
||||
.formLogin() //使用自带的登录
|
||||
//登录失败,返回json
|
||||
.failureHandler((request, response, ex) -> {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
PrintWriter out = response.getWriter();
|
||||
String msg;
|
||||
if (ex instanceof UsernameNotFoundException || ex instanceof BadCredentialsException) {
|
||||
msg = "用户名或密码错误";
|
||||
} else {
|
||||
msg = "登录失败";
|
||||
}
|
||||
out.write(objectMapper.writeValueAsString(ResultBean.error(msg)));
|
||||
out.flush();
|
||||
out.close();
|
||||
})
|
||||
//登录成功,返回json
|
||||
.successHandler((request, response, authentication) -> {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(objectMapper.writeValueAsString(ResultBean.success(authentication)));
|
||||
out.flush();
|
||||
out.close();
|
||||
})
|
||||
.and()
|
||||
.exceptionHandling()
|
||||
//没有权限,返回json
|
||||
.accessDeniedHandler((request, response, ex) -> {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(objectMapper.writeValueAsString(ResultBean.error("权限不足")));
|
||||
out.flush();
|
||||
out.close();
|
||||
})
|
||||
.and()
|
||||
.logout()
|
||||
//退出成功,返回json
|
||||
.logoutSuccessHandler((request, response, authentication) -> {
|
||||
response.setContentType("application/json;charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(objectMapper.writeValueAsString(ResultBean.error("注销成功")));
|
||||
out.flush();
|
||||
out.close();
|
||||
})
|
||||
.and()
|
||||
.logout().permitAll();
|
||||
|
||||
http.cors();
|
||||
http.csrf().disable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder web) throws Exception {
|
||||
web.userDetailsService(myUserDetailsServiceImpl()).passwordEncoder(passwordEncoder());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public MyUserDetailsServiceImpl myUserDetailsServiceImpl() {
|
||||
return new MyUserDetailsServiceImpl();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(WebSecurity web) {
|
||||
//对于在header里面增加token等类似情况,放行所有OPTIONS请求。
|
||||
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PasswordEncoder passwordEncoder() {
|
||||
return new BCryptPasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,26 +0,0 @@
|
||||
package im.zhaojun.common.security;
|
||||
|
||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import org.springframework.security.core.userdetails.User;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
|
||||
public class MyUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
/**
|
||||
* 授权的时候是对角色授权,认证的时候应该基于资源,而不是角色,因为资源是不变的,而用户的角色是会变的
|
||||
*/
|
||||
@Override
|
||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
|
||||
return new User(systemConfig.getUsername(), systemConfig.getPassword(), Collections.emptyList());
|
||||
}
|
||||
}
|
||||
@@ -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 ));
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
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();
|
||||
}
|
||||
@@ -1,122 +0,0 @@
|
||||
package im.zhaojun.common.service;
|
||||
|
||||
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;
|
||||
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 = new BCryptPasswordEncoder().encode(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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
package im.zhaojun.common.util;
|
||||
|
||||
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(url, String.class);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,79 +0,0 @@
|
||||
package im.zhaojun.common.util;
|
||||
|
||||
public class StringUtils {
|
||||
|
||||
/**
|
||||
* 移除 URL 中的第一个 '/'
|
||||
* @return 如 path = '/folder1/file1', 返回 'folder1/file1'
|
||||
*/
|
||||
public static String removeFirstSeparator(String path) {
|
||||
if (!"".equals(path) && path.charAt(0) == '/') {
|
||||
path = path.substring(1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除 URL 中的最后一个 '/'
|
||||
* @return 如 path = '/folder1/file1/', 返回 '/folder1/file1'
|
||||
*/
|
||||
public static String removeLastSeparator(String path) {
|
||||
if (!"".equals(path) && path.charAt(path.length() - 1) == '/') {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static String concatUrl(String path, String name) {
|
||||
return removeDuplicateSeparator("/" + path + "/" + name);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 将域名和路径组装成 URL, 主要用来处理分隔符 '/'
|
||||
* @param domain 域名
|
||||
* @param path 路径
|
||||
* @return URL
|
||||
*/
|
||||
public static String concatPath(String domain, String path) {
|
||||
if (path != null && path.length() > 1 && path.charAt(0) != '/') {
|
||||
path = '/' + path;
|
||||
}
|
||||
|
||||
if (domain.charAt(domain.length() - 1) == '/') {
|
||||
domain = domain.substring(0, domain.length() - 2);
|
||||
}
|
||||
|
||||
return domain + path;
|
||||
}
|
||||
|
||||
public static String removeDuplicateSeparator(String path) {
|
||||
if (path == null || path.length() < 2) {
|
||||
return path;
|
||||
}
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (path.indexOf("http://") == 0) {
|
||||
sb.append("http://");
|
||||
} else if (path.indexOf("https://") == 0) {
|
||||
sb.append("http://");
|
||||
}
|
||||
|
||||
for (int i = sb.length(); i < path.length() - 1; i++) {
|
||||
char current = path.charAt(i);
|
||||
char next = path.charAt(i + 1);
|
||||
if (!(current == '/' && next == '/')) {
|
||||
sb.append(current);
|
||||
}
|
||||
}
|
||||
sb.append(path.charAt(path.length() - 1));
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
public static boolean isNullOrEmpty(String s) {
|
||||
return s == null || "".equals(s);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,66 +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.nio.file.Files;
|
||||
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 {
|
||||
// 获取文件 MIME 类型
|
||||
String fileMimeType = Files.probeContentType(file.toPath());
|
||||
|
||||
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
|
||||
if (fileMimeType == null || "".equals(fileMimeType)) {
|
||||
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
|
||||
headers.add("Content-Disposition", "attachment; filename=" + file.getName());
|
||||
} else {
|
||||
mediaType = MediaType.parseMediaType(fileMimeType);
|
||||
}
|
||||
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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,109 +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.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
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.concatPath( 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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
// }
|
||||
// }
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,111 +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 String domain;
|
||||
|
||||
private UpYun upYun;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@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();
|
||||
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(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(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;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,14 +1,17 @@
|
||||
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.data.jpa.repository.config.EnableJpaRepositories;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@EnableAsync
|
||||
@SpringBootApplication
|
||||
@EnableCaching
|
||||
@EnableJpaRepositories("im.zhaojun.zfile.repository")
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
public class ZfileApplication {
|
||||
|
||||
@@ -0,0 +1,66 @@
|
||||
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.Collections;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* 缓存切面类, 用于访问文件夹时, 缓存文件列表内容.
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class FileListCacheAspect {
|
||||
|
||||
@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 = Collections.unmodifiableList((List<FileItemDTO>) point.proceed());
|
||||
zFileCache.put(driveId, path, result);
|
||||
} else {
|
||||
result = cacheFileList;
|
||||
}
|
||||
} else {
|
||||
result = (List<FileItemDTO>) point.proceed();
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
}
|
||||
19
src/main/java/im/zhaojun/zfile/cache/DriveCacheKey.java
vendored
Normal file
19
src/main/java/im/zhaojun/zfile/cache/DriveCacheKey.java
vendored
Normal 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;
|
||||
|
||||
}
|
||||
55
src/main/java/im/zhaojun/zfile/cache/MyTimedCache.java
vendored
Normal file
55
src/main/java/im/zhaojun/zfile/cache/MyTimedCache.java
vendored
Normal file
@@ -0,0 +1,55 @@
|
||||
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) {
|
||||
if (driveContext == null) {
|
||||
driveContext = SpringContextHolder.getBean(DriveContext.class);
|
||||
}
|
||||
|
||||
DriveCacheKey cacheKey = (DriveCacheKey) key;
|
||||
AbstractBaseFileService baseFileService = driveContext.get(cacheKey.getDriveId());
|
||||
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("尝试刷新缓存: {}", cacheKey);
|
||||
}
|
||||
|
||||
if (baseFileService == null) {
|
||||
log.error("尝试刷新缓存: {}, 时出现异常, 驱动器已不存在", cacheKey);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
baseFileService.fileList(cacheKey.getKey());
|
||||
} catch (Exception e) {
|
||||
log.error("尝试刷新缓存 {} 失败", cacheKey);
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
331
src/main/java/im/zhaojun/zfile/cache/ZFileCache.java
vendored
Normal file
331
src/main/java/im/zhaojun/zfile/cache/ZFileCache.java
vendored
Normal file
@@ -0,0 +1,331 @@
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
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
|
||||
@Slf4j
|
||||
public class ZFileCache {
|
||||
|
||||
@Resource
|
||||
private DriverConfigRepository driverConfigRepository;
|
||||
|
||||
/**
|
||||
* 缓存过期时间
|
||||
*/
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private long timeout;
|
||||
|
||||
/**
|
||||
* 缓存自动刷新间隔
|
||||
*/
|
||||
@Value("${zfile.cache.auto-refresh.interval}")
|
||||
private long autoRefreshInterval;
|
||||
|
||||
/**
|
||||
* 文件/文件对象缓存.
|
||||
*
|
||||
* 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;
|
||||
|
||||
|
||||
/**
|
||||
* 写入缓存
|
||||
*
|
||||
* @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) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("清空驱动器所有缓存, driveId: {}", 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) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("开启缓存自动刷新 driveId: {}", 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) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("停止缓存自动刷新 driveId: {}", driveId);
|
||||
}
|
||||
MyTimedCache<DriveCacheKey, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
|
||||
if (driveCache != null) {
|
||||
driveCache.cancelPruneSchedule();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
47
src/main/java/im/zhaojun/zfile/config/OneDriveConfig.java
Normal file
47
src/main/java/im/zhaojun/zfile/config/OneDriveConfig.java
Normal file
@@ -0,0 +1,47 @@
|
||||
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 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.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
public class OneDriveConfig {
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
/**
|
||||
* 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(((List)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;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.config;
|
||||
53
src/main/java/im/zhaojun/zfile/config/WebMvcConfig.java
Normal file
53
src/main/java/im/zhaojun/zfile/config/WebMvcConfig.java
Normal file
@@ -0,0 +1,53 @@
|
||||
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.server.ConfigurableWebServerFactory;
|
||||
import org.springframework.boot.web.server.ErrorPage;
|
||||
import org.springframework.boot.web.server.WebServerFactoryCustomizer;
|
||||
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.http.HttpStatus;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @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;
|
||||
}
|
||||
|
||||
@Bean
|
||||
public WebServerFactoryCustomizer<ConfigurableWebServerFactory> webServerFactoryCustomizer(){
|
||||
return factory -> {
|
||||
ErrorPage error404Page = new ErrorPage(HttpStatus.NOT_FOUND, "/index.html");
|
||||
ErrorPage error200Page = new ErrorPage(HttpStatus.OK, "/index.html");
|
||||
Set<ErrorPage> errorPages = new HashSet<>();
|
||||
errorPages.add(error404Page);
|
||||
errorPages.add(error200Page);
|
||||
factory.setErrorPages(errorPages);
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package im.zhaojun.zfile.config;
|
||||
|
||||
import im.zhaojun.zfile.filter.CorsFilter;
|
||||
import org.apache.http.client.HttpClient;
|
||||
import org.apache.http.impl.client.HttpClientBuilder;
|
||||
import org.springframework.boot.web.servlet.FilterRegistrationBean;
|
||||
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.client.HttpComponentsClientHttpRequestFactory;
|
||||
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 {
|
||||
|
||||
@Bean
|
||||
public RestTemplate restTemplate(){
|
||||
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
|
||||
HttpClient httpClient = HttpClientBuilder.create().build();
|
||||
httpRequestFactory.setHttpClient(httpClient);
|
||||
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
||||
147
src/main/java/im/zhaojun/zfile/context/DriveContext.java
Normal file
147
src/main/java/im/zhaojun/zfile/context/DriveContext.java
Normal file
@@ -0,0 +1,147 @@
|
||||
package im.zhaojun.zfile.context;
|
||||
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import im.zhaojun.zfile.exception.InvalidDriveException;
|
||||
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 lombok.extern.slf4j.Slf4j;
|
||||
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.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
/**
|
||||
* 每个驱动器对应一个 Service, 其中初始化好了与对象存储的连接信息.
|
||||
* 此驱动器上下文环境用户缓存每个 Service, 避免重复创建连接.
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Component
|
||||
@DependsOn("springContextHolder")
|
||||
@Slf4j
|
||||
public class DriveContext implements ApplicationContextAware {
|
||||
|
||||
/**
|
||||
* Map<Integer, AbstractBaseFileService>
|
||||
* Map<驱动器 ID, 驱动器连接 Service>
|
||||
*/
|
||||
private static Map<Integer, AbstractBaseFileService> drivesServiceMap = new ConcurrentHashMap<>();
|
||||
|
||||
@Resource
|
||||
private DriveConfigService driveConfigService;
|
||||
|
||||
|
||||
/**
|
||||
* 项目启动时, 自动调用数据库已存储的所有驱动器进行初始化.
|
||||
*/
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
List<DriveConfig> list = driveConfigService.list();
|
||||
for (DriveConfig driveConfig : list) {
|
||||
try {
|
||||
init(driveConfig.getId());
|
||||
log.info("启动时初始化驱动器成功, 驱动器信息: {}", JSON.toJSONString(driveConfig));
|
||||
} catch (Exception e) {
|
||||
log.error("启动时初始化驱动器失败, 驱动器信息: {}", JSON.toJSONString(driveConfig), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化指定驱动器的 Service, 添加到上下文环境中.
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID.
|
||||
*/
|
||||
public void init(Integer driveId) {
|
||||
AbstractBaseFileService baseFileService = getBeanByDriveId(driveId);
|
||||
if (baseFileService != null) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("尝试初始化驱动器, driveId: {}", driveId);
|
||||
}
|
||||
baseFileService.init(driveId);
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("初始化驱动器成功, driveId: {}", driveId);
|
||||
}
|
||||
drivesServiceMap.put(driveId, baseFileService);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定驱动器的 Service.
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*
|
||||
* @return 驱动器对应的 Service
|
||||
*/
|
||||
public AbstractBaseFileService get(Integer driveId) {
|
||||
AbstractBaseFileService abstractBaseFileService = drivesServiceMap.get(driveId);
|
||||
if (abstractBaseFileService == null) {
|
||||
throw new InvalidDriveException("此驱动器不存在或初始化失败, 请检查后台参数配置");
|
||||
}
|
||||
return abstractBaseFileService;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 销毁指定驱动器的 Service.
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
public void destroy(Integer driveId) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("清理驱动器上下文对象, driveId: {}", 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;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新上下文环境中的驱动器 ID
|
||||
*
|
||||
* @param updateId
|
||||
* 驱动器原 ID
|
||||
*
|
||||
* @param newId
|
||||
* 驱动器新 ID
|
||||
*/
|
||||
public void updateDriveId(Integer updateId, Integer newId) {
|
||||
AbstractBaseFileService fileService = drivesServiceMap.remove(updateId);
|
||||
fileService.setDriveId(newId);
|
||||
drivesServiceMap.put(newId, fileService);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
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;
|
||||
@@ -9,13 +9,19 @@ 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 +30,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 +48,9 @@ public class StorageTypeFactory implements ApplicationContextAware {
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
public static ApplicationContext getApplicationContext() {
|
||||
return applicationContext;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.SystemConfigService;
|
||||
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;
|
||||
|
||||
/**
|
||||
* 管理后台接口
|
||||
* @author zhaojun
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
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) {
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import im.zhaojun.zfile.model.dto.CacheInfoDTO;
|
||||
import im.zhaojun.zfile.model.support.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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.SystemConfigService;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
@Controller
|
||||
public class DebugController {
|
||||
|
||||
@Value("${zfile.debug}")
|
||||
private Boolean debug;
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@ResponseBody
|
||||
@GetMapping("/debug/resetPwd")
|
||||
public ResultBean resetPwd() {
|
||||
if (debug) {
|
||||
systemConfigService.updateUsernameAndPwd("admin", "123456");
|
||||
return ResultBean.success();
|
||||
} else {
|
||||
return ResultBean.error("未开启 DEBUG 模式,不允许进行此操作。");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,173 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import im.zhaojun.zfile.model.dto.DriveConfigDTO;
|
||||
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||
import im.zhaojun.zfile.model.entity.FilterConfig;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.DriveConfigService;
|
||||
import im.zhaojun.zfile.service.FilterConfigService;
|
||||
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")
|
||||
public class DriveController {
|
||||
|
||||
@Resource
|
||||
private DriveConfigService driveConfigService;
|
||||
|
||||
@Resource
|
||||
private FilterConfigService filterConfigService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有驱动器列表
|
||||
*
|
||||
* @return 驱动器列表
|
||||
*/
|
||||
@GetMapping("/drives")
|
||||
public ResultBean driveList() {
|
||||
List<DriveConfig> list = driveConfigService.list();
|
||||
return ResultBean.success(list);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定驱动器基本信息及其参数
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*
|
||||
* @return 驱动器基本信息
|
||||
*/
|
||||
@GetMapping("/drive/{driveId}")
|
||||
public ResultBean driveItem(@PathVariable Integer driveId) {
|
||||
DriveConfigDTO driveConfig = driveConfigService.findDriveConfigDTOById(driveId);
|
||||
return ResultBean.success(driveConfig);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存驱动器设置
|
||||
*/
|
||||
@PostMapping("/drive")
|
||||
public ResultBean saveDriveItem(@RequestBody DriveConfigDTO driveConfigDTO) {
|
||||
driveConfigService.saveDriveConfigDTO(driveConfigDTO);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 删除驱动器设置
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
@DeleteMapping("/drive/{driveId}")
|
||||
public ResultBean deleteDriveItem(@PathVariable Integer driveId) {
|
||||
driveConfigService.deleteById(driveId);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 启用驱动器
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
@PostMapping("/drive/{driveId}/enable")
|
||||
public ResultBean enable(@PathVariable Integer driveId) {
|
||||
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||
driveConfig.setEnable(true);
|
||||
driveConfigService.updateDriveConfig(driveConfig);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止驱动器
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
@PostMapping("/drive/{driveId}/disable")
|
||||
public ResultBean disable(@PathVariable Integer driveId) {
|
||||
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||
driveConfig.setEnable(false);
|
||||
driveConfigService.updateDriveConfig(driveConfig);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据驱动器 ID 获取过滤文件列表
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
@GetMapping("/drive/{driveId}/filters")
|
||||
public ResultBean getFilters(@PathVariable Integer driveId) {
|
||||
return ResultBean.success(filterConfigService.findByDriveId(driveId));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 停止驱动器
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
@PostMapping("/drive/{driveId}/filters")
|
||||
public ResultBean saveFilters(@RequestBody List<FilterConfig> filter, @PathVariable Integer driveId) {
|
||||
filterConfigService.batchSave(filter, driveId);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 保存拖拽排序信息
|
||||
*
|
||||
* @param driveConfigs
|
||||
* 拖拽排序信息
|
||||
*/
|
||||
@PostMapping("/drive/drag")
|
||||
public ResultBean saveDriveDrag(@RequestBody List<JSONObject> driveConfigs) {
|
||||
driveConfigService.saveDriveDrag(driveConfigs);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 更新驱动器 ID
|
||||
*
|
||||
* @param updateId
|
||||
* 驱动器原 ID
|
||||
*
|
||||
* @param newId
|
||||
* 驱动器新 ID
|
||||
*/
|
||||
@PostMapping("/drive/updateId")
|
||||
public ResultBean updateDriveId(Integer updateId, Integer newId) {
|
||||
DriveConfig driveConfig = driveConfigService.findById(newId);
|
||||
if (driveConfig != null) {
|
||||
return ResultBean.error("已存在的 ID,请更换 ID 后重试。");
|
||||
}
|
||||
driveConfigService.updateId(updateId, newId);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import cn.hutool.core.date.DateUtil;
|
||||
import cn.hutool.core.util.ZipUtil;
|
||||
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.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* 日志相关 Controller
|
||||
* @author zhaojun
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
@Slf4j
|
||||
public class LogController {
|
||||
|
||||
/**
|
||||
* 系统日志下载
|
||||
*/
|
||||
@GetMapping("/log")
|
||||
public ResponseEntity<Object> downloadLog() {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("下载诊断日志");
|
||||
}
|
||||
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.exportSingleThread(fileZip, "ZFile 诊断日志 - " + currentDate + ".zip");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
@@ -0,0 +1,47 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import im.zhaojun.zfile.context.StorageTypeContext;
|
||||
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 系统元数据 Controller
|
||||
* @author zhaojun
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
public class MateDataController {
|
||||
|
||||
/**
|
||||
* 返回支持的存储引擎.
|
||||
*/
|
||||
@GetMapping("/support-strategy")
|
||||
public ResultBean supportStrategy() {
|
||||
StorageTypeEnum[] values = StorageTypeEnum.values();
|
||||
return ResultBean.successData(values);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取指定存储策略的表单域
|
||||
*
|
||||
* @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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package im.zhaojun.zfile.controller.admin;
|
||||
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.ShortLinkConfigService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 直链管理 Controller
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/admin")
|
||||
public class ShortLinkManagerController {
|
||||
|
||||
@Resource
|
||||
private ShortLinkConfigService shortLinkConfigService;
|
||||
|
||||
@GetMapping("/link/list")
|
||||
@ResponseBody
|
||||
public ResultBean list(String key,
|
||||
String url,
|
||||
String dateFrom,
|
||||
String dateTo,
|
||||
Integer page,
|
||||
Integer limit,
|
||||
@RequestParam(required = false, defaultValue = "createDate") String orderBy,
|
||||
@RequestParam(required = false, defaultValue = "desc") String orderDirection) {
|
||||
return ResultBean.success(shortLinkConfigService.find(key, url, dateFrom, dateTo, page, limit, orderBy, orderDirection));
|
||||
}
|
||||
|
||||
@GetMapping("/link/delete/{id}")
|
||||
@ResponseBody
|
||||
public ResultBean deleteById(@PathVariable Integer id) {
|
||||
shortLinkConfigService.deleteById(id);
|
||||
return ResultBean.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,102 @@
|
||||
package im.zhaojun.zfile.controller.home;
|
||||
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import im.zhaojun.zfile.context.DriveContext;
|
||||
import im.zhaojun.zfile.exception.NotEnabledDriveException;
|
||||
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||
import im.zhaojun.zfile.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.zfile.service.DriveConfigService;
|
||||
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||
import im.zhaojun.zfile.util.HttpUtil;
|
||||
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 javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
import java.io.PrintWriter;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 直链 Controller
|
||||
* @author Zhao Jun
|
||||
*/
|
||||
@Controller
|
||||
public class DirectLinkController {
|
||||
|
||||
@Resource
|
||||
private DriveContext driveContext;
|
||||
|
||||
@Resource
|
||||
private DriveConfigService driveConfigService;
|
||||
|
||||
/**
|
||||
* 获取指定驱动器, 某个文件的直链, 然后重定向过去.
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*
|
||||
* @return 重定向至文件直链
|
||||
*/
|
||||
@GetMapping("/${zfile.directLinkPrefix}/{driveId}/**")
|
||||
public String directlink(@PathVariable("driveId") Integer driveId,
|
||||
final HttpServletRequest request,
|
||||
final HttpServletResponse response) throws IOException {
|
||||
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||
Boolean enable = driveConfig.getEnable();
|
||||
if (!enable) {
|
||||
throw new NotEnabledDriveException();
|
||||
}
|
||||
|
||||
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.get(driveId);
|
||||
FileItemDTO fileItem = fileService.getFileItem(filePath);
|
||||
|
||||
String url = fileItem.getUrl();
|
||||
|
||||
if (StrUtil.equalsIgnoreCase(FileUtil.extName(fileItem.getName()), "m3u8")) {
|
||||
String textContent = HttpUtil.getTextContent(url);
|
||||
response.setContentType("application/vnd.apple.mpegurl;charset=utf-8");
|
||||
PrintWriter out = response.getWriter();
|
||||
out.write(textContent);
|
||||
out.flush();
|
||||
out.close();
|
||||
return null;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,243 @@
|
||||
package im.zhaojun.zfile.controller.home;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson.JSON;
|
||||
import im.zhaojun.zfile.context.DriveContext;
|
||||
import im.zhaojun.zfile.exception.NotEnabledDriveException;
|
||||
import im.zhaojun.zfile.exception.PasswordVerifyException;
|
||||
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||
import im.zhaojun.zfile.model.dto.DriveListDTO;
|
||||
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||
import im.zhaojun.zfile.model.dto.FileListDTO;
|
||||
import im.zhaojun.zfile.model.dto.SystemFrontConfigDTO;
|
||||
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.model.support.VerifyResult;
|
||||
import im.zhaojun.zfile.service.DriveConfigService;
|
||||
import im.zhaojun.zfile.service.FilterConfigService;
|
||||
import im.zhaojun.zfile.service.SystemConfigService;
|
||||
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||
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.beans.factory.annotation.Value;
|
||||
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.List;
|
||||
import java.util.Objects;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 前台文件管理
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Slf4j
|
||||
@RequestMapping("/api")
|
||||
@RestController
|
||||
public class FileController {
|
||||
|
||||
@Value("${zfile.debug}")
|
||||
private Boolean debug;
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
private DriveContext driveContext;
|
||||
|
||||
@Resource
|
||||
private DriveConfigService driveConfigService;
|
||||
|
||||
@Resource
|
||||
private FilterConfigService filterConfigService;
|
||||
|
||||
|
||||
/**
|
||||
* 获取所有已启用的驱动器
|
||||
*
|
||||
* @return 所有已启用驱动器
|
||||
*/
|
||||
@GetMapping("/drive/list")
|
||||
public ResultBean drives() {
|
||||
List<DriveConfig> driveList = driveConfigService.listOnlyEnable();
|
||||
boolean isInstall = systemConfigService.getIsInstall();
|
||||
DriveListDTO driveListDTO = new DriveListDTO(driveList, isInstall);
|
||||
return ResultBean.success(driveListDTO);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取某个驱动器下, 指定路径的数据
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*
|
||||
* @param path
|
||||
* 路径
|
||||
*
|
||||
* @param password
|
||||
* 文件夹密码, 某些文件夹需要密码才能访问, 当不需要密码时, 此参数可以为空
|
||||
*
|
||||
* @return 当前路径下所有文件及文件夹
|
||||
*/
|
||||
@GetMapping("/list/{driveId}")
|
||||
public ResultBean list(@PathVariable(name = "driveId") Integer driveId,
|
||||
@RequestParam(defaultValue = "/") String path,
|
||||
@RequestParam(required = false) String password,
|
||||
@RequestParam(required = false) String orderBy,
|
||||
@RequestParam(required = false, defaultValue = "asc") String orderDirection) throws Exception {
|
||||
AbstractBaseFileService fileService = driveContext.get(driveId);
|
||||
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator(ZFileConstant.PATH_SEPARATOR + path + ZFileConstant.PATH_SEPARATOR));
|
||||
|
||||
// 创建副本, 防止排序和过滤对原数据产生影响
|
||||
List<FileItemDTO> copyList = new ArrayList<>(fileItemList);
|
||||
|
||||
// 校验密码, 如果校验不通过, 则返回错误消息
|
||||
VerifyResult verifyResult = verifyPassword(copyList, driveId, path, password);
|
||||
if (!verifyResult.isPassed()) {
|
||||
return ResultBean.error(verifyResult.getMsg(), verifyResult.getCode());
|
||||
}
|
||||
|
||||
// 过滤掉驱动器配置的表达式中要隐藏的数据
|
||||
filterFileList(copyList, driveId);
|
||||
|
||||
// 按照自然排序
|
||||
copyList.sort(new FileComparator(orderBy, orderDirection));
|
||||
|
||||
|
||||
|
||||
// 开始获取参数信息
|
||||
SystemFrontConfigDTO systemConfig = systemConfigService.getSystemFrontConfig(driveId);
|
||||
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||
Boolean enable = driveConfig.getEnable();
|
||||
if (!enable) {
|
||||
throw new NotEnabledDriveException();
|
||||
}
|
||||
|
||||
systemConfig.setDebugMode(debug);
|
||||
systemConfig.setDefaultSwitchToImgMode(driveConfig.getDefaultSwitchToImgMode());
|
||||
systemConfig.setDirectLinkPrefix(ZFileConstant.DIRECT_LINK_PREFIX);
|
||||
|
||||
// 如果不是 FTP 模式,则尝试获取当前文件夹中的 README 文件,有则读取,没有则停止
|
||||
if (!Objects.equals(driveConfig.getType(), StorageTypeEnum.FTP)) {
|
||||
fileItemList.stream()
|
||||
.filter(fileItemDTO -> Objects.equals(ZFileConstant.README_FILE_NAME, fileItemDTO.getName()))
|
||||
.findFirst()
|
||||
.ifPresent(fileItemDTO -> {
|
||||
String readme = HttpUtil.getTextContent(fileItemDTO.getUrl());
|
||||
systemConfig.setReadme(readme);
|
||||
});
|
||||
}
|
||||
|
||||
return ResultBean.successData(new FileListDTO(copyList, systemConfig));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验密码
|
||||
* @param fileItemList
|
||||
* 文件列表
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
* @param path
|
||||
* 请求路径
|
||||
* @param inputPassword
|
||||
* 用户输入的密码
|
||||
* @return 是否校验通过
|
||||
*/
|
||||
private VerifyResult verifyPassword(List<FileItemDTO> fileItemList, Integer driveId, String path, String inputPassword) {
|
||||
AbstractBaseFileService fileService = driveContext.get(driveId);
|
||||
|
||||
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
|
||||
String expectedPasswordContent;
|
||||
try {
|
||||
expectedPasswordContent = HttpUtil.getTextContent(fileItemDTO.getUrl());
|
||||
} catch (HttpClientErrorException httpClientErrorException) {
|
||||
log.trace("尝试重新获取密码文件缓存中链接后仍失败, driveId: {}, path: {}, inputPassword: {}, passwordFile:{} ",
|
||||
driveId, path, inputPassword, JSON.toJSONString(fileItemDTO), httpClientErrorException);
|
||||
try {
|
||||
String pwdFileFullPath = StringUtils.removeDuplicateSeparator(fileItemDTO.getPath() + ZFileConstant.PATH_SEPARATOR + fileItemDTO.getName());
|
||||
FileItemDTO pwdFileItem = fileService.getFileItem(pwdFileFullPath);
|
||||
expectedPasswordContent = HttpUtil.getTextContent(pwdFileItem.getUrl());
|
||||
} catch (Exception e) {
|
||||
throw new PasswordVerifyException("此文件夹为加密文件夹, 但密码检查异常, 请联系管理员检查密码设置", e);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
throw new PasswordVerifyException("此文件夹为加密文件夹, 但密码检查异常, 请联系管理员检查密码设置", e);
|
||||
}
|
||||
|
||||
if (matchPassword(expectedPasswordContent, inputPassword)) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (StrUtil.isEmpty(inputPassword)) {
|
||||
return VerifyResult.fail("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
|
||||
}
|
||||
return VerifyResult.fail("密码错误.", ResultBean.INVALID_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
return VerifyResult.success();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 校验两个密码是否相同, 忽略空白字符
|
||||
*
|
||||
* @param expectedPasswordContent
|
||||
* 预期密码
|
||||
*
|
||||
* @param password
|
||||
* 实际输入密码
|
||||
*
|
||||
* @return 是否匹配
|
||||
*/
|
||||
private boolean matchPassword(String expectedPasswordContent, String password) {
|
||||
if (Objects.equals(expectedPasswordContent, password)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (expectedPasswordContent == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (password == null) {
|
||||
return false;
|
||||
}
|
||||
|
||||
expectedPasswordContent = expectedPasswordContent.replace("\n", "").trim();
|
||||
password = password.replace("\n", "").trim();
|
||||
return Objects.equals(expectedPasswordContent, password);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 过滤文件列表, 去除密码, 文档文件和此驱动器通过规则过滤的文件.
|
||||
*
|
||||
* @param fileItemList
|
||||
* 文件列表
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
*/
|
||||
private void filterFileList(List<FileItemDTO> fileItemList, Integer driveId) {
|
||||
if (fileItemList == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
fileItemList.removeIf(
|
||||
fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|
||||
|| ZFileConstant.README_FILE_NAME.equals(fileItem.getName())
|
||||
|| filterConfigService.filterResultIsHidden(driveId, StringUtils.concatUrl(fileItem.getPath(), fileItem.getName()))
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package im.zhaojun.zfile.controller.home;
|
||||
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.util.AudioUtil;
|
||||
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 FileParseController {
|
||||
|
||||
/**
|
||||
* 获取文件内容, 仅限用于 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(AudioUtil.getAudioInfo(url));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,52 @@
|
||||
package im.zhaojun.zfile.controller.home;
|
||||
|
||||
import im.zhaojun.zfile.context.DriveContext;
|
||||
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||
import im.zhaojun.zfile.service.impl.LocalServiceImpl;
|
||||
import im.zhaojun.zfile.util.FileUtil;
|
||||
import im.zhaojun.zfile.util.StringUtils;
|
||||
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 javax.servlet.http.HttpServletResponse;
|
||||
import java.io.File;
|
||||
|
||||
/**
|
||||
* 本地存储 Controller
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Controller
|
||||
public class LocalController {
|
||||
|
||||
@Resource
|
||||
private DriveContext driveContext;
|
||||
|
||||
/**
|
||||
* 本地存储下载指定文件
|
||||
*
|
||||
* @param driveId
|
||||
* 驱动器 ID
|
||||
* @param type
|
||||
* 附件预览类型:
|
||||
* download:下载
|
||||
* default: 浏览器默认行为
|
||||
*/
|
||||
@GetMapping("/file/{driveId}/**")
|
||||
@ResponseBody
|
||||
public void downAttachment(@PathVariable("driveId") Integer driveId, String type, final HttpServletRequest request, final HttpServletResponse response) {
|
||||
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.get(driveId);
|
||||
File file = new File(StringUtils.removeDuplicateSeparator(localService.getFilePath() + ZFileConstant.PATH_SEPARATOR + filePath));
|
||||
FileUtil.export(request, response, file, type);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
package im.zhaojun.zfile.controller.home;
|
||||
|
||||
import cn.hutool.core.util.RandomUtil;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.zfile.model.entity.ShortLinkConfig;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import im.zhaojun.zfile.service.ShortLinkConfigService;
|
||||
import im.zhaojun.zfile.service.SystemConfigService;
|
||||
import im.zhaojun.zfile.util.StringUtils;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* 短链 Controller
|
||||
* @author zhao
|
||||
*/
|
||||
@Controller
|
||||
public class ShortLinkController {
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
private ShortLinkConfigService shortLinkConfigService;
|
||||
|
||||
@GetMapping("/api/short-link")
|
||||
@ResponseBody
|
||||
public ResultBean shortLink(String driveId, String path) {
|
||||
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
|
||||
String domain = systemConfig.getDomain();
|
||||
// 拼接直链地址.
|
||||
String fullPath = StringUtils.concatUrl(StringUtils.DELIMITER_STR, ZFileConstant.DIRECT_LINK_PREFIX, driveId, path);
|
||||
ShortLinkConfig shortLinkConfig = shortLinkConfigService.findByUrl(fullPath);
|
||||
|
||||
if (shortLinkConfig == null) {
|
||||
|
||||
String randomKey;
|
||||
do {
|
||||
// 获取短链
|
||||
randomKey = RandomUtil.randomString(6);
|
||||
shortLinkConfig = shortLinkConfigService.findByKey(randomKey);
|
||||
} while (shortLinkConfig != null);
|
||||
|
||||
shortLinkConfig = new ShortLinkConfig();
|
||||
shortLinkConfig.setKey(randomKey);
|
||||
shortLinkConfig.setUrl(fullPath);
|
||||
shortLinkConfigService.save(shortLinkConfig);
|
||||
}
|
||||
|
||||
|
||||
String shortUrl = StringUtils.removeDuplicateSeparator(domain + "/s/" + shortLinkConfig.getKey());
|
||||
return ResultBean.successData(shortUrl);
|
||||
}
|
||||
|
||||
@GetMapping("/s/{key}")
|
||||
public String parseShortKey(@PathVariable String key) {
|
||||
ShortLinkConfig shortLinkConfig = shortLinkConfigService.findByKey(key);
|
||||
if (shortLinkConfig == null) {
|
||||
throw new RuntimeException("此直链不存在或已失效.");
|
||||
}
|
||||
|
||||
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
|
||||
String domain = systemConfig.getDomain();
|
||||
|
||||
String url = URLUtil.encode(StringUtils.removeDuplicateSeparator(domain + shortLinkConfig.getUrl()));
|
||||
return "redirect:" + url;
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("admin/api/short-link/key")
|
||||
@ResponseBody
|
||||
public ResultBean updateShortKey(Integer id, String newKey) {
|
||||
ShortLinkConfig newShortLinkConfig = shortLinkConfigService.findByKey(newKey);
|
||||
if (newShortLinkConfig != null) {
|
||||
throw new RuntimeException("您输入的 Key 已存在,请重新输入");
|
||||
}
|
||||
|
||||
ShortLinkConfig shortLinkConfig = shortLinkConfigService.findById(id);
|
||||
if (shortLinkConfig == null) {
|
||||
throw new RuntimeException("此直链不存在或已失效.");
|
||||
}
|
||||
|
||||
shortLinkConfig.setKey(newKey);
|
||||
shortLinkConfigService.save(shortLinkConfig);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 批量删除直链
|
||||
*/
|
||||
@DeleteMapping("admin/api/short-link")
|
||||
@ResponseBody
|
||||
public ResultBean batchDelete(@RequestParam("id[]") Integer[] ids) {
|
||||
for (Integer id : ids) {
|
||||
shortLinkConfigService.deleteById(id);
|
||||
}
|
||||
return ResultBean.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package im.zhaojun.zfile.controller.install;
|
||||
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
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;
|
||||
|
||||
@GetMapping("/is-installed")
|
||||
public ResultBean isInstall() {
|
||||
if (!StringUtils.isEmpty(systemConfigService.getAdminUsername())) {
|
||||
return ResultBean.error("请勿重复初始化");
|
||||
}
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
@PostMapping("/doInstall")
|
||||
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();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package im.zhaojun.zfile.controller.onedrive;
|
||||
|
||||
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(value = {"/onedrive", "/onedirve"})
|
||||
public class OneDriveCallbackController {
|
||||
|
||||
@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("/authorize")
|
||||
public String authorize() {
|
||||
return "redirect:https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=" + oneDriveServiceImpl.getClientId() +
|
||||
"&response_type=code&redirect_uri=" + oneDriveServiceImpl.getRedirectUri() +
|
||||
"&scope=" + oneDriveServiceImpl.getScope();
|
||||
}
|
||||
|
||||
|
||||
@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";
|
||||
}
|
||||
|
||||
@GetMapping("/china-authorize")
|
||||
public String authorizeChina() {
|
||||
return "redirect:https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?client_id=" + oneDriveChinaServiceImpl.getClientId() +
|
||||
"&response_type=code&redirect_uri=" + oneDriveChinaServiceImpl.getRedirectUri() +
|
||||
"&scope=" + oneDriveChinaServiceImpl.getScope();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,134 @@
|
||||
package im.zhaojun.zfile.controller.onedrive;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.alibaba.fastjson.JSONObject;
|
||||
import im.zhaojun.zfile.model.dto.SharePointInfoVO;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import org.springframework.http.HttpStatus;
|
||||
import org.springframework.stereotype.Controller;
|
||||
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.ResponseBody;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* SharePoint 工具类
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/sharepoint")
|
||||
public class SharePointHelperController {
|
||||
|
||||
|
||||
/**
|
||||
* 根据 AccessToken 获取域名前缀
|
||||
*/
|
||||
@PostMapping("/getDomainPrefix")
|
||||
@ResponseBody
|
||||
public ResultBean getDomainPrefix(@RequestBody SharePointInfoVO sharePointInfoVO) {
|
||||
|
||||
String host = "";
|
||||
|
||||
// 判断是标准版还是世纪互联版
|
||||
if (Objects.equals(sharePointInfoVO.getType(), "Standard")) {
|
||||
host = "graph.microsoft.com";
|
||||
} else if (Objects.equals(sharePointInfoVO.getType(), "China")) {
|
||||
host = "microsoftgraph.chinacloudapi.cn";
|
||||
}
|
||||
|
||||
// 请求 URL
|
||||
String requestUrl = StrUtil.format("https://{}/v1.0/sites/root", host);
|
||||
|
||||
// 构建请求认证 Token 信息
|
||||
String tokenValue = String.format("%s %s", "Bearer", sharePointInfoVO.getAccessToken());
|
||||
HashMap<String, String> headers = new HashMap<>();
|
||||
headers.put("Authorization", tokenValue);
|
||||
|
||||
// 请求接口
|
||||
HttpRequest getRequest = HttpUtil.createGet(requestUrl);
|
||||
HttpResponse execute = getRequest.addHeaders(headers).execute();
|
||||
String body = execute.body();
|
||||
if (execute.getStatus() != HttpStatus.OK.value()) {
|
||||
return ResultBean.error(body);
|
||||
}
|
||||
|
||||
// 解析前缀
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
String hostname = jsonObject.getJSONObject("siteCollection").getString("hostname");
|
||||
String domainPrefix = StrUtil.subBefore(hostname, ".sharepoint", false);
|
||||
return ResultBean.successData(domainPrefix);
|
||||
}
|
||||
|
||||
@PostMapping("/getSiteId")
|
||||
@ResponseBody
|
||||
public ResultBean getSiteId(@RequestBody SharePointInfoVO sharePointInfoVO) {
|
||||
|
||||
// 判断必填参数
|
||||
if (sharePointInfoVO == null || sharePointInfoVO.getAccessToken() == null || sharePointInfoVO.getSiteName() == null) {
|
||||
return ResultBean.error("参数不全");
|
||||
}
|
||||
|
||||
String host = "";
|
||||
|
||||
// 判断是标准版还是世纪互联版
|
||||
if (Objects.equals(sharePointInfoVO.getType(), "Standard")) {
|
||||
host = "graph.microsoft.com";
|
||||
sharePointInfoVO.setDomainType("com");
|
||||
} else if (Objects.equals(sharePointInfoVO.getType(), "China")) {
|
||||
host = "microsoftgraph.chinacloudapi.cn";
|
||||
sharePointInfoVO.setDomainType("cn");
|
||||
} else {
|
||||
return ResultBean.error("参数不全");
|
||||
}
|
||||
|
||||
// 构建请求认证 Token 信息
|
||||
String tokenValue = String.format("%s %s", "Bearer", sharePointInfoVO.getAccessToken());
|
||||
HashMap<String, String> authorizationHeaders = new HashMap<>();
|
||||
authorizationHeaders.put("Authorization", tokenValue);
|
||||
|
||||
|
||||
// 如果没有域名前缀, 则先获取
|
||||
if (sharePointInfoVO.getDomainPrefix() == null || sharePointInfoVO.getDomainType() == null) {
|
||||
String requestUrl = StrUtil.format("https://{}/v1.0/sites/root", host);
|
||||
HttpRequest getRequest = HttpUtil.createGet(requestUrl);
|
||||
HttpResponse execute = getRequest.addHeaders(authorizationHeaders).execute();
|
||||
String body = execute.body();
|
||||
if (execute.getStatus() != HttpStatus.OK.value()) {
|
||||
return ResultBean.error(body);
|
||||
}
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
String hostname = jsonObject.getJSONObject("siteCollection").getString("hostname");
|
||||
String domainPrefix = StrUtil.subBefore(hostname, ".sharepoint", false);
|
||||
sharePointInfoVO.setDomainPrefix(domainPrefix);
|
||||
}
|
||||
|
||||
|
||||
if (StrUtil.isEmpty(sharePointInfoVO.getSiteType())) {
|
||||
sharePointInfoVO.setSiteType("/sites/");
|
||||
}
|
||||
|
||||
// 请求接口
|
||||
String requestUrl = StrUtil.format("https://{}/v1.0/sites/{}.sharepoint.{}:/{}/{}", host,
|
||||
sharePointInfoVO.getDomainPrefix(),
|
||||
sharePointInfoVO.getDomainType(),
|
||||
sharePointInfoVO.getSiteType(),
|
||||
sharePointInfoVO.getSiteName());
|
||||
HttpRequest getRequest = HttpUtil.createGet(requestUrl);
|
||||
HttpResponse execute = getRequest.addHeaders(authorizationHeaders).execute();
|
||||
String body = execute.body();
|
||||
|
||||
// 解析数据
|
||||
if (execute.getStatus() != HttpStatus.OK.value()) {
|
||||
return ResultBean.error(body);
|
||||
}
|
||||
JSONObject jsonObject = JSONObject.parseObject(body);
|
||||
return ResultBean.successData(jsonObject.getString("id"));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,135 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
import cn.dev33.satoken.exception.NotLoginException;
|
||||
import im.zhaojun.zfile.model.support.ResultBean;
|
||||
import org.apache.catalina.connector.ClientAbortException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.HttpMediaTypeNotAcceptableException;
|
||||
import org.springframework.web.bind.annotation.ControllerAdvice;
|
||||
import org.springframework.web.bind.annotation.ExceptionHandler;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
import java.net.ConnectException;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
* @author zhaojun
|
||||
*/
|
||||
@ControllerAdvice
|
||||
public class GlobleExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
|
||||
|
||||
|
||||
/**
|
||||
* 不存在的文件异常
|
||||
*/
|
||||
@ExceptionHandler({NotEnabledDriveException.class})
|
||||
@ResponseBody
|
||||
public ResultBean notEnabledDrive() {
|
||||
return ResultBean.error("驱动器已关闭");
|
||||
}
|
||||
|
||||
/**
|
||||
* 不存在的文件异常
|
||||
*/
|
||||
@ExceptionHandler({NotExistFileException.class})
|
||||
@ResponseBody
|
||||
public ResultBean notExistFile() {
|
||||
return ResultBean.error("文件不存在");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
|
||||
*/
|
||||
@ExceptionHandler({HttpMediaTypeNotAcceptableException.class, ClientAbortException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public void clientAbortException() {
|
||||
// if (log.isDebugEnabled()) {
|
||||
// log.debug("出现了断开异常:", ex);
|
||||
// }
|
||||
}
|
||||
|
||||
/**
|
||||
* 文件预览异常
|
||||
*/
|
||||
@ExceptionHandler({PasswordVerifyException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean passwordVerifyException(PasswordVerifyException ex) {
|
||||
return ResultBean.error(ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 无效的驱动器异常
|
||||
*/
|
||||
@ExceptionHandler({InvalidDriveException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean invalidDriveException(InvalidDriveException ex) {
|
||||
return ResultBean.error(ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 文件预览异常
|
||||
*/
|
||||
@ExceptionHandler({PreviewException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean previewException(PreviewException ex) {
|
||||
return ResultBean.error(ex.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 初始化异常
|
||||
*/
|
||||
@ExceptionHandler({InitializeDriveException.class})
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean initializeException(InitializeDriveException ex) {
|
||||
return ResultBean.error(ex.getMessage());
|
||||
}
|
||||
|
||||
/**
|
||||
* 登录异常拦截器
|
||||
*/
|
||||
@ExceptionHandler(NotLoginException.class)
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean handlerNotLoginException(NotLoginException e) {
|
||||
return ResultBean.error("未登录");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 登录异常拦截器
|
||||
*/
|
||||
@ExceptionHandler(ConnectException.class)
|
||||
@ResponseBody
|
||||
public ResultBean handlerConnectException(ConnectException e) {
|
||||
return ResultBean.error("请求失败, 清稍后再试");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@ExceptionHandler
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean extraExceptionHandler(Exception e) {
|
||||
log.error(e.getMessage(), e);
|
||||
|
||||
if (e.getClass() == Exception.class) {
|
||||
return ResultBean.error("系统异常, 请联系管理员");
|
||||
} else {
|
||||
return ResultBean.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 对象存储初始化异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InitializeDriveException extends RuntimeException {
|
||||
|
||||
private static final long serialVersionUID = -1920550904063819880L;
|
||||
|
||||
public InitializeDriveException() {
|
||||
}
|
||||
|
||||
public InitializeDriveException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InitializeDriveException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InitializeDriveException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InitializeDriveException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 无效的驱动器异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InvalidDriveException extends RuntimeException {
|
||||
|
||||
public InvalidDriveException() {
|
||||
}
|
||||
|
||||
public InvalidDriveException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidDriveException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InvalidDriveException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InvalidDriveException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 无效的直链异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InvalidShortLinkException extends RuntimeException {
|
||||
public InvalidShortLinkException() {
|
||||
}
|
||||
|
||||
public InvalidShortLinkException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public InvalidShortLinkException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public InvalidShortLinkException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public InvalidShortLinkException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 文件不允许下载异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class NotAllowedDownloadException extends RuntimeException {
|
||||
public NotAllowedDownloadException() {
|
||||
}
|
||||
|
||||
public NotAllowedDownloadException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NotAllowedDownloadException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NotAllowedDownloadException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NotAllowedDownloadException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 未启用的驱动器异常
|
||||
*/
|
||||
public class NotEnabledDriveException extends RuntimeException {
|
||||
|
||||
public NotEnabledDriveException() {
|
||||
}
|
||||
|
||||
public NotEnabledDriveException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NotEnabledDriveException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NotEnabledDriveException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public NotEnabledDriveException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 密码校验失败异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class PasswordVerifyException extends RuntimeException {
|
||||
|
||||
public PasswordVerifyException() {
|
||||
}
|
||||
|
||||
public PasswordVerifyException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public PasswordVerifyException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public PasswordVerifyException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public PasswordVerifyException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 刷新缓存时出现的异常信息
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class RefreshCacheException extends RuntimeException {
|
||||
|
||||
public RefreshCacheException() {
|
||||
}
|
||||
|
||||
public RefreshCacheException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public RefreshCacheException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public RefreshCacheException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
public RefreshCacheException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,7 +1,8 @@
|
||||
package im.zhaojun.common.exception;
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 存储策略未初始化异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class StorageStrategyUninitializedException extends RuntimeException {
|
||||
|
||||
@@ -25,4 +26,5 @@ public class StorageStrategyUninitializedException extends RuntimeException {
|
||||
public StorageStrategyUninitializedException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package im.zhaojun.zfile.exception;
|
||||
|
||||
/**
|
||||
* 文件解析异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class TextParseException extends RuntimeException {
|
||||
|
||||
public TextParseException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public TextParseException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public TextParseException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public TextParseException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected TextParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,8 @@
|
||||
package im.zhaojun.common.config;
|
||||
package im.zhaojun.zfile.filter;
|
||||
|
||||
import org.springframework.core.annotation.Order;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.web.cors.CorsUtils;
|
||||
import org.springframework.web.filter.GenericFilterBean;
|
||||
|
||||
@@ -8,13 +10,18 @@ import javax.servlet.FilterChain;
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.ServletRequest;
|
||||
import javax.servlet.ServletResponse;
|
||||
import javax.servlet.annotation.WebFilter;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 开启跨域支持. 一般用于开发环境, 或前后端分离部署时开启.
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Order(1)
|
||||
@WebFilter(value = "/*")
|
||||
@Component
|
||||
public class CorsFilter extends GenericFilterBean {
|
||||
|
||||
@Override
|
||||
@@ -22,7 +29,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 +39,5 @@ public class CorsFilter extends GenericFilterBean {
|
||||
chain.doFilter(httpServletRequest, httpServletResponse);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.filter;
|
||||
@@ -0,0 +1 @@
|
||||
package im.zhaojun.zfile.model.constant;
|
||||
@@ -0,0 +1,48 @@
|
||||
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 SHAREPOINT_SITE_ID = "siteId";
|
||||
|
||||
public static final String SHAREPOINT_SITE_NAME = "siteName";
|
||||
|
||||
public static final String PATH_STYLE = "pathStyle";
|
||||
|
||||
public static final String IS_PRIVATE = "isPrivate";
|
||||
|
||||
public static final String PROXY_DOMAIN = "proxyDomain";
|
||||
|
||||
public static final String REGION_KEY = "region";
|
||||
|
||||
}
|
||||
@@ -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";
|
||||
@@ -0,0 +1,80 @@
|
||||
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 Character PATH_SEPARATOR_CHAR = '/';
|
||||
|
||||
public static final String PATH_SEPARATOR = "/";
|
||||
|
||||
/**
|
||||
* 直链前缀名称
|
||||
*/
|
||||
public static String DIRECT_LINK_PREFIX = "directlink";
|
||||
|
||||
/**
|
||||
* 系统产生的临时文件路径
|
||||
*/
|
||||
public static String TMP_FILE_PATH = "/.zfile/tmp2/";
|
||||
|
||||
/**
|
||||
* 页面文档文件
|
||||
*/
|
||||
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 setTmpFilePath(@Value("${zfile.tmp.path}") String tmpFilePath) {
|
||||
ZFileConstant.TMP_FILE_PATH = tmpFilePath;
|
||||
}
|
||||
|
||||
|
||||
@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;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setDirectLinkPrefix(@Value("${zfile.directLinkPrefix}") String directLinkPrefix) {
|
||||
ZFileConstant.DIRECT_LINK_PREFIX = directLinkPrefix;
|
||||
}
|
||||
|
||||
}
|
||||
27
src/main/java/im/zhaojun/zfile/model/dto/AudioInfoDTO.java
Normal file
27
src/main/java/im/zhaojun/zfile/model/dto/AudioInfoDTO.java
Normal 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;
|
||||
}
|
||||
|
||||
}
|
||||
23
src/main/java/im/zhaojun/zfile/model/dto/CacheInfoDTO.java
Normal file
23
src/main/java/im/zhaojun/zfile/model/dto/CacheInfoDTO.java
Normal 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;
|
||||
|
||||
}
|
||||
39
src/main/java/im/zhaojun/zfile/model/dto/DriveConfigDTO.java
Normal file
39
src/main/java/im/zhaojun/zfile/model/dto/DriveConfigDTO.java
Normal file
@@ -0,0 +1,39 @@
|
||||
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 enable;
|
||||
|
||||
private boolean enableCache;
|
||||
|
||||
private boolean autoRefreshCache;
|
||||
|
||||
private boolean searchEnable;
|
||||
|
||||
private boolean searchIgnoreCase;
|
||||
|
||||
private boolean searchContainEncryptedFile;
|
||||
|
||||
private Integer orderNum;
|
||||
|
||||
private StorageStrategyConfig storageStrategyConfig;
|
||||
|
||||
private boolean defaultSwitchToImgMode;
|
||||
|
||||
}
|
||||
21
src/main/java/im/zhaojun/zfile/model/dto/DriveListDTO.java
Normal file
21
src/main/java/im/zhaojun/zfile/model/dto/DriveListDTO.java
Normal file
@@ -0,0 +1,21 @@
|
||||
package im.zhaojun.zfile.model.dto;
|
||||
|
||||
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author Zhao Jun
|
||||
* 2021/5/26 15:17
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
public class DriveListDTO {
|
||||
|
||||
private List<DriveConfig> driveList;
|
||||
|
||||
private Boolean isInstall;
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
18
src/main/java/im/zhaojun/zfile/model/dto/FileListDTO.java
Normal file
18
src/main/java/im/zhaojun/zfile/model/dto/FileListDTO.java
Normal file
@@ -0,0 +1,18 @@
|
||||
package im.zhaojun.zfile.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class FileListDTO {
|
||||
|
||||
private List<FileItemDTO> files;
|
||||
|
||||
private SystemFrontConfigDTO config;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package im.zhaojun.zfile.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class SharePointInfoVO {
|
||||
|
||||
private String type;
|
||||
|
||||
private String accessToken;
|
||||
|
||||
private String domainPrefix;
|
||||
|
||||
private String siteType;
|
||||
|
||||
private String siteName;
|
||||
|
||||
private String domainType;
|
||||
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user