Compare commits

...

45 Commits
0.7 ... 1.2.1

Author SHA1 Message Date
zhaojun1998
946113216d 🔖 发布 1.2.1 版 2020-02-03 20:57:07 +08:00
zhaojun1998
77b05c6dac 🐛 修复 OneDrive 的 Token 某些情况下, 可能超出 2000 字符的 BUG 2020-02-03 20:52:49 +08:00
zhaojun1998
07c9fca210 🔖 发布 1.2 版 2020-02-01 21:54:32 +08:00
zhaojun1998
27cf61693a 更新前端页面, 修复搜索模式下无法进入文件夹和滚动加载的 BUG 2020-02-01 21:54:20 +08:00
zhaojun1998
37e1aa1fec 🐛 修复 OneDrive 文件夹包含特殊符号时, 获取下一页数据 URL 中重复进行了 URL 编码的 BUG. 2020-02-01 21:51:15 +08:00
zhaojun1998
31b54a3c05 调整 OneDrive Token 自动刷新时间为 15 分钟. 2020-02-01 21:50:08 +08:00
zhaojun1998
589f07c103 🔖 发布 1.1 版 2020-01-31 11:52:27 +08:00
zhaojun1998
fe8b60d873 调整日志级别 2020-01-31 11:52:21 +08:00
zhaojun1998
1734619eac 📝 更新页面 2020-01-31 11:50:55 +08:00
zhaojun1998
f5724dc9ab OneDrive 基础路径支持 2020-01-31 11:21:36 +08:00
zhaojun1998
f7bb147b71 📝 更新文档 2020-01-30 19:31:50 +08:00
zhaojun1998
47fc1bc2df 🔖 发布 1.0 版 2020-01-30 18:06:09 +08:00
zhaojun1998
45172f69ba 📝 更新文档 2020-01-30 18:05:56 +08:00
zhaojun1998
9566b138ff 📝 更新页面 2020-01-30 17:58:26 +08:00
zhaojun1998
e15b6c2242 更新配置文件, 增加 h2 console, 便与调试. 2020-01-30 16:52:20 +08:00
zhaojun1998
acc41511e0 S3 协议新增是否为私有空间支持 2020-01-30 16:51:05 +08:00
zhaojun1998
b882b87405 数据库文件初始化更新, 新增 S3 通用协议支持 2020-01-30 16:50:37 +08:00
zhaojun1998
518b5170ae 优化代码 2020-01-30 16:48:37 +08:00
zhaojun1998
8bfac6d9ac 新增 S3 协议通用支持 2020-01-30 16:47:58 +08:00
zhaojun1998
3ffdb4f1b2 清洁代码 2020-01-30 16:47:03 +08:00
zhaojun1998
47509450a0 📝 更新文档, 修改 Debian/Ubuntu 安装命令. 2020-01-29 18:47:38 +08:00
zhaojun1998
812fd18aac 🐛 修复 OneDrive 世纪互联版自动刷新 REFRESH_TOKEN 失败的 BUG 2020-01-29 16:24:00 +08:00
zhaojun1998
77a13cf8ad 📝 更新文档, 新增预览图片 2020-01-29 13:56:20 +08:00
zhaojun1998
4c914793b0 📝 更新文档 2020-01-29 13:43:19 +08:00
zhaojun1998
5698cfb2d3 🔖 发布 0.9 版 2020-01-29 13:41:42 +08:00
zhaojun1998
3cd5f8f9a7 调整显示顺序 2020-01-29 12:58:03 +08:00
zhaojun1998
76747771de OneDrive 世纪互联支持 2020-01-29 12:53:38 +08:00
zhaojun1998
cfacd39210 优化代码, 增强健壮性 2020-01-29 12:52:07 +08:00
zhaojun1998
90cd13f2c3 🔖 发布 0.8 版 2020-01-28 15:19:04 +08:00
zhaojun1998
018a68246e 💄 更新页面 2020-01-28 15:16:27 +08:00
zhaojun1998
b6a2e3ccb8 添加获取指定路径文件信息的 API 2020-01-28 14:55:06 +08:00
zhaojun1998
38b811f8e6 🐛 新增 '搜索包含加密文件' 支持. 2020-01-28 13:25:28 +08:00
zhaojun1998
6922fa2195 添加自定义 JS, CSS 支持 2020-01-28 13:14:23 +08:00
zhaojun1998
4bca6cf7a5 移除尾部说明文件支持 2020-01-28 13:13:52 +08:00
zhaojun1998
c3484426ab 🐛 修复 OneDrive 教育版和部分国际版无法正常获取文件的 BUG 2020-01-28 10:18:36 +08:00
zhaojun1998
0455bd366c 🔖 发布 0.7.1 版 2020-01-26 13:42:19 +08:00
zhaojun1998
bbe3c053f8 OneDrive 回调页面友好提示 2020-01-26 13:41:15 +08:00
zhaojun1998
f47708f45d Merge remote-tracking branch 'origin/master' 2020-01-26 13:38:24 +08:00
zhaojun1998
2e7a7b8cec 🐛 修复文件夹包含特殊字符编码 BUG 2020-01-26 13:35:50 +08:00
zhaojun1998
9e067dbce9 🐛 修复国际版 OneDrive, 无法获取子目录的 BUG 2020-01-26 13:35:27 +08:00
zhaojun1998
a4a236e488 🐛 修复 OneDrive 列目录, 文件数超出 200 个无法显示的 BUG. 2020-01-26 13:21:49 +08:00
赵俊
7d5b0431f5 Update README.md 2020-01-25 18:10:22 +08:00
zhaojun1998
a758c8cc6d 📝 更新文档 2020-01-25 18:06:13 +08:00
zhaojun1998
21a64ec0f3 🐛 修复循环依赖 BUG 2020-01-25 18:00:38 +08:00
zhaojun1998
3f241d129a 📝 更新文档 2020-01-25 18:00:14 +08:00
59 changed files with 998 additions and 294 deletions

164
API.md Normal file
View File

