mirror of
https://github.com/zfile-dev/zfile.git
synced 2025-04-19 05:34:52 +00:00
Compare commits
165 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
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 |
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 的文档:http://docs.zhaojun.im/zfile
|
||||||
|
- 我已经搜索了已有的 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: ''
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
<!--
|
||||||
|
如果你有任何问题也可以通过此渠道来向我们反馈。
|
||||||
|
|
||||||
|
谢谢!
|
||||||
|
-->
|
||||||
164
API.md
Normal file
164
API.md
Normal file
@@ -0,0 +1,164 @@
|
|||||||
|
## API 标准
|
||||||
|
|
||||||
|
所有 API 均返回 `msg`, `code`, `data` 三个属性.
|
||||||
|
|
||||||
|
| code | 描述 |
|
||||||
|
| :---: | :------------: |
|
||||||
|
| 0 | 请求成功 |
|
||||||
|
| -1 | 请求失败 |
|
||||||
|
| -2 | 文件夹需要密码 |
|
||||||
|
|
||||||
|
当 `code == 0` 时, `data` 中为请求所需数据.
|
||||||
|
|
||||||
|
当 `code != 0` 时, 应当将 `msg` 中的属性作为参考值.
|
||||||
|
|
||||||
|
|
||||||
|
## 获取文件列表
|
||||||
|
|
||||||
|
### 请求 URL
|
||||||
|
|
||||||
|
`/api/list` `GET`
|
||||||
|
|
||||||
|
### 参数
|
||||||
|
|
||||||
|
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||||
|
| :------: | :--------: | :------: | :--------------------------: |
|
||||||
|
| path | 路径 | 是 | `/`, `/文件夹名称` |
|
||||||
|
| password | 文件夹密码 | 否 | 当文件夹需要密码时, |
|
||||||
|
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "操作成功",
|
||||||
|
"code": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "密码文件夹",
|
||||||
|
"time": "2020-01-28 13:17",
|
||||||
|
"size": 4096,
|
||||||
|
"type": "FOLDER",
|
||||||
|
"path": "/",
|
||||||
|
"url": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "新建 文本文档.txt",
|
||||||
|
"time": "2020-01-28 13:16",
|
||||||
|
"size": 3,
|
||||||
|
"type": "FILE",
|
||||||
|
"path": "/",
|
||||||
|
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 搜索
|
||||||
|
|
||||||
|
|
||||||
|
### 请求 URL
|
||||||
|
|
||||||
|
`/api/search` `GET`
|
||||||
|
|
||||||
|
### 参数
|
||||||
|
|
||||||
|
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||||
|
| :----: | :----: | :------: | :--------------------------: |
|
||||||
|
| name | 搜索值 | 是 | 模糊匹配 |
|
||||||
|
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "操作成功",
|
||||||
|
"code": 0,
|
||||||
|
"data": [
|
||||||
|
{
|
||||||
|
"name": "密码文件夹",
|
||||||
|
"time": "2020-01-28 13:17",
|
||||||
|
"size": 4096,
|
||||||
|
"type": "FOLDER",
|
||||||
|
"path": "/",
|
||||||
|
"url": null
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "新建 文本文档.txt",
|
||||||
|
"time": "2020-01-28 13:16",
|
||||||
|
"size": 3,
|
||||||
|
"type": "FILE",
|
||||||
|
"path": "/",
|
||||||
|
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
## 获取单个文件信息
|
||||||
|
|
||||||
|
### 请求 URL
|
||||||
|
|
||||||
|
`/api/directlink` `GET`
|
||||||
|
|
||||||
|
### 参数
|
||||||
|
|
||||||
|
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||||
|
| :----: | :--------: | :------: | :------------------: |
|
||||||
|
| path | 文件全路径 | 是 | `/新建 文本文档.txt` |
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "操作成功",
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"name": "新建 文本文档.txt",
|
||||||
|
"time": "2020-01-28 13:16",
|
||||||
|
"size": 3,
|
||||||
|
"type": "FILE",
|
||||||
|
"path": "d:/test",
|
||||||
|
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
## 获取系统配置
|
||||||
|
|
||||||
|
|
||||||
|
### 请求 URL
|
||||||
|
|
||||||
|
`/api/config` `GET`
|
||||||
|
|
||||||
|
### 参数
|
||||||
|
|
||||||
|
| 参数名 | 描述 | 是否必填 | 参考值 |
|
||||||
|
| :----: | :--------: | :------: | :-----------: |
|
||||||
|
| path | 文件夹名称 | 是 | `/文件夹名称` |
|
||||||
|
|
||||||
|
### 响应
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"msg": "操作成功",
|
||||||
|
"code": 0,
|
||||||
|
"data": {
|
||||||
|
"readme": null, # 文档文件名称
|
||||||
|
"viewConfig": {
|
||||||
|
"siteName": "站点名称", # 站点名称
|
||||||
|
"infoEnable": false, # 是否开启右侧信息框
|
||||||
|
"searchEnable": false, # 是否开启搜索
|
||||||
|
"searchIgnoreCase": true, # 搜索是否忽略大小写
|
||||||
|
"storageStrategy": "local", # 当前启用存储引擎
|
||||||
|
"username": "2", # 用户名
|
||||||
|
"domain": "http://127.0.0.1:8080", # 域名
|
||||||
|
"enableCache": false, # 是否开启缓存
|
||||||
|
"searchContainEncryptedFile": false, # 搜索是否包含加密文件夹
|
||||||
|
"customJs": "", # 自定义 js 片段
|
||||||
|
"customCss": "" # 自定义 css 片段
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
127
README.md
127
README.md
@@ -11,58 +11,79 @@
|
|||||||
|
|
||||||
预览地址: [https://zfile.jun6.net](https://zfile.jun6.net)
|
预览地址: [https://zfile.jun6.net](https://zfile.jun6.net)
|
||||||
|
|
||||||
|
文档地址: [http://docs.zhaojun.im/zfile](http://docs.zhaojun.im/zfile)
|
||||||
|
|
||||||
## 系统特色
|
## 系统特色
|
||||||
|
|
||||||
* 内存缓存 (免安装)
|
* 内存缓存 (免安装)
|
||||||
* 内存数据库 (免安装)
|
* 内存数据库 (免安装)
|
||||||
* 个性化配置
|
* 个性化配置
|
||||||
* 自定义目录的 header 和 footer 说明文件
|
* 自定义目录的 readme 说明文件
|
||||||
|
* 自定义 JS, CSS
|
||||||
* 文件夹密码
|
* 文件夹密码
|
||||||
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
|
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
|
||||||
* 文件/目录二维码
|
* 文件/目录二维码
|
||||||
* 缓存动态开启, 缓存自动刷新
|
* 缓存动态开启, ~~缓存自动刷新 (v2.2 及以前版本支持)~~
|
||||||
* 全局搜索
|
* ~~全局搜索 (v2.2 及以前版本支持)~~
|
||||||
|
* 同时挂载多个存储策略
|
||||||
|
* 支持 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版, OneDrive 世纪互联版, 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
|
||||||
|
|
||||||
## 快速开始
|
## 快速开始
|
||||||
|
|
||||||
安装 JDK 1.8 :
|
安装依赖环境:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
yum install -y java # 适用于 Centos 7.x
|
# CentOS系统
|
||||||
|
yum install -y java-1.8.0-openjdk unzip
|
||||||
```
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Debian 9 / Ubuntu 14+
|
||||||
|
apt update
|
||||||
|
apt install -y openjdk-8-jre-headless unzip
|
||||||
|
```
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Debian 10 (Buster) 系统
|
||||||
|
apt update && apt install -y apt-transport-https software-properties-common ca-certificates dirmngr gnupg
|
||||||
|
wget -qO - https://adoptopenjdk.jfrog.io/adoptopenjdk/api/gpg/key/public | apt-key add -
|
||||||
|
add-apt-repository --yes https://adoptopenjdk.jfrog.io/adoptopenjdk/deb/
|
||||||
|
apt update && apt install -y adoptopenjdk-8-hotspot-jre
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
> 如为更新程序, 则请先执行 `~/zfile/bin/stop.sh && rm -rf ~/zfile` 清理旧程序. 首次安装请忽略此选项.
|
||||||
|
|
||||||
|
|
||||||
下载项目:
|
下载项目:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
wget https://github.com/zhaojun1998/zfile/releases/download/0.5/zfile-0.5.jar
|
cd ~
|
||||||
|
wget https://c.jun6.net/ZFILE/zfile-release.war
|
||||||
|
mkdir zfile && unzip zfile-release.war -d zfile && rm -rf zfile-release.war
|
||||||
|
chmod +x zfile/bin/*.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
> 下载指定版本可以将 `zfile-release.war` 改为 `zfile-x.x.war`,如 `zfile-2.2.war`。
|
||||||
|
|
||||||
|
程序的目录结构为:
|
||||||
|
```
|
||||||
|
├── zfile
|
||||||
|
├── META-INF
|
||||||
|
├── WEB-INF
|
||||||
|
└── bin
|
||||||
|
├── start.sh # 启动脚本
|
||||||
|
└── stop.sh # 停止脚本
|
||||||
|
├── restart.sh # 重启脚本
|
||||||
```
|
```
|
||||||
|
|
||||||
启动项目:
|
启动项目:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar
|
~/zfile/bin/start.sh
|
||||||
|
|
||||||
## 高级启动
|
|
||||||
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar --server.port=18777
|
|
||||||
|
|
||||||
## 后台运行
|
|
||||||
nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar &
|
|
||||||
```
|
```
|
||||||
|
|
||||||
> 系统使用的是内置配置文件, 默认配置请参考: [application.yml](https://github.com/zhaojun1998/zfile/blob/master/src/main/resources/application.yml)
|
篇幅有限, 更详细的安装教程及介绍请参考: [ZFile 文档](http://zhaojun.im/zfile-install)
|
||||||
|
|
||||||
> **可下载此文件放置与 jar 包同目录, 此时会以外部配置文件为准, 推荐适用此方式!.**
|
|
||||||
|
|
||||||
> 所有参数都可在命令行启动时, 以类似 `--server.port=18777` 的方式强制执行, 此方式的优先级最高.
|
|
||||||
|
|
||||||
> *指定 `-Djava.security.egd=file:/dev/./urandom` 是为了防止在 Linux 环境中, 生成首次登陆生成 sessionId 取系统随机数过慢的问题.*
|
|
||||||
|
|
||||||
重要参数:
|
|
||||||
- `server.port` 为指定端口, 默认为 `8080`
|
|
||||||
- `logging.path` 为日志文件存放路径, 默认为 `${user.home}/.zfile/logs`
|
|
||||||
- `spring.datasource` 下配置了 `h2` 和 `mysql` 两种数据库的支持, 默认采用 `h2`.
|
|
||||||
- `spring.cache.type` 为指定缓存方式, 默认为 `caffeine`, 即内存缓存, 无需安装, 支持切换为 `redis`, 但需配置 `spring.redis.host` 和 `spring.redis.password` 参数后才可使用.
|
|
||||||
|
|
||||||
|
|
||||||
访问地址:
|
访问地址:
|
||||||
|
|
||||||
@@ -73,33 +94,51 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar &
|
|||||||
管理后台: http://127.0.0.1:8080/#/admin
|
管理后台: http://127.0.0.1:8080/#/admin
|
||||||
|
|
||||||
|
|
||||||
## 运行环境
|
## 预览
|
||||||
|
|
||||||
* JDK: `1.8`
|

|
||||||
* 缓存: `caffeine`
|

|
||||||
* 数据库: `h2/mysql`
|

|
||||||
|

|
||||||
|
|
||||||
## 常见问题
|
## 常见问题
|
||||||
|
|
||||||
### 数据库
|
|
||||||
|
|
||||||
缓存默认支持 `h2` 和 `mysql`, 前者为嵌入式数据库, 无需安装, 但后者相对性能更好.
|
|
||||||
|
|
||||||
|
|
||||||
### 默认路径
|
### 默认路径
|
||||||
|
|
||||||
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录, windows 为 `C:/Users/用户名/`, linux 为 `/home/用户名/`, root 用户为 `/root/`
|
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录
|
||||||
|
|
||||||
|
windows 为 `C:/Users/用户名/`
|
||||||
|
|
||||||
### 头尾文件和加密文件
|
linux 为 `/home/用户名/`, root 用户为 `/root/`
|
||||||
|
|
||||||
- 目录头部显示文件名为 `header.md`
|
> 2.3 及以后版本路径为 `~/.zfile-new/db/`
|
||||||
- 目录底部显示文件名为 `footer.md`
|
|
||||||
|
### 文档文件和加密文件
|
||||||
|
|
||||||
|
- 目录文档显示文件名为 `readme.md`
|
||||||
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
|
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
|
||||||
|
|
||||||
## TODO
|
## 开发计划
|
||||||
|
|
||||||
- 文本预览更换更好用的编辑器
|
- [x] API 支持 [点击查看文档](https://github.com/zhaojun1998/zfile/blob/master/API.md)
|
||||||
- 后台支持上传、编辑、删除等操作
|
- [x] 更方便的部署方式
|
||||||
- API 支持
|
- [x] 布局优化 - 自定义操作按钮 (现为右键实现)
|
||||||
- 更方便的部署方式
|
- [x] 后台优化 - 设置按照其功能进行分离
|
||||||
|
- [x] 体验优化 - 支持前后端分离部署
|
||||||
|
- [x] 体验优化 - 文本预览更换 vscode 同款编辑器 monaco editor
|
||||||
|
- [x] 新功能 - Docker 支持
|
||||||
|
- [x] 架构调整 - 支持多存储策略
|
||||||
|
- [ ] 新功能 - 后台支持上传、编辑、删除等操作
|
||||||
|
- [ ] 新功能 - WebDav 支持
|
||||||
|
- [ ] 新功能 - 离线下载 (aria2)
|
||||||
|
- [ ] 体验优化 - 忽略文件列表 (正则表达式)
|
||||||
|
- [ ] 体验优化 - 自定义支持预览的文件后缀 (正则表达式)
|
||||||
|
- [ ] 体验优化 - 一键安装脚本
|
||||||
|
|
||||||
|
## 支持作者
|
||||||
|
|
||||||
|
如果本项目对你有帮助,请作者喝杯咖啡吧。
|
||||||
|
|
||||||
|
<img src="http://cdn.jun6.net/alipay.png" width="200" height="312">
|
||||||
|
<img src="http://cdn.jun6.net/wechat.png" width="222" height="300">
|
||||||
|
|||||||
40
pom.xml
40
pom.xml
@@ -12,8 +12,9 @@
|
|||||||
|
|
||||||
<groupId>im.zhaojun</groupId>
|
<groupId>im.zhaojun</groupId>
|
||||||
<artifactId>zfile</artifactId>
|
<artifactId>zfile</artifactId>
|
||||||
<version>0.5</version>
|
<version>2.4</version>
|
||||||
<name>zfile</name>
|
<name>zfile</name>
|
||||||
|
<packaging>war</packaging>
|
||||||
<description>一个在线的文件浏览系统</description>
|
<description>一个在线的文件浏览系统</description>
|
||||||
|
|
||||||
<properties>
|
<properties>
|
||||||
@@ -44,7 +45,15 @@
|
|||||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||||
<optional>true</optional>
|
<optional>true</optional>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-cache</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.springframework.boot</groupId>
|
||||||
|
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||||
|
</dependency>
|
||||||
|
|
||||||
<!-- 数据库驱动-->
|
<!-- 数据库驱动-->
|
||||||
<dependency>
|
<dependency>
|
||||||
@@ -62,10 +71,10 @@
|
|||||||
<dependency>
|
<dependency>
|
||||||
<groupId>cn.hutool</groupId>
|
<groupId>cn.hutool</groupId>
|
||||||
<artifactId>hutool-all</artifactId>
|
<artifactId>hutool-all</artifactId>
|
||||||
<version>4.5.11</version>
|
<version>5.1.3</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<!-- 存储引擎相关 API, 对象存储、FTP、 Rest API-->
|
<!-- 存储策略相关 API, 对象存储、FTP、 Rest API-->
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.upyun</groupId>
|
<groupId>com.upyun</groupId>
|
||||||
<artifactId>java-sdk</artifactId>
|
<artifactId>java-sdk</artifactId>
|
||||||
@@ -101,9 +110,9 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
<dependency>
|
<dependency>
|
||||||
<groupId>com.alicp.jetcache</groupId>
|
<groupId>com.alibaba</groupId>
|
||||||
<artifactId>jetcache-starter-redis</artifactId>
|
<artifactId>fastjson</artifactId>
|
||||||
<version>2.5.14</version>
|
<version>1.2.61</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
@@ -114,6 +123,25 @@
|
|||||||
<groupId>org.springframework.boot</groupId>
|
<groupId>org.springframework.boot</groupId>
|
||||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||||
</plugin>
|
</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>
|
</plugins>
|
||||||
</build>
|
</build>
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 标记注解, 用于在调用前检查是否已存储策略
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Target(ElementType.METHOD)
|
|
||||||
@Retention(RetentionPolicy.RUNTIME)
|
|
||||||
public @interface CheckStorageStrategyInit {
|
|
||||||
}
|
|
||||||
@@ -1,31 +0,0 @@
|
|||||||
package im.zhaojun.common.aspect;
|
|
||||||
|
|
||||||
import im.zhaojun.common.exception.StorageStrategyUninitializedException;
|
|
||||||
import im.zhaojun.common.service.AbstractFileService;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Aspect
|
|
||||||
@Component
|
|
||||||
public class StorageStrategyInitCheckAspect {
|
|
||||||
|
|
||||||
@Before("@annotation(im.zhaojun.common.annotation.CheckStorageStrategyInit)")
|
|
||||||
public void logStart() {
|
|
||||||
SystemConfigService systemConfigService = SpringContextHolder.getBean(SystemConfigService.class);
|
|
||||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
|
||||||
if (currentFileService == null) {
|
|
||||||
throw new StorageStrategyUninitializedException("存储策略尚未初始化, 请联系管理员!");
|
|
||||||
}
|
|
||||||
if (currentFileService.getIsUnInitialized()) {
|
|
||||||
throw new StorageStrategyUninitializedException("存储策略异常, 请联系管理员!");
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,18 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class WebMvcConfig implements WebMvcConfigurer {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void addFormatters(FormatterRegistry registry) {
|
|
||||||
registry.addConverter(new StorageTypeEnumDeSerializerConvert());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,147 +0,0 @@
|
|||||||
package im.zhaojun.common.controller;
|
|
||||||
|
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
|
||||||
import im.zhaojun.common.model.dto.CacheConfigDTO;
|
|
||||||
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.AbstractFileService;
|
|
||||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
|
||||||
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;
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 后台管理
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@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("/config")
|
|
||||||
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) throws Exception {
|
|
||||||
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
|
|
||||||
|
|
||||||
systemConfigDTO.setId(1);
|
|
||||||
systemConfigService.updateSystemConfig(systemConfigDTO);
|
|
||||||
|
|
||||||
if (!currentStorageStrategy.equals(systemConfigDTO.getStorageStrategy())) {
|
|
||||||
refreshStorageStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 修改管理员登陆密码
|
|
||||||
*/
|
|
||||||
@PostMapping("/update-pwd")
|
|
||||||
public ResultBean updatePwd(String username, String password) {
|
|
||||||
systemConfigService.updateUsernameAndPwd(username, password);
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取指定存储引擎的设置
|
|
||||||
* @param storageType 存储引擎
|
|
||||||
* @return 所有设置
|
|
||||||
*/
|
|
||||||
@GetMapping("/strategy-form")
|
|
||||||
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
|
|
||||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageType);
|
|
||||||
return ResultBean.success(storageConfigList);
|
|
||||||
}
|
|
||||||
|
|
||||||
@GetMapping("/cache/config")
|
|
||||||
public ResultBean cacheConfig() throws Exception {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
Set<String> cacheKeys = fileService.getCacheKeys();
|
|
||||||
|
|
||||||
CacheConfigDTO cacheConfigDTO = new CacheConfigDTO();
|
|
||||||
cacheConfigDTO.setEnableCache(systemConfigService.getEnableCache());
|
|
||||||
cacheConfigDTO.setCacheFinish(fileAsyncCacheService.isCacheFinish());
|
|
||||||
cacheConfigDTO.setCacheKeys(cacheKeys);
|
|
||||||
|
|
||||||
return ResultBean.success(cacheConfigDTO);
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/cache/refresh")
|
|
||||||
public ResultBean refreshCache(String key) throws Exception {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
fileService.refreshCache(key);
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/cache/clear")
|
|
||||||
public ResultBean clearCache(String key) throws Exception {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
fileService.clearCache();
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/cache/all")
|
|
||||||
public ResultBean cacheAll() throws Exception {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
fileService.clearCache();
|
|
||||||
fileAsyncCacheService.cacheGlobalFile();
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新存储策略
|
|
||||||
*/
|
|
||||||
public void refreshStorageStrategy() {
|
|
||||||
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
|
|
||||||
refreshStorageStrategy(storageStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 更新存储策略
|
|
||||||
*/
|
|
||||||
public void refreshStorageStrategy(StorageTypeEnum storageStrategy) {
|
|
||||||
if (storageStrategy == null) {
|
|
||||||
log.info("尚未配置存储策略.");
|
|
||||||
} else {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
fileService.init();
|
|
||||||
log.info("当前启用存储类型: {}", storageStrategy.getDescription());
|
|
||||||
|
|
||||||
// if 判断是否开启搜索.
|
|
||||||
fileAsyncCacheService.cacheGlobalFile();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,187 +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.AbstractFileService;
|
|
||||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
|
||||||
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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 前台文件管理
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@RequestMapping("/api")
|
|
||||||
@RestController
|
|
||||||
public class FileController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemService systemService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigService systemConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StorageConfigService storageConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private FileAsyncCacheService fileAsyncCacheService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 滚动加载每页条数.
|
|
||||||
*/
|
|
||||||
private static final Integer PAGE_SIZE = 30;
|
|
||||||
|
|
||||||
@CheckStorageStrategyInit
|
|
||||||
@GetMapping("/list")
|
|
||||||
public ResultBean list(@RequestParam(defaultValue = "/") String path,
|
|
||||||
@RequestParam(defaultValue = "name") String sortBy,
|
|
||||||
@RequestParam(defaultValue = "asc") String order,
|
|
||||||
@RequestParam(required = false) String password,
|
|
||||||
@RequestParam(defaultValue = "1") Integer page) throws Exception {
|
|
||||||
AbstractFileService 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())
|
|
||||||
&& !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);
|
|
||||||
|
|
||||||
int total = fileItemList.size();
|
|
||||||
int totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
|
|
||||||
|
|
||||||
if (page > totalPage) {
|
|
||||||
return ResultBean.successData(new ArrayList<>());
|
|
||||||
}
|
|
||||||
|
|
||||||
int start = (page - 1) * PAGE_SIZE;
|
|
||||||
int end = page * PAGE_SIZE;
|
|
||||||
end = Math.min(end, total);
|
|
||||||
List<FileItemDTO> fileSubItem = new ArrayList<>(fileItemList.subList(start, end));
|
|
||||||
return ResultBean.successData(fileSubItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件类容, 仅限用于, txt, md, ini 等普通文本文件.
|
|
||||||
* @param url 文件路径
|
|
||||||
* @return 文件内容
|
|
||||||
*/
|
|
||||||
@GetMapping("/content")
|
|
||||||
public ResultBean getContent(String url) {
|
|
||||||
return ResultBean.successData(HttpUtil.getTextContent(url));
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取文件类容, 仅限用于, txt, md, ini 等普通文本文件.
|
|
||||||
* @param url 文件路径
|
|
||||||
* @return 文件内容
|
|
||||||
*/
|
|
||||||
@GetMapping("/content/origin")
|
|
||||||
public String getContentOrigin(String url) {
|
|
||||||
return HttpUtil.getTextContent(url);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 检测文件是否存在
|
|
||||||
* @param url 文件路径
|
|
||||||
* @return 是否存在
|
|
||||||
*/
|
|
||||||
@GetMapping("/content/exist")
|
|
||||||
public boolean checkFileExist(String url) {
|
|
||||||
return HttpUtil.checkUrlExist(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() throws Exception {
|
|
||||||
AbstractFileService 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 {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
|
|
||||||
if (!systemConfigDTO.getSearchEnable()) {
|
|
||||||
throw new SearchDisableException("搜索功能未开启");
|
|
||||||
}
|
|
||||||
if (!fileAsyncCacheService.isCacheFinish()) {
|
|
||||||
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,108 +0,0 @@
|
|||||||
package im.zhaojun.common.controller;
|
|
||||||
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
|
||||||
import im.zhaojun.common.model.dto.InstallModelDTO;
|
|
||||||
import im.zhaojun.common.model.dto.ResultBean;
|
|
||||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
|
||||||
import im.zhaojun.common.service.AbstractFileService;
|
|
||||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
|
||||||
import im.zhaojun.common.service.StorageConfigService;
|
|
||||||
import im.zhaojun.common.service.SystemConfigService;
|
|
||||||
import org.springframework.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.PostMapping;
|
|
||||||
import org.springframework.web.bind.annotation.RequestParam;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 系统安装初始化
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
public class InstallController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigService systemConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StorageConfigService storageConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private AdminController adminController;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private FileAsyncCacheService fileAsyncCacheService;
|
|
||||||
|
|
||||||
@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) throws Exception {
|
|
||||||
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
|
|
||||||
|
|
||||||
if (systemConfigDTO.getStorageStrategy() != null) {
|
|
||||||
return ResultBean.error("请勿重复初始化.");
|
|
||||||
}
|
|
||||||
|
|
||||||
systemConfigDTO.setSiteName(installModelDTO.getSiteName());
|
|
||||||
StorageTypeEnum storageTypeEnum = installModelDTO.getStorageStrategy();
|
|
||||||
systemConfigDTO.setStorageStrategy(storageTypeEnum);
|
|
||||||
systemConfigDTO.setUsername(installModelDTO.getUsername());
|
|
||||||
systemConfigDTO.setPassword(SecureUtil.md5(installModelDTO.getPassword()));
|
|
||||||
systemConfigDTO.setDomain(installModelDTO.getDomain());
|
|
||||||
systemConfigService.updateSystemConfig(systemConfigDTO);
|
|
||||||
|
|
||||||
Map<String, String> storageStrategyConfig = installModelDTO.getStorageStrategyConfig();
|
|
||||||
|
|
||||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageTypeEnum);
|
|
||||||
for (StorageConfig storageConfig : storageConfigList) {
|
|
||||||
String key = storageConfig.getKey();
|
|
||||||
String value = storageStrategyConfig.get(key);
|
|
||||||
storageConfig.setValue(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
storageConfigService.updateStorageConfig(storageConfigList);
|
|
||||||
adminController.refreshStorageStrategy();
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
|
|
||||||
@PostMapping("/storage-strategy")
|
|
||||||
@ResponseBody
|
|
||||||
public ResultBean save(@RequestParam Map<String, String> storageStrategyConfig, StorageTypeEnum storageStrategy) throws Exception {
|
|
||||||
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)) {
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
fileService.clearCache();
|
|
||||||
|
|
||||||
if (systemConfigService.getEnableCache()) {
|
|
||||||
fileAsyncCacheService.cacheGlobalFile();
|
|
||||||
}
|
|
||||||
fileService.init();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ResultBean.success();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
package im.zhaojun.common.model.constant;
|
|
||||||
|
|
||||||
import org.springframework.beans.factory.annotation.Autowired;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
import org.springframework.context.annotation.Configuration;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Configuration
|
|
||||||
public class ZFileConstant {
|
|
||||||
|
|
||||||
public final static String USER_HOME = System.getProperty("user.home");
|
|
||||||
|
|
||||||
public static final String AUDIO_TMP_PATH = "/.zfile/tmp/audio/";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 页面头部文件
|
|
||||||
*/
|
|
||||||
public static String HEADER_FILE_NAME = "header.md";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 页面尾部文件
|
|
||||||
*/
|
|
||||||
public static String FOOTER_FILE_NAME = "footer.md";
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 密码文件
|
|
||||||
*/
|
|
||||||
public static String PASSWORD_FILE_NAME = "password.txt";
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
public void setHeaderFileName(@Value("${zfile.constant.header}") String headerFileName) {
|
|
||||||
ZFileConstant.HEADER_FILE_NAME = headerFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
public void setFooterFileName(@Value("${zfile.constant.footer}") String footerFileName) {
|
|
||||||
ZFileConstant.FOOTER_FILE_NAME = footerFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Autowired(required = false)
|
|
||||||
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
|
|
||||||
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
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,16 +0,0 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
|
||||||
|
|
||||||
import lombok.Data;
|
|
||||||
|
|
||||||
import java.util.Set;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
* @date 2020/1/3 12:39
|
|
||||||
*/
|
|
||||||
@Data
|
|
||||||
public class CacheConfigDTO {
|
|
||||||
private boolean enableCache;
|
|
||||||
private boolean cacheFinish;
|
|
||||||
private Set<String> cacheKeys;
|
|
||||||
}
|
|
||||||
@@ -1,53 +0,0 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonProperty;
|
|
||||||
|
|
||||||
import java.io.Serializable;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
public class SiteConfigDTO implements Serializable {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 8811196207046121740L;
|
|
||||||
|
|
||||||
private String header;
|
|
||||||
|
|
||||||
private String footer;
|
|
||||||
|
|
||||||
@JsonProperty("viewConfig")
|
|
||||||
private SystemConfigDTO systemConfigDTO;
|
|
||||||
|
|
||||||
public String getHeader() {
|
|
||||||
return header;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setHeader(String header) {
|
|
||||||
this.header = header;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFooter() {
|
|
||||||
return footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFooter(String footer) {
|
|
||||||
this.footer = footer;
|
|
||||||
}
|
|
||||||
|
|
||||||
public SystemConfigDTO getSystemConfigDTO() {
|
|
||||||
return systemConfigDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setSystemConfigDTO(SystemConfigDTO systemConfigDTO) {
|
|
||||||
this.systemConfigDTO = systemConfigDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String toString() {
|
|
||||||
return "SiteConfigDTO{" +
|
|
||||||
"header='" + header + '\'' +
|
|
||||||
", footer='" + footer + '\'' +
|
|
||||||
", systemConfig=" + systemConfigDTO +
|
|
||||||
'}';
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,23 +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;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Repository
|
|
||||||
public interface StorageConfigRepository extends JpaRepository<StorageConfig, Integer> {
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 根据存储类型找对应的配置信息
|
|
||||||
* @param type 存储类型
|
|
||||||
* @return 此类型所有的配置信息
|
|
||||||
*/
|
|
||||||
List<StorageConfig> findByTypeOrderById(StorageTypeEnum type);
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,194 +0,0 @@
|
|||||||
package im.zhaojun.common.service;
|
|
||||||
|
|
||||||
import com.alicp.jetcache.Cache;
|
|
||||||
import com.alicp.jetcache.RefreshPolicy;
|
|
||||||
import com.alicp.jetcache.anno.CacheRefresh;
|
|
||||||
import com.alicp.jetcache.anno.CacheType;
|
|
||||||
import com.alicp.jetcache.anno.Cached;
|
|
||||||
import com.alicp.jetcache.anno.CreateCache;
|
|
||||||
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 lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.aop.framework.AopContext;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
|
||||||
|
|
||||||
import javax.annotation.PostConstruct;
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collections;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Set;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.stream.Collectors;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
* @date 2019/12/28 19:27
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
public abstract class AbstractFileService implements FileService {
|
|
||||||
|
|
||||||
public static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-cache:";
|
|
||||||
|
|
||||||
@Value("${zfile.cache.timeout}")
|
|
||||||
protected Long timeout;
|
|
||||||
|
|
||||||
protected boolean isInitialized;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigService systemConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private FileAsyncCacheService fileAsyncCacheService;
|
|
||||||
|
|
||||||
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
|
|
||||||
private Cache<String, List<FileItemDTO>> cache;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* 获取指定路径下的文件及文件夹, 默认缓存 60 分钟,每隔 30 分钟刷新一次.
|
|
||||||
* @param path 文件路径
|
|
||||||
* @return 文件及文件夹列表
|
|
||||||
* @throws Exception 获取文件列表中出现的异常
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
@Cached(name = SYSTEM_CONFIG_CACHE_PREFIX,
|
|
||||||
key = "args[0]",
|
|
||||||
cacheType = CacheType.LOCAL, localLimit = 100000, condition = "mvel{bean('systemConfigService').enableCache}")
|
|
||||||
@CacheRefresh(refresh = 30, timeUnit = TimeUnit.MINUTES)
|
|
||||||
public abstract List<FileItemDTO> fileList(String path) throws Exception;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 清理当前存储引擎的缓存
|
|
||||||
*/
|
|
||||||
public void clearCache() throws Exception {
|
|
||||||
Set<String> cacheKeys = getCacheKeys();
|
|
||||||
cache.removeAll(cacheKeys);
|
|
||||||
closeCacheAutoRefresh();
|
|
||||||
fileAsyncCacheService.setCacheFinish(false);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 初始化方法, 启动时自动调用实现类的此方法进行初始化.
|
|
||||||
*/
|
|
||||||
@PostConstruct
|
|
||||||
public abstract void init();
|
|
||||||
|
|
||||||
protected boolean testConnection() {
|
|
||||||
boolean flag = true;
|
|
||||||
try {
|
|
||||||
fileList("/");
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(getStorageTypeEnum().getDescription() + "初始化异常", e);
|
|
||||||
flag = false;
|
|
||||||
}
|
|
||||||
return flag;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取是否初始化成功
|
|
||||||
* @return 初始化成功与否
|
|
||||||
*/
|
|
||||||
public boolean getIsUnInitialized() {
|
|
||||||
return !isInitialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取存储引擎类型
|
|
||||||
* @return 存储引擎类型枚举
|
|
||||||
*/
|
|
||||||
public abstract StorageTypeEnum getStorageTypeEnum();
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 搜索文件
|
|
||||||
* @param name 文件名
|
|
||||||
* @return 包含该文件名的所有文件或文件夹
|
|
||||||
* @throws Exception 搜索过程出现的异常
|
|
||||||
*/
|
|
||||||
public 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 查询所有文件, 仅去缓存中查询.
|
|
||||||
* @return 所有文件
|
|
||||||
*/
|
|
||||||
public List<FileItemDTO> selectAllFileList() throws Exception {
|
|
||||||
List<FileItemDTO> result = new ArrayList<>();
|
|
||||||
boolean enableCache = systemConfigService.getEnableCache();
|
|
||||||
if (!enableCache) {
|
|
||||||
log.debug("未开启缓存, 不支持查询所有文件.");
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
String path = "/";
|
|
||||||
|
|
||||||
List<FileItemDTO> fileItemList = cache.get(path);
|
|
||||||
fileItemList = fileItemList == null ? new ArrayList<>() : fileItemList;
|
|
||||||
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() + "/");
|
|
||||||
List<FileItemDTO> cacheList = cache.get(filePath);
|
|
||||||
if (cacheList != null) {
|
|
||||||
queue.addAll(cacheList);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 获取所有缓存的 Key, 仅当开启缓存, 且缓存完成时, 可获取.
|
|
||||||
* @return 所有缓存的 Key
|
|
||||||
* @throws Exception 可能出现的异常
|
|
||||||
*/
|
|
||||||
public Set<String> getCacheKeys() throws Exception {
|
|
||||||
if (systemConfigService.getEnableCache() && fileAsyncCacheService.isCacheFinish()) {
|
|
||||||
Set<String> collect = selectAllFileList().stream().map(fileItemDTO -> {
|
|
||||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
|
||||||
return StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
|
||||||
}
|
|
||||||
return null;
|
|
||||||
}).collect(Collectors.toSet());
|
|
||||||
collect.remove(null);
|
|
||||||
collect.add("/");
|
|
||||||
return collect;
|
|
||||||
} else {
|
|
||||||
return Collections.emptySet();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 刷新缓存
|
|
||||||
*/
|
|
||||||
public void refreshCache(String key) throws Exception {
|
|
||||||
cache.remove(key);
|
|
||||||
FileService currentFileService = (FileService) AopContext.currentProxy();
|
|
||||||
currentFileService.fileList(key);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void closeCacheAutoRefresh() {
|
|
||||||
cache.config().setRefreshPolicy(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void openCacheAutoRefresh() {
|
|
||||||
RefreshPolicy refreshPolicy = RefreshPolicy.newPolicy(1, TimeUnit.MINUTES);
|
|
||||||
cache.config().setRefreshPolicy(refreshPolicy);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
package im.zhaojun.common.service;
|
|
||||||
|
|
||||||
import im.zhaojun.common.config.StorageTypeFactory;
|
|
||||||
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 lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.scheduling.annotation.Async;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.ArrayDeque;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class FileAsyncCacheService {
|
|
||||||
|
|
||||||
private boolean cacheFinish;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigService systemConfigService;
|
|
||||||
|
|
||||||
@Async
|
|
||||||
public void cacheGlobalFile() {
|
|
||||||
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
|
|
||||||
|
|
||||||
if (storageStrategy == null) {
|
|
||||||
log.info("尚未配置存储策略. 跳过启动缓存.");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean enableCache = systemConfigService.getEnableCache();
|
|
||||||
if (!enableCache) {
|
|
||||||
log.info("未开启缓存, 跳过启动缓存");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
AbstractFileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
|
|
||||||
|
|
||||||
|
|
||||||
if (fileService.getIsUnInitialized()) {
|
|
||||||
log.info("存储引擎 {} 未初始化成功, 跳过启动缓存.", storageStrategy.getDescription());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
log.info("缓存 {} 所有文件开始", storageStrategy.getDescription());
|
|
||||||
long startTime = System.currentTimeMillis();
|
|
||||||
try {
|
|
||||||
String path = "/";
|
|
||||||
|
|
||||||
FileService currentFileService = systemConfigService.getCurrentFileService();
|
|
||||||
List<FileItemDTO> fileItemList = currentFileService.fileList(path);
|
|
||||||
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
|
|
||||||
|
|
||||||
while (!queue.isEmpty()) {
|
|
||||||
FileItemDTO fileItemDTO = queue.pop();
|
|
||||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
|
||||||
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
|
||||||
queue.addAll(currentFileService.fileList(filePath));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("缓存所有文件失败", e);
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
long endTime = System.currentTimeMillis();
|
|
||||||
log.info("缓存 {} 所有文件结束, 用时: {} 秒", storageStrategy.getDescription(), ( (endTime - startTime) / 1000 ));
|
|
||||||
cacheFinish = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
public boolean isCacheFinish() {
|
|
||||||
return cacheFinish;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setCacheFinish(boolean cacheFinish) {
|
|
||||||
this.cacheFinish = cacheFinish;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,182 +0,0 @@
|
|||||||
package im.zhaojun.common.service;
|
|
||||||
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
|
||||||
import com.alicp.jetcache.Cache;
|
|
||||||
import com.alicp.jetcache.anno.CacheType;
|
|
||||||
import com.alicp.jetcache.anno.CreateCache;
|
|
||||||
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 lombok.extern.slf4j.Slf4j;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Slf4j
|
|
||||||
@Service
|
|
||||||
public class SystemConfigService {
|
|
||||||
|
|
||||||
public static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-config-cache:";
|
|
||||||
|
|
||||||
public static final String SYSTEM_CONFIG_CACHE_KEY = "1";
|
|
||||||
|
|
||||||
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
|
|
||||||
private Cache<String, Object> configCache;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigRepository systemConfigRepository;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private FileAsyncCacheService fileAsyncCacheService;
|
|
||||||
|
|
||||||
public SystemConfigDTO getSystemConfig() {
|
|
||||||
Object cache = configCache.get(SYSTEM_CONFIG_CACHE_KEY);
|
|
||||||
if (configCache.get(SYSTEM_CONFIG_CACHE_KEY) != null) {
|
|
||||||
return (SystemConfigDTO) cache;
|
|
||||||
}
|
|
||||||
|
|
||||||
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
|
|
||||||
List<SystemConfig> systemConfigList = systemConfigRepository.findAll();
|
|
||||||
|
|
||||||
for (SystemConfig systemConfig : systemConfigList) {
|
|
||||||
switch (systemConfig.getKey()) {
|
|
||||||
case SystemConfigConstant.SITE_NAME:
|
|
||||||
systemConfigDTO.setSiteName(systemConfig.getValue());
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.INFO_ENABLE:
|
|
||||||
systemConfigDTO.setInfoEnable("true".equals(systemConfig.getValue()));
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.SEARCH_ENABLE:
|
|
||||||
systemConfigDTO.setSearchEnable("true".equals(systemConfig.getValue()));
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.SEARCH_IGNORE_CASE:
|
|
||||||
systemConfigDTO.setSearchIgnoreCase("true".equals(systemConfig.getValue()));
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.STORAGE_STRATEGY:
|
|
||||||
String value = systemConfig.getValue();
|
|
||||||
systemConfigDTO.setStorageStrategy(StorageTypeEnum.getEnum(value));
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.USERNAME:
|
|
||||||
systemConfigDTO.setUsername(systemConfig.getValue());
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.PASSWORD:
|
|
||||||
systemConfigDTO.setPassword(systemConfig.getValue());
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.DOMAIN:
|
|
||||||
systemConfigDTO.setDomain(systemConfig.getValue());
|
|
||||||
break;
|
|
||||||
case SystemConfigConstant.ENABLE_CACHE:
|
|
||||||
systemConfigDTO.setEnableCache("true".equals(systemConfig.getValue()));
|
|
||||||
break;
|
|
||||||
default:break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
configCache.put(SYSTEM_CONFIG_CACHE_KEY, systemConfigDTO);
|
|
||||||
return systemConfigDTO;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) throws Exception {
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
boolean oldEnableCache = getEnableCache();
|
|
||||||
Boolean curEnableCache = systemConfigDTO.getEnableCache();
|
|
||||||
|
|
||||||
SystemConfig enableCacheSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.ENABLE_CACHE);
|
|
||||||
enableCacheSystemConfig.setValue(systemConfigDTO.getEnableCache() ? "true" : "false");
|
|
||||||
systemConfigList.add(enableCacheSystemConfig);
|
|
||||||
|
|
||||||
SystemConfig storageStrategySystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.STORAGE_STRATEGY);
|
|
||||||
storageStrategySystemConfig.setValue(systemConfigDTO.getStorageStrategy().getKey());
|
|
||||||
systemConfigList.add(storageStrategySystemConfig);
|
|
||||||
|
|
||||||
if (StringUtils.isNotNullOrEmpty(systemConfigDTO.getUsername())) {
|
|
||||||
SystemConfig usernameSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
|
|
||||||
usernameSystemConfig.setValue(systemConfigDTO.getUsername());
|
|
||||||
systemConfigList.add(usernameSystemConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (StringUtils.isNotNullOrEmpty(systemConfigDTO.getPassword())) {
|
|
||||||
SystemConfig passwordSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
|
|
||||||
passwordSystemConfig.setValue(systemConfigDTO.getPassword());
|
|
||||||
systemConfigList.add(passwordSystemConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
|
|
||||||
|
|
||||||
systemConfigRepository.saveAll(systemConfigList);
|
|
||||||
|
|
||||||
AbstractFileService currentFileService = getCurrentFileService();
|
|
||||||
|
|
||||||
if (!oldEnableCache && curEnableCache) {
|
|
||||||
log.debug("检测到开启了缓存, 开启预热缓存");
|
|
||||||
currentFileService.openCacheAutoRefresh();
|
|
||||||
fileAsyncCacheService.cacheGlobalFile();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (oldEnableCache && !curEnableCache) {
|
|
||||||
log.debug("检测到关闭了缓存, 正在清理缓存数据及关闭自动刷新");
|
|
||||||
currentFileService.clearCache();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void updateUsernameAndPwd(String username, String password) {
|
|
||||||
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
|
|
||||||
usernameConfig.setValue(username);
|
|
||||||
systemConfigRepository.save(usernameConfig);
|
|
||||||
|
|
||||||
String encryptionPassword = SecureUtil.md5(password);
|
|
||||||
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
|
|
||||||
systemConfig.setValue(encryptionPassword);
|
|
||||||
|
|
||||||
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
|
|
||||||
|
|
||||||
systemConfigRepository.save(systemConfig);
|
|
||||||
}
|
|
||||||
|
|
||||||
public AbstractFileService getCurrentFileService() {
|
|
||||||
StorageTypeEnum storageStrategy = getCurrentStorageStrategy();
|
|
||||||
return StorageTypeFactory.getStorageTypeService(storageStrategy);
|
|
||||||
}
|
|
||||||
|
|
||||||
public StorageTypeEnum getCurrentStorageStrategy() {
|
|
||||||
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
|
||||||
return systemConfigDTO.getStorageStrategy();
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean getEnableCache() {
|
|
||||||
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
|
||||||
return systemConfigDTO.getEnableCache();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,42 +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.ArrayList;
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class SystemService {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigService systemConfigService;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 构建指定路径下标题, 页头, 页尾
|
|
||||||
* @param path 路径
|
|
||||||
*/
|
|
||||||
public synchronized SiteConfigDTO getConfig(String path) throws Exception {
|
|
||||||
|
|
||||||
SiteConfigDTO siteConfigDTO = new SiteConfigDTO();
|
|
||||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
|
||||||
|
|
||||||
List<FileItemDTO> fileItemList = new ArrayList<>(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,28 +0,0 @@
|
|||||||
package im.zhaojun.common.util;
|
|
||||||
|
|
||||||
import org.springframework.web.client.RestClientException;
|
|
||||||
import org.springframework.web.client.RestTemplate;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean checkUrlExist(String url) {
|
|
||||||
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
|
|
||||||
try {
|
|
||||||
restTemplate.headForHeaders(url);
|
|
||||||
return true;
|
|
||||||
} catch (RestClientException e) {
|
|
||||||
e.printStackTrace();
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,93 +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.constant.StorageConfigConstant;
|
|
||||||
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.AbstractFileService;
|
|
||||||
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;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class FtpServiceImpl extends AbstractFileService implements FileService {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(FtpServiceImpl.class);
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StorageConfigService storageConfigService;
|
|
||||||
|
|
||||||
private Ftp ftp;
|
|
||||||
|
|
||||||
private String domain;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
try {
|
|
||||||
Map<String, StorageConfig> stringStorageConfigMap =
|
|
||||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.FTP);
|
|
||||||
String host = stringStorageConfigMap.get(StorageConfigConstant.HOST_KEY).getValue();
|
|
||||||
String port = stringStorageConfigMap.get(StorageConfigConstant.PORT_KEY).getValue();
|
|
||||||
String username = stringStorageConfigMap.get(StorageConfigConstant.USERNAME_KEY).getValue();
|
|
||||||
String password = stringStorageConfigMap.get(StorageConfigConstant.PASSWORD_KEY).getValue();
|
|
||||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
|
||||||
|
|
||||||
if (Objects.isNull(host) || Objects.isNull(port) || Objects.isNull(username) || Objects.isNull(password)) {
|
|
||||||
isInitialized = true;
|
|
||||||
} else {
|
|
||||||
ftp = new Ftp(host, Integer.parseInt(port), username, password);
|
|
||||||
isInitialized = testConnection();
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(getStorageTypeEnum().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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,62 +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.util.Date;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
public class LocalController {
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private LocalServiceImpl localServiceImpl;
|
|
||||||
|
|
||||||
@GetMapping("/file/**")
|
|
||||||
@ResponseBody
|
|
||||||
public ResponseEntity<FileSystemResource> downAttachment(final HttpServletRequest request) {
|
|
||||||
String path = (String) request.getAttribute(
|
|
||||||
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
|
||||||
String bestMatchPattern = (String ) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
|
||||||
AntPathMatcher apm = new AntPathMatcher();
|
|
||||||
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
|
|
||||||
|
|
||||||
return export(new File(StringUtils.concatPath(localServiceImpl.getFilePath(), URLUtil.decode(filePath))));
|
|
||||||
}
|
|
||||||
|
|
||||||
private ResponseEntity<FileSystemResource> export(File file) {
|
|
||||||
|
|
||||||
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
|
|
||||||
|
|
||||||
HttpHeaders headers = new HttpHeaders();
|
|
||||||
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
|
|
||||||
headers.setContentDispositionFormData("attachment", URLUtil.encode(file.getName()));
|
|
||||||
|
|
||||||
headers.add("Pragma", "no-cache");
|
|
||||||
headers.add("Expires", "0");
|
|
||||||
headers.add("Last-Modified", new Date().toString());
|
|
||||||
headers.add("ETag", String.valueOf(System.currentTimeMillis()));
|
|
||||||
return ResponseEntity
|
|
||||||
.ok()
|
|
||||||
.headers(headers)
|
|
||||||
.contentLength(file.length())
|
|
||||||
.contentType(mediaType)
|
|
||||||
.body(new FileSystemResource(file));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,106 +0,0 @@
|
|||||||
package im.zhaojun.local.service;
|
|
||||||
|
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
|
||||||
import im.zhaojun.common.model.SystemConfig;
|
|
||||||
import im.zhaojun.common.model.constant.StorageConfigConstant;
|
|
||||||
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.AbstractFileService;
|
|
||||||
import im.zhaojun.common.service.FileService;
|
|
||||||
import im.zhaojun.common.service.StorageConfigService;
|
|
||||||
import im.zhaojun.common.util.StringUtils;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Date;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class LocalServiceImpl extends AbstractFileService implements FileService {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(LocalServiceImpl.class);
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private StorageConfigService storageConfigService;
|
|
||||||
|
|
||||||
@Resource
|
|
||||||
private SystemConfigRepository systemConfigRepository;
|
|
||||||
|
|
||||||
private String filePath;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
try {
|
|
||||||
Map<String, StorageConfig> stringStorageConfigMap =
|
|
||||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.LOCAL);
|
|
||||||
filePath = stringStorageConfigMap.get(StorageConfigConstant.FILE_PATH_KEY).getValue();
|
|
||||||
if (Objects.isNull(filePath)) {
|
|
||||||
isInitialized = false;
|
|
||||||
} else {
|
|
||||||
isInitialized = testConnection();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(getStorageTypeEnum().getDescription() + "初始化异常, 已跳过");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public List<FileItemDTO> fileList(String path) {
|
|
||||||
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) {
|
|
||||||
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
|
|
||||||
return StringUtils.removeDuplicateSeparator(usernameConfig.getValue() + "/file/" + path);
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getFilePath() {
|
|
||||||
return filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setFilePath(String filePath) {
|
|
||||||
this.filePath = filePath;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StorageTypeEnum getStorageTypeEnum() {
|
|
||||||
return StorageTypeEnum.LOCAL;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
package im.zhaojun.minio;
|
|
||||||
|
|
||||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
|
||||||
import com.amazonaws.auth.BasicAWSCredentials;
|
|
||||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
|
||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
|
||||||
import im.zhaojun.common.model.constant.StorageConfigConstant;
|
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
|
||||||
import im.zhaojun.common.service.AbstractS3FileService;
|
|
||||||
import im.zhaojun.common.service.FileService;
|
|
||||||
import org.slf4j.Logger;
|
|
||||||
import org.slf4j.LoggerFactory;
|
|
||||||
import org.springframework.stereotype.Service;
|
|
||||||
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.Objects;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Service
|
|
||||||
public class MinIOServiceImpl extends AbstractS3FileService implements FileService {
|
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(MinIOServiceImpl.class);
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void init() {
|
|
||||||
try {
|
|
||||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.MINIO);
|
|
||||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
|
||||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
|
||||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
|
||||||
bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
|
||||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
|
||||||
|
|
||||||
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
|
|
||||||
isInitialized = false;
|
|
||||||
} else {
|
|
||||||
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
|
|
||||||
s3Client = AmazonS3ClientBuilder.standard()
|
|
||||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
|
||||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "minio")).build();
|
|
||||||
|
|
||||||
isInitialized = testConnection();
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.debug(getStorageTypeEnum().getDescription() + "初始化异常, 已跳过");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public StorageTypeEnum getStorageTypeEnum() {
|
|
||||||
return StorageTypeEnum.MINIO;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
@@ -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,32 +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.stereotype.Controller;
|
|
||||||
import org.springframework.web.bind.annotation.GetMapping;
|
|
||||||
import org.springframework.web.bind.annotation.ResponseBody;
|
|
||||||
|
|
||||||
import javax.servlet.http.HttpServletRequest;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @author zhaojun
|
|
||||||
*/
|
|
||||||
@Controller
|
|
||||||
public class OneDriveController {
|
|
||||||
|
|
||||||
@GetMapping("/onedirve/callback")
|
|
||||||
@ResponseBody
|
|
||||||
public String onedriveCallback(String code, HttpServletRequest request) {
|
|
||||||
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,7 +1,5 @@
|
|||||||
package im.zhaojun;
|
package im.zhaojun.zfile;
|
||||||
|
|
||||||
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
|
|
||||||
import com.alicp.jetcache.anno.config.EnableMethodCache;
|
|
||||||
import org.springframework.boot.SpringApplication;
|
import org.springframework.boot.SpringApplication;
|
||||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||||
@@ -12,8 +10,6 @@ import org.springframework.scheduling.annotation.EnableAsync;
|
|||||||
*/
|
*/
|
||||||
@EnableAsync
|
@EnableAsync
|
||||||
@SpringBootApplication
|
@SpringBootApplication
|
||||||
@EnableMethodCache(basePackages = "im.zhaojun", proxyTargetClass = true)
|
|
||||||
@EnableCreateCacheAnnotation
|
|
||||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||||
public class ZfileApplication {
|
public class ZfileApplication {
|
||||||
|
|
||||||
65
src/main/java/im/zhaojun/zfile/aspect/FileListCacheAop.java
Normal file
65
src/main/java/im/zhaojun/zfile/aspect/FileListCacheAop.java
Normal file
@@ -0,0 +1,65 @@
|
|||||||
|
package im.zhaojun.zfile.aspect;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.cache.ZFileCache;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import org.aspectj.lang.ProceedingJoinPoint;
|
||||||
|
import org.aspectj.lang.annotation.Around;
|
||||||
|
import org.aspectj.lang.annotation.Aspect;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
* 缓存切面类, 用于访问文件夹时, 缓存文件列表内容.
|
||||||
|
*/
|
||||||
|
@Aspect
|
||||||
|
@Component
|
||||||
|
public class FileListCacheAop {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ZFileCache zFileCache;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存切面, 如果此驱动器开启了缓存, 则从缓存中取数据, 没有开启, 则直接调用方法.
|
||||||
|
*/
|
||||||
|
@Around(value = "execution(public * im.zhaojun.zfile.service.base.AbstractBaseFileService.fileList(..))")
|
||||||
|
public Object around(ProceedingJoinPoint point) throws Throwable {
|
||||||
|
List<FileItemDTO> result;
|
||||||
|
|
||||||
|
// 获取请求路径
|
||||||
|
Object[] args = point.getArgs();
|
||||||
|
String path = String.valueOf(args[0]);
|
||||||
|
|
||||||
|
// 获取当前驱动器
|
||||||
|
AbstractBaseFileService fileService = ((AbstractBaseFileService) point.getTarget());
|
||||||
|
Integer driveId = fileService.driveId;
|
||||||
|
|
||||||
|
// 判断驱动器是否开启了缓存
|
||||||
|
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||||
|
boolean enableCache = driveConfig.getEnableCache();
|
||||||
|
|
||||||
|
if (enableCache) {
|
||||||
|
List<FileItemDTO> cacheFileList = zFileCache.get(driveId, path);
|
||||||
|
if (cacheFileList == null) {
|
||||||
|
result = (List<FileItemDTO>) point.proceed();
|
||||||
|
zFileCache.put(driveId, path, result);
|
||||||
|
} else {
|
||||||
|
result = cacheFileList;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result = (List<FileItemDTO>) point.proceed();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
254
src/main/java/im/zhaojun/zfile/cache/ZFileCache.java
vendored
Normal file
254
src/main/java/im/zhaojun/zfile/cache/ZFileCache.java
vendored
Normal file
@@ -0,0 +1,254 @@
|
|||||||
|
package im.zhaojun.zfile.cache;
|
||||||
|
|
||||||
|
import cn.hutool.cache.CacheUtil;
|
||||||
|
import cn.hutool.cache.impl.CacheObj;
|
||||||
|
import cn.hutool.cache.impl.TimedCache;
|
||||||
|
import cn.hutool.core.util.StrUtil;
|
||||||
|
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.repository.DriverConfigRepository;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.Set;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
import java.util.concurrent.ConcurrentMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* ZFile 缓存类
|
||||||
|
*
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
public class ZFileCache {
|
||||||
|
|
||||||
|
@Value("${zfile.cache.timeout}")
|
||||||
|
private long timeout;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 缓存 map 对象.
|
||||||
|
*
|
||||||
|
* ConcurrentMap<Integer, ConcurrentHashMap<String, List<FileItemDTO>>>
|
||||||
|
* ConcurrentMap<driveId, ConcurrentHashMap<key, value>>
|
||||||
|
*
|
||||||
|
* driveId: 驱动器 ID
|
||||||
|
* key: 文件夹路径
|
||||||
|
* value: 文件夹中内容
|
||||||
|
*/
|
||||||
|
private ConcurrentMap<Integer, TimedCache<String, List<FileItemDTO>>> drivesCache = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统设置缓存
|
||||||
|
*/
|
||||||
|
private SystemConfigDTO systemConfigCache;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriverConfigRepository driverConfigRepository;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 写入缓存
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* 文件夹路径
|
||||||
|
*
|
||||||
|
* @param value
|
||||||
|
* 文件夹中列表
|
||||||
|
*/
|
||||||
|
public synchronized void put(Integer driveId, String key, List<FileItemDTO> value) {
|
||||||
|
getCacheByDriveId(driveId).put(key, value);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器, 某个文件夹的名称
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* 文件夹路径
|
||||||
|
*
|
||||||
|
* @return 驱动器中文件夹的内容
|
||||||
|
*/
|
||||||
|
public List<FileItemDTO> get(Integer driveId, String key) {
|
||||||
|
return getCacheByDriveId(driveId).get(key, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清空指定驱动器的缓存.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
public void clear(Integer driveId) {
|
||||||
|
getCacheByDriveId(driveId).clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器中已缓存文件夹数量
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 已缓存文件夹数量
|
||||||
|
*/
|
||||||
|
public int cacheCount(Integer driveId) {
|
||||||
|
return getCacheByDriveId(driveId).size();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 指定驱动器, 根据文件及文件名查找相关的文件
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* 搜索键, 可匹配文件夹名称和文件名称.
|
||||||
|
*
|
||||||
|
* @return 搜索结果, 包含文件夹和文件.
|
||||||
|
*/
|
||||||
|
public List<FileItemDTO> find(Integer driveId, String key) {
|
||||||
|
List<FileItemDTO> result = new ArrayList<>();
|
||||||
|
|
||||||
|
DriveConfig driveConfig = driverConfigRepository.getOne(driveId);
|
||||||
|
boolean searchContainEncryptedFile = driveConfig.getSearchContainEncryptedFile();
|
||||||
|
boolean ignoreCase = driveConfig.getSearchIgnoreCase();
|
||||||
|
|
||||||
|
for (List<FileItemDTO> fileItemList : getCacheByDriveId(driveId)) {
|
||||||
|
// 过滤加密文件
|
||||||
|
if (!searchContainEncryptedFile && isEncryptedFolder(fileItemList)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||||
|
boolean testResult;
|
||||||
|
|
||||||
|
// 根据是否需要忽略大小写来匹配文件(夹)名
|
||||||
|
if (ignoreCase) {
|
||||||
|
testResult = StrUtil.containsIgnoreCase(fileItemDTO.getName(), key);
|
||||||
|
} else {
|
||||||
|
testResult = fileItemDTO.getName().contains(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (testResult) {
|
||||||
|
result.add(fileItemDTO);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有缓存 key (文件夹名称)
|
||||||
|
*
|
||||||
|
* @return 所有缓存 key
|
||||||
|
*/
|
||||||
|
public Set<String> keySet(Integer driveId) {
|
||||||
|
Iterator<CacheObj<String, List<FileItemDTO>>> cacheObjIterator = getCacheByDriveId(driveId).cacheObjIterator();
|
||||||
|
Set<String> keys = new HashSet<>();
|
||||||
|
while (cacheObjIterator.hasNext()) {
|
||||||
|
keys.add(cacheObjIterator.next().getKey());
|
||||||
|
}
|
||||||
|
return keys;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从缓存中删除指定存储器的某个路径的缓存
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* 文件夹路径
|
||||||
|
*/
|
||||||
|
public void remove(Integer driveId, String key) {
|
||||||
|
getCacheByDriveId(driveId).remove(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 TimedCache<String, List<FileItemDTO>> getCacheByDriveId(Integer driveId) {
|
||||||
|
TimedCache<String, List<FileItemDTO>> driveCache = drivesCache.get(driveId);
|
||||||
|
if (driveCache == null) {
|
||||||
|
driveCache = CacheUtil.newTimedCache(timeout * 1000);
|
||||||
|
drivesCache.put(driveId, driveCache);
|
||||||
|
}
|
||||||
|
|
||||||
|
return driveCache;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
57
src/main/java/im/zhaojun/zfile/config/OneDriveConfig.java
Normal file
57
src/main/java/im/zhaojun/zfile/config/OneDriveConfig.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package im.zhaojun.zfile.config;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.StorageConfigService;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.client.ClientHttpRequestInterceptor;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.LinkedList;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class OneDriveConfig {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigService storageConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveServiceImpl oneDriveServiceImpl;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OneDrive 请求 RestTemplate, 会在请求头中添加 Bearer: Authorization {token} 信息, 用于 API 认证.
|
||||||
|
*/
|
||||||
|
@Bean
|
||||||
|
public RestTemplate oneDriveRestTemplate() {
|
||||||
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
|
|
||||||
|
ClientHttpRequestInterceptor interceptor = (httpRequest, bytes, clientHttpRequestExecution) -> {
|
||||||
|
HttpHeaders headers = httpRequest.getHeaders();
|
||||||
|
Integer driveId = Integer.valueOf(((LinkedList)headers.get("driveId")).get(0).toString());
|
||||||
|
|
||||||
|
StorageConfig accessTokenConfig =
|
||||||
|
storageConfigService.findByDriveIdAndKey(driveId, StorageConfigConstant.ACCESS_TOKEN_KEY);
|
||||||
|
|
||||||
|
String tokenValue = String.format("%s %s", "Bearer", accessTokenConfig.getValue());
|
||||||
|
httpRequest.getHeaders().add("Authorization", tokenValue);
|
||||||
|
return clientHttpRequestExecution.execute(httpRequest, bytes);
|
||||||
|
};
|
||||||
|
restTemplate.setInterceptors(Collections.singletonList(interceptor));
|
||||||
|
return restTemplate;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
34
src/main/java/im/zhaojun/zfile/config/WebMvcConfig.java
Normal file
34
src/main/java/im/zhaojun/zfile/config/WebMvcConfig.java
Normal file
@@ -0,0 +1,34 @@
|
|||||||
|
package im.zhaojun.zfile.config;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnumDeSerializerConvert;
|
||||||
|
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
|
||||||
|
import org.springframework.boot.web.servlet.server.ServletWebServerFactory;
|
||||||
|
import org.springframework.context.annotation.Bean;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.format.FormatterRegistry;
|
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class WebMvcConfig implements WebMvcConfigurer {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addFormatters(FormatterRegistry registry) {
|
||||||
|
registry.addConverter(new StorageTypeEnumDeSerializerConvert());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public ServletWebServerFactory webServerFactory() {
|
||||||
|
TomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory();
|
||||||
|
|
||||||
|
// 添加对 URL 中特殊符号的支持.
|
||||||
|
webServerFactory.addConnectorCustomizers(connector -> {
|
||||||
|
connector.setAttribute("relaxedPathChars", "<>[\\]^`{|}");
|
||||||
|
connector.setAttribute("relaxedQueryChars", "<>[\\]^`{|}");
|
||||||
|
});
|
||||||
|
return webServerFactory;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,11 +1,14 @@
|
|||||||
package im.zhaojun.common.config;
|
package im.zhaojun.zfile.config;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.client.ClientHttpResponse;
|
||||||
import org.springframework.http.converter.StringHttpMessageConverter;
|
import org.springframework.http.converter.StringHttpMessageConverter;
|
||||||
import org.springframework.web.client.RestTemplate;
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
import java.nio.charset.StandardCharsets;
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.Collections;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
@@ -17,6 +20,14 @@ public class ZFileConfiguration {
|
|||||||
public RestTemplate restTemplate(){
|
public RestTemplate restTemplate(){
|
||||||
RestTemplate restTemplate = new RestTemplate();
|
RestTemplate restTemplate = new RestTemplate();
|
||||||
restTemplate.getMessageConverters().set(1, new StringHttpMessageConverter(StandardCharsets.UTF_8));
|
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;
|
return restTemplate;
|
||||||
}
|
}
|
||||||
|
|
||||||
107
src/main/java/im/zhaojun/zfile/context/DriveContext.java
Normal file
107
src/main/java/im/zhaojun/zfile/context/DriveContext.java
Normal file
@@ -0,0 +1,107 @@
|
|||||||
|
package im.zhaojun.zfile.context;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.util.SpringContextHolder;
|
||||||
|
import org.springframework.beans.BeansException;
|
||||||
|
import org.springframework.context.ApplicationContext;
|
||||||
|
import org.springframework.context.ApplicationContextAware;
|
||||||
|
import org.springframework.context.annotation.DependsOn;
|
||||||
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.concurrent.ConcurrentHashMap;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动器上下文环境
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Component
|
||||||
|
@DependsOn("springContextHolder")
|
||||||
|
public class DriveContext implements ApplicationContextAware {
|
||||||
|
|
||||||
|
private static Map<Integer, AbstractBaseFileService> drivesServiceMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
private static Map<StorageTypeEnum, Class<AbstractBaseFileService>> storageTypeEnumClassMap = new ConcurrentHashMap<>();
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化指定驱动器的 Service, 添加到上下文环境中.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID.
|
||||||
|
*/
|
||||||
|
public void initDrive(Integer driveId) {
|
||||||
|
AbstractBaseFileService baseFileService = getBeanByDriveId(driveId);
|
||||||
|
if (baseFileService != null) {
|
||||||
|
baseFileService.init(driveId);
|
||||||
|
drivesServiceMap.put(driveId, baseFileService);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器的 Service.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器对应的 Service
|
||||||
|
*/
|
||||||
|
public AbstractBaseFileService getDriveService(Integer driveId) {
|
||||||
|
return drivesServiceMap.get(driveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 销毁指定驱动器的 Service.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
public void destroyDrive(Integer driveId) {
|
||||||
|
drivesServiceMap.remove(driveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器对应的 Service, 状态为未初始化
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器对应未初始化的 Service
|
||||||
|
*/
|
||||||
|
private AbstractBaseFileService getBeanByDriveId(Integer driveId) {
|
||||||
|
StorageTypeEnum storageTypeEnum = driveConfigService.findStorageTypeById(driveId);
|
||||||
|
Map<String, AbstractBaseFileService> beansOfType = SpringContextHolder.getBeansOfType(AbstractBaseFileService.class);
|
||||||
|
for (AbstractBaseFileService value : beansOfType.values()) {
|
||||||
|
if (Objects.equals(value.getStorageTypeEnum(), storageTypeEnum)) {
|
||||||
|
return SpringContextHolder.getBean(value.getClass());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目启动时, 自动调用所有驱动器进行初始化.
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||||
|
List<DriveConfig> list = driveConfigService.list();
|
||||||
|
for (DriveConfig driveConfig : list) {
|
||||||
|
initDrive(driveConfig.getId());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,24 +1,26 @@
|
|||||||
package im.zhaojun.common.config;
|
package im.zhaojun.zfile.context;
|
||||||
|
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
import im.zhaojun.common.service.AbstractFileService;
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
import org.springframework.beans.BeansException;
|
import org.springframework.beans.BeansException;
|
||||||
import org.springframework.context.ApplicationContext;
|
import org.springframework.context.ApplicationContext;
|
||||||
import org.springframework.context.ApplicationContextAware;
|
import org.springframework.context.ApplicationContextAware;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* 存储类型工厂类
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
public class StorageTypeFactory implements ApplicationContextAware {
|
public class StorageTypeContext implements ApplicationContextAware {
|
||||||
|
|
||||||
private static Map<String, AbstractFileService> storageTypeEnumFileServiceMap;
|
private static Map<String, AbstractBaseFileService> storageTypeEnumFileServiceMap;
|
||||||
|
|
||||||
private static ApplicationContext applicationContext;
|
private static ApplicationContext applicationContext;
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 项目启动时执行
|
* 项目启动时执行
|
||||||
*/
|
*/
|
||||||
@@ -27,15 +29,16 @@ public class StorageTypeFactory implements ApplicationContextAware {
|
|||||||
applicationContext = act;
|
applicationContext = act;
|
||||||
|
|
||||||
// 获取 Spring 容器中所有 FileService 类型的类
|
// 获取 Spring 容器中所有 FileService 类型的类
|
||||||
storageTypeEnumFileServiceMap = act.getBeansOfType(AbstractFileService.class);
|
storageTypeEnumFileServiceMap = act.getBeansOfType(AbstractBaseFileService.class);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 获取指定存储类型 Service
|
* 获取指定存储类型 Service
|
||||||
*/
|
*/
|
||||||
public static AbstractFileService getStorageTypeService(StorageTypeEnum type) {
|
public static AbstractBaseFileService getStorageTypeService(StorageTypeEnum type) {
|
||||||
AbstractFileService result = null;
|
AbstractBaseFileService result = null;
|
||||||
for (AbstractFileService fileService : storageTypeEnumFileServiceMap.values()) {
|
for (AbstractBaseFileService fileService : storageTypeEnumFileServiceMap.values()) {
|
||||||
if (fileService.getStorageTypeEnum() == type) {
|
if (fileService.getStorageTypeEnum() == type) {
|
||||||
result = fileService;
|
result = fileService;
|
||||||
break;
|
break;
|
||||||
@@ -44,7 +47,9 @@ public class StorageTypeFactory implements ApplicationContextAware {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public static ApplicationContext getApplicationContext() {
|
public static ApplicationContext getApplicationContext() {
|
||||||
return applicationContext;
|
return applicationContext;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,58 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.util.AudioHelper;
|
||||||
|
import im.zhaojun.zfile.util.HttpUtil;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 公共 Controller
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/common")
|
||||||
|
public class CommonController {
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回系统支持的所有存储策略
|
||||||
|
*
|
||||||
|
* @return 存储策略
|
||||||
|
*/
|
||||||
|
@GetMapping("/support-strategy")
|
||||||
|
public ResultBean supportStrategy() {
|
||||||
|
return ResultBean.successData(StorageTypeEnum.values());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取文件内容, 仅限用于 txt, md, ini 等普通文本文件.
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* 文件路径
|
||||||
|
*
|
||||||
|
* @return 文件内容
|
||||||
|
*/
|
||||||
|
@GetMapping("/content")
|
||||||
|
public ResultBean getContent(String url) {
|
||||||
|
return ResultBean.successData(HttpUtil.getTextContent(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取音频文件信息
|
||||||
|
*
|
||||||
|
* @param url
|
||||||
|
* 文件 URL
|
||||||
|
*
|
||||||
|
* @return 音频信息, 标题封面等信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/audio-info")
|
||||||
|
public ResultBean getAudioInfo(String url) throws Exception {
|
||||||
|
return ResultBean.success(AudioHelper.getAudioInfo(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
220
src/main/java/im/zhaojun/zfile/controller/FileController.java
Normal file
220
src/main/java/im/zhaojun/zfile/controller/FileController.java
Normal file
@@ -0,0 +1,220 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemFrontConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.support.FilePageModel;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
import im.zhaojun.zfile.service.SystemConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
import im.zhaojun.zfile.util.FileComparator;
|
||||||
|
import im.zhaojun.zfile.util.HttpUtil;
|
||||||
|
import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestParam;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 前台文件管理
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@RequestMapping("/api")
|
||||||
|
@RestController
|
||||||
|
public class FileController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemConfigService systemConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveContext driveContext;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 滚动加载每页条数.
|
||||||
|
*/
|
||||||
|
private static final Integer PAGE_SIZE = 30;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有驱动器
|
||||||
|
*
|
||||||
|
* @return 所有驱动器
|
||||||
|
*/
|
||||||
|
@GetMapping("/drive/list")
|
||||||
|
public ResultBean drives() {
|
||||||
|
return ResultBean.success(driveConfigService.list());
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取某个驱动器下, 指定路径的数据, 每页固定 {@link #PAGE_SIZE} 条数据.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* 路径
|
||||||
|
*
|
||||||
|
* @param password
|
||||||
|
* 文件夹密码, 某些文件夹需要密码才能访问, 当不需要密码时, 此参数可以为空
|
||||||
|
*
|
||||||
|
* @param page
|
||||||
|
* 页数
|
||||||
|
*
|
||||||
|
* @return 当前路径下所有文件及文件夹
|
||||||
|
*/
|
||||||
|
@GetMapping("/list/{driveId}")
|
||||||
|
public ResultBean list(@PathVariable(name = "driveId") Integer driveId,
|
||||||
|
@RequestParam(defaultValue = "/") String path,
|
||||||
|
@RequestParam(required = false) String password,
|
||||||
|
@RequestParam(defaultValue = "1") Integer page) throws Exception {
|
||||||
|
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
|
||||||
|
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + path + "/"));
|
||||||
|
|
||||||
|
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||||
|
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
|
||||||
|
String expectedPasswordContent;
|
||||||
|
try {
|
||||||
|
expectedPasswordContent = HttpUtil.getTextContent(fileItemDTO.getUrl());
|
||||||
|
} catch (HttpClientErrorException httpClientErrorException) {
|
||||||
|
log.debug("尝试重新获取密码文件缓存中链接后仍失败", httpClientErrorException);
|
||||||
|
try {
|
||||||
|
String fullPath = StringUtils.removeDuplicateSeparator(fileItemDTO.getPath() + "/" + fileItemDTO.getName());
|
||||||
|
FileItemDTO fileItem = fileService.getFileItem(fullPath);
|
||||||
|
expectedPasswordContent = HttpUtil.getTextContent(fileItem.getUrl());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("尝试重新获取密码文件链接后仍失败, 已暂时取消密码", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Objects.equals(expectedPasswordContent, password)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (password != null && !"".equals(password)) {
|
||||||
|
return ResultBean.error("密码错误.", ResultBean.INVALID_PASSWORD);
|
||||||
|
}
|
||||||
|
return ResultBean.error("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ResultBean.successData(getSortedPagingData(fileItemList, page));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统配置信息和当前页的标题, 页面文档信息
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 返回指定存储器的系统配置信息
|
||||||
|
*/
|
||||||
|
@GetMapping("/config/{driveId}")
|
||||||
|
public ResultBean getConfig(@PathVariable(name = "driveId") Integer driveId, String path) {
|
||||||
|
SystemFrontConfigDTO systemConfig = systemConfigService.getSystemFrontConfig(driveId);
|
||||||
|
|
||||||
|
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
|
||||||
|
String fullPath = StringUtils.removeDuplicateSeparator(path + "/" + ZFileConstant.README_FILE_NAME);
|
||||||
|
try {
|
||||||
|
FileItemDTO fileItem = fileService.getFileItem(fullPath);
|
||||||
|
String readme = HttpUtil.getTextContent(fileItem.getUrl());
|
||||||
|
systemConfig.setReadme(readme);
|
||||||
|
} catch (Exception e) {
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
return ResultBean.successData(systemConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/search/{driveId}")
|
||||||
|
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name,
|
||||||
|
@RequestParam(defaultValue = "name") String sortBy,
|
||||||
|
@RequestParam(defaultValue = "asc") String order,
|
||||||
|
@RequestParam(defaultValue = "1") Integer page,
|
||||||
|
@PathVariable("driveId") Integer driveId) {
|
||||||
|
return ResultBean.error("暂不支持搜索功能");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 过滤文件列表, 去除密码, 文档文件.
|
||||||
|
*
|
||||||
|
* @param fileItemList
|
||||||
|
* 文件列表
|
||||||
|
*/
|
||||||
|
private void filterFileList(List<FileItemDTO> fileItemList) {
|
||||||
|
if (fileItemList == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|
||||||
|
|| ZFileConstant.README_FILE_NAME.equals(fileItem.getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 对传入的文件列表, 按照文件名进行排序, 然后取相应页数的文件
|
||||||
|
*
|
||||||
|
* @param fileItemList
|
||||||
|
* 文件列表
|
||||||
|
*
|
||||||
|
* @param page
|
||||||
|
* 要取的页数
|
||||||
|
*
|
||||||
|
* @return 排序及分页后的那段数据
|
||||||
|
*/
|
||||||
|
private FilePageModel getSortedPagingData(List<FileItemDTO> fileItemList, Integer page) {
|
||||||
|
ArrayList<FileItemDTO> copy = new ArrayList<>(Arrays.asList(new FileItemDTO[fileItemList.size()]));
|
||||||
|
Collections.copy(copy, fileItemList);
|
||||||
|
|
||||||
|
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
|
||||||
|
copy.sort(new FileComparator());
|
||||||
|
filterFileList(copy);
|
||||||
|
|
||||||
|
int total = copy.size();
|
||||||
|
int totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||||
|
|
||||||
|
if (page > totalPage) {
|
||||||
|
return new FilePageModel(totalPage, Collections.emptyList());
|
||||||
|
}
|
||||||
|
|
||||||
|
int start = (page - 1) * PAGE_SIZE;
|
||||||
|
int end = page * PAGE_SIZE;
|
||||||
|
end = Math.min(end, total);
|
||||||
|
return new FilePageModel(totalPage, copy.subList(start, end));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定路径下的文件信息内容
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* 文件全路径
|
||||||
|
*
|
||||||
|
* @return 该文件的名称, 路径, 大小, 下载地址等信息.
|
||||||
|
*/
|
||||||
|
@GetMapping("/directlink/{driveId}")
|
||||||
|
public ResultBean directlink(@PathVariable(name = "driveId") Integer driveId, String path) {
|
||||||
|
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
|
||||||
|
return ResultBean.successData(fileService.getFileItem(path));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import im.zhaojun.zfile.controller.admin.AdminController;
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||||
|
import im.zhaojun.zfile.service.StorageConfigService;
|
||||||
|
import im.zhaojun.zfile.service.SystemConfigService;
|
||||||
|
import org.springframework.util.StringUtils;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统安装初始化
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
public class InstallController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemConfigService systemConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigService storageConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private AdminController adminController;
|
||||||
|
|
||||||
|
@GetMapping("/is-installed")
|
||||||
|
public ResultBean isInstall() {
|
||||||
|
if (!StringUtils.isEmpty(systemConfigService.getAdminUsername())) {
|
||||||
|
return ResultBean.error("请勿重复初始化");
|
||||||
|
}
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@PostMapping("/install")
|
||||||
|
public ResultBean install(SystemConfigDTO systemConfigDTO) {
|
||||||
|
if (!StringUtils.isEmpty(systemConfigService.getAdminUsername())) {
|
||||||
|
return ResultBean.error("请勿重复初始化.");
|
||||||
|
}
|
||||||
|
|
||||||
|
systemConfigDTO.setPassword(SecureUtil.md5(systemConfigDTO.getPassword()));
|
||||||
|
systemConfigService.updateSystemConfig(systemConfigDTO);
|
||||||
|
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,49 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.service.impl.LocalServiceImpl;
|
||||||
|
import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
import im.zhaojun.zfile.util.FileUtil;
|
||||||
|
import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.ResponseBody;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地存储 Controller
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class LocalController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveContext driveContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 本地存储下载指定文件
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 文件
|
||||||
|
*/
|
||||||
|
@GetMapping("/file/{driveId}/**")
|
||||||
|
@ResponseBody
|
||||||
|
public ResponseEntity<Object> downAttachment(@PathVariable("driveId") Integer driveId, final HttpServletRequest request) {
|
||||||
|
String path = (String) request.getAttribute(
|
||||||
|
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||||||
|
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||||
|
AntPathMatcher apm = new AntPathMatcher();
|
||||||
|
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
|
||||||
|
LocalServiceImpl localService = (LocalServiceImpl) driveContext.getDriveService(driveId);
|
||||||
|
return FileUtil.export(new File(StringUtils.concatPath(localService.getFilePath(), filePath)));
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.support.OneDriveToken;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.ui.Model;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
@RequestMapping("/onedrive")
|
||||||
|
public class OneDriveController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveServiceImpl oneDriveServiceImpl;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
|
||||||
|
|
||||||
|
@GetMapping("/callback")
|
||||||
|
public String oneDriveCallback(String code, Model model) {
|
||||||
|
OneDriveToken oneDriveToken = oneDriveServiceImpl.getToken(code);
|
||||||
|
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
|
||||||
|
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
|
||||||
|
return "callback";
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@GetMapping("/china-callback")
|
||||||
|
public String oneDriveChinaCallback(String code, Model model) {
|
||||||
|
OneDriveToken oneDriveToken = oneDriveChinaServiceImpl.getToken(code);
|
||||||
|
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
|
||||||
|
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
|
||||||
|
return "callback";
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package im.zhaojun.zfile.controller;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.enums.FileTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
import org.springframework.stereotype.Controller;
|
||||||
|
import org.springframework.util.AntPathMatcher;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.servlet.HandlerMapping;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zhao Jun
|
||||||
|
*/
|
||||||
|
@Controller
|
||||||
|
public class PageController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveContext driveContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器, 某个文件的直链, 然后重定向过去.
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 重定向至文件直链
|
||||||
|
*/
|
||||||
|
@GetMapping("/directlink/{driveId}/**")
|
||||||
|
public String directlink(@PathVariable("driveId") Integer driveId, final HttpServletRequest request) {
|
||||||
|
String path = (String) request.getAttribute(
|
||||||
|
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||||||
|
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||||
|
AntPathMatcher apm = new AntPathMatcher();
|
||||||
|
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
|
||||||
|
|
||||||
|
if (filePath.length() > 0 && filePath.charAt(0) != ZFileConstant.PATH_SEPARATOR_CHAR) {
|
||||||
|
filePath = "/" + filePath;
|
||||||
|
}
|
||||||
|
|
||||||
|
AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
|
||||||
|
FileItemDTO fileItem = fileService.getFileItem(filePath);
|
||||||
|
|
||||||
|
String url = fileItem.getUrl();
|
||||||
|
|
||||||
|
int queryIndex = url.indexOf('?');
|
||||||
|
|
||||||
|
if (queryIndex != -1) {
|
||||||
|
String origin = url.substring(0, queryIndex);
|
||||||
|
String queryString = url.substring(queryIndex + 1);
|
||||||
|
|
||||||
|
url = URLUtil.encode(origin) + "?" + URLUtil.encode(queryString);
|
||||||
|
} else {
|
||||||
|
url = URLUtil.encode(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
if (Objects.equals(fileItem.getType(), FileTypeEnum.FOLDER)) {
|
||||||
|
return "redirect:" + fileItem.getUrl();
|
||||||
|
} else {
|
||||||
|
return "redirect:" + url;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,119 @@
|
|||||||
|
package im.zhaojun.zfile.controller.admin;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import cn.hutool.core.util.ZipUtil;
|
||||||
|
import im.zhaojun.zfile.context.StorageTypeContext;
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.model.dto.StorageStrategyDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.model.support.SystemMonitorInfo;
|
||||||
|
import im.zhaojun.zfile.service.SystemConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.util.FileUtil;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.http.ResponseEntity;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import javax.servlet.http.HttpServletResponse;
|
||||||
|
import java.io.File;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 管理后台接口
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin")
|
||||||
|
@Slf4j
|
||||||
|
public class AdminController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemConfigService systemConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统配置
|
||||||
|
*/
|
||||||
|
@GetMapping("/config")
|
||||||
|
public ResultBean getConfig() {
|
||||||
|
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
|
||||||
|
return ResultBean.success(systemConfigDTO);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新系统配置
|
||||||
|
*/
|
||||||
|
@PostMapping("/config")
|
||||||
|
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) throws Exception {
|
||||||
|
systemConfigDTO.setId(1);
|
||||||
|
systemConfigService.updateSystemConfig(systemConfigDTO);
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 修改管理员登陆密码
|
||||||
|
*/
|
||||||
|
@PostMapping("/update-pwd")
|
||||||
|
public ResultBean updatePwd(String username, String password) {
|
||||||
|
systemConfigService.updateUsernameAndPwd(username, password);
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定存储策略的表单域
|
||||||
|
*
|
||||||
|
* @param storageType
|
||||||
|
* 存储策略
|
||||||
|
*
|
||||||
|
* @return 所有表单域
|
||||||
|
*/
|
||||||
|
@GetMapping("/strategy-form")
|
||||||
|
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
|
||||||
|
AbstractBaseFileService storageTypeService = StorageTypeContext.getStorageTypeService(storageType);
|
||||||
|
List<StorageConfig> storageConfigList = storageTypeService.storageStrategyConfigList();
|
||||||
|
return ResultBean.success(storageConfigList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 返回支持的存储引擎.
|
||||||
|
*/
|
||||||
|
@GetMapping("/support-strategy")
|
||||||
|
public ResultBean supportStrategy() {
|
||||||
|
List<StorageStrategyDTO> result = new ArrayList<>();
|
||||||
|
StorageTypeEnum[] values = StorageTypeEnum.values();
|
||||||
|
return ResultBean.successData(values);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统日志下载
|
||||||
|
*/
|
||||||
|
@GetMapping("/log")
|
||||||
|
public ResponseEntity<Object> downloadLog(HttpServletResponse response) {
|
||||||
|
String userHome = System.getProperty("user.home");
|
||||||
|
File fileZip = ZipUtil.zip(userHome + "/.zfile/logs");
|
||||||
|
String currentDate = DateUtil.format(new Date(), "yyyy-MM-dd HH:mm:ss");
|
||||||
|
return FileUtil.export(fileZip, "ZFile 诊断日志 - " + currentDate + ".zip");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统监控信息
|
||||||
|
*/
|
||||||
|
@GetMapping("monitor")
|
||||||
|
public ResultBean monitor() {
|
||||||
|
return ResultBean.success(new SystemMonitorInfo());
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,37 @@
|
|||||||
|
package im.zhaojun.zfile.controller.admin;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
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();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,81 @@
|
|||||||
|
package im.zhaojun.zfile.controller.admin;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.dto.DriveConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||||
|
import org.springframework.web.bind.annotation.GetMapping;
|
||||||
|
import org.springframework.web.bind.annotation.PathVariable;
|
||||||
|
import org.springframework.web.bind.annotation.PostMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RequestBody;
|
||||||
|
import org.springframework.web.bind.annotation.RequestMapping;
|
||||||
|
import org.springframework.web.bind.annotation.RestController;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动器 Controller
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@RestController
|
||||||
|
@RequestMapping("/admin")
|
||||||
|
@Slf4j
|
||||||
|
public class DriveController {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有驱动器列表
|
||||||
|
*
|
||||||
|
* @return 驱动器列表
|
||||||
|
*/
|
||||||
|
@GetMapping("drives")
|
||||||
|
public ResultBean driveList() {
|
||||||
|
List<DriveConfig> list = driveConfigService.list();
|
||||||
|
return ResultBean.success(list);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器基本信息及其参数
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器基本信息信息
|
||||||
|
*/
|
||||||
|
@GetMapping("drive/{id}")
|
||||||
|
public ResultBean driveItem(@PathVariable Integer id) {
|
||||||
|
DriveConfigDTO driveConfig = driveConfigService.findDriveConfigDTOById(id);
|
||||||
|
return ResultBean.success(driveConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存驱动器设置
|
||||||
|
*/
|
||||||
|
@PostMapping("drive")
|
||||||
|
public ResultBean saveDriveItem(@RequestBody DriveConfigDTO driveConfigDTO) {
|
||||||
|
driveConfigService.save(driveConfigDTO);
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除驱动器设置
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
@DeleteMapping("drive/{id}")
|
||||||
|
public ResultBean deleteDriveItem(@PathVariable Integer id) {
|
||||||
|
driveConfigService.deleteById(id);
|
||||||
|
return ResultBean.success();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package im.zhaojun.common.exception;
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
import im.zhaojun.common.model.dto.ResultBean;
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
import org.apache.catalina.connector.ClientAbortException;
|
import org.apache.catalina.connector.ClientAbortException;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
@@ -16,12 +16,12 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
|||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
@ControllerAdvice
|
@ControllerAdvice
|
||||||
@ResponseBody
|
|
||||||
public class GlobleExceptionHandler {
|
public class GlobleExceptionHandler {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
|
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
|
||||||
|
|
||||||
@ExceptionHandler(SearchDisableException.class)
|
@ExceptionHandler(SearchDisableException.class)
|
||||||
|
@ResponseBody
|
||||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
public ResultBean searchDisableExceptionHandler(SearchDisableException e) {
|
public ResultBean searchDisableExceptionHandler(SearchDisableException e) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
@@ -32,6 +32,7 @@ public class GlobleExceptionHandler {
|
|||||||
|
|
||||||
|
|
||||||
@ExceptionHandler
|
@ExceptionHandler
|
||||||
|
@ResponseBody
|
||||||
@ResponseStatus
|
@ResponseStatus
|
||||||
public ResultBean searchDisableExceptionHandler(StorageStrategyUninitializedException e) {
|
public ResultBean searchDisableExceptionHandler(StorageStrategyUninitializedException e) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
@@ -40,6 +41,16 @@ public class GlobleExceptionHandler {
|
|||||||
return ResultBean.error(e.getMessage());
|
return ResultBean.error(e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 不存在的文件异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({NotExistFileException.class})
|
||||||
|
@ResponseBody
|
||||||
|
public ResultBean notExistFile(Exception ex) {
|
||||||
|
return ResultBean.error("文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
|
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
|
||||||
*/
|
*/
|
||||||
@@ -52,7 +63,32 @@ public class GlobleExceptionHandler {
|
|||||||
// }
|
// }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 文件预览异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({PreviewException.class})
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus
|
||||||
|
public ResultBean previewException(PreviewException ex) {
|
||||||
|
return ResultBean.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化异常
|
||||||
|
*/
|
||||||
|
@ExceptionHandler({InitializeException.class})
|
||||||
|
@ResponseBody
|
||||||
|
@ResponseStatus
|
||||||
|
public ResultBean initializeException(InitializeException ex) {
|
||||||
|
return ResultBean.error(ex.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ExceptionHandler
|
@ExceptionHandler
|
||||||
|
@ResponseBody
|
||||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||||
public ResultBean searchDisableExceptionHandler(Exception e) {
|
public ResultBean searchDisableExceptionHandler(Exception e) {
|
||||||
if (log.isDebugEnabled()) {
|
if (log.isDebugEnabled()) {
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.exception;
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 对象存储初始化异常
|
* 对象存储初始化异常
|
||||||
@@ -0,0 +1,28 @@
|
|||||||
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
public class NotExistFileException extends RuntimeException {
|
||||||
|
|
||||||
|
public NotExistFileException() {
|
||||||
|
super();
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotExistFileException(String message) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotExistFileException(String message, Throwable cause) {
|
||||||
|
super(message, cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
public NotExistFileException(Throwable cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected NotExistFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||||
|
super(message, cause, enableSuppression, writableStackTrace);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.exception;
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.exception;
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 存储策略未初始化异常
|
* 存储策略未初始化异常
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.exception;
|
package im.zhaojun.zfile.exception;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 未知的存储类型异常
|
* 未知的存储类型异常
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.config;
|
package im.zhaojun.zfile.filter;
|
||||||
|
|
||||||
import org.springframework.http.HttpHeaders;
|
import org.springframework.http.HttpHeaders;
|
||||||
import org.springframework.web.cors.CorsUtils;
|
import org.springframework.web.cors.CorsUtils;
|
||||||
@@ -23,7 +23,6 @@ public class CorsFilter extends GenericFilterBean {
|
|||||||
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
HttpServletRequest httpServletRequest = (HttpServletRequest) request;
|
||||||
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
HttpServletResponse httpServletResponse = (HttpServletResponse) response;
|
||||||
|
|
||||||
// Set customized header
|
|
||||||
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, httpServletRequest.getHeader(HttpHeaders.ORIGIN));
|
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_HEADERS, "Origin, X-Requested-With, Content-Type, Accept");
|
||||||
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, OPTIONS");
|
httpServletResponse.setHeader(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, "GET, POST, PUT, DELETE, OPTIONS");
|
||||||
@@ -34,4 +33,5 @@ public class CorsFilter extends GenericFilterBean {
|
|||||||
chain.doFilter(httpServletRequest, httpServletResponse);
|
chain.doFilter(httpServletRequest, httpServletResponse);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.security;
|
package im.zhaojun.zfile.filter;
|
||||||
|
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.context.annotation.Configuration;
|
import org.springframework.context.annotation.Configuration;
|
||||||
@@ -1,12 +1,11 @@
|
|||||||
package im.zhaojun.common.model.constant;
|
package im.zhaojun.zfile.model.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
* @date 2019/12/28 18:47
|
|
||||||
*/
|
*/
|
||||||
public class StorageConfigConstant {
|
public class StorageConfigConstant {
|
||||||
|
|
||||||
public static final String BUCKET_NAME_KEY = "bucket-name";
|
public static final String BUCKET_NAME_KEY = "bucketName";
|
||||||
|
|
||||||
public static final String SECRET_ID_KEY = "secretId";
|
public static final String SECRET_ID_KEY = "secretId";
|
||||||
|
|
||||||
@@ -16,7 +15,7 @@ public class StorageConfigConstant {
|
|||||||
|
|
||||||
public static final String ENDPOINT_KEY = "endPoint";
|
public static final String ENDPOINT_KEY = "endPoint";
|
||||||
|
|
||||||
public static final String BASE_PATH = "base-path";
|
public static final String BASE_PATH = "basePath";
|
||||||
|
|
||||||
public static final String DOMAIN_KEY = "domain";
|
public static final String DOMAIN_KEY = "domain";
|
||||||
|
|
||||||
@@ -30,4 +29,12 @@ public class StorageConfigConstant {
|
|||||||
|
|
||||||
public static final String FILE_PATH_KEY = "filePath";
|
public static final String FILE_PATH_KEY = "filePath";
|
||||||
|
|
||||||
}
|
public static final String ACCESS_TOKEN_KEY = "accessToken";
|
||||||
|
|
||||||
|
public static final String REFRESH_TOKEN_KEY = "refreshToken";
|
||||||
|
|
||||||
|
public static final String PATH_STYLE = "pathStyle";
|
||||||
|
|
||||||
|
public static final String IS_PRIVATE = "isPrivate";
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.constant;
|
package im.zhaojun.zfile.model.constant;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
@@ -7,8 +7,6 @@ public class SystemConfigConstant {
|
|||||||
|
|
||||||
public static final String SITE_NAME = "siteName";
|
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_ENABLE = "searchEnable";
|
||||||
|
|
||||||
public static final String SEARCH_IGNORE_CASE = "searchIgnoreCase";
|
public static final String SEARCH_IGNORE_CASE = "searchIgnoreCase";
|
||||||
@@ -0,0 +1,63 @@
|
|||||||
|
package im.zhaojun.zfile.model.constant;
|
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
public class ZFileConstant {
|
||||||
|
|
||||||
|
public final static String USER_HOME = System.getProperty("user.home");
|
||||||
|
|
||||||
|
public static final String AUDIO_TMP_PATH = "/.zfile/tmp/audio/";
|
||||||
|
|
||||||
|
public static final Character PATH_SEPARATOR_CHAR = '/';
|
||||||
|
|
||||||
|
public static final String PATH_SEPARATOR = "/";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 页面文档文件
|
||||||
|
*/
|
||||||
|
public static String README_FILE_NAME = "readme.md";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 密码文件
|
||||||
|
*/
|
||||||
|
public static String PASSWORD_FILE_NAME = "password.txt";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大支持文件大小为 ? MB 的音乐文件解析封面, 歌手等信息.
|
||||||
|
*/
|
||||||
|
public static Long AUDIO_MAX_FILE_SIZE_MB = 1L;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 最大支持文本文件大小为 ? KB 的文件内容.
|
||||||
|
*/
|
||||||
|
public static Long TEXT_MAX_FILE_SIZE_KB = 100L;
|
||||||
|
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
public void setHeaderFileName(@Value("${zfile.constant.readme}") String headerFileName) {
|
||||||
|
ZFileConstant.README_FILE_NAME = headerFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
|
||||||
|
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
public void setAudioMaxFileSizeMb(@Value("${zfile.preview.audio.maxFileSizeMb}") Long maxFileSizeMb) {
|
||||||
|
ZFileConstant.AUDIO_MAX_FILE_SIZE_MB = maxFileSizeMb;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Autowired(required = false)
|
||||||
|
public void setTextMaxFileSizeMb(@Value("${zfile.preview.text.maxFileSizeKb}") Long maxFileSizeKb) {
|
||||||
|
ZFileConstant.TEXT_MAX_FILE_SIZE_KB = maxFileSizeKb;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
19
src/main/java/im/zhaojun/zfile/model/dto/CacheConfigDTO.java
Normal file
19
src/main/java/im/zhaojun/zfile/model/dto/CacheConfigDTO.java
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.Set;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class CacheConfigDTO {
|
||||||
|
private Boolean enableCache;
|
||||||
|
private Boolean cacheFinish;
|
||||||
|
private Set<String> cacheKeys;
|
||||||
|
private Integer cacheDirectoryCount;
|
||||||
|
private Integer cacheFileCount;
|
||||||
|
private Date lastCacheAutoRefreshDate;
|
||||||
|
}
|
||||||
33
src/main/java/im/zhaojun/zfile/model/dto/DriveConfigDTO.java
Normal file
33
src/main/java/im/zhaojun/zfile/model/dto/DriveConfigDTO.java
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnumJsonDeSerializerConvert;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class DriveConfigDTO {
|
||||||
|
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
@JsonDeserialize(using = StorageTypeEnumJsonDeSerializerConvert.class)
|
||||||
|
private StorageTypeEnum type;
|
||||||
|
|
||||||
|
private boolean enableCache;
|
||||||
|
|
||||||
|
private boolean autoRefreshCache;
|
||||||
|
|
||||||
|
private boolean searchEnable;
|
||||||
|
|
||||||
|
private boolean searchIgnoreCase;
|
||||||
|
|
||||||
|
private boolean searchContainEncryptedFile;
|
||||||
|
|
||||||
|
private StorageStrategyConfig storageStrategyConfig;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
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.io.Serializable;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
import java.io.Serializable;
|
import java.io.Serializable;
|
||||||
|
|
||||||
@@ -15,6 +15,8 @@ public class ResultBean implements Serializable {
|
|||||||
|
|
||||||
public static final int REQUIRED_PASSWORD = -2;
|
public static final int REQUIRED_PASSWORD = -2;
|
||||||
|
|
||||||
|
public static final int INVALID_PASSWORD = -3;
|
||||||
|
|
||||||
private String msg = "操作成功";
|
private String msg = "操作成功";
|
||||||
|
|
||||||
private int code = SUCCESS;
|
private int code = SUCCESS;
|
||||||
@@ -43,6 +45,10 @@ public class ResultBean implements Serializable {
|
|||||||
return success("操作成功", data);
|
return success("操作成功", data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static ResultBean successPage(Object data, Long total) {
|
||||||
|
return success("操作成功", data);
|
||||||
|
}
|
||||||
|
|
||||||
public static ResultBean success(Object data) {
|
public static ResultBean success(Object data) {
|
||||||
return success("操作成功", data);
|
return success("操作成功", data);
|
||||||
}
|
}
|
||||||
23
src/main/java/im/zhaojun/zfile/model/dto/SiteConfigDTO.java
Normal file
23
src/main/java/im/zhaojun/zfile/model/dto/SiteConfigDTO.java
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// package im.zhaojun.zfile.model.dto;
|
||||||
|
//
|
||||||
|
// import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
// import lombok.Data;
|
||||||
|
// import lombok.ToString;
|
||||||
|
//
|
||||||
|
// import java.io.Serializable;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @author zhaojun
|
||||||
|
// */
|
||||||
|
// @Data
|
||||||
|
// @ToString
|
||||||
|
// public class SiteConfigDTO implements Serializable {
|
||||||
|
//
|
||||||
|
// private static final long serialVersionUID = 8811196207046121740L;
|
||||||
|
//
|
||||||
|
// private String readme;
|
||||||
|
//
|
||||||
|
// @JsonProperty("viewConfig")
|
||||||
|
// private SystemConfigDTO systemConfigDTO;
|
||||||
|
//
|
||||||
|
// }
|
||||||
@@ -0,0 +1,43 @@
|
|||||||
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class StorageStrategyConfig {
|
||||||
|
|
||||||
|
private String endPoint;
|
||||||
|
|
||||||
|
private String pathStyle;
|
||||||
|
|
||||||
|
private Boolean isPrivate;
|
||||||
|
|
||||||
|
private String accessKey;
|
||||||
|
|
||||||
|
private String secretKey;
|
||||||
|
|
||||||
|
private String bucketName;
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private String port;
|
||||||
|
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
private String refreshToken;
|
||||||
|
|
||||||
|
private String secretId;
|
||||||
|
|
||||||
|
private String filePath;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
private String basePath;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.NoArgsConstructor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zhao Jun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
@NoArgsConstructor
|
||||||
|
public class StorageStrategyDTO {
|
||||||
|
|
||||||
|
private String key;
|
||||||
|
|
||||||
|
private String description;
|
||||||
|
|
||||||
|
@JsonProperty(defaultValue = "false")
|
||||||
|
private Boolean available;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,14 +1,15 @@
|
|||||||
package im.zhaojun.common.model.dto;
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
import com.fasterxml.jackson.annotation.JsonIgnore;
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnumSerializerConvert;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnumSerializerConvert;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
import lombok.ToString;
|
import lombok.ToString;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 系统设置传输类
|
* 系统设置传输类
|
||||||
|
*
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
@ToString
|
@ToString
|
||||||
@@ -20,21 +21,29 @@ public class SystemConfigDTO {
|
|||||||
|
|
||||||
private String siteName;
|
private String siteName;
|
||||||
|
|
||||||
private Boolean infoEnable;
|
private String username;
|
||||||
|
|
||||||
private Boolean searchEnable;
|
|
||||||
|
|
||||||
private Boolean searchIgnoreCase;
|
|
||||||
|
|
||||||
@JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
|
@JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
|
||||||
private StorageTypeEnum storageStrategy;
|
private StorageTypeEnum storageStrategy;
|
||||||
|
|
||||||
private String username;
|
|
||||||
|
|
||||||
@JsonIgnore
|
@JsonIgnore
|
||||||
private String password;
|
private String password;
|
||||||
|
|
||||||
private String domain;
|
private String domain;
|
||||||
|
|
||||||
private Boolean enableCache;
|
private String customJs;
|
||||||
|
|
||||||
|
private String customCss;
|
||||||
|
|
||||||
|
private String tableSize;
|
||||||
|
|
||||||
|
private Boolean showOperator;
|
||||||
|
|
||||||
|
private Boolean showDocument;
|
||||||
|
|
||||||
|
private String announcement;
|
||||||
|
|
||||||
|
private Boolean showAnnouncement;
|
||||||
|
|
||||||
|
private String layout;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,47 @@
|
|||||||
|
package im.zhaojun.zfile.model.dto;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||||
|
import lombok.Data;
|
||||||
|
import lombok.ToString;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统设置传输类
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@ToString
|
||||||
|
@Data
|
||||||
|
public class SystemFrontConfigDTO {
|
||||||
|
|
||||||
|
@JsonIgnore
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String siteName;
|
||||||
|
|
||||||
|
private Boolean searchEnable;
|
||||||
|
|
||||||
|
// @JsonSerialize(using = StorageTypeEnumSerializerConvert.class)
|
||||||
|
// private StorageTypeEnum storageStrategy;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
private String customJs;
|
||||||
|
|
||||||
|
private String customCss;
|
||||||
|
|
||||||
|
private String tableSize;
|
||||||
|
|
||||||
|
private Boolean showOperator;
|
||||||
|
|
||||||
|
private Boolean showDocument;
|
||||||
|
|
||||||
|
private String announcement;
|
||||||
|
|
||||||
|
private Boolean showAnnouncement;
|
||||||
|
|
||||||
|
private String layout;
|
||||||
|
|
||||||
|
private String readme;
|
||||||
|
|
||||||
|
}
|
||||||
38
src/main/java/im/zhaojun/zfile/model/entity/DriveConfig.java
Normal file
38
src/main/java/im/zhaojun/zfile/model/entity/DriveConfig.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package im.zhaojun.zfile.model.entity;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import javax.persistence.Entity;
|
||||||
|
import javax.persistence.GeneratedValue;
|
||||||
|
import javax.persistence.GenerationType;
|
||||||
|
import javax.persistence.Id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动器
|
||||||
|
*
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Entity(name = "DRIVER_CONFIG")
|
||||||
|
@Data
|
||||||
|
public class DriveConfig {
|
||||||
|
|
||||||
|
@Id
|
||||||
|
@GeneratedValue(strategy = GenerationType.IDENTITY)
|
||||||
|
private Integer id;
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
private Boolean enableCache;
|
||||||
|
|
||||||
|
private Boolean autoRefreshCache;
|
||||||
|
|
||||||
|
private StorageTypeEnum type;
|
||||||
|
|
||||||
|
private Boolean searchEnable;
|
||||||
|
|
||||||
|
private Boolean searchIgnoreCase;
|
||||||
|
|
||||||
|
private Boolean searchContainEncryptedFile;
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package im.zhaojun.common.model;
|
package im.zhaojun.zfile.model.entity;
|
||||||
|
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
@@ -27,8 +27,16 @@ public class StorageConfig {
|
|||||||
|
|
||||||
private String title;
|
private String title;
|
||||||
|
|
||||||
|
@Column(length = 4000)
|
||||||
private String value;
|
private String value;
|
||||||
|
|
||||||
|
private Integer driveId;
|
||||||
|
|
||||||
|
public StorageConfig(String key, String title) {
|
||||||
|
this.key = key;
|
||||||
|
this.title = title;
|
||||||
|
}
|
||||||
|
|
||||||
public Integer getId() {
|
public Integer getId() {
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model;
|
package im.zhaojun.zfile.model.entity;
|
||||||
|
|
||||||
import lombok.Data;
|
import lombok.Data;
|
||||||
|
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.enums;
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
package im.zhaojun.common.model.enums;
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@@ -6,19 +8,24 @@ import java.util.Map;
|
|||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
|
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||||
public enum StorageTypeEnum {
|
public enum StorageTypeEnum {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 当前系统支持的所有存储策略
|
* 当前系统支持的所有存储策略
|
||||||
*/
|
*/
|
||||||
UPYUN("upyun", "又拍云 USS"),
|
|
||||||
QINIU("qiniu", "七牛云 KODO"),
|
|
||||||
HUAWEI("huawei", "华为云 OBS"),
|
|
||||||
ALIYUN("aliyun", "阿里云 OSS"),
|
|
||||||
FTP("ftp", "FTP"),
|
|
||||||
LOCAL("local", "本地存储"),
|
LOCAL("local", "本地存储"),
|
||||||
|
ALIYUN("aliyun", "阿里云 OSS"),
|
||||||
TENCENT("tencent", "腾讯云 COS"),
|
TENCENT("tencent", "腾讯云 COS"),
|
||||||
MINIO("minio", "MINIO");
|
UPYUN("upyun", "又拍云 USS"),
|
||||||
|
FTP("ftp", "FTP"),
|
||||||
|
UFILE("ufile", "UFile"),
|
||||||
|
HUAWEI("huawei", "华为云 OBS"),
|
||||||
|
MINIO("minio", "MINIO"),
|
||||||
|
S3("s3", "S3通用协议"),
|
||||||
|
ONE_DRIVE("onedrive", "OneDrive"),
|
||||||
|
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
|
||||||
|
QINIU("qiniu", "七牛云 KODO");
|
||||||
|
|
||||||
private String key;
|
private String key;
|
||||||
private String description;
|
private String description;
|
||||||
@@ -53,7 +60,7 @@ public enum StorageTypeEnum {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public static StorageTypeEnum getEnum(String value) {
|
public static StorageTypeEnum getEnum(String value) {
|
||||||
return enumMap.get(value);
|
return enumMap.get(value.toLowerCase());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.enums;
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
import javax.persistence.AttributeConverter;
|
import javax.persistence.AttributeConverter;
|
||||||
import javax.persistence.Converter;
|
import javax.persistence.Converter;
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.enums;
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
import org.springframework.core.convert.converter.Converter;
|
import org.springframework.core.convert.converter.Converter;
|
||||||
import org.springframework.lang.NonNull;
|
import org.springframework.lang.NonNull;
|
||||||
@@ -12,4 +12,5 @@ public class StorageTypeEnumDeSerializerConvert implements Converter<String, Sto
|
|||||||
public StorageTypeEnum convert(@NonNull String s) {
|
public StorageTypeEnum convert(@NonNull String s) {
|
||||||
return StorageTypeEnum.getEnum(s);
|
return StorageTypeEnum.getEnum(s);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,18 @@
|
|||||||
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
|
import com.fasterxml.jackson.core.JsonParser;
|
||||||
|
import com.fasterxml.jackson.databind.DeserializationContext;
|
||||||
|
import com.fasterxml.jackson.databind.JsonDeserializer;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
public class StorageTypeEnumJsonDeSerializerConvert extends JsonDeserializer<StorageTypeEnum> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageTypeEnum deserialize(JsonParser jsonParser, DeserializationContext deserializationContext) throws IOException {
|
||||||
|
return StorageTypeEnum.getEnum(jsonParser.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.model.enums;
|
package im.zhaojun.zfile.model.enums;
|
||||||
|
|
||||||
import com.fasterxml.jackson.core.JsonGenerator;
|
import com.fasterxml.jackson.core.JsonGenerator;
|
||||||
import com.fasterxml.jackson.databind.JsonSerializer;
|
import com.fasterxml.jackson.databind.JsonSerializer;
|
||||||
@@ -0,0 +1,20 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import lombok.AllArgsConstructor;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
@AllArgsConstructor
|
||||||
|
public class FilePageModel {
|
||||||
|
|
||||||
|
private int totalPage;
|
||||||
|
|
||||||
|
private List<FileItemDTO> fileList;
|
||||||
|
|
||||||
|
}
|
||||||
39
src/main/java/im/zhaojun/zfile/model/support/Jvm.java
Normal file
39
src/main/java/im/zhaojun/zfile/model/support/Jvm.java
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Jvm {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 当前 JVM 占用的内存总数 (M)
|
||||||
|
*/
|
||||||
|
private double total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM 最大可用内存总数 (M)
|
||||||
|
*/
|
||||||
|
private double max;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM 空闲内存 (M)
|
||||||
|
*/
|
||||||
|
private double free;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JDK 版本
|
||||||
|
*/
|
||||||
|
private String version;
|
||||||
|
|
||||||
|
public Jvm() {
|
||||||
|
Runtime runtime = Runtime.getRuntime();
|
||||||
|
this.total = runtime.totalMemory();
|
||||||
|
this.free = runtime.freeMemory();
|
||||||
|
this.max = runtime.maxMemory();
|
||||||
|
this.version = System.getProperty("java.version");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
41
src/main/java/im/zhaojun/zfile/model/support/Mem.java
Normal file
41
src/main/java/im/zhaojun/zfile/model/support/Mem.java
Normal file
@@ -0,0 +1,41 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import com.sun.management.OperatingSystemMXBean;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Mem {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 内存总量
|
||||||
|
*/
|
||||||
|
private double total;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 已用内存
|
||||||
|
*/
|
||||||
|
private double used;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 剩余内存
|
||||||
|
*/
|
||||||
|
private double free;
|
||||||
|
|
||||||
|
public Mem() {
|
||||||
|
OperatingSystemMXBean osb = (OperatingSystemMXBean) ManagementFactory.getOperatingSystemMXBean();
|
||||||
|
// 总的物理内存+虚拟内存
|
||||||
|
long totalVirtualMemory = osb.getTotalSwapSpaceSize();
|
||||||
|
// 剩余的物理内存
|
||||||
|
long freePhysicalMemorySize = osb.getFreePhysicalMemorySize();
|
||||||
|
this.total = totalVirtualMemory;
|
||||||
|
this.free = freePhysicalMemorySize;
|
||||||
|
this.used = totalVirtualMemory - freePhysicalMemorySize;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import com.alibaba.fastjson.annotation.JSONField;
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class OneDriveToken {
|
||||||
|
|
||||||
|
@JSONField(name = "access_token")
|
||||||
|
private String accessToken;
|
||||||
|
|
||||||
|
@JSONField(name = "refresh_token")
|
||||||
|
private String refreshToken;
|
||||||
|
}
|
||||||
58
src/main/java/im/zhaojun/zfile/model/support/Sys.java
Normal file
58
src/main/java/im/zhaojun/zfile/model/support/Sys.java
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import cn.hutool.core.date.BetweenFormater;
|
||||||
|
import cn.hutool.core.date.DateUtil;
|
||||||
|
import lombok.Data;
|
||||||
|
import org.springframework.core.io.ClassPathResource;
|
||||||
|
import org.springframework.core.io.Resource;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.lang.management.ManagementFactory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class Sys {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目路径
|
||||||
|
*/
|
||||||
|
private String projectDir;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 操作系统
|
||||||
|
*/
|
||||||
|
private String osName;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统架构
|
||||||
|
*/
|
||||||
|
private String osArch;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统版本
|
||||||
|
*/
|
||||||
|
private String osVersion;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 启动时间
|
||||||
|
*/
|
||||||
|
private String upTime;
|
||||||
|
|
||||||
|
public Sys() {
|
||||||
|
this.osName = System.getProperty("os.name");
|
||||||
|
this.osArch = System.getProperty("os.arch");
|
||||||
|
this.osVersion = System.getProperty("os.version");
|
||||||
|
Resource resource = new ClassPathResource("");
|
||||||
|
try {
|
||||||
|
this.projectDir = resource.getFile().getAbsolutePath();
|
||||||
|
} catch (IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
|
||||||
|
long uptime = ManagementFactory.getRuntimeMXBean().getUptime();
|
||||||
|
this.upTime = DateUtil.formatBetween(uptime, BetweenFormater.Level.SECOND);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package im.zhaojun.zfile.model.support;
|
||||||
|
|
||||||
|
import lombok.Data;
|
||||||
|
|
||||||
|
import java.io.Serializable;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Data
|
||||||
|
public class SystemMonitorInfo implements Serializable {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 服务器基本信息
|
||||||
|
*/
|
||||||
|
private Sys sys;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* JVM 信息
|
||||||
|
*/
|
||||||
|
private Jvm jvm;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 系统内存
|
||||||
|
*/
|
||||||
|
private Mem mem;
|
||||||
|
|
||||||
|
public SystemMonitorInfo() {
|
||||||
|
this.jvm = new Jvm();
|
||||||
|
this.sys = new Sys();
|
||||||
|
this.mem = new Mem();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,26 @@
|
|||||||
|
package im.zhaojun.zfile.repository;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface DriverConfigRepository extends JpaRepository<DriveConfig, Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据存储策略类型获取所有驱动器
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* 存储类型
|
||||||
|
*
|
||||||
|
* @return 指定存储类型的存储器
|
||||||
|
*/
|
||||||
|
List<DriveConfig> findByType(StorageTypeEnum type);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,71 @@
|
|||||||
|
package im.zhaojun.zfile.repository;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Repository
|
||||||
|
public interface StorageConfigRepository extends JpaRepository<StorageConfig, Integer> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据存储类型找对应的配置信息
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* 存储类型
|
||||||
|
*
|
||||||
|
* @return 此类型所有的配置信息
|
||||||
|
*/
|
||||||
|
List<StorageConfig> findByTypeOrderById(StorageTypeEnum type);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据存储类型找对应的配置信息
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 此驱动器所有的配置信息
|
||||||
|
*/
|
||||||
|
List<StorageConfig> findByDriveIdOrderById(Integer driveId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据驱动器找到对应的配置信息
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 此驱动器所有的配置信息
|
||||||
|
*/
|
||||||
|
List<StorageConfig> findByDriveId(Integer driveId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定驱动器对应的配置信息
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
void deleteByDriveId(Integer driveId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 查找某个驱动器的某个 KEY 的值
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* KEY 值
|
||||||
|
*
|
||||||
|
* @return KEY 对应的对象
|
||||||
|
*/
|
||||||
|
StorageConfig findByDriveIdAndKey(Integer driveId, String key);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,6 +1,6 @@
|
|||||||
package im.zhaojun.common.repository;
|
package im.zhaojun.zfile.repository;
|
||||||
|
|
||||||
import im.zhaojun.common.model.SystemConfig;
|
import im.zhaojun.zfile.model.entity.SystemConfig;
|
||||||
import org.springframework.data.jpa.repository.JpaRepository;
|
import org.springframework.data.jpa.repository.JpaRepository;
|
||||||
import org.springframework.stereotype.Repository;
|
import org.springframework.stereotype.Repository;
|
||||||
|
|
||||||
@@ -12,8 +12,12 @@ public interface SystemConfigRepository extends JpaRepository<SystemConfig, Inte
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 查找系统设置中, 某个设置项对应的值
|
* 查找系统设置中, 某个设置项对应的值
|
||||||
* @param key 设置项
|
*
|
||||||
* @return 设置值
|
* @param key
|
||||||
|
* 设置项
|
||||||
|
*
|
||||||
|
* @return 设置值
|
||||||
*/
|
*/
|
||||||
SystemConfig findByKey(String key);
|
SystemConfig findByKey(String key);
|
||||||
}
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,72 @@
|
|||||||
|
package im.zhaojun.zfile.schedule;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.DriveConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractOneDriveServiceBase;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveChinaServiceImpl;
|
||||||
|
import im.zhaojun.zfile.service.impl.OneDriveServiceImpl;
|
||||||
|
import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Configuration;
|
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||||
|
import org.springframework.scheduling.annotation.Scheduled;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 计划任务工具类
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Configuration
|
||||||
|
@EnableScheduling
|
||||||
|
@Slf4j
|
||||||
|
public class GlobalScheduleTask {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveServiceImpl oneDriveServiceImpl;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveContext driveContext;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 项目启动 30 秒后, 每 15 分钟执行一次刷新 OneDrive Token 的定时任务.
|
||||||
|
*/
|
||||||
|
@Scheduled(fixedRate = 1000 * 60 * 10, initialDelay = 1000 * 30)
|
||||||
|
public void autoRefreshOneDriveToken() {
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.debug("尝试调用 OneDrive 自动刷新 AccessToken 定时任务");
|
||||||
|
|
||||||
|
List<DriveConfig> driveConfigList = driveConfigService.findByType(StorageTypeEnum.ONE_DRIVE);
|
||||||
|
driveConfigList.addAll(driveConfigService.findByType(StorageTypeEnum.ONE_DRIVE_CHINA));
|
||||||
|
|
||||||
|
driveConfigList.forEach(driveConfig -> {
|
||||||
|
StorageTypeEnum storageType = driveConfig.getType();
|
||||||
|
String name = driveConfig.getName();
|
||||||
|
|
||||||
|
try {
|
||||||
|
AbstractOneDriveServiceBase driveService = (AbstractOneDriveServiceBase) driveContext.getDriveService(driveConfig.getId());
|
||||||
|
driveService.refreshOneDriveToken();
|
||||||
|
log.info("刷新驱动器 {}, {} key 时间: {}", name, storageType.getDescription(), LocalDateTime.now());
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("刷新驱动器 " + name + " Token 失败.", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
});
|
||||||
|
|
||||||
|
} catch (Throwable e) {
|
||||||
|
log.debug("尝试调用 OneDrive 自动刷新 AccessToken 定时任务出现未知异常", e);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
package im.zhaojun.common.security;
|
package im.zhaojun.zfile.security;
|
||||||
|
|
||||||
import cn.hutool.crypto.SecureUtil;
|
import cn.hutool.crypto.SecureUtil;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package im.zhaojun.common.security;
|
package im.zhaojun.zfile.security;
|
||||||
|
|
||||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
import im.zhaojun.common.model.dto.ResultBean;
|
import im.zhaojun.zfile.model.dto.ResultBean;
|
||||||
import org.springframework.context.annotation.Bean;
|
import org.springframework.context.annotation.Bean;
|
||||||
import org.springframework.http.HttpMethod;
|
import org.springframework.http.HttpMethod;
|
||||||
import org.springframework.security.authentication.BadCredentialsException;
|
import org.springframework.security.authentication.BadCredentialsException;
|
||||||
@@ -12,6 +12,8 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
|||||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||||
|
import org.springframework.security.web.firewall.HttpFirewall;
|
||||||
|
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
@@ -19,6 +21,7 @@ import java.io.PrintWriter;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* 自定义 Security 配置类
|
* 自定义 Security 配置类
|
||||||
|
*
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
@EnableWebSecurity
|
@EnableWebSecurity
|
||||||
@@ -32,7 +35,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
http
|
http
|
||||||
// .authenticationProvider(authenticationProvider())
|
// .authenticationProvider(authenticationProvider())
|
||||||
.exceptionHandling()
|
.exceptionHandling()
|
||||||
//未登录时,进行json格式的提示,很喜欢这种写法,不用单独写一个又一个的类
|
// 未登录时,进行 json 格式的提示.
|
||||||
.authenticationEntryPoint((request, response, authException) -> {
|
.authenticationEntryPoint((request, response, authException) -> {
|
||||||
response.setContentType("application/json;charset=utf-8");
|
response.setContentType("application/json;charset=utf-8");
|
||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
|
||||||
@@ -46,8 +49,8 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
.antMatchers("/").permitAll()
|
.antMatchers("/").permitAll()
|
||||||
.antMatchers("/admin/**").authenticated()
|
.antMatchers("/admin/**").authenticated()
|
||||||
.and()
|
.and()
|
||||||
.formLogin() //使用自带的登录
|
.formLogin() // 使用自带的登录
|
||||||
//登录失败,返回json
|
// 登录失败,返回json
|
||||||
.failureHandler((request, response, ex) -> {
|
.failureHandler((request, response, ex) -> {
|
||||||
response.setContentType("application/json;charset=utf-8");
|
response.setContentType("application/json;charset=utf-8");
|
||||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||||
@@ -62,7 +65,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
out.flush();
|
out.flush();
|
||||||
out.close();
|
out.close();
|
||||||
})
|
})
|
||||||
//登录成功,返回json
|
// 登录成功,返回json
|
||||||
.successHandler((request, response, authentication) -> {
|
.successHandler((request, response, authentication) -> {
|
||||||
response.setContentType("application/json;charset=utf-8");
|
response.setContentType("application/json;charset=utf-8");
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
@@ -72,7 +75,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
})
|
})
|
||||||
.and()
|
.and()
|
||||||
.exceptionHandling()
|
.exceptionHandling()
|
||||||
//没有权限,返回json
|
// 没有权限,返回json
|
||||||
.accessDeniedHandler((request, response, ex) -> {
|
.accessDeniedHandler((request, response, ex) -> {
|
||||||
response.setContentType("application/json;charset=utf-8");
|
response.setContentType("application/json;charset=utf-8");
|
||||||
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
response.setStatus(HttpServletResponse.SC_FORBIDDEN);
|
||||||
@@ -83,7 +86,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
})
|
})
|
||||||
.and()
|
.and()
|
||||||
.logout()
|
.logout()
|
||||||
//退出成功,返回json
|
// 退出成功,返回 json
|
||||||
.logoutSuccessHandler((request, response, authentication) -> {
|
.logoutSuccessHandler((request, response, authentication) -> {
|
||||||
response.setContentType("application/json;charset=utf-8");
|
response.setContentType("application/json;charset=utf-8");
|
||||||
PrintWriter out = response.getWriter();
|
PrintWriter out = response.getWriter();
|
||||||
@@ -96,6 +99,14 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
http.cors();
|
http.cors();
|
||||||
http.csrf().disable();
|
http.csrf().disable();
|
||||||
|
http.headers().frameOptions().sameOrigin();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Bean
|
||||||
|
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
|
||||||
|
StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||||
|
firewall.setAllowUrlEncodedPercent(true);
|
||||||
|
return firewall;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -110,8 +121,9 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void configure(WebSecurity web) {
|
public void configure(WebSecurity web) {
|
||||||
//对于在header里面增加token等类似情况,放行所有OPTIONS请求。
|
// 对于在 header 里面增加 token 等类似情况,放行所有 OPTIONS 请求。
|
||||||
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
||||||
|
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Bean
|
@Bean
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
package im.zhaojun.common.security;
|
package im.zhaojun.zfile.security;
|
||||||
|
|
||||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||||
import im.zhaojun.common.service.SystemConfigService;
|
import im.zhaojun.zfile.service.SystemConfigService;
|
||||||
import org.springframework.security.core.userdetails.User;
|
import org.springframework.security.core.userdetails.User;
|
||||||
import org.springframework.security.core.userdetails.UserDetails;
|
import org.springframework.security.core.userdetails.UserDetails;
|
||||||
import org.springframework.security.core.userdetails.UserDetailsService;
|
import org.springframework.security.core.userdetails.UserDetailsService;
|
||||||
@@ -9,6 +9,7 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
@@ -24,6 +25,10 @@ public class MyUserDetailsServiceImpl implements UserDetailsService {
|
|||||||
@Override
|
@Override
|
||||||
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
|
||||||
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
|
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
|
||||||
|
if (!Objects.equals(systemConfig.getUsername(), username)) {
|
||||||
|
throw new UsernameNotFoundException("用户名不存在");
|
||||||
|
}
|
||||||
return new User(systemConfig.getUsername(), systemConfig.getPassword(), Collections.emptyList());
|
return new User(systemConfig.getUsername(), systemConfig.getPassword(), Collections.emptyList());
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
224
src/main/java/im/zhaojun/zfile/service/DriveConfigService.java
Normal file
224
src/main/java/im/zhaojun/zfile/service/DriveConfigService.java
Normal file
@@ -0,0 +1,224 @@
|
|||||||
|
package im.zhaojun.zfile.service;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.context.StorageTypeContext;
|
||||||
|
import im.zhaojun.zfile.exception.InitializeException;
|
||||||
|
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.DriveConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.StorageStrategyConfig;
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.repository.DriverConfigRepository;
|
||||||
|
import im.zhaojun.zfile.repository.StorageConfigRepository;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
import org.springframework.transaction.annotation.Transactional;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 驱动器 Service 类
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class DriveConfigService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriverConfigRepository driverConfigRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigRepository storageConfigRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveContext driveContext;
|
||||||
|
|
||||||
|
public static final Class<StorageStrategyConfig> STORAGE_STRATEGY_CONFIG_CLASS = StorageStrategyConfig.class;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取所有驱动器列表
|
||||||
|
*
|
||||||
|
* @return 驱动器列表
|
||||||
|
*/
|
||||||
|
public List<DriveConfig> list() {
|
||||||
|
return driverConfigRepository.findAll();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器设置
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器设置
|
||||||
|
*/
|
||||||
|
public DriveConfig findById(Integer id) {
|
||||||
|
return driverConfigRepository.getOne(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器 DTO 对象, 此对象包含详细的参数设置.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器 DTO
|
||||||
|
*/
|
||||||
|
public DriveConfigDTO findDriveConfigDTOById(Integer id) {
|
||||||
|
DriveConfig driveConfig = driverConfigRepository.getOne(id);
|
||||||
|
|
||||||
|
DriveConfigDTO driveConfigDTO = new DriveConfigDTO();
|
||||||
|
|
||||||
|
List<StorageConfig> storageConfigList = storageConfigRepository.findByDriveId(driveConfig.getId());
|
||||||
|
BeanUtils.copyProperties(driveConfig, driveConfigDTO);
|
||||||
|
|
||||||
|
StorageStrategyConfig storageStrategyConfig = new StorageStrategyConfig();
|
||||||
|
for (StorageConfig storageConfig : storageConfigList) {
|
||||||
|
String key = storageConfig.getKey();
|
||||||
|
String value = storageConfig.getValue();
|
||||||
|
|
||||||
|
Field declaredField;
|
||||||
|
try {
|
||||||
|
declaredField = STORAGE_STRATEGY_CONFIG_CLASS.getDeclaredField(key);
|
||||||
|
declaredField.setAccessible(true);
|
||||||
|
if (Objects.equals(StorageConfigConstant.IS_PRIVATE, key)) {
|
||||||
|
declaredField.set(storageStrategyConfig, Boolean.valueOf(value));
|
||||||
|
} else {
|
||||||
|
declaredField.set(storageStrategyConfig, value);
|
||||||
|
}
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("通过反射, 将字段 {" + key + "}注入 DriveConfigDTO 时出现异常:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
driveConfigDTO.setStorageStrategyConfig(storageStrategyConfig);
|
||||||
|
return driveConfigDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取指定驱动器的存储策略.
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 驱动器对应的存储策略.
|
||||||
|
*/
|
||||||
|
public StorageTypeEnum findStorageTypeById(Integer id) {
|
||||||
|
// return findById(id).getType();
|
||||||
|
return driverConfigRepository.findById(id).get().getType();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存驱动器基本信息及其对应的参数设置
|
||||||
|
*
|
||||||
|
* @param driveConfigDTO 驱动器 DTO 对象
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void save(DriveConfigDTO driveConfigDTO) {
|
||||||
|
|
||||||
|
// 判断是新增还是修改
|
||||||
|
boolean updateFlag = driveConfigDTO.getId() != null;
|
||||||
|
|
||||||
|
// 保存基本信息
|
||||||
|
DriveConfig driveConfig = new DriveConfig();
|
||||||
|
StorageTypeEnum storageType = driveConfigDTO.getType();
|
||||||
|
BeanUtils.copyProperties(driveConfigDTO, driveConfig);
|
||||||
|
driverConfigRepository.save(driveConfig);
|
||||||
|
|
||||||
|
// 保存存储策略设置.
|
||||||
|
StorageStrategyConfig storageStrategyConfig = driveConfigDTO.getStorageStrategyConfig();
|
||||||
|
|
||||||
|
AbstractBaseFileService storageTypeService = StorageTypeContext.getStorageTypeService(storageType);
|
||||||
|
|
||||||
|
List<StorageConfig> storageConfigList;
|
||||||
|
if (updateFlag) {
|
||||||
|
storageConfigList = storageConfigRepository.findByDriveId(driveConfigDTO.getId());
|
||||||
|
} else {
|
||||||
|
storageConfigList = storageTypeService.storageStrategyConfigList();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (StorageConfig storageConfig : storageConfigList) {
|
||||||
|
String key = storageConfig.getKey();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field field = STORAGE_STRATEGY_CONFIG_CLASS.getDeclaredField(key);
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object o = field.get(storageStrategyConfig);
|
||||||
|
String value = o == null ? null : o.toString();
|
||||||
|
storageConfig.setValue(value);
|
||||||
|
storageConfig.setType(storageType);
|
||||||
|
storageConfig.setDriveId(driveConfig.getId());
|
||||||
|
} catch (IllegalAccessException | NoSuchFieldException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("通过反射, 从 StorageStrategyConfig 中获取字段 {" + key + "} 时出现异常:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
storageConfigRepository.saveAll(storageConfigList);
|
||||||
|
|
||||||
|
driveContext.initDrive(driveConfig.getId());
|
||||||
|
|
||||||
|
AbstractBaseFileService driveService = driveContext.getDriveService(driveConfig.getId());
|
||||||
|
if (driveService.getIsUnInitialized()) {
|
||||||
|
throw new InitializeException("初始化异常, 请检查配置是否正确.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 删除指定驱动器设置, 会级联删除其参数设置
|
||||||
|
*
|
||||||
|
* @param id
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
@Transactional(rollbackFor = Exception.class)
|
||||||
|
public void deleteById(Integer id) {
|
||||||
|
driverConfigRepository.deleteById(id);
|
||||||
|
storageConfigRepository.deleteByDriveId(id);
|
||||||
|
driveContext.destroyDrive(id);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据存储策略类型获取所有驱动器
|
||||||
|
*
|
||||||
|
* @param type
|
||||||
|
* 存储类型
|
||||||
|
*
|
||||||
|
* @return 指定存储类型的存储器
|
||||||
|
*/
|
||||||
|
public List<DriveConfig> findByType(StorageTypeEnum type) {
|
||||||
|
return driverConfigRepository.findByType(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新指定驱动器的缓存启用状态
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @param cacheEnable
|
||||||
|
* 是否启用缓存
|
||||||
|
*/
|
||||||
|
public void updateCacheStatus(Integer driveId, Boolean cacheEnable) {
|
||||||
|
DriveConfig driveConfig = findById(driveId);
|
||||||
|
if (driveConfig != null) {
|
||||||
|
driveConfig.setEnableCache(cacheEnable);
|
||||||
|
driverConfigRepository.save(driveConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,8 @@
|
|||||||
package im.zhaojun.common.service;
|
package im.zhaojun.zfile.service;
|
||||||
|
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
import im.zhaojun.common.repository.StorageConfigRepository;
|
import im.zhaojun.zfile.repository.StorageConfigRepository;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
@@ -19,10 +19,22 @@ public class StorageConfigService {
|
|||||||
@Resource
|
@Resource
|
||||||
private StorageConfigRepository storageConfigRepository;
|
private StorageConfigRepository storageConfigRepository;
|
||||||
|
|
||||||
|
|
||||||
public List<StorageConfig> selectStorageConfigByType(StorageTypeEnum storageTypeEnum) {
|
public List<StorageConfig> selectStorageConfigByType(StorageTypeEnum storageTypeEnum) {
|
||||||
return storageConfigRepository.findByTypeOrderById(storageTypeEnum);
|
return storageConfigRepository.findByTypeOrderById(storageTypeEnum);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public List<StorageConfig> selectStorageConfigByDriveId(Integer driveId) {
|
||||||
|
return storageConfigRepository.findByDriveIdOrderById(driveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public StorageConfig findByDriveIdAndKey(Integer driveId, String key) {
|
||||||
|
return storageConfigRepository.findByDriveIdAndKey(driveId, key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public Map<String, StorageConfig> selectStorageConfigMapByKey(StorageTypeEnum storageTypeEnum) {
|
public Map<String, StorageConfig> selectStorageConfigMapByKey(StorageTypeEnum storageTypeEnum) {
|
||||||
Map<String, StorageConfig> map = new HashMap<>(24);
|
Map<String, StorageConfig> map = new HashMap<>(24);
|
||||||
for (StorageConfig storageConfig : selectStorageConfigByType(storageTypeEnum)) {
|
for (StorageConfig storageConfig : selectStorageConfigByType(storageTypeEnum)) {
|
||||||
@@ -31,8 +43,18 @@ public class StorageConfigService {
|
|||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public Map<String, StorageConfig> selectStorageConfigMapByDriveId(Integer driveId) {
|
||||||
|
Map<String, StorageConfig> map = new HashMap<>(24);
|
||||||
|
for (StorageConfig storageConfig : selectStorageConfigByDriveId(driveId)) {
|
||||||
|
map.put(storageConfig.getKey(), storageConfig);
|
||||||
|
}
|
||||||
|
return map;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public void updateStorageConfig(List<StorageConfig> storageConfigList) {
|
public void updateStorageConfig(List<StorageConfig> storageConfigList) {
|
||||||
storageConfigRepository.saveAll(storageConfigList);
|
storageConfigRepository.saveAll(storageConfigList);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
166
src/main/java/im/zhaojun/zfile/service/SystemConfigService.java
Normal file
166
src/main/java/im/zhaojun/zfile/service/SystemConfigService.java
Normal file
@@ -0,0 +1,166 @@
|
|||||||
|
package im.zhaojun.zfile.service;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
|
import cn.hutool.crypto.SecureUtil;
|
||||||
|
import im.zhaojun.zfile.cache.ZFileCache;
|
||||||
|
import im.zhaojun.zfile.model.constant.SystemConfigConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.dto.SystemFrontConfigDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.DriveConfig;
|
||||||
|
import im.zhaojun.zfile.model.entity.SystemConfig;
|
||||||
|
import im.zhaojun.zfile.repository.SystemConfigRepository;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.beans.BeanUtils;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@Service
|
||||||
|
public class SystemConfigService {
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ZFileCache zFileCache;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemConfigRepository systemConfigRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private DriveConfigService driveConfigService;
|
||||||
|
|
||||||
|
private Class<SystemConfigDTO> systemConfigClazz = SystemConfigDTO.class;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取系统设置, 如果缓存中有, 则去缓存取, 没有则查询数据库并写入到缓存中.
|
||||||
|
*
|
||||||
|
* @return 系统设置
|
||||||
|
*/
|
||||||
|
public SystemConfigDTO getSystemConfig() {
|
||||||
|
SystemConfigDTO cacheConfig = zFileCache.getConfig();
|
||||||
|
if (cacheConfig != null) {
|
||||||
|
return cacheConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
|
||||||
|
List<SystemConfig> systemConfigList = systemConfigRepository.findAll();
|
||||||
|
|
||||||
|
for (SystemConfig systemConfig : systemConfigList) {
|
||||||
|
String key = systemConfig.getKey();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Field field = systemConfigClazz.getDeclaredField(key);
|
||||||
|
field.setAccessible(true);
|
||||||
|
String strVal = systemConfig.getValue();
|
||||||
|
Object convertVal = Convert.convert(field.getType(), strVal);
|
||||||
|
field.set(systemConfigDTO, convertVal);
|
||||||
|
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("通过反射, 将字段 {" + key + "}注入 SystemConfigDTO 时出现异常:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zFileCache.updateConfig(systemConfigDTO);
|
||||||
|
return systemConfigDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新系统设置, 并清空缓存中的内容.
|
||||||
|
*
|
||||||
|
* @param systemConfigDTO
|
||||||
|
* 系统
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) {
|
||||||
|
List<SystemConfig> systemConfigList = new ArrayList<>();
|
||||||
|
|
||||||
|
Field[] fields = systemConfigClazz.getDeclaredFields();
|
||||||
|
for (Field field : fields) {
|
||||||
|
String key = field.getName();
|
||||||
|
SystemConfig systemConfig = systemConfigRepository.findByKey(key);
|
||||||
|
if (systemConfig != null) {
|
||||||
|
field.setAccessible(true);
|
||||||
|
Object val = null;
|
||||||
|
|
||||||
|
try {
|
||||||
|
val = field.get(systemConfigDTO);
|
||||||
|
} catch (IllegalAccessException e) {
|
||||||
|
if (log.isDebugEnabled()) {
|
||||||
|
log.debug("通过反射, 从 SystemConfigDTO 获取字段 {" + key + "} 时出现异常:", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (val != null) {
|
||||||
|
systemConfig.setValue(val.toString());
|
||||||
|
systemConfigList.add(systemConfig);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zFileCache.removeConfig();
|
||||||
|
systemConfigRepository.saveAll(systemConfigList);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据驱动器 ID, 获取对于前台页面的系统设置.
|
||||||
|
*
|
||||||
|
* @param driveId
|
||||||
|
* 驱动器 ID
|
||||||
|
*
|
||||||
|
* @return 前台系统设置
|
||||||
|
*/
|
||||||
|
public SystemFrontConfigDTO getSystemFrontConfig(Integer driveId) {
|
||||||
|
SystemConfigDTO systemConfig = getSystemConfig();
|
||||||
|
SystemFrontConfigDTO systemFrontConfigDTO = new SystemFrontConfigDTO();
|
||||||
|
BeanUtils.copyProperties(systemConfig, systemFrontConfigDTO);
|
||||||
|
|
||||||
|
DriveConfig driveConfig = driveConfigService.findById(driveId);
|
||||||
|
systemFrontConfigDTO.setSearchEnable(driveConfig.getSearchEnable());
|
||||||
|
return systemFrontConfigDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新后台账号密码
|
||||||
|
*
|
||||||
|
* @param username
|
||||||
|
* 用户名
|
||||||
|
*
|
||||||
|
* @param password
|
||||||
|
* 密码
|
||||||
|
*/
|
||||||
|
public void updateUsernameAndPwd(String username, String password) {
|
||||||
|
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
|
||||||
|
usernameConfig.setValue(username);
|
||||||
|
systemConfigRepository.save(usernameConfig);
|
||||||
|
|
||||||
|
String encryptionPassword = SecureUtil.md5(password);
|
||||||
|
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
|
||||||
|
systemConfig.setValue(encryptionPassword);
|
||||||
|
|
||||||
|
zFileCache.removeConfig();
|
||||||
|
|
||||||
|
systemConfigRepository.save(systemConfig);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取管理员名称
|
||||||
|
*
|
||||||
|
* @return 管理员名称
|
||||||
|
*/
|
||||||
|
public String getAdminUsername() {
|
||||||
|
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
||||||
|
return systemConfigDTO.getUsername();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
69
src/main/java/im/zhaojun/zfile/service/SystemService.java
Normal file
69
src/main/java/im/zhaojun/zfile/service/SystemService.java
Normal file
@@ -0,0 +1,69 @@
|
|||||||
|
// package im.zhaojun.zfile.service;
|
||||||
|
//
|
||||||
|
// import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||||
|
// import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
// import im.zhaojun.zfile.model.dto.SiteConfigDTO;
|
||||||
|
// import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
// import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
// import im.zhaojun.zfile.context.DriveContext;
|
||||||
|
// import im.zhaojun.zfile.util.HttpUtil;
|
||||||
|
// import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
// import lombok.extern.slf4j.Slf4j;
|
||||||
|
// import org.springframework.stereotype.Service;
|
||||||
|
// import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
//
|
||||||
|
// import javax.annotation.Resource;
|
||||||
|
// import java.util.ArrayList;
|
||||||
|
// import java.util.List;
|
||||||
|
// import java.util.Objects;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * @author zhaojun
|
||||||
|
// */
|
||||||
|
// @Slf4j
|
||||||
|
// @Service
|
||||||
|
// public class SystemService {
|
||||||
|
//
|
||||||
|
// @Resource
|
||||||
|
// private DriveContext driveContext;
|
||||||
|
//
|
||||||
|
// /**
|
||||||
|
// * 构建指定路径下标题, 页面文档信息
|
||||||
|
// * @param path 路径
|
||||||
|
// */
|
||||||
|
// public SiteConfigDTO getConfig(Integer driveId, String path) throws Exception {
|
||||||
|
//
|
||||||
|
// SiteConfigDTO siteConfigDTO = new SiteConfigDTO();
|
||||||
|
//
|
||||||
|
// AbstractBaseFileService fileService = driveContext.getDriveService(driveId);
|
||||||
|
//
|
||||||
|
// List<FileItemDTO> fileItemList;
|
||||||
|
//
|
||||||
|
// if (Objects.equals(fileService.getStorageTypeEnum(), StorageTypeEnum.FTP)) {
|
||||||
|
// fileItemList = new ArrayList<>();
|
||||||
|
// } else {
|
||||||
|
// fileItemList = fileService.fileList(path);
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// for (FileItemDTO fileItemDTO : fileItemList) {
|
||||||
|
// if (ZFileConstant.README_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
|
||||||
|
// String textContent = null;
|
||||||
|
// try {
|
||||||
|
// textContent = HttpUtil.getTextContent(fileItemDTO.getUrl());
|
||||||
|
// } catch (HttpClientErrorException httpClientErrorException) {
|
||||||
|
// log.debug("尝试重新获取文档区缓存中链接后仍失败", httpClientErrorException);
|
||||||
|
// try {
|
||||||
|
// String fullPath = StringUtils.removeDuplicateSeparator(fileItemDTO.getPath() + "/" + fileItemDTO.getName());
|
||||||
|
// FileItemDTO fileItem = fileService.getFileItem(fullPath);
|
||||||
|
// textContent = HttpUtil.getTextContent(fileItem.getUrl());
|
||||||
|
// } catch (Exception e) {
|
||||||
|
// log.debug("尝试重新获取文档区链接后仍失败, 已置为空", e);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// siteConfigDTO.setReadme(textContent);
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// return siteConfigDTO;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// }
|
||||||
@@ -0,0 +1,168 @@
|
|||||||
|
package im.zhaojun.zfile.service.base;
|
||||||
|
|
||||||
|
import im.zhaojun.zfile.cache.ZFileCache;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.SystemConfigService;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.aop.framework.AopContext;
|
||||||
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractBaseFileService implements BaseFileService {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 下载链接过期时间, 目前只在兼容 S3 协议的存储策略中使用到.
|
||||||
|
*/
|
||||||
|
@Value("${zfile.cache.timeout}")
|
||||||
|
protected Long timeout;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 是否初始化成功
|
||||||
|
*/
|
||||||
|
protected boolean isInitialized = false;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 基路径
|
||||||
|
*/
|
||||||
|
protected String basePath;
|
||||||
|
/**
|
||||||
|
* 驱动器 ID
|
||||||
|
*/
|
||||||
|
public Integer driveId;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private SystemConfigService systemConfigService;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private ZFileCache zFileCache;
|
||||||
|
|
||||||
|
|
||||||
|
/***
|
||||||
|
* 获取指定路径下的文件及文件夹, 默认缓存 60 分钟,每隔 30 分钟刷新一次.
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* 文件路径
|
||||||
|
*
|
||||||
|
* @return 文件及文件夹列表
|
||||||
|
*
|
||||||
|
* @throws Exception 获取文件列表中出现的异常
|
||||||
|
*/
|
||||||
|
@Override
|
||||||
|
public abstract List<FileItemDTO> fileList(String path) throws Exception;
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 清理当前存储策略的缓存
|
||||||
|
*/
|
||||||
|
public void clearFileCache() {
|
||||||
|
zFileCache.clear(driveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 初始化方法, 启动时自动调用实现类的此方法进行初始化.
|
||||||
|
*/
|
||||||
|
public abstract void init(Integer driveId);
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 测试是否连接成功, 会尝试取调用获取根路径的文件, 如果没有抛出异常, 则认为连接成功, 某些存储策略需要复写此方法.
|
||||||
|
*
|
||||||
|
* @return 连接结果
|
||||||
|
*/
|
||||||
|
protected boolean testConnection() {
|
||||||
|
boolean flag = true;
|
||||||
|
try {
|
||||||
|
fileList("/");
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常", e);
|
||||||
|
flag = false;
|
||||||
|
}
|
||||||
|
return flag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否初始化成功
|
||||||
|
*
|
||||||
|
* @return 初始化成功与否
|
||||||
|
*/
|
||||||
|
public boolean getIsUnInitialized() {
|
||||||
|
return !isInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取是否初始化成功
|
||||||
|
*
|
||||||
|
* @return 初始化成功与否
|
||||||
|
*/
|
||||||
|
public boolean getIsInitialized() {
|
||||||
|
return isInitialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前实现类的存储策略类型
|
||||||
|
*
|
||||||
|
* @return 存储策略类型枚举对象
|
||||||
|
*/
|
||||||
|
public abstract StorageTypeEnum getStorageTypeEnum();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取初始化当前存储策略, 所需要的参数信息 (表单填写)
|
||||||
|
*
|
||||||
|
* @return 初始化所需的参数列表
|
||||||
|
*/
|
||||||
|
public abstract List<StorageConfig> storageStrategyConfigList();
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 搜索文件
|
||||||
|
*
|
||||||
|
* @param name
|
||||||
|
* 文件名
|
||||||
|
*
|
||||||
|
* @return 包含该文件名的所有文件或文件夹
|
||||||
|
*/
|
||||||
|
public List<FileItemDTO> search(String name) {
|
||||||
|
return zFileCache.find(driveId, name);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 刷新指定 key 的缓存:
|
||||||
|
* 1. 清空此 key 的缓存.
|
||||||
|
* 2. 重新调用方法写入缓存.
|
||||||
|
*
|
||||||
|
* @param key
|
||||||
|
* 缓存 key (文件夹名称)
|
||||||
|
*/
|
||||||
|
public void refreshCache(String key) throws Exception {
|
||||||
|
zFileCache.remove(driveId, key);
|
||||||
|
BaseFileService currentFileService = (BaseFileService) AopContext.currentProxy();
|
||||||
|
currentFileService.fileList(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取单个文件信息
|
||||||
|
*
|
||||||
|
* @param path
|
||||||
|
* 文件路径
|
||||||
|
*
|
||||||
|
* @return 单个文件的内容.
|
||||||
|
*/
|
||||||
|
public abstract FileItemDTO getFileItem(String path);
|
||||||
|
|
||||||
|
}
|
||||||
@@ -0,0 +1,247 @@
|
|||||||
|
package im.zhaojun.zfile.service.base;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.http.HttpRequest;
|
||||||
|
import cn.hutool.http.HttpResponse;
|
||||||
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.alibaba.fastjson.JSONArray;
|
||||||
|
import com.alibaba.fastjson.JSONObject;
|
||||||
|
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
|
||||||
|
import im.zhaojun.zfile.model.constant.ZFileConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.FileTypeEnum;
|
||||||
|
import im.zhaojun.zfile.model.support.OneDriveToken;
|
||||||
|
import im.zhaojun.zfile.repository.StorageConfigRepository;
|
||||||
|
import im.zhaojun.zfile.service.StorageConfigService;
|
||||||
|
import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.context.annotation.Lazy;
|
||||||
|
import org.springframework.http.HttpEntity;
|
||||||
|
import org.springframework.http.HttpHeaders;
|
||||||
|
import org.springframework.http.HttpMethod;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.web.client.HttpClientErrorException;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author Zhao Jun
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
public abstract class AbstractOneDriveServiceBase extends AbstractBaseFileService {
|
||||||
|
|
||||||
|
protected static final String DRIVER_INFO_URL = "https://{graphEndPoint}/v1.0/me/drives";
|
||||||
|
|
||||||
|
protected static final String DRIVER_ROOT_URL = "https://{graphEndPoint}/v1.0/me/drive/root/children";
|
||||||
|
|
||||||
|
protected static final String DRIVER_ITEMS_URL = "https://{graphEndPoint}/v1.0/me/drive/root:{path}:/children";
|
||||||
|
|
||||||
|
protected static final String DRIVER_ITEM_URL = "https://{graphEndPoint}/v1.0/me/drive/root:{path}";
|
||||||
|
|
||||||
|
protected static final String AUTHENTICATE_URL = "https://{authenticateEndPoint}/common/oauth2/v2.0/token";
|
||||||
|
|
||||||
|
private static final String ONE_DRIVE_FILE_FLAG = "file";
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
@Lazy
|
||||||
|
private RestTemplate oneDriveRestTemplate;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigRepository storageConfigRepository;
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigService storageConfigService;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 根据 RefreshToken 刷新 AccessToken, 返回刷新后的 Token.
|
||||||
|
*
|
||||||
|
* @return 刷新后的 Token
|
||||||
|
*/
|
||||||
|
public OneDriveToken getRefreshToken() {
|
||||||
|
StorageConfig refreshStorageConfig =
|
||||||
|
storageConfigRepository.findByDriveIdAndKey(driveId, StorageConfigConstant.REFRESH_TOKEN_KEY);
|
||||||
|
|
||||||
|
String param = "client_id=" + getClientId() +
|
||||||
|
"&redirect_uri=" + getRedirectUri() +
|
||||||
|
"&client_secret=" + getClientSecret() +
|
||||||
|
"&refresh_token=" + refreshStorageConfig.getValue() +
|
||||||
|
"&grant_type=refresh_token";
|
||||||
|
|
||||||
|
String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint());
|
||||||
|
HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl);
|
||||||
|
|
||||||
|
post.body(param, "application/x-www-form-urlencoded");
|
||||||
|
HttpResponse response = post.execute();
|
||||||
|
return JSONObject.parseObject(response.body(), OneDriveToken.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* OAuth2 协议中, 根据 code 换取 access_token 和 refresh_token.
|
||||||
|
*
|
||||||
|
* @param code
|
||||||
|
* 代码
|
||||||
|
*
|
||||||
|
* @return 获取的 Token 信息.
|
||||||
|
*/
|
||||||
|
public OneDriveToken getToken(String code) {
|
||||||
|
String param = "client_id=" + getClientId() +
|
||||||
|
"&redirect_uri=" + getRedirectUri() +
|
||||||
|
"&client_secret=" + getClientSecret() +
|
||||||
|
"&code=" + code +
|
||||||
|
"&scope=" + getScope() +
|
||||||
|
"&grant_type=authorization_code";
|
||||||
|
|
||||||
|
String fullAuthenticateUrl = AUTHENTICATE_URL.replace("{authenticateEndPoint}", getAuthenticateEndPoint());
|
||||||
|
HttpRequest post = HttpUtil.createPost(fullAuthenticateUrl);
|
||||||
|
|
||||||
|
post.body(param, "application/x-www-form-urlencoded");
|
||||||
|
HttpResponse response = post.execute();
|
||||||
|
return JSONObject.parseObject(response.body(), OneDriveToken.class);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FileItemDTO> fileList(String path) {
|
||||||
|
path = StringUtils.removeFirstSeparator(path);
|
||||||
|
String fullPath = StringUtils.getFullPath(basePath, path);
|
||||||
|
|
||||||
|
List<FileItemDTO> result = new ArrayList<>();
|
||||||
|
String nextLink = null;
|
||||||
|
|
||||||
|
do {
|
||||||
|
|
||||||
|
String requestUrl;
|
||||||
|
|
||||||
|
if (nextLink != null) {
|
||||||
|
nextLink = nextLink.replace("+", "%2B");
|
||||||
|
requestUrl = URLUtil.decode(nextLink);
|
||||||
|
}else if (ZFileConstant.PATH_SEPARATOR.equalsIgnoreCase(fullPath) || "".equalsIgnoreCase(fullPath)) {
|
||||||
|
requestUrl = DRIVER_ROOT_URL;
|
||||||
|
} else {
|
||||||
|
requestUrl = DRIVER_ITEMS_URL;
|
||||||
|
}
|
||||||
|
fullPath = StringUtils.removeLastSeparator(fullPath);
|
||||||
|
|
||||||
|
JSONObject root;
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("driveId", driveId.toString());
|
||||||
|
HttpEntity<Object> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
try {
|
||||||
|
root = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), fullPath).getBody();
|
||||||
|
} catch (HttpClientErrorException e) {
|
||||||
|
log.debug("调用 OneDrive 时出现了网络异常: {} , 已尝试重新刷新 token 后再试.", e.getMessage());
|
||||||
|
refreshOneDriveToken();
|
||||||
|
root = oneDriveRestTemplate.exchange(requestUrl, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), fullPath).getBody();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (root == null) {
|
||||||
|
return Collections.emptyList();
|
||||||
|
}
|
||||||
|
|
||||||
|
nextLink = root.getString("@odata.nextLink");
|
||||||
|
|
||||||
|
JSONArray fileList = root.getJSONArray("value");
|
||||||
|
|
||||||
|
for (int i = 0; i < fileList.size(); i++) {
|
||||||
|
|
||||||
|
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||||
|
JSONObject fileItem = fileList.getJSONObject(i);
|
||||||
|
fileItemDTO.setName(fileItem.getString("name"));
|
||||||
|
fileItemDTO.setSize(fileItem.getLong("size"));
|
||||||
|
fileItemDTO.setTime(fileItem.getDate("lastModifiedDateTime"));
|
||||||
|
|
||||||
|
if (fileItem.containsKey("file")) {
|
||||||
|
fileItemDTO.setUrl(fileItem.getString("@microsoft.graph.downloadUrl"));
|
||||||
|
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||||
|
} else {
|
||||||
|
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileItemDTO.setPath(path);
|
||||||
|
result.add(fileItemDTO);
|
||||||
|
}
|
||||||
|
} while (nextLink != null);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileItemDTO getFileItem(String path) {
|
||||||
|
|
||||||
|
String fullPath = StringUtils.getFullPath(basePath, path);
|
||||||
|
|
||||||
|
String requestUrl;
|
||||||
|
|
||||||
|
HttpHeaders headers = new HttpHeaders();
|
||||||
|
headers.set("driveId", driveId.toString());
|
||||||
|
HttpEntity<Object> entity = new HttpEntity<>(headers);
|
||||||
|
|
||||||
|
JSONObject fileItem = oneDriveRestTemplate.exchange(DRIVER_ITEM_URL, HttpMethod.GET, entity, JSONObject.class, getGraphEndPoint(), fullPath).getBody();
|
||||||
|
|
||||||
|
if (fileItem == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||||
|
fileItemDTO.setName(fileItem.getString("name"));
|
||||||
|
fileItemDTO.setSize(fileItem.getLong("size"));
|
||||||
|
fileItemDTO.setTime(fileItem.getDate("lastModifiedDateTime"));
|
||||||
|
|
||||||
|
if (fileItem.containsKey(ONE_DRIVE_FILE_FLAG)) {
|
||||||
|
fileItemDTO.setUrl(fileItem.getString("@microsoft.graph.downloadUrl"));
|
||||||
|
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||||
|
} else {
|
||||||
|
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||||
|
}
|
||||||
|
|
||||||
|
fileItemDTO.setPath(path);
|
||||||
|
return fileItemDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public abstract String getGraphEndPoint();
|
||||||
|
|
||||||
|
public abstract String getAuthenticateEndPoint();
|
||||||
|
|
||||||
|
public abstract String getClientId();
|
||||||
|
|
||||||
|
public abstract String getRedirectUri();
|
||||||
|
|
||||||
|
public abstract String getClientSecret();
|
||||||
|
|
||||||
|
public abstract String getScope();
|
||||||
|
|
||||||
|
public void refreshOneDriveToken() {
|
||||||
|
OneDriveToken refreshToken = getRefreshToken();
|
||||||
|
|
||||||
|
if (refreshToken.getAccessToken() == null || refreshToken.getRefreshToken() == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
StorageConfig accessTokenConfig =
|
||||||
|
storageConfigService.findByDriveIdAndKey(driveId, StorageConfigConstant.ACCESS_TOKEN_KEY);
|
||||||
|
StorageConfig refreshTokenConfig =
|
||||||
|
storageConfigService.findByDriveIdAndKey(driveId, StorageConfigConstant.REFRESH_TOKEN_KEY);
|
||||||
|
accessTokenConfig.setValue(refreshToken.getAccessToken());
|
||||||
|
refreshTokenConfig.setValue(refreshToken.getRefreshToken());
|
||||||
|
|
||||||
|
storageConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageConfig> storageStrategyConfigList() {
|
||||||
|
return new ArrayList<StorageConfig>() {{
|
||||||
|
add(new StorageConfig("accessToken", "访问令牌"));
|
||||||
|
add(new StorageConfig("refreshToken", "刷新令牌"));
|
||||||
|
add(new StorageConfig("basePath", "基路径"));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -1,39 +1,42 @@
|
|||||||
package im.zhaojun.common.service;
|
package im.zhaojun.zfile.service.base;
|
||||||
|
|
||||||
import cn.hutool.core.util.ObjectUtil;
|
import cn.hutool.core.util.BooleanUtil;
|
||||||
import cn.hutool.core.util.URLUtil;
|
import cn.hutool.core.util.URLUtil;
|
||||||
import com.amazonaws.services.s3.AmazonS3;
|
import com.amazonaws.services.s3.AmazonS3;
|
||||||
import com.amazonaws.services.s3.model.ListObjectsRequest;
|
import com.amazonaws.services.s3.model.ListObjectsRequest;
|
||||||
import com.amazonaws.services.s3.model.ObjectListing;
|
import com.amazonaws.services.s3.model.ObjectListing;
|
||||||
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
import com.amazonaws.services.s3.model.S3ObjectSummary;
|
||||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
import im.zhaojun.zfile.exception.NotExistFileException;
|
||||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
import im.zhaojun.common.util.StringUtils;
|
import im.zhaojun.zfile.model.enums.FileTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.StorageConfigService;
|
||||||
|
import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
|
||||||
import javax.annotation.Resource;
|
import javax.annotation.Resource;
|
||||||
import java.net.URL;
|
import java.net.URL;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
* @date 2019/12/26 22:26
|
|
||||||
*/
|
*/
|
||||||
public abstract class AbstractS3FileService extends AbstractFileService {
|
public abstract class AbstractS3BaseFileService extends AbstractBaseFileService {
|
||||||
|
|
||||||
@Resource
|
@Resource
|
||||||
protected StorageConfigService storageConfigService;
|
protected StorageConfigService storageConfigService;
|
||||||
|
|
||||||
protected String path;
|
protected String path;
|
||||||
|
|
||||||
protected String basePath;
|
|
||||||
|
|
||||||
protected String bucketName;
|
protected String bucketName;
|
||||||
|
|
||||||
protected String domain;
|
protected String domain;
|
||||||
|
|
||||||
protected AmazonS3 s3Client;
|
protected AmazonS3 s3Client;
|
||||||
|
|
||||||
|
protected boolean isPrivate;
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<FileItemDTO> fileList(String path) {
|
public List<FileItemDTO> fileList(String path) {
|
||||||
this.path = path;
|
this.path = path;
|
||||||
@@ -53,7 +56,7 @@ public abstract class AbstractS3FileService extends AbstractFileService {
|
|||||||
*/
|
*/
|
||||||
public List<FileItemDTO> s3FileList(String path) {
|
public List<FileItemDTO> s3FileList(String path) {
|
||||||
path = StringUtils.removeFirstSeparator(path);
|
path = StringUtils.removeFirstSeparator(path);
|
||||||
String fullPath = StringUtils.removeFirstSeparator(getFullPath());
|
String fullPath = StringUtils.removeFirstSeparator(StringUtils.getFullPath(basePath, path));
|
||||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||||
ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest(bucketName, fullPath, "", "/", 1000));
|
ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest(bucketName, fullPath, "", "/", 1000));
|
||||||
|
|
||||||
@@ -73,6 +76,9 @@ public abstract class AbstractS3FileService extends AbstractFileService {
|
|||||||
|
|
||||||
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
||||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||||
|
if (Objects.equals(commonPrefix, "/")) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
fileItemDTO.setName(commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1));
|
fileItemDTO.setName(commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1));
|
||||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||||
fileItemDTO.setPath(path);
|
fileItemDTO.setPath(path);
|
||||||
@@ -87,8 +93,14 @@ public abstract class AbstractS3FileService extends AbstractFileService {
|
|||||||
* @return S3 对象访问地址
|
* @return S3 对象访问地址
|
||||||
*/
|
*/
|
||||||
public String s3ObjectUrl(String path) {
|
public String s3ObjectUrl(String path) {
|
||||||
|
basePath = basePath == null ? "" : basePath;
|
||||||
String fullPath = StringUtils.removeFirstSeparator(StringUtils.removeDuplicateSeparator(basePath + "/" + path));
|
String fullPath = StringUtils.removeFirstSeparator(StringUtils.removeDuplicateSeparator(basePath + "/" + path));
|
||||||
|
|
||||||
|
// 如果不是私有空间, 且指定了加速域名, 则直接返回下载地址.
|
||||||
|
if (BooleanUtil.isFalse(isPrivate) && StringUtils.isNotNullOrEmpty(domain)) {
|
||||||
|
return StringUtils.concatPath(domain, fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
|
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
|
||||||
URL url = s3Client.generatePresignedUrl(bucketName, fullPath, expirationDate);
|
URL url = s3Client.generatePresignedUrl(bucketName, fullPath, expirationDate);
|
||||||
|
|
||||||
@@ -99,13 +111,23 @@ public abstract class AbstractS3FileService extends AbstractFileService {
|
|||||||
return URLUtil.decode(defaultUrl);
|
return URLUtil.decode(defaultUrl);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
@Override
|
||||||
* 获取 basePath + path 的全路径地址.
|
public FileItemDTO getFileItem(String path) {
|
||||||
* @return basePath + path 的全路径地址.
|
List<FileItemDTO> list;
|
||||||
*/
|
try {
|
||||||
public String getFullPath() {
|
int end = path.lastIndexOf("/");
|
||||||
String basePath = ObjectUtil.defaultIfNull(this.basePath, "");
|
list = fileList(path.substring(0, end + 1));
|
||||||
String path = ObjectUtil.defaultIfNull(this.path, "");
|
} catch (Exception e) {
|
||||||
return StringUtils.removeDuplicateSeparator(basePath + "/" + path);
|
throw new NotExistFileException();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (FileItemDTO fileItemDTO : list) {
|
||||||
|
String fullPath = StringUtils.concatUrl(fileItemDTO.getPath(), fileItemDTO.getName());
|
||||||
|
if (Objects.equals(fullPath, path)) {
|
||||||
|
return fileItemDTO;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
throw new NotExistFileException();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,13 +1,13 @@
|
|||||||
package im.zhaojun.common.service;
|
package im.zhaojun.zfile.service.base;
|
||||||
|
|
||||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
public interface FileService {
|
public interface BaseFileService {
|
||||||
|
|
||||||
/***
|
/***
|
||||||
* 获取指定路径下的文件及文件夹
|
* 获取指定路径下的文件及文件夹
|
||||||
@@ -1,18 +1,23 @@
|
|||||||
package im.zhaojun.aliyun.service;
|
package im.zhaojun.zfile.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.convert.Convert;
|
||||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||||
import com.amazonaws.auth.BasicAWSCredentials;
|
import com.amazonaws.auth.BasicAWSCredentials;
|
||||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||||
import im.zhaojun.common.model.StorageConfig;
|
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
|
||||||
import im.zhaojun.common.model.constant.StorageConfigConstant;
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
import im.zhaojun.common.service.AbstractS3FileService;
|
import im.zhaojun.zfile.service.base.AbstractS3BaseFileService;
|
||||||
import im.zhaojun.common.service.FileService;
|
import im.zhaojun.zfile.service.base.BaseFileService;
|
||||||
import org.slf4j.Logger;
|
import org.slf4j.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
|
|
||||||
@@ -20,23 +25,28 @@ import java.util.Objects;
|
|||||||
* @author zhaojun
|
* @author zhaojun
|
||||||
*/
|
*/
|
||||||
@Service
|
@Service
|
||||||
public class AliyunServiceImpl extends AbstractS3FileService implements FileService {
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public class AliyunServiceImpl extends AbstractS3BaseFileService implements BaseFileService {
|
||||||
|
|
||||||
private static final Logger log = LoggerFactory.getLogger(AliyunServiceImpl.class);
|
private static final Logger log = LoggerFactory.getLogger(AliyunServiceImpl.class);
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void init() {
|
public void init(Integer driveId) {
|
||||||
try {
|
try {
|
||||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ALIYUN);
|
this.driveId = driveId;
|
||||||
|
Map<String, StorageConfig> stringStorageConfigMap =
|
||||||
|
storageConfigService.selectStorageConfigMapByDriveId(driveId);
|
||||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
||||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
||||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
||||||
|
|
||||||
super.bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
|
||||||
super.domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
super.domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||||
super.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
super.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||||
|
super.bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
||||||
|
super.isPrivate = Convert.toBool(stringStorageConfigMap.get(StorageConfigConstant.IS_PRIVATE).getValue(), true);
|
||||||
|
|
||||||
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
|
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
|
||||||
|
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
|
||||||
isInitialized = false;
|
isInitialized = false;
|
||||||
} else {
|
} else {
|
||||||
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
|
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
|
||||||
@@ -46,10 +56,8 @@ public class AliyunServiceImpl extends AbstractS3FileService implements FileServ
|
|||||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "oss")).build();
|
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "oss")).build();
|
||||||
isInitialized = testConnection();
|
isInitialized = testConnection();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.debug(getStorageTypeEnum().getDescription() + "初始化异常, 已跳过");
|
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过", e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,4 +66,16 @@ public class AliyunServiceImpl extends AbstractS3FileService implements FileServ
|
|||||||
return StorageTypeEnum.ALIYUN;
|
return StorageTypeEnum.ALIYUN;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
@Override
|
||||||
|
public List<StorageConfig> storageStrategyConfigList() {
|
||||||
|
return new ArrayList<StorageConfig>() {{
|
||||||
|
add(new StorageConfig("accessKey", "AccessKey"));
|
||||||
|
add(new StorageConfig("secretKey", "SecretKey"));
|
||||||
|
add(new StorageConfig("bucketName", "Bucket 名称"));
|
||||||
|
add(new StorageConfig("domain", "Bucket 域名 / CDN 加速域名"));
|
||||||
|
add(new StorageConfig("endPoint", "区域"));
|
||||||
|
add(new StorageConfig("basePath", "基路径"));
|
||||||
|
add(new StorageConfig("isPrivate", "是否是私有空间"));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
148
src/main/java/im/zhaojun/zfile/service/impl/FtpServiceImpl.java
Normal file
148
src/main/java/im/zhaojun/zfile/service/impl/FtpServiceImpl.java
Normal file
@@ -0,0 +1,148 @@
|
|||||||
|
package im.zhaojun.zfile.service.impl;
|
||||||
|
|
||||||
|
import cn.hutool.core.util.URLUtil;
|
||||||
|
import cn.hutool.extra.ftp.Ftp;
|
||||||
|
import im.zhaojun.zfile.model.constant.StorageConfigConstant;
|
||||||
|
import im.zhaojun.zfile.model.dto.FileItemDTO;
|
||||||
|
import im.zhaojun.zfile.model.entity.StorageConfig;
|
||||||
|
import im.zhaojun.zfile.model.enums.FileTypeEnum;
|
||||||
|
import im.zhaojun.zfile.model.enums.StorageTypeEnum;
|
||||||
|
import im.zhaojun.zfile.service.StorageConfigService;
|
||||||
|
import im.zhaojun.zfile.service.base.AbstractBaseFileService;
|
||||||
|
import im.zhaojun.zfile.service.base.BaseFileService;
|
||||||
|
import im.zhaojun.zfile.util.StringUtils;
|
||||||
|
import org.apache.commons.net.ftp.FTP;
|
||||||
|
import org.apache.commons.net.ftp.FTPClientConfig;
|
||||||
|
import org.apache.commons.net.ftp.FTPFile;
|
||||||
|
import org.slf4j.Logger;
|
||||||
|
import org.slf4j.LoggerFactory;
|
||||||
|
import org.springframework.beans.factory.config.ConfigurableBeanFactory;
|
||||||
|
import org.springframework.context.annotation.Scope;
|
||||||
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import javax.annotation.Resource;
|
||||||
|
import java.nio.charset.StandardCharsets;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @author zhaojun
|
||||||
|
*/
|
||||||
|
@Service
|
||||||
|
@Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)
|
||||||
|
public class FtpServiceImpl extends AbstractBaseFileService implements BaseFileService {
|
||||||
|
|
||||||
|
private static final Logger log = LoggerFactory.getLogger(FtpServiceImpl.class);
|
||||||
|
|
||||||
|
@Resource
|
||||||
|
private StorageConfigService storageConfigService;
|
||||||
|
|
||||||
|
private Ftp ftp;
|
||||||
|
|
||||||
|
private String domain;
|
||||||
|
|
||||||
|
private String host;
|
||||||
|
|
||||||
|
private String port;
|
||||||
|
|
||||||
|
private String username;
|
||||||
|
|
||||||
|
private String password;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void init(Integer driveId) {
|
||||||
|
try {
|
||||||
|
this.driveId = driveId;
|
||||||
|
Map<String, StorageConfig> stringStorageConfigMap =
|
||||||
|
storageConfigService.selectStorageConfigMapByDriveId(driveId);
|
||||||
|
host = stringStorageConfigMap.get(StorageConfigConstant.HOST_KEY).getValue();
|
||||||
|
port = stringStorageConfigMap.get(StorageConfigConstant.PORT_KEY).getValue();
|
||||||
|
username = stringStorageConfigMap.get(StorageConfigConstant.USERNAME_KEY).getValue();
|
||||||
|
password = stringStorageConfigMap.get(StorageConfigConstant.PASSWORD_KEY).getValue();
|
||||||
|
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||||
|
super.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||||
|
if (Objects.isNull(host) || Objects.isNull(port) || Objects.isNull(username) || Objects.isNull(password)) {
|
||||||
|
isInitialized = false;
|
||||||
|
} else {
|
||||||
|
ftp = new Ftp(host, Integer.parseInt(port), username, password, StandardCharsets.UTF_8);
|
||||||
|
ftp.getClient().configure(new FTPClientConfig(FTPClientConfig.SYST_UNIX));
|
||||||
|
ftp.getClient().type(FTP.BINARY_FILE_TYPE);
|
||||||
|
isInitialized = testConnection();
|
||||||
|
}
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<FileItemDTO> fileList(String path) {
|
||||||
|
ftp.reconnectIfTimeout();
|
||||||
|
String fullPath = StringUtils.getFullPath(basePath, path);
|
||||||
|
ftp.cd(fullPath);
|
||||||
|
FTPFile[] ftpFiles = new FTPFile[]{};
|
||||||
|
try {
|
||||||
|
ftp.getClient().changeWorkingDirectory("/");
|
||||||
|
ftpFiles = ftp.getClient().listFiles(fullPath);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
|
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) {
|
||||||
|
String fullPath = StringUtils.getFullPath(basePath, path);
|
||||||
|
if (StringUtils.isNullOrEmpty(domain)) {
|
||||||
|
return "ftp://"
|
||||||
|
+ URLUtil.encodeQuery(username)
|
||||||
|
+ ":"
|
||||||
|
+ URLUtil.encodeQuery(password)
|
||||||
|
+ "@"
|
||||||
|
+ host + ":" + port + fullPath;
|
||||||
|
}
|
||||||
|
|
||||||
|
return URLUtil.complateUrl(domain, fullPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public StorageTypeEnum getStorageTypeEnum() {
|
||||||
|
return StorageTypeEnum.FTP;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public FileItemDTO getFileItem(String path) {
|
||||||
|
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||||
|
fileItemDTO.setUrl(getDownloadUrl(path));
|
||||||
|
return fileItemDTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public List<StorageConfig> storageStrategyConfigList() {
|
||||||
|
return new ArrayList<StorageConfig>() {{
|
||||||
|
add(new StorageConfig("host", "域名或IP"));
|
||||||
|
add(new StorageConfig("port", "端口"));
|
||||||
|
add(new StorageConfig("username", "用户名"));
|
||||||
|
add(new StorageConfig("password", "密码"));
|
||||||
|
add(new StorageConfig("domain", "加速域名"));
|
||||||
|
add(new StorageConfig("basePath", "基路径"));
|
||||||
|
}};
|
||||||
|
}
|
||||||
|
}
|
||||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user