@@ -0,0 +1,164 @@
## API 标准
所有 API 均返回 `msg`, `code`, `data` 三个属性.
| code | 描述 |
| :---: | :------------: |
| 0 | 请求成功 |
| -1 | 请求失败 |
| -2 | 文件夹需要密码 |
`code == 0` 时, `data` 中为请求所需数据.
`code != 0` 时, 应当将 `msg` 中的属性作为参考值.
## 获取文件列表
### 请求 URL
`/api/list` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :------: | :--------: | :------: | :--------------------------: |
| path | 路径 | 是 | `/`, `/文件夹名称` |
| password | 文件夹密码 | 否 | 当文件夹需要密码时, |
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": [
{
"name": "密码文件夹",
"time": "2020-01-28 13:17",
"size": 4096,
"type": "FOLDER",
"path": "/",
"url": null
},
{
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "/",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
]
}
```
## 搜索
### 请求 URL
`/api/search` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :----: | :------: | :--------------------------: |
| name | 搜索值 | 是 | 模糊匹配 |
| page | 页数 | 否 | 默认取第一页, 每页固定 30 条 |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": [
{
"name": "密码文件夹",
"time": "2020-01-28 13:17",
"size": 4096,
"type": "FOLDER",
"path": "/",
"url": null
},
{
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "/",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
]
}
```
## 获取单个文件信息
### 请求 URL
`/api/directlink` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :--------: | :------: | :------------------: |
| path | 文件全路径 | 是 | `/新建 文本文档.txt` |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": {
"name": "新建 文本文档.txt",
"time": "2020-01-28 13:16",
"size": 3,
"type": "FILE",
"path": "d:/test",
"url": "http://127.0.0.1:8080/file/新建 文本文档.txt"
}
}
```
## 获取系统配置
### 请求 URL
`/api/config` `GET`
### 参数
| 参数名 | 描述 | 是否必填 | 参考值 |
| :----: | :--------: | :------: | :-----------: |
| path | 文件夹名称 | 是 | `/文件夹名称` |
### 响应
```json
{
"msg": "操作成功",
"code": 0,
"data": {
"header": 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 片段
}
}
}
```

View File

@@ -16,46 +16,57 @@
* 内存缓存 (免安装)
* 内存数据库 (免安装)
* 个性化配置
* 自定义目录的 header 和 footer 说明文件
* 自定义目录的 header 说明文件
* 自定义 JS, CSS
* 文件夹密码
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
* 文件/目录二维码
* 缓存动态开启, 缓存自动刷新
* 全局搜索
* 支持 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版, OneDrive 世纪互联版, 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
## 快速开始
安装 JDK 1.8 :
安装依赖环境:
```bash
yum install -y java # 适用于 Centos 7.x
# CentOS系统
yum install -y java-1.8.0-openjdk unzip
# Debian/Ubuntu系统
apt update
apt install -y openjdk-8-jre-headless unzip
```
> 如为更新程序, 则请先执行 `rm -rf ~/zfile` 清理旧程序. 首次安装请忽略此选项.
下载项目:
```bash
wget https://github.com/zhaojun1998/zfile/releases/download/0.7/zfile-0.7.jar
wget -P ~ https://c.jun6.net/ZFILE/zfile-1.2.1.war
cd ~
mkdir zfile && unzip zfile-1.2.1.war -d zfile && rm -rf zfile-1.2.1.war
chmod +x ~/zfile/bin/*.sh
```
程序的目录结构为:
```
├── zfile
├── META-INF
├── WEB-INF
└── bin
├── start.sh # 启动脚本
└── stop.sh # 停止脚本
├── restart.sh # 重启脚本
```
启动项目:
```bash
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar
## 高级启动
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar --server.port=18777
## 后台运行
nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar &
~/zfile/bin/start.sh
```
> 系统使用的是内置配置文件, 默认配置请参考: [application.yml](https://github.com/zhaojun1998/zfile/blob/master/src/main/resources/application.yml)
> **可下载此文件放置与 jar 包同目录, 此时会以外部配置文件为准, 推荐适用此方式!.**
> 所有参数都可在命令行启动时, 以类似 `--server.port=18777` 的方式强制执行, 此方式的优先级最高.
> *指定 `-Djava.security.egd=file:/dev/./urandom` 是为了防止在 Linux 环境中, 生成首次登陆生成 sessionId 取系统随机数过慢的问题.*
篇幅有限, 更详细的安装教程请参考: [安装文档](http://zhaojun.im/zfile-install)
访问地址:
@@ -68,7 +79,18 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar &
## OneDrive 使用教程.
访问地址进行授权, 获取 accessToken 和 refreshToken: https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=09939809-c617-43c8-a220-a93c1513c5d4&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
访问地址进行授权, 获取 accessToken 和 refreshToken:
国际/家庭/个人版:
https://login.microsoftonline.com/common/oauth2/v2.0/authorize?client_id=09939809-c617-43c8-a220-a93c1513c5d4&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
世纪互联版:
https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?client_id=4a72d927-1907-488d-9eb2-1b465c53c1c5&response_type=code&redirect_uri=https://zfile.jun6.net/onedirve/china-callback&scope=offline_access%20User.Read%20Files.ReadWrite.All
然后分别填写至访问令牌和刷新令牌即可:
@@ -80,6 +102,13 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar &
* 缓存: `caffeine`
* 数据库: `h2/mysql`
## 预览
![前台首页](http://cdn.jun6.net/2020/01/29/a252a5cec7134.png)
![后台设置](http://cdn.jun6.net/2020/01/29/d5c85221bcffc.png)
![存储策略](http://cdn.jun6.net/2020/01/29/4b79bfba4e003.png)
![缓存管理](http://cdn.jun6.net/2020/01/29/60b0538e50f9f.png)
## 常见问题
### 数据库
@@ -93,12 +122,21 @@ nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.7.jar &
### 头尾文件和加密文件
- 目录头部显示文件名为 `header.md`
- 目录底部显示文件名为 `footer.md`
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
## TODO
- 文本预览更换更好用的编辑器
- 后台支持上传、编辑、删除等操作
- API 支持
- 更方便的部署方式
- [x] API 支持 [点击查看文档](https://github.com/zhaojun1998/zfile/blob/master/API.md)
- [x] 更方便的部署方式
- [ ] 文本预览更换更好用的编辑器
- [ ] 后台支持上传、编辑、删除等操作
- [ ] WebDav 支持
- [ ] Docker 支持
## 支持作者
如果本项目对你有帮助,请作者喝杯咖啡吧。
<img src="http://cdn.jun6.net/alipay.png" width="200" height="312">
<img src="http://cdn.jun6.net/wechat.png" width="222" height="300">

23
pom.xml
View File

@@ -12,8 +12,9 @@
<groupId>im.zhaojun</groupId>
<artifactId>zfile</artifactId>
<version>0.7</version>
<version>1.2.1</version>
<name>zfile</name>
<packaging>war</packaging>
<description>一个在线的文件浏览系统</description>
<properties>
@@ -132,6 +133,26 @@
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
<plugin>
<groupId>com.uyoqu.framework</groupId>
<artifactId>maven-plugin-starter</artifactId>
<version>1.0.0</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>bin</goal>
</goals>
</execution>
</executions>
<configuration>
<jvms>
<jvm>-server</jvm>
<jvm>-Xmx512m</jvm>
<jvm>-Djava.security.egd=file:/dev/./urandom</jvm>
</jvms>
</configuration>
</plugin>
</plugins>
</build>

View File

@@ -27,14 +27,15 @@ public class AliyunServiceImpl extends AbstractS3FileService implements FileServ
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ALIYUN);
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_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.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
super.bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());

View File

@@ -6,9 +6,11 @@ import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import im.zhaojun.onedrive.service.OneDriveService;
import im.zhaojun.onedrive.service.OneDriveServiceImpl;
import im.zhaojun.onedrive.service.OneDriveToken;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.china.service.OneDriveServiceChinaImpl;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import im.zhaojun.onedrive.international.service.OneDriveService;
import im.zhaojun.onedrive.international.service.OneDriveServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;
@@ -17,6 +19,7 @@ import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
/**
* @author zhaojun
@@ -32,18 +35,22 @@ public class GlobalScheduleTask {
@Resource
private OneDriveService oneDriveService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@Resource
private SystemConfigService systemConfigService;
/**
* 项目启动 30 秒后, 每半小时执行一次刷新 OneDrive Token 的定时任务.
* 项目启动 30 秒后, 每 15 分支执行一次刷新 OneDrive Token 的定时任务.
*/
@Scheduled(fixedRate = 1000 * 60 * 30, initialDelay = 1000 * 30)
@Scheduled(fixedRate = 1000 * 60 * 15, initialDelay = 1000 * 30)
public void autoRefreshOneDriveToken() {
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
if (!(currentFileService instanceof OneDriveServiceImpl)) {
if (!(currentFileService instanceof OneDriveServiceImpl
|| currentFileService instanceof OneDriveServiceChinaImpl)) {
log.debug("当前启用存储类型, 不是 OneDrive, 跳过自动刷新 AccessToken");
return;
}
@@ -53,23 +60,44 @@ public class GlobalScheduleTask {
return;
}
refreshOneDriveToken();
try {
refreshOneDriveToken(StorageTypeEnum.ONE_DRIVE);
} catch (Exception e) {
log.debug("刷新 OneDrive Token 失败.", e);
}
try {
refreshOneDriveToken(StorageTypeEnum.ONE_DRIVE_CHINA);
} catch (Exception e) {
log.debug("刷新 OneDrive 世纪互联 Token 失败.", e);
}
}
/**
* 调用刷新 OneDrive Token
*/
public void refreshOneDriveToken() {
OneDriveToken refreshToken = oneDriveService.getRefreshToken();
public void refreshOneDriveToken(StorageTypeEnum storageType) {
OneDriveToken refreshToken;
if (Objects.equals(storageType, StorageTypeEnum.ONE_DRIVE_CHINA)) {
refreshToken = oneDriveChinaService.getRefreshToken(storageType);
} else {
refreshToken = oneDriveService.getRefreshToken(storageType);
}
if (refreshToken.getAccessToken() == null || refreshToken.getRefreshToken() == null) {
return;
}
StorageConfig accessTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.ACCESS_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.ACCESS_TOKEN_KEY);
StorageConfig refreshTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.REFRESH_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.REFRESH_TOKEN_KEY);
accessTokenConfig.setValue(refreshToken.getAccessToken());
refreshTokenConfig.setValue(refreshToken.getRefreshToken());
storageConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig));
log.info("刷新 OneDrive key 时间: " + LocalDateTime.now());
log.info("刷新 {} key 时间: {}", storageType.getDescription(), LocalDateTime.now());
}
}

View File

@@ -63,7 +63,9 @@ public class AdminController {
StorageTypeEnum currentStorageStrategy = currentFileService.getStorageTypeEnum();
if (!Objects.equals(currentStorageStrategy, systemConfigDTO.getStorageStrategy())) {
log.info("已将存储策略由 {} 切换为 {}", currentStorageStrategy, systemConfigDTO.getStorageStrategy());
log.info("已将存储策略由 {} 切换为 {}",
currentStorageStrategy.getDescription(),
systemConfigDTO.getStorageStrategy().getDescription());
refreshStorageStrategy();
}

View File

@@ -16,7 +16,6 @@ import java.util.Set;
/**
* @author zhaojun
* @date 2020/1/11 14:03
*/
@RestController
@RequestMapping("/admin/cache")

View File

@@ -10,7 +10,6 @@ import org.springframework.web.bind.annotation.RestController;
/**
* @author zhaojun
* @date 2020/1/13 21:40
*/
@RestController
@RequestMapping("/common")

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.controller;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.annotation.CheckStorageStrategyInit;
import im.zhaojun.common.exception.SearchDisableException;
@@ -54,7 +55,7 @@ public class FileController {
@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) + "/"));
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + path + "/"));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())
&& !HttpUtil.getTextContent(fileItemDTO.getUrl()).equals(password)) {
@@ -77,7 +78,7 @@ public class FileController {
@CheckStorageStrategyInit
@GetMapping("/config")
public ResultBean getConfig(String path) throws Exception {
SiteConfigDTO config = systemService.getConfig(URLUtil.decode(StringUtils.removeDuplicateSeparator("/" + path + "/")));
SiteConfigDTO config = systemService.getConfig(StringUtils.removeDuplicateSeparator("/" + path + "/"));
config.setSystemConfigDTO(systemConfigService.getSystemConfig());
return ResultBean.successData(config);
}
@@ -88,10 +89,10 @@ public class FileController {
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name,
@RequestParam(defaultValue = "name") String sortBy,
@RequestParam(defaultValue = "asc") String order,
@RequestParam(defaultValue = "1") Integer page) throws Exception {
@RequestParam(defaultValue = "1") Integer page) {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
if (!systemConfigDTO.getSearchEnable()) {
if (BooleanUtil.isFalse(systemConfigDTO.getSearchEnable())) {
throw new SearchDisableException("搜索功能未开启");
}
if (!fileAsyncCacheService.isCacheFinish()) {
@@ -112,7 +113,6 @@ public class FileController {
}
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.FOOTER_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.HEADER_FILE_NAME.equals(fileItem.getName()));
}
@@ -134,4 +134,17 @@ public class FileController {
end = Math.min(end, total);
return new ArrayList<>(fileItemList.subList(start, end));
}
/**
* 获取指定路径下的文件信息内容
* @param path 文件全路径
* @return 该文件的名称, 路径, 大小, 下载地址等信息.
*/
@CheckStorageStrategyInit
@GetMapping("/directlink")
public ResultBean directlink(String path) {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
return ResultBean.successData(fileService.getFileItem(path));
}
}

View File

@@ -46,9 +46,9 @@ public class GlobleExceptionHandler {
* 不存在的文件异常
*/
@ExceptionHandler({NotExistFileException.class})
@ResponseStatus(HttpStatus.NOT_FOUND)
public String notExistFile(Exception ex) {
return "error/404";
@ResponseBody
public ResultBean notExistFile(Exception ex) {
return ResultBean.error("文件不存在");
}
/**

View File

@@ -2,7 +2,6 @@ package im.zhaojun.common.exception;
/**
* @author zhaojun
* @date 2020/1/20 22:15
*/
public class NotExistFileException extends RuntimeException {

View File

@@ -27,7 +27,7 @@ public class StorageConfig {
private String title;
@Column(length = 2048)
@Column(length = 4000)
private String value;
public Integer getId() {

View File

@@ -2,7 +2,6 @@ package im.zhaojun.common.model.constant;
/**
* @author zhaojun
* @date 2019/12/28 18:47
*/
public class StorageConfigConstant {
@@ -34,4 +33,8 @@ public class StorageConfigConstant {
public static final String REFRESH_TOKEN_KEY = "refreshToken";
public static final String PATH_STYLE = "pathStyle";
public static final String IS_PRIVATE = "isPrivate";
}

View File

@@ -19,11 +19,6 @@ public class ZFileConstant {
*/
public static String HEADER_FILE_NAME = "header.md";
/**
* 页面尾部文件
*/
public static String FOOTER_FILE_NAME = "footer.md";
/**
* 密码文件
*/
@@ -34,11 +29,6 @@ public class ZFileConstant {
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;

View File

@@ -6,7 +6,6 @@ import java.util.Set;
/**
* @author zhaojun
* @date 2020/1/3 12:39
*/
@Data
public class CacheConfigDTO {

View File

@@ -1,53 +1,23 @@
package im.zhaojun.common.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 header;
private String footer;
@JsonProperty("viewConfig")
private SystemConfigDTO systemConfigDTO;
public String getHeader() {
return header;
}
public void setHeader(String header) {
this.header = header;
}
public String getFooter() {
return footer;
}
public void setFooter(String footer) {
this.footer = footer;
}
public SystemConfigDTO getSystemConfigDTO() {
return systemConfigDTO;
}
public void setSystemConfigDTO(SystemConfigDTO systemConfigDTO) {
this.systemConfigDTO = systemConfigDTO;
}
@Override
public String toString() {
return "SiteConfigDTO{" +
"header='" + header + '\'' +
", footer='" + footer + '\'' +
", systemConfig=" + systemConfigDTO +
'}';
}
}

View File

@@ -37,4 +37,11 @@ public class SystemConfigDTO {
private String domain;
private Boolean enableCache;
private Boolean searchContainEncryptedFile;
private String customJs;
private String customCss;
}

View File

@@ -19,11 +19,14 @@ public enum StorageTypeEnum {
HUAWEI("huawei", "华为云 OBS"),
LOCAL("local", "本地存储"),
MINIO("minio", "MINIO"),
S3("s3", "S3通用协议"),
ONE_DRIVE("onedrive", "OneDrive"),
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
QINIU("qiniu", "七牛云 KODO"),
TENCENT("tencent", "腾讯云 COS"),
UPYUN("upyun", "又拍云 USS");
private String key;
private String description;

View File

@@ -98,6 +98,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
http.cors();
http.csrf().disable();
http.headers().frameOptions().sameOrigin();
}
@Bean

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.service;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.StrUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.RefreshPolicy;
@@ -7,7 +8,9 @@ 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.constant.ZFileConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.util.StringUtils;
@@ -21,13 +24,13 @@ import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
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 extends FileCacheService implements FileService {
@@ -39,6 +42,8 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
protected boolean isInitialized = false;
protected String basePath;
@Resource
private SystemConfigService systemConfigService;
@@ -119,9 +124,8 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
* 搜索文件
* @param name 文件名
* @return 包含该文件名的所有文件或文件夹
* @throws Exception 搜索过程出现的异常
*/
public List<FileItemDTO> search(String name) throws Exception {
public List<FileItemDTO> search(String name) {
List<FileItemDTO> result = new ArrayList<>();
boolean searchIgnoreCase = systemConfigService.getSearchIgnoreCase();
@@ -168,7 +172,7 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
List<FileItemDTO> cacheList = cache.get(filePath);
if (cacheList != null) {
if (cacheList != null && isNotEncryptedFolder(cacheList)) {
queue.addAll(cacheList);
}
}
@@ -177,12 +181,32 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
return result;
}
/**
* 不是加密文件夹
* @param list 文件夹中的内容
* @return 返回此文件夹是否加密.
*/
private boolean isNotEncryptedFolder(List<FileItemDTO> list) {
// 如果开启了 "搜索包含加密文件" 选项, 则直接返回 true.
SystemConfigDTO systemConfig = systemConfigService.getSystemConfig();
if (BooleanUtil.isFalse(systemConfig.getSearchContainEncryptedFile())) {
return true;
}
// 遍历文件判断是否包含
for (FileItemDTO fileItemDTO : list) {
if (Objects.equals(ZFileConstant.PASSWORD_FILE_NAME, fileItemDTO.getName())) {
return false;
}
}
return true;
}
/**
* 获取所有缓存的 Key, 仅当开启缓存, 且缓存完成时, 可获取.
* @return 所有缓存的 Key
* @throws Exception 可能出现的异常
*/
public Set<String> getCacheKeys() throws Exception {
public Set<String> getCacheKeys() {
if (systemConfigService.getEnableCache() && fileAsyncCacheService.isCacheFinish()) {
Set<String> collect = selectAllFileList().stream().map(fileItemDTO -> {
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
@@ -216,4 +240,6 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
cache.config().setRefreshPolicy(refreshPolicy);
}
public abstract FileItemDTO getFileItem(String path);
}

View File

@@ -1,11 +1,13 @@
package im.zhaojun.common.service;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsRequest;
import com.amazonaws.services.s3.model.ObjectListing;
import com.amazonaws.services.s3.model.S3ObjectSummary;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.util.StringUtils;
@@ -19,7 +21,6 @@ import java.util.Objects;
/**
* @author zhaojun
* @date 2019/12/26 22:26
*/
public abstract class AbstractS3FileService extends AbstractFileService {
@@ -28,14 +29,14 @@ public abstract class AbstractS3FileService extends AbstractFileService {
protected String path;
protected String basePath;
protected String bucketName;
protected String domain;
protected AmazonS3 s3Client;
protected boolean isPrivate;
@Override
public List<FileItemDTO> fileList(String path) {
this.path = path;
@@ -55,7 +56,7 @@ public abstract class AbstractS3FileService extends AbstractFileService {
*/
public List<FileItemDTO> s3FileList(String path) {
path = StringUtils.removeFirstSeparator(path);
String fullPath = StringUtils.removeFirstSeparator(getFullPath());
String fullPath = StringUtils.removeFirstSeparator(StringUtils.getFullPath(basePath, path));
List<FileItemDTO> fileItemList = new ArrayList<>();
ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest(bucketName, fullPath, "", "/", 1000));
@@ -94,6 +95,11 @@ public abstract class AbstractS3FileService extends AbstractFileService {
public String s3ObjectUrl(String 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);
URL url = s3Client.generatePresignedUrl(bucketName, fullPath, expirationDate);
@@ -104,13 +110,13 @@ public abstract class AbstractS3FileService extends AbstractFileService {
return URLUtil.decode(defaultUrl);
}
/**
* 获取 basePath + path 的全路径地址.
* @return basePath + path 的全路径地址.
*/
public String getFullPath() {
String basePath = ObjectUtil.defaultIfNull(this.basePath, "");
String path = ObjectUtil.defaultIfNull(this.path, "");
return StringUtils.removeDuplicateSeparator(basePath + "/" + path);
@Override
public FileItemDTO getFileItem(String path) {
List<FileItemDTO> list = fileList(path);
if (list == null || list.size() == 0) {
throw new NotExistFileException();
}
return list.get(0);
}
}

View File

@@ -1,12 +1,12 @@
package im.zhaojun.common.service;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;
/**
* @author zhaojun
* @date 2020/1/11 14:08
*/
@Service
public class FileCacheService {
@@ -15,6 +15,7 @@ public class FileCacheService {
private SystemConfigService systemConfigService;
@Resource
@Lazy
private FileAsyncCacheService fileAsyncCacheService;
public void enableCache() {

View File

@@ -1,7 +1,7 @@
package im.zhaojun.common.service;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.crypto.SecureUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
@@ -92,7 +92,7 @@ public class SystemConfigService {
}
boolean oldEnableCache = getEnableCache();
boolean curEnableCache = ObjectUtil.defaultIfNull(systemConfigDTO.getEnableCache(), false);
boolean curEnableCache = BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
@@ -146,12 +146,12 @@ public class SystemConfigService {
public boolean getEnableCache() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return ObjectUtil.defaultIfNull(systemConfigDTO.getEnableCache(), false);
return BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
}
public boolean getSearchIgnoreCase() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return ObjectUtil.defaultIfNull(systemConfigDTO.getSearchIgnoreCase(), false);
return BooleanUtil.isTrue(systemConfigDTO.getSearchIgnoreCase());
}

View File

@@ -30,9 +30,7 @@ public class SystemService {
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())) {
if (ZFileConstant.HEADER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setHeader(HttpUtil.getTextContent(fileItemDTO.getUrl()));
}
}

View File

@@ -1,5 +1,7 @@
package im.zhaojun.common.util;
import cn.hutool.core.util.ObjectUtil;
/**
* @author zhaojun
*/
@@ -88,4 +90,14 @@ public class StringUtils {
public static boolean isNotNullOrEmpty(String s) {
return !isNullOrEmpty(s);
}
/**
* 获取 basePath + path 的全路径地址.
* @return basePath + path 的全路径地址.
*/
public static String getFullPath(String basePath, String path) {
basePath = ObjectUtil.defaultIfNull(basePath, "");
path = ObjectUtil.defaultIfNull(path, "");
return StringUtils.removeDuplicateSeparator(basePath + "/" + path);
}
}

View File

@@ -41,7 +41,7 @@ public class FtpServiceImpl extends AbstractFileService implements FileService {
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.FTP);
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String host = stringStorageConfigMap.get(StorageConfigConstant.HOST_KEY).getValue();
String port = stringStorageConfigMap.get(StorageConfigConstant.PORT_KEY).getValue();
String username = stringStorageConfigMap.get(StorageConfigConstant.USERNAME_KEY).getValue();
@@ -90,4 +90,12 @@ public class FtpServiceImpl extends AbstractFileService implements FileService {
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.FTP;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setUrl(getDownloadUrl(path));
return fileItemDTO;
}
}

View File

@@ -27,7 +27,8 @@ public class HuaweiServiceImpl extends AbstractS3FileService implements FileServ
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.HUAWEI);
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();

View File

@@ -1,6 +1,7 @@
package im.zhaojun.local.service;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
@@ -45,7 +46,7 @@ public class LocalServiceImpl extends AbstractFileService implements FileService
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.LOCAL);
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
filePath = stringStorageConfigMap.get(StorageConfigConstant.FILE_PATH_KEY).getValue();
if (Objects.isNull(filePath)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
@@ -105,4 +106,26 @@ public class LocalServiceImpl extends AbstractFileService implements FileService
return StorageTypeEnum.LOCAL;
}
@Override
public FileItemDTO getFileItem(String path) {
String fullPath = StringUtils.concatPath(filePath, path);
File file = new File(fullPath);
if (!file.exists()) {
throw new NotExistFileException();
}
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setType(file.isDirectory() ? FileTypeEnum.FOLDER : FileTypeEnum.FILE);
fileItemDTO.setTime(new Date(file.lastModified()));
fileItemDTO.setSize(file.length());
fileItemDTO.setName(file.getName());
fileItemDTO.setPath(filePath);
if (file.isFile()) {
fileItemDTO.setUrl(getDownloadUrl(path));
}
return fileItemDTO;
}
}

View File

@@ -27,7 +27,8 @@ public class MinIOServiceImpl extends AbstractS3FileService implements FileServi
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.MINIO);
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();

View File

@@ -0,0 +1,54 @@
package im.zhaojun.onedrive.china.service;
import im.zhaojun.onedrive.common.service.AbstractOneDriveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @author zhaojun
*/
@Service
public class OneDriveChinaService extends AbstractOneDriveService {
@Value("${zfile.onedirve-china.clientId}")
private String clientId;
@Value("${zfile.onedirve-china.redirectUri}")
private String redirectUri;
@Value("${zfile.onedirve-china.clientSecret}")
private String clientSecret;
@Value("${zfile.onedirve-china.scope}")
private String scope;
@Override
public String getGraphEndPoint() {
return "microsoftgraph.chinacloudapi.cn";
}
@Override
public String getAuthenticateEndPoint() {
return "login.partner.microsoftonline.cn";
}
@Override
public String getClientId() {
return clientId;
}
@Override
public String getRedirectUri() {
return redirectUri;
}
@Override
public String getClientSecret() {
return clientSecret;
}
@Override
public String getScope() {
return scope;
}
}

View File

@@ -0,0 +1,83 @@
package im.zhaojun.onedrive.china.service;
import im.zhaojun.common.config.GlobalScheduleTask;
import im.zhaojun.common.exception.NotExistFileException;
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.StorageTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author zhaojun
*/
@Service
@Slf4j
public class OneDriveServiceChinaImpl extends AbstractFileService implements FileService {
@Resource
private GlobalScheduleTask globalScheduleTask;
@Resource
private StorageConfigService storageConfigService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessToken = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_TOKEN_KEY).getValue();
String refreshToken = stringStorageConfigMap.get(StorageConfigConstant.REFRESH_TOKEN_KEY).getValue();
super.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
isInitialized = false;
} else {
globalScheduleTask.refreshOneDriveToken(getStorageTypeEnum());
isInitialized = testConnection();
}
} catch (Exception e) {
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
return oneDriveChinaService.list(basePath, path);
}
@Override
public String getDownloadUrl(String path) {
return null;
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.ONE_DRIVE_CHINA;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
try {
fileItemDTO = oneDriveChinaService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
}
}

View File

@@ -1,11 +1,14 @@
package im.zhaojun.onedrive.config;
package im.zhaojun.onedrive.common.config;
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.StorageConfigService;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.international.service.OneDriveService;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
import org.springframework.http.client.ClientHttpRequestInterceptor;
import org.springframework.web.client.RestTemplate;
@@ -14,7 +17,6 @@ import java.util.Collections;
/**
* @author zhaojun
* @date 2020/1/18 17:13
*/
@Configuration
public class OneDriveConfig {
@@ -22,13 +24,32 @@ public class OneDriveConfig {
@Resource
private StorageConfigService storageConfigService;
@Resource
@Lazy
private OneDriveService oneDriveService;
@Resource
@Lazy
private OneDriveChinaService oneDriveChinaService;
@Bean
public RestTemplate oneDriveRestTemplate() {
RestTemplate restTemplate = new RestTemplate();
ClientHttpRequestInterceptor interceptor = (httpRequest, bytes, clientHttpRequestExecution) -> {
String host = httpRequest.getURI().getHost();
StorageTypeEnum type;
if (oneDriveChinaService.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE_CHINA;
} else if (oneDriveService.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE;
} else {
return clientHttpRequestExecution.execute(httpRequest, bytes);
}
StorageConfig accessTokenConfig =
storageConfigService.selectByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.ACCESS_TOKEN_KEY);
storageConfigService.selectByTypeAndKey(type, StorageConfigConstant.ACCESS_TOKEN_KEY);
String tokenValue = String.format("%s %s", "Bearer", accessTokenConfig.getValue());
httpRequest.getHeaders().add("Authorization", tokenValue);
return clientHttpRequestExecution.execute(httpRequest, bytes);
@@ -37,5 +58,4 @@ public class OneDriveConfig {
return restTemplate;
}
}

View File

@@ -1,7 +1,8 @@
package im.zhaojun.onedrive.controller;
package im.zhaojun.onedrive.common.controller;
import im.zhaojun.onedrive.service.OneDriveService;
import im.zhaojun.onedrive.service.OneDriveToken;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import im.zhaojun.onedrive.international.service.OneDriveService;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -19,6 +20,9 @@ public class OneDriveController {
@Resource
private OneDriveService oneDriveService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@GetMapping("/callback")
public String onedriveCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveService.getToken(code);
@@ -27,4 +31,13 @@ public class OneDriveController {
return "callback";
}
@GetMapping("/china-callback")
public String onedriveChinaCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveChinaService.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";
}
}

View File

@@ -1,11 +1,10 @@
package im.zhaojun.onedrive.service;
package im.zhaojun.onedrive.common.model;
import com.alibaba.fastjson.annotation.JSONField;
import lombok.Data;
/**
* @author zhaojun
* @date 2020/1/18 17:28
*/
@Data
public class OneDriveToken {

View File

@@ -0,0 +1,177 @@
package im.zhaojun.onedrive.common.service;
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.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.repository.StorageConfigRepository;
import im.zhaojun.common.util.StringUtils;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import org.springframework.http.ResponseEntity;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.net.URLDecoder;
import java.util.ArrayList;
import java.util.List;
/**
* @author Zhao Jun
* 2020/1/29 11:54
*/
public abstract class AbstractOneDriveService {
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";
@Resource
private RestTemplate oneDriveRestTemplate;
@Resource
private StorageConfigRepository storageConfigRepository;
public OneDriveToken getRefreshToken(StorageTypeEnum storageType) {
StorageConfig refreshStorageConfig =
storageConfigRepository.findByTypeAndKey(storageType, 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);
}
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);
}
public String getUserInfo() {
return oneDriveRestTemplate.getForObject(DRIVER_INFO_URL, String.class);
}
public List<FileItemDTO> list(String basePath, 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) {
requestUrl = URLUtil.decode(nextLink);
}else if ("/".equalsIgnoreCase(fullPath) || "".equalsIgnoreCase(fullPath)) {
requestUrl = DRIVER_ROOT_URL;
} else {
requestUrl = DRIVER_ITEMS_URL;
}
fullPath = StringUtils.removeLastSeparator(fullPath);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, getGraphEndPoint(), fullPath);
String body = responseEntity.getBody();
JSONObject root = JSON.parseObject(body);
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;
}
public FileItemDTO getItem(String path) {
String requestUrl;
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(DRIVER_ITEM_URL, String.class, path);
String body = responseEntity.getBody();
JSONObject fileItem = JSON.parseObject(body);
FileItemDTO fileItemDTO = new FileItemDTO();
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);
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();
}

View File

@@ -0,0 +1,54 @@
package im.zhaojun.onedrive.international.service;
import im.zhaojun.onedrive.common.service.AbstractOneDriveService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
/**
* @author zhaojun
*/
@Service
public class OneDriveService extends AbstractOneDriveService {
@Value("${zfile.onedirve.clientId}")
protected String clientId;
@Value("${zfile.onedirve.redirectUri}")
protected String redirectUri;
@Value("${zfile.onedirve.clientSecret}")
protected String clientSecret;
@Value("${zfile.onedirve.scope}")
protected String scope;
@Override
public String getGraphEndPoint() {
return "graph.microsoft.com";
}
@Override
public String getAuthenticateEndPoint() {
return "login.microsoftonline.com";
}
@Override
public String getClientId() {
return clientId;
}
@Override
public String getRedirectUri() {
return redirectUri;
}
@Override
public String getClientSecret() {
return clientSecret;
}
@Override
public String getScope() {
return scope;
}
}

View File

@@ -1,6 +1,7 @@
package im.zhaojun.onedrive.service;
package im.zhaojun.onedrive.international.service;
import im.zhaojun.common.config.GlobalScheduleTask;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
@@ -18,18 +19,11 @@ import java.util.Map;
/**
* @author zhaojun
* @date 2020/1/12 13:53
*/
@Service
@Slf4j
public class OneDriveServiceImpl extends AbstractFileService implements FileService {
public static final String SYSTEM_ONEDRIVE_CACHE_PREFIX = "zfile-onedrive-cache:";
public static final String SYSTEM_ONEDRIVE_CACHE_ASSESS_TOKEN_KEY = "accessToken";
public static final String SYSTEM_ONEDRIVE_CACHE_REFRESH_TOKEN_KEY = "refreshToken";
@Resource
private GlobalScheduleTask globalScheduleTask;
@@ -43,15 +37,16 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ONE_DRIVE);
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessToken = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_TOKEN_KEY).getValue();
String refreshToken = stringStorageConfigMap.get(StorageConfigConstant.REFRESH_TOKEN_KEY).getValue();
super.basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
if (StringUtils.isEmpty(accessToken) || StringUtils.isEmpty(refreshToken)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
isInitialized = false;
} else {
globalScheduleTask.refreshOneDriveToken();
globalScheduleTask.refreshOneDriveToken(getStorageTypeEnum());
isInitialized = testConnection();
}
} catch (Exception e) {
@@ -61,7 +56,7 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
@Override
public List<FileItemDTO> fileList(String path) {
return oneDriveService.list(path);
return oneDriveService.list(basePath, path);
}
@Override
@@ -73,4 +68,16 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.ONE_DRIVE;
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
try {
fileItemDTO = oneDriveService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
}
}

View File

@@ -1,124 +0,0 @@
package im.zhaojun.onedrive.service;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
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.repository.StorageConfigRepository;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.List;
/**
* @author zhaojun
* @date 2020/1/12 12:17
*/
@Service
public class OneDriveService {
public static final String DRIVER_INFO_URL = "https://graph.microsoft.com/v1.0/drive";
public static final String DRIVER_ROOT_URL = "https://graph.microsoft.com/v1.0/drive/root/children";
public static final String DRIVER_ITEMS_URL = "https://graph.microsoft.com/v1.0/drive/root:{path}:/children";
public static final String AUTHENTICATE_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token";
@Value("${zfile.onedirve.clientId}")
private String clientId;
@Value("${zfile.onedirve.redirectUri}")
private String redirectUri;
@Value("${zfile.onedirve.clientSecret}")
private String clientSecret;
@Value("${zfile.onedirve.scope}")
private String scope;
@Resource
private RestTemplate oneDriveRestTemplate;
@Resource
private StorageConfigRepository storageConfigRepository;
public OneDriveToken getToken(String code) {
String param = "client_id=" + clientId +
"&redirect_uri=" + redirectUri +
"&client_secret=" + clientSecret +
"&code=" + code +
"&scope=" + scope +
"&grant_type=authorization_code";
HttpRequest post = HttpUtil.createPost(AUTHENTICATE_URL);
post.body(param, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public OneDriveToken getRefreshToken() {
StorageConfig refreshStorageConfig =
storageConfigRepository.findByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.REFRESH_TOKEN_KEY);
String param = "client_id=" + clientId +
"&redirect_uri=" + redirectUri +
"&client_secret=" + clientSecret +
"&refresh_token=" + refreshStorageConfig.getValue() +
"&grant_type=refresh_token";
HttpRequest post = HttpUtil.createPost(AUTHENTICATE_URL);
post.body(param, "application/x-www-form-urlencoded");
HttpResponse response = post.execute();
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public String getUserInfo() {
return oneDriveRestTemplate.getForObject(DRIVER_INFO_URL, String.class);
}
public List<FileItemDTO> list(String path) {
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity("/".equalsIgnoreCase(path) ? DRIVER_ROOT_URL : DRIVER_ITEMS_URL, String.class, path);
String body = responseEntity.getBody();
JSONObject root = JSON.parseObject(body);
JSONArray fileList = root.getJSONArray("value");
List<FileItemDTO> result = new ArrayList<>();
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);
}
return result;
}
}

View File

@@ -27,7 +27,8 @@ public class QiniuServiceImpl extends AbstractS3FileService implements FileServi
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.QINIU);
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();

View File

@@ -0,0 +1,68 @@
package im.zhaojun.s3;
import cn.hutool.core.convert.Convert;
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 S3ServiceImpl extends AbstractS3FileService implements FileService {
private static final Logger log = LoggerFactory.getLogger(S3ServiceImpl.class);
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
super.domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).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);
String pathStyle = stringStorageConfigMap.get(StorageConfigConstant.PATH_STYLE).getValue();
boolean isPathStyle = "path-style".equals(pathStyle);
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
isInitialized = false;
} else {
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
s3Client = AmazonS3ClientBuilder.standard()
.withPathStyleAccessEnabled(isPathStyle)
.withCredentials(new AWSStaticCredentialsProvider(credentials))
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "")).build();
isInitialized = testConnection();
}
} catch (Exception e) {
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
}
}
@Override
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.S3;
}
}

View File

@@ -27,7 +27,8 @@ public class TencentServiceImpl extends AbstractS3FileService implements FileSer
@Override
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.TENCENT);
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String secretId = stringStorageConfigMap.get(StorageConfigConstant.SECRET_ID_KEY).getValue();
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();

View File

@@ -3,6 +3,7 @@ package im.zhaojun.upyun.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import com.UpYun;
import im.zhaojun.common.exception.NotExistFileException;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
@@ -44,7 +45,7 @@ public class UpYunServiceImpl extends AbstractFileService implements FileService
public void init() {
try {
Map<String, StorageConfig> stringStorageConfigMap =
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.UPYUN);
storageConfigService.selectStorageConfigMapByKey(getStorageTypeEnum());
String bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
String username = stringStorageConfigMap.get(StorageConfigConstant.USERNAME_KEY).getValue();
String password = stringStorageConfigMap.get(StorageConfigConstant.PASSWORD_KEY).getValue();
@@ -108,4 +109,23 @@ public class UpYunServiceImpl extends AbstractFileService implements FileService
return StorageTypeEnum.UPYUN;
}
@Override
public FileItemDTO getFileItem(String path) {
List<FileItemDTO> list;
try {
int end = path.lastIndexOf("/");
list = fileList(path.substring(0, end));
} catch (Exception e) {
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();
}
}

View File

@@ -11,12 +11,6 @@
"defaultValue": "header.md",
"description": "头部文件 文件名."
},
{
"name": "zfile.constant.footer",
"type": "java.lang.String",
"defaultValue": "footer.md",
"description": "尾部文件 文件名."
},
{
"name": "zfile.constant.password",
"type": "java.lang.String",

View File

@@ -8,6 +8,12 @@ server:
enabled: true
spring:
h2:
console:
settings:
web-allow-others: true
path: /h2-console
enabled: false
datasource:
# 初始化数据导入
data: classpath*:db/data.sql
@@ -45,13 +51,17 @@ zfile:
timeout: 300
constant:
header: header.md
footer: footer.md
password: password.txt
onedirve:
clientId: 09939809-c617-43c8-a220-a93c1513c5d4
clientSecret: _l:zI-_yrW75lV8M61K@z.I2K@B/On6Q
redirectUri: https://zfile.jun6.net/onedirve/callback
scope: offline_access User.Read Files.ReadWrite.All
onedirve-china:
clientId: 4a72d927-1907-488d-9eb2-1b465c53c1c5
clientSecret: Y9CEA=82da5n-y_]KAWAgLH3?R9xf7Uw
redirectUri: https://zfile.jun6.net/onedirve/china-callback
scope: offline_access User.Read Files.ReadWrite.All
jetcache:
statIntervalMinutes: 0

View File

@@ -7,7 +7,9 @@ INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (6, 'username', '管理
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (7, 'password', '管理员密码');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (8, 'domain', '站点域名');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (9, 'enableCache', '是否开启缓存');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (10, 'searchContainEncryptedFile', '搜索包含加密文件');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (11, 'customCss', '自定义 CSS');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (12, 'customJs', '自定义 JS (可用于统计代码)');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (1, 'bucket-name', '云存储服务名称', 'upyun');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (2, 'username', '操作员名称', 'upyun');
@@ -49,6 +51,18 @@ INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (37, 'endPoint',
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (38, 'base-path', '基路径', 'qiniu');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (39, 'base-path', '基路径', 'aliyun');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (40, 'base-path', '基路径', 'huawei');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (41, 'ftp', '基路径', 'ftp');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (41, 'base-path', '基路径', 'ftp');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (42, 'accessToken', '访问令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (43, 'refreshToken', '刷新令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (43, 'refreshToken', '刷新令牌', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (44, 'accessToken', '访问令牌', 'onedrive-china');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (45, 'refreshToken', '刷新令牌', 'onedrive-china');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (46, 'accessKey', 'AccessKey', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (47, 'secretKey', 'SecretKey', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (48, 'endPoint', '服务地址(EndPoint)', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (49, 'bucket-name', '存储空间名称', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (50, 'base-path', '基路径', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (51, 'domain', '加速域名', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (52, 'pathStyle', '域名风格', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (53, 'isPrivate', '是否是私有空间', 's3');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (54, 'base-path', '基路径', 'onedrive');
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (55, 'base-path', '基路径', 'onedrive-china');

View File

@@ -1 +0,0 @@
.el-menu[data-v-0d38e212],.el-row[data-v-0d38e212]{height:100vh}

View File

@@ -0,0 +1 @@
.el-menu[data-v-d26ac70e],.el-row[data-v-d26ac70e]{height:100vh}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title></title><link href=/css/adminIndex.25eab1c6.css rel=prefetch><link href=/css/install.b4e8b552.css rel=prefetch><link href=/js/adminIndex.456ac23a.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.f6845f54.js rel=prefetch><link href=/css/app.a731b1dd.css rel=preload as=style><link href=/css/chunk-vendors.39edcc5c.css rel=preload as=style><link href=/js/app.e0beab33.js rel=preload as=script><link href=/js/chunk-vendors.065da641.js rel=preload as=script><link href=/css/chunk-vendors.39edcc5c.css rel=stylesheet><link href=/css/app.a731b1dd.css rel=stylesheet></head><body><noscript><strong>We're sorry but zfile doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.065da641.js></script><script src=/js/app.e0beab33.js></script></body></html>
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><title></title><link href=/css/adminIndex.9c87dd59.css rel=prefetch><link href=/css/install.b4e8b552.css rel=prefetch><link href=/js/adminIndex.f735b8ee.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.6a075002.js rel=prefetch><link href=/css/app.a2e3ef88.css rel=preload as=style><link href=/css/chunk-vendors.6ed6dc12.css rel=preload as=style><link href=/js/app.9d145c66.js rel=preload as=script><link href=/js/chunk-vendors.1f42ad6f.js rel=preload as=script><link href=/css/chunk-vendors.6ed6dc12.css rel=stylesheet><link href=/css/app.a2e3ef88.css rel=stylesheet></head><body><noscript><strong>We're sorry but zfile doesn't work properly without JavaScript enabled. Please enable it to continue.</strong></noscript><div id=app></div><script src=/js/chunk-vendors.1f42ad6f.js></script><script src=/js/app.9d145c66.js></script></body></html>

View File

@@ -1 +0,0 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["adminIndex"],{7869:function(t,e,a){},adf4:function(t,e,a){"use strict";a.r(e);var i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("el-row",[a("el-col",{attrs:{span:3}},[a("el-menu",{staticClass:"el-menu-vertical-demo",attrs:{"default-active":"/admin"!==this.$route.path?this.$route.path:"/admin/site",router:!0}},[a("el-menu-item",{attrs:{index:"/admin/site"}},[a("i",{staticClass:"el-icon-setting"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("站点设置")])]),a("el-menu-item",{attrs:{index:"/admin/storage"}},[a("i",{staticClass:"el-icon-s-operation"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("存储策略")])]),a("el-menu-item",{attrs:{index:"/admin/password"}},[a("i",{staticClass:"el-icon-key"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("修改密码")])]),a("el-menu-item",{attrs:{index:"/admin/cache"}},[a("i",{staticClass:"el-icon-collection"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("缓存管理")])])],1)],1),a("el-col",{attrs:{span:16}},[a("keep-alive",{attrs:{exclude:"CacheManager,SiteSetting"}},[a("router-view")],1)],1)],1)},s=[],n={name:"Index",data:function(){return{active:"/admin/storage"}}},l=n,o=(a("f2cb"),a("2877")),r=Object(o["a"])(l,i,s,!1,null,"0d38e212",null);e["default"]=r.exports},f2cb:function(t,e,a){"use strict";var i=a("7869"),s=a.n(i);s.a}}]);

View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["adminIndex"],{"197f":function(t,e,a){"use strict";var i=a("9e7d"),s=a.n(i);s.a},"9e7d":function(t,e,a){},adf4:function(t,e,a){"use strict";a.r(e);var i=function(){var t=this,e=t.$createElement,a=t._self._c||e;return a("el-row",[a("el-col",{attrs:{span:3}},[a("el-menu",{staticClass:"el-menu-vertical-demo",attrs:{"default-active":"/admin"!==this.$route.path?this.$route.path:"/admin/site",router:!0}},[a("el-menu-item",{attrs:{index:"/admin/site"}},[a("i",{staticClass:"el-icon-setting"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("站点设置")])]),a("el-menu-item",{attrs:{index:"/admin/storage"}},[a("i",{staticClass:"el-icon-s-operation"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("存储策略")])]),a("el-menu-item",{attrs:{index:"/admin/password"}},[a("i",{staticClass:"el-icon-key"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("修改密码")])]),a("el-menu-item",{attrs:{index:"/admin/cache"}},[a("i",{staticClass:"el-icon-collection"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("缓存管理")])]),a("el-menu-item",{attrs:{index:"/admin/api"}},[a("i",{staticClass:"el-icon-document"}),a("span",{attrs:{slot:"title"},slot:"title"},[t._v("API 文档")])])],1)],1),a("el-col",{attrs:{span:16}},[a("keep-alive",{attrs:{exclude:"CacheManager,SiteSetting"}},[a("router-view")],1)],1)],1)},s=[],n={name:"Index",data:function(){return{active:"/admin/storage"}}},l=n,o=(a("197f"),a("2877")),r=Object(o["a"])(l,i,s,!1,null,"d26ac70e",null);e["default"]=r.exports}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -6,12 +6,12 @@
</head>
<body>
<h1>accessToken</h1>
<h1>accessToken (访问令牌)</h1>
<div>
<input type="text" th:value="${accessToken}">
</div>
<h1>refreshToken</h1>
<h1>refreshToken (刷新令牌)</h1>
<div>
<input type="text" th:value="${refreshToken}">
</div>