Compare commits

..

42 Commits
0.9 ... 1.5

Author SHA1 Message Date
zhaojun1998
0b4a38218c 🔖 发布 1.5 版 2020-02-15 18:25:41 +08:00
zhaojun1998
2f57c5b5cc 新增功能: 自定义表格大小, 显示操作按钮, 显示文档, 公告信息 2020-02-15 18:22:37 +08:00
zhaojun1998
610f68295f 📝 更新页面 2020-02-15 18:22:01 +08:00
zhaojun1998
39ced8eb84 📝 更新页面 2020-02-15 18:05:43 +08:00
zhaojun1998
368b7a1df2 优化排序方式为自然排序 2020-02-14 20:22:22 +08:00
zhaojun1998
8e2107cd46 📝 更新开发计划 2020-02-11 18:27:34 +08:00
zhaojun1998
fa32a33371 📝 更新页面 2020-02-09 21:49:27 +08:00
zhaojun1998
59116a9414 🔖 发布 1.4.1 版 2020-02-09 21:47:27 +08:00
zhaojun1998
b2c732a389 🐛 修复 URL 中包含特殊字符, 返回 400 错误的 BUG. 2020-02-09 21:35:25 +08:00
zhaojun1998
0e1ffef92b 🔖 发布 1.4 版 2020-02-09 18:06:50 +08:00
zhaojun1998
a5b19d3577 新增获取直链下载功能. 2020-02-09 18:06:42 +08:00
zhaojun1998
185c84dd79 新增获取直链下载功能. 2020-02-09 18:05:56 +08:00
zhaojun1998
d554dd298c 优化 OneDrive 相关代码结构. 2020-02-09 18:05:01 +08:00
zhaojun1998
aa6ecf0aaa 优化 OneDrive 相关代码结构. 2020-02-09 18:04:33 +08:00
zhaojun1998
83692718e3 📝 更新页面 2020-02-09 18:01:57 +08:00
zhaojun1998
030bd95941 🔖 发布 1.3 版 2020-02-08 17:47:37 +08:00
zhaojun1998
8722d11ac3 📝 更新页面 2020-02-08 17:46:33 +08:00
zhaojun1998
0131ff02c0 🐛 修复头部文件和密码文件, 在开启缓存的状态下, 仅第一次生效的 BUG. 2020-02-08 17:43:02 +08:00
zhaojun1998
2d115bf1c6 更改本地存储, 文件下载时, 文件不存在的响应状态码为 404. 2020-02-08 17:14:01 +08:00
zhaojun1998
946113216d 🔖 发布 1.2.1 版 2020-02-03 20:57:07 +08:00
zhaojun1998
77b05c6dac 🐛 修复 OneDrive 的 Token 某些情况下, 可能超出 2000 字符的 BUG 2020-02-03 20:52:49 +08:00
zhaojun1998
07c9fca210 🔖 发布 1.2 版 2020-02-01 21:54:32 +08:00
zhaojun1998
27cf61693a 更新前端页面, 修复搜索模式下无法进入文件夹和滚动加载的 BUG 2020-02-01 21:54:20 +08:00
zhaojun1998
37e1aa1fec 🐛 修复 OneDrive 文件夹包含特殊符号时, 获取下一页数据 URL 中重复进行了 URL 编码的 BUG. 2020-02-01 21:51:15 +08:00
zhaojun1998
31b54a3c05 调整 OneDrive Token 自动刷新时间为 15 分钟. 2020-02-01 21:50:08 +08:00
zhaojun1998
589f07c103 🔖 发布 1.1 版 2020-01-31 11:52:27 +08:00
zhaojun1998
fe8b60d873 调整日志级别 2020-01-31 11:52:21 +08:00
zhaojun1998
1734619eac 📝 更新页面 2020-01-31 11:50:55 +08:00
zhaojun1998
f5724dc9ab OneDrive 基础路径支持 2020-01-31 11:21:36 +08:00
zhaojun1998
f7bb147b71 📝 更新文档 2020-01-30 19:31:50 +08:00
zhaojun1998
47fc1bc2df 🔖 发布 1.0 版 2020-01-30 18:06:09 +08:00
zhaojun1998
45172f69ba 📝 更新文档 2020-01-30 18:05:56 +08:00
zhaojun1998
9566b138ff 📝 更新页面 2020-01-30 17:58:26 +08:00
zhaojun1998
e15b6c2242 更新配置文件, 增加 h2 console, 便与调试. 2020-01-30 16:52:20 +08:00
zhaojun1998
acc41511e0 S3 协议新增是否为私有空间支持 2020-01-30 16:51:05 +08:00
zhaojun1998
b882b87405 数据库文件初始化更新, 新增 S3 通用协议支持 2020-01-30 16:50:37 +08:00
zhaojun1998
518b5170ae 优化代码 2020-01-30 16:48:37 +08:00
zhaojun1998
8bfac6d9ac 新增 S3 协议通用支持 2020-01-30 16:47:58 +08:00
zhaojun1998
3ffdb4f1b2 清洁代码 2020-01-30 16:47:03 +08:00
zhaojun1998
47509450a0 📝 更新文档, 修改 Debian/Ubuntu 安装命令. 2020-01-29 18:47:38 +08:00
zhaojun1998
812fd18aac 🐛 修复 OneDrive 世纪互联版自动刷新 REFRESH_TOKEN 失败的 BUG 2020-01-29 16:24:00 +08:00
zhaojun1998
77a13cf8ad 📝 更新文档, 新增预览图片 2020-01-29 13:56:20 +08:00
59 changed files with 780 additions and 329 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": {
"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 片段
}
}
}
```

View File

@@ -16,7 +16,7 @@
* 内存缓存 (免安装)
* 内存数据库 (免安装)
* 个性化配置
* 自定义目录的 header 说明文件
* 自定义目录的 readme 说明文件
* 自定义 JS, CSS
* 文件夹密码
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
@@ -35,15 +35,17 @@ yum install -y java-1.8.0-openjdk unzip
# Debian/Ubuntu系统
apt update
apt install -y default-jdk unzip
apt install -y openjdk-8-jre-headless unzip
```
> 如为更新程序, 则请先执行 `rm -rf ~/zfile` 清理旧程序. 首次安装请忽略此选项.
下载项目:
```bash
wget -P ~ https://c.jun6.net/ZFILE/zfile-0.9.war
wget -P ~ https://c.jun6.net/ZFILE/zfile-release.war
cd ~
mkdir zfile && unzip zfile-0.9.war -d zfile && rm -rf zfile-0.9.war
mkdir zfile && unzip zfile-release.war -d zfile && rm -rf zfile-release.war
chmod +x ~/zfile/bin/*.sh
```
@@ -64,26 +66,7 @@ chmod +x ~/zfile/bin/*.sh
~/zfile/bin/start.sh
```
停止项目:
```bash
~/zfile/bin/stop.sh
```
重启项目:
```bash
~/zfile/bin/restart.sh
```
修改配置文件:
```bash
vim ~/zfile/WEB-INF/classes/application.yml
```
> 默认启动端口为 8080, 如需请配置文件请编辑上述文件, 修改后重启程序生效.
篇幅有限, 更详细的安装教程请参考: [安装文档](http://zhaojun.im/zfile-install)
访问地址:
@@ -119,6 +102,13 @@ https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?client_id=4a72d927-1
* 缓存: `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)
## 常见问题
### 数据库
@@ -129,18 +119,27 @@ https://login.chinacloudapi.cn/common/oauth2/v2.0/authorize?client_id=4a72d927-1
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录, windows 为 `C:/Users/用户名/`, linux 为 `/home/用户名/`, root 用户为 `/root/`
### 头尾文件和加密文件
### 文档文件和加密文件
- 目录头部显示文件名为 `header.md`
- 目录文档显示文件名为 `readme.md`
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
## TODO
- 文本预览更换更好用的编辑器
- 后台支持上传、编辑、删除等操作
- API 支持
- 更方便的部署方式
## 开发计划
- [x] API 支持 [点击查看文档](https://github.com/zhaojun1998/zfile/blob/master/API.md)
- [x] 更方便的部署方式
- [ ] 新功能 - 后台支持上传、编辑、删除等操作
- [ ] 新功能 - WebDav 支持
- [ ] 新功能 - Docker 支持
- [ ] 新功能 - 离线下载 (aria2)
- [ ] 体验优化 - 文本预览更换 vscode 同款编辑器 monaco editor
- [ ] 体验优化 - 忽略文件列表 (正则表达式)
- [ ] 体验优化 - 自定义支持预览的文件后缀 (正则表达式)
- [ ] 布局优化 - 底部增加固定栏, 用于填写备案信息, 友情链接等信息.
- [ ] 布局优化 - 自定义操作按钮 (现为右键实现)
- [ ] 后台优化 - 设置按照其功能进行分离
- [ ] 架构调整 - 支持多存储策略
- [ ] 体验优化 - 一键安装脚本
## 支持作者

View File

@@ -12,7 +12,7 @@
<groupId>im.zhaojun</groupId>
<artifactId>zfile</artifactId>
<version>0.9</version>
<version>1.5</version>
<name>zfile</name>
<packaging>war</packaging>
<description>一个在线的文件浏览系统</description>

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

@@ -1,15 +1,10 @@
package im.zhaojun.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.AbstractFileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
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.china.service.OneDriveChinaServiceImpl;
import im.zhaojun.onedrive.international.service.OneDriveServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Configuration;
@@ -18,7 +13,6 @@ import org.springframework.scheduling.annotation.Scheduled;
import javax.annotation.Resource;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.Objects;
/**
@@ -33,24 +27,24 @@ public class GlobalScheduleTask {
private StorageConfigService storageConfigService;
@Resource
private OneDriveService oneDriveService;
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
private OneDriveChinaService oneDriveChinaService;
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
@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
|| currentFileService instanceof OneDriveServiceChinaImpl)) {
|| currentFileService instanceof OneDriveChinaServiceImpl)) {
log.debug("当前启用存储类型, 不是 OneDrive, 跳过自动刷新 AccessToken");
return;
}
@@ -77,27 +71,11 @@ public class GlobalScheduleTask {
* 调用刷新 OneDrive Token
*/
public void refreshOneDriveToken(StorageTypeEnum storageType) {
OneDriveToken refreshToken;
if (Objects.equals(storageType, StorageTypeEnum.ONE_DRIVE_CHINA)) {
refreshToken = oneDriveChinaService.getRefreshToken();
oneDriveChinaServiceImpl.refreshOneDriveToken();
} else {
refreshToken = oneDriveService.getRefreshToken();
oneDriveServiceImpl.refreshOneDriveToken();
}
if (refreshToken.getAccessToken() == null || refreshToken.getRefreshToken() == null) {
return;
}
StorageConfig accessTokenConfig =
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.ACCESS_TOKEN_KEY);
StorageConfig refreshTokenConfig =
storageConfigService.selectByTypeAndKey(storageType, StorageConfigConstant.REFRESH_TOKEN_KEY);
accessTokenConfig.setValue(refreshToken.getAccessToken());
refreshTokenConfig.setValue(refreshToken.getRefreshToken());
storageConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig));
log.info("刷新 {} key 时间: {}", storageType.getDescription(), LocalDateTime.now());
}
}

View File

@@ -1,6 +1,9 @@
package im.zhaojun.common.config;
import im.zhaojun.common.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;
@@ -15,4 +18,14 @@ public class WebMvcConfig implements WebMvcConfigurer {
public void addFormatters(FormatterRegistry registry) {
registry.addConverter(new StorageTypeEnumDeSerializerConvert());
}
@Bean
public ServletWebServerFactory webServerFactory() {
TomcatServletWebServerFactory webServerFactory = new TomcatServletWebServerFactory();
webServerFactory.addConnectorCustomizers(connector -> {
connector.setAttribute("relaxedPathChars", "<>[\\]^`{|}");
connector.setAttribute("relaxedQueryChars", "<>[\\]^`{|}");
});
return webServerFactory;
}
}

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

@@ -23,6 +23,8 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
/**
@@ -72,7 +74,7 @@ public class FileController {
/**
* 获取系统配置信息和当前页的标题, 文件头, 文件尾信息
* 获取系统配置信息和当前页的标题, 页面文档信息
* @param path 路径
*/
@CheckStorageStrategyInit
@@ -105,7 +107,7 @@ public class FileController {
/**
* 过滤文件列表, 不显示密码, 头部和尾部文件.
* 过滤文件列表, 不显示密码, 文档文件.
*/
private void filterFileList(List<FileItemDTO> fileItemList) {
if (fileItemList == null) {
@@ -113,16 +115,19 @@ public class FileController {
}
fileItemList.removeIf(fileItem -> ZFileConstant.PASSWORD_FILE_NAME.equals(fileItem.getName())
|| ZFileConstant.HEADER_FILE_NAME.equals(fileItem.getName()));
|| ZFileConstant.README_FILE_NAME.equals(fileItem.getName()));
}
private List<FileItemDTO> getSortedPagingData(List<FileItemDTO> fileItemList, Integer page) {
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
fileItemList.sort(new FileComparator());
filterFileList(fileItemList);
ArrayList<FileItemDTO> copy = new ArrayList<>(Arrays.asList(new FileItemDTO[fileItemList.size()]));
Collections.copy(copy, fileItemList);
int total = fileItemList.size();
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
copy.sort(new FileComparator());
filterFileList(copy);
int total = copy.size();
int totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
if (page > totalPage) {
@@ -132,7 +137,7 @@ public class FileController {
int start = (page - 1) * PAGE_SIZE;
int end = page * PAGE_SIZE;
end = Math.min(end, total);
return new ArrayList<>(fileItemList.subList(start, end));
return new ArrayList<>(copy.subList(start, end));
}

View File

@@ -0,0 +1,63 @@
package im.zhaojun.common.controller;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.SystemConfigService;
import org.springframework.stereotype.Controller;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.servlet.HandlerMapping;
import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.net.MalformedURLException;
import java.util.Objects;
/**
* @author Zhao Jun
* 2020/2/9 11:17
*/
@Controller
public class PageController {
@Resource
private SystemConfigService systemConfigService;
@GetMapping("/directlink/**")
public String directlink(final HttpServletRequest request) throws MalformedURLException {
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) != '/') {
filePath = "/" + filePath;
}
AbstractFileService fileService = systemConfigService.getCurrentFileService();
FileItemDTO fileItem = fileService.getFileItem(filePath);
String url = fileItem.getUrl();
int queryIndex = url.indexOf('?');
if (queryIndex != -1) {
String origin = url.substring(0, queryIndex);
String queryString = url.substring(queryIndex + 1);
url = URLUtil.encode(origin) + "?" + URLUtil.encode(queryString);
} else {
url = URLUtil.encode(url);
}
if (Objects.equals(fileItem.getType(), FileTypeEnum.FOLDER)) {
return "redirect:" + fileItem.getUrl();
} else {
return "redirect:" + url;
}
}
}

View File

@@ -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

@@ -15,9 +15,9 @@ public class ZFileConstant {
public static final String AUDIO_TMP_PATH = "/.zfile/tmp/audio/";
/**
* 页面头部文件
* 页面文档文件
*/
public static String HEADER_FILE_NAME = "header.md";
public static String README_FILE_NAME = "readme.md";
/**
* 密码文件
@@ -25,8 +25,8 @@ public class ZFileConstant {
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;
public void setHeaderFileName(@Value("${zfile.constant.readme}") String headerFileName) {
ZFileConstant.README_FILE_NAME = headerFileName;
}
@Autowired(required = false)

View File

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

View File

@@ -15,7 +15,7 @@ public class SiteConfigDTO implements Serializable {
private static final long serialVersionUID = 8811196207046121740L;
private String header;
private String readme;
@JsonProperty("viewConfig")
private SystemConfigDTO systemConfigDTO;

View File

@@ -44,4 +44,15 @@ public class SystemConfigDTO {
private String customCss;
private String tableSize;
private Boolean showOperator;
private Boolean showDocument;
private String announcement;
private Boolean showAnnouncement;
private String layout;
}

View File

@@ -19,6 +19,7 @@ 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"),

View File

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

View File

@@ -31,7 +31,6 @@ import java.util.stream.Collectors;
/**
* @author zhaojun
* @date 2019/12/28 19:27
*/
@Slf4j
public abstract class AbstractFileService extends FileCacheService implements FileService {
@@ -43,6 +42,8 @@ public abstract class AbstractFileService extends FileCacheService implements Fi
protected boolean isInitialized = false;
protected String basePath;
@Resource
private SystemConfigService systemConfigService;

View File

@@ -1,6 +1,6 @@
package im.zhaojun.common.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.BooleanUtil;
import cn.hutool.core.util.URLUtil;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.ListObjectsRequest;
@@ -20,7 +20,6 @@ import java.util.Objects;
/**
* @author zhaojun
* @date 2019/12/26 22:26
*/
public abstract class AbstractS3FileService extends AbstractFileService {
@@ -29,14 +28,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;
@@ -56,7 +55,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));
@@ -95,6 +94,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);
@@ -105,23 +109,23 @@ 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) {
List<FileItemDTO> list;
try {
int end = path.lastIndexOf("/");
list = fileList(path.substring(0, end + 1));
} catch (Exception e) {
throw new NotExistFileException();
}
return list.get(0);
for (FileItemDTO fileItemDTO : list) {
String fullPath = StringUtils.concatUrl(fileItemDTO.getPath(), fileItemDTO.getName());
if (Objects.equals(fullPath, path)) {
return fileItemDTO;
}
}
throw new NotExistFileException();
}
}

View File

@@ -7,7 +7,6 @@ import javax.annotation.Resource;
/**
* @author zhaojun
* @date 2020/1/11 14:08
*/
@Service
public class FileCacheService {

View File

@@ -20,7 +20,7 @@ public class SystemService {
private SystemConfigService systemConfigService;
/**
* 构建指定路径下标题, 页头, 页尾
* 构建指定路径下标题, 页面文档信息
* @param path 路径
*/
public synchronized SiteConfigDTO getConfig(String path) throws Exception {
@@ -30,8 +30,8 @@ public class SystemService {
List<FileItemDTO> fileItemList = new ArrayList<>(fileService.fileList(path));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.HEADER_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setHeader(HttpUtil.getTextContent(fileItemDTO.getUrl()));
if (ZFileConstant.README_FILE_NAME.equalsIgnoreCase(fileItemDTO.getName())) {
siteConfigDTO.setReadme(HttpUtil.getTextContent(fileItemDTO.getUrl()));
}
}
return siteConfigDTO;

View File

@@ -37,16 +37,15 @@ public class FileComparator implements Comparator<FileItemDTO> {
if (order == null) {
order = "asc";
}
FileTypeEnum o1Type = o1.getType();
FileTypeEnum o2Type = o2.getType();
NaturalOrderComparator naturalOrderComparator = new NaturalOrderComparator();
if (o1Type.equals(o2Type)) {
int result;
switch (sortBy) {
case "time": result = o1.getTime().compareTo(o2.getTime()); break;
case "size": result = o1.getSize().compareTo(o2.getSize()); break;
default: result = o1.getName().compareToIgnoreCase(o2.getName()); break;
default: result = naturalOrderComparator.compare(o1.getName(), o2.getName()); break;
}
return "asc".equals(order) ? result : -result;
}
@@ -57,4 +56,4 @@ public class FileComparator implements Comparator<FileItemDTO> {
return 1;
}
}
}
}

View File

@@ -0,0 +1,142 @@
package im.zhaojun.common.util;
/*
NaturalOrderComparator.java -- Perform 'natural order' comparisons of strings in Java.
Copyright (C) 2003 by Pierre-Luc Paour <natorder@paour.com>
Based on the C version by Martin Pool, of which this is more or less a straight conversion.
Copyright (C) 2000 by Martin Pool <mbp@humbug.org.au>
This software is provided 'as-is', without any express or implied
warranty. In no event will the authors be held liable for any damages
arising from the use of this software.
Permission is granted to anyone to use this software for any purpose,
including commercial applications, and to alter it and redistribute it
freely, subject to the following restrictions:
1. The origin of this software must not be misrepresented; you must not
claim that you wrote the original software. If you use this software
in a product, an acknowledgment in the product documentation would be
appreciated but is not required.
2. Altered source versions must be plainly marked as such, and must not be
misrepresented as being the original software.
3. This notice may not be removed or altered from any source distribution.
*/
import java.util.Comparator;
public class NaturalOrderComparator implements Comparator<String> {
private int compareRight(String a, String b) {
int bias = 0, ia = 0, ib = 0;
// The longest run of digits wins. That aside, the greatest
// value wins, but we can't know that it will until we've scanned
// both numbers to know that they have the same magnitude, so we
// remember it in BIAS.
for (; ; ia++, ib++) {
char ca = charAt(a, ia);
char cb = charAt(b, ib);
if (!isDigit(ca) && !isDigit(cb)) {
return bias;
}
if (!isDigit(ca)) {
return -1;
}
if (!isDigit(cb)) {
return +1;
}
if (ca == 0 && cb == 0) {
return bias;
}
if (bias == 0) {
if (ca < cb) {
bias = -1;
} else if (ca > cb) {
bias = +1;
}
}
}
}
public int compare(String a, String b) {
int ia = 0, ib = 0;
int nza = 0, nzb = 0;
char ca, cb;
while (true) {
// Only count the number of zeroes leading the last number compared
nza = nzb = 0;
ca = charAt(a, ia);
cb = charAt(b, ib);
// skip over leading spaces or zeros
while (Character.isSpaceChar(ca) || ca == '0') {
if (ca == '0') {
nza++;
} else {
// Only count consecutive zeroes
nza = 0;
}
ca = charAt(a, ++ia);
}
while (Character.isSpaceChar(cb) || cb == '0') {
if (cb == '0') {
nzb++;
} else {
// Only count consecutive zeroes
nzb = 0;
}
cb = charAt(b, ++ib);
}
// Process run of digits
if (Character.isDigit(ca) && Character.isDigit(cb)) {
int bias = compareRight(a.substring(ia), b.substring(ib));
if (bias != 0) {
return bias;
}
}
if (ca == 0 && cb == 0) {
// The strings compare the same. Perhaps the caller
// will want to call strcmp to break the tie.
return compareEqual(a, b, nza, nzb);
}
if (ca < cb) {
return -1;
}
if (ca > cb) {
return +1;
}
++ia;
++ib;
}
}
private static boolean isDigit(char c) {
return Character.isDigit(c) || c == '.' || c == ',';
}
private static char charAt(String s, int i) {
return i >= s.length() ? 0 : s.charAt(i);
}
private static int compareEqual(String a, String b, int nza, int nzb) {
if (nza - nzb != 0)
return nza - nzb;
if (a.length() == b.length())
return a.compareTo(b);
return a.length() - b.length();
}
}

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();

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,11 +1,11 @@
package im.zhaojun.local.controller;
import cn.hutool.core.util.URLUtil;
import im.zhaojun.common.exception.NotExistFileException;
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.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
@@ -30,7 +30,7 @@ public class LocalController {
@GetMapping("/file/**")
@ResponseBody
public ResponseEntity<FileSystemResource> downAttachment(final HttpServletRequest request) {
public ResponseEntity<Object> 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);
@@ -40,10 +40,10 @@ public class LocalController {
return export(new File(StringUtils.concatPath(localServiceImpl.getFilePath(), URLUtil.decode(filePath))));
}
private ResponseEntity<FileSystemResource> export(File file) {
private ResponseEntity<Object> export(File file) {
if (!file.exists()) {
throw new NotExistFileException();
return ResponseEntity.status(HttpStatus.NOT_FOUND).body("404 FILE NOT FOUND");
}

View File

@@ -46,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());

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

@@ -1,54 +0,0 @@
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

@@ -1,29 +1,26 @@
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 im.zhaojun.onedrive.common.service.AbstractOneDriveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author zhaojun
* @date 2020/1/12 13:53
*/
@Service
@Slf4j
public class OneDriveServiceChinaImpl extends AbstractFileService implements FileService {
public class OneDriveChinaServiceImpl extends AbstractOneDriveService implements FileService {
@Resource
private GlobalScheduleTask globalScheduleTask;
@@ -31,8 +28,17 @@ public class OneDriveServiceChinaImpl extends AbstractFileService implements Fil
@Resource
private StorageConfigService storageConfigService;
@Resource
private OneDriveChinaService oneDriveChinaService;
@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 void init() {
@@ -41,12 +47,13 @@ public class OneDriveServiceChinaImpl extends AbstractFileService implements Fil
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());
refreshOneDriveToken();
isInitialized = testConnection();
}
} catch (Exception e) {
@@ -54,11 +61,6 @@ public class OneDriveServiceChinaImpl extends AbstractFileService implements Fil
}
}
@Override
public List<FileItemDTO> fileList(String path) {
return oneDriveChinaService.list(path);
}
@Override
public String getDownloadUrl(String path) {
return null;
@@ -70,14 +72,32 @@ public class OneDriveServiceChinaImpl extends AbstractFileService implements Fil
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
public String getGraphEndPoint() {
return "microsoftgraph.chinacloudapi.cn";
}
try {
fileItemDTO = oneDriveChinaService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
@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

@@ -4,8 +4,8 @@ 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 im.zhaojun.onedrive.china.service.OneDriveChinaServiceImpl;
import im.zhaojun.onedrive.international.service.OneDriveServiceImpl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Lazy;
@@ -17,7 +17,6 @@ import java.util.Collections;
/**
* @author zhaojun
* @date 2020/1/18 17:13
*/
@Configuration
public class OneDriveConfig {
@@ -27,11 +26,11 @@ public class OneDriveConfig {
@Resource
@Lazy
private OneDriveService oneDriveService;
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
@Lazy
private OneDriveChinaService oneDriveChinaService;
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
@Bean
public RestTemplate oneDriveRestTemplate() {
@@ -40,9 +39,9 @@ public class OneDriveConfig {
ClientHttpRequestInterceptor interceptor = (httpRequest, bytes, clientHttpRequestExecution) -> {
String host = httpRequest.getURI().getHost();
StorageTypeEnum type;
if (oneDriveChinaService.getGraphEndPoint().contains(host)) {
if (oneDriveChinaServiceImpl.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE_CHINA;
} else if (oneDriveService.getGraphEndPoint().contains(host)) {
} else if (oneDriveServiceImpl.getGraphEndPoint().contains(host)) {
type = StorageTypeEnum.ONE_DRIVE;
} else {
return clientHttpRequestExecution.execute(httpRequest, bytes);

View File

@@ -1,8 +1,8 @@
package im.zhaojun.onedrive.common.controller;
import im.zhaojun.onedrive.china.service.OneDriveChinaService;
import im.zhaojun.onedrive.china.service.OneDriveChinaServiceImpl;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import im.zhaojun.onedrive.international.service.OneDriveService;
import im.zhaojun.onedrive.international.service.OneDriveServiceImpl;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
@@ -18,14 +18,14 @@ import javax.annotation.Resource;
public class OneDriveController {
@Resource
private OneDriveService oneDriveService;
private OneDriveServiceImpl oneDriveServiceImpl;
@Resource
private OneDriveChinaService oneDriveChinaService;
private OneDriveChinaServiceImpl oneDriveChinaServiceImpl;
@GetMapping("/callback")
public String onedriveCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveService.getToken(code);
OneDriveToken oneDriveToken = oneDriveServiceImpl.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";
@@ -34,7 +34,7 @@ public class OneDriveController {
@GetMapping("/china-callback")
public String onedriveChinaCallback(String code, Model model) {
OneDriveToken oneDriveToken = oneDriveChinaService.getToken(code);
OneDriveToken oneDriveToken = oneDriveChinaServiceImpl.getToken(code);
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
return "callback";

View File

@@ -5,7 +5,6 @@ import lombok.Data;
/**
* @author zhaojun
* @date 2020/1/18 17:28
*/
@Data
public class OneDriveToken {

View File

@@ -1,5 +1,6 @@
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;
@@ -10,8 +11,9 @@ 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.service.AbstractFileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import im.zhaojun.onedrive.common.model.OneDriveToken;
import org.springframework.http.ResponseEntity;
@@ -19,13 +21,14 @@ import org.springframework.web.client.RestTemplate;
import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* @author Zhao Jun
* 2020/1/29 11:54
*/
public abstract class AbstractOneDriveService {
public abstract class AbstractOneDriveService extends AbstractFileService {
protected static final String DRIVER_INFO_URL = "https://{graphEndPoint}/v1.0/me/drives";
@@ -43,9 +46,12 @@ public abstract class AbstractOneDriveService {
@Resource
private StorageConfigRepository storageConfigRepository;
@Resource
private StorageConfigService storageConfigService;
public OneDriveToken getRefreshToken() {
StorageConfig refreshStorageConfig =
storageConfigRepository.findByTypeAndKey(StorageTypeEnum.ONE_DRIVE, StorageConfigConstant.REFRESH_TOKEN_KEY);
storageConfigRepository.findByTypeAndKey(this.getStorageTypeEnum(), StorageConfigConstant.REFRESH_TOKEN_KEY);
String param = "client_id=" + getClientId() +
"&redirect_uri=" + getRedirectUri() +
@@ -77,13 +83,15 @@ public abstract class AbstractOneDriveService {
return JSONObject.parseObject(response.body(), OneDriveToken.class);
}
public String getUserInfo() {
return oneDriveRestTemplate.getForObject(DRIVER_INFO_URL, String.class);
}
public List<FileItemDTO> list(String path) {
@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;
@@ -92,15 +100,15 @@ public abstract class AbstractOneDriveService {
String requestUrl;
if (nextLink != null) {
requestUrl = nextLink;
}else if ("/".equalsIgnoreCase(path)) {
requestUrl = URLUtil.decode(nextLink);
}else if ("/".equalsIgnoreCase(fullPath) || "".equalsIgnoreCase(fullPath)) {
requestUrl = DRIVER_ROOT_URL;
} else {
requestUrl = DRIVER_ITEMS_URL;
}
path = StringUtils.removeLastSeparator(path);
fullPath = StringUtils.removeLastSeparator(fullPath);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, getGraphEndPoint(), path);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, getGraphEndPoint(), fullPath);
String body = responseEntity.getBody();
JSONObject root = JSON.parseObject(body);
@@ -132,11 +140,14 @@ public abstract class AbstractOneDriveService {
return result;
}
@Override
public FileItemDTO getFileItem(String path) {
String fullPath = StringUtils.getFullPath(basePath, path);
public FileItemDTO getItem(String path) {
String requestUrl;
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(DRIVER_ITEM_URL, String.class, path);
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(DRIVER_ITEM_URL, String.class, getGraphEndPoint(), fullPath);
String body = responseEntity.getBody();
JSONObject fileItem = JSON.parseObject(body);
@@ -169,4 +180,21 @@ public abstract class AbstractOneDriveService {
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.selectByTypeAndKey(this.getStorageTypeEnum(), StorageConfigConstant.ACCESS_TOKEN_KEY);
StorageConfig refreshTokenConfig =
storageConfigService.selectByTypeAndKey(this.getStorageTypeEnum(), StorageConfigConstant.REFRESH_TOKEN_KEY);
accessTokenConfig.setValue(refreshToken.getAccessToken());
refreshTokenConfig.setValue(refreshToken.getRefreshToken());
storageConfigService.updateStorageConfig(Arrays.asList(accessTokenConfig, refreshTokenConfig));
}
}

View File

@@ -1,54 +0,0 @@
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,29 +1,26 @@
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;
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.onedrive.common.service.AbstractOneDriveService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
/**
* @author zhaojun
* @date 2020/1/12 13:53
*/
@Service
@Slf4j
public class OneDriveServiceImpl extends AbstractFileService implements FileService {
public class OneDriveServiceImpl extends AbstractOneDriveService implements FileService {
@Resource
private GlobalScheduleTask globalScheduleTask;
@@ -31,8 +28,17 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
@Resource
private StorageConfigService storageConfigService;
@Resource
private OneDriveService oneDriveService;
@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 void init() {
@@ -41,12 +47,13 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
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());
refreshOneDriveToken();
isInitialized = testConnection();
}
} catch (Exception e) {
@@ -54,11 +61,6 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
}
}
@Override
public List<FileItemDTO> fileList(String path) {
return oneDriveService.list(path);
}
@Override
public String getDownloadUrl(String path) {
return null;
@@ -70,14 +72,32 @@ public class OneDriveServiceImpl extends AbstractFileService implements FileServ
}
@Override
public FileItemDTO getFileItem(String path) {
FileItemDTO fileItemDTO ;
try {
fileItemDTO = oneDriveService.getItem(path);
} catch (Exception e) {
throw new NotExistFileException();
}
return fileItemDTO;
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

@@ -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

@@ -45,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();

View File

@@ -6,10 +6,10 @@
"description": "目录缓存过期时间 和 下载地址过期时间. 单位为秒."
},
{
"name": "zfile.constant.header",
"name": "zfile.constant.readme",
"type": "java.lang.String",
"defaultValue": "header.md",
"description": "头部文件 文件名."
"defaultValue": "readme.md",
"description": "文档文件 文件名."
},
{
"name": "zfile.constant.password",

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
@@ -44,7 +50,7 @@ zfile:
cache:
timeout: 300
constant:
header: header.md
readme: readme.md
password: password.txt
onedirve:
clientId: 09939809-c617-43c8-a220-a93c1513c5d4

View File

@@ -10,6 +10,12 @@ 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 SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (13, 'tableSize', '表格大小');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (14, 'showOperator', '是否显示操作按钮');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (15, 'showDocument', '是否显示文档');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (16, 'announcement', '网站公告');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (17, 'showAnnouncement', '是否显示网站公告');
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (18, 'layout', '页面布局');
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');
@@ -51,8 +57,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 (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 (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-7f233ce7],.el-row[data-v-7f233ce7]{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.22664175.css rel=preload as=style><link href=/css/chunk-vendors.39edcc5c.css rel=preload as=style><link href=/js/app.ce8716ec.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.22664175.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.ce8716ec.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.a8c53261.css rel=prefetch><link href=/css/install.b4e8b552.css rel=prefetch><link href=/js/adminIndex.0916d17e.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.0f6d1155.js rel=prefetch><link href=/css/app.398136f5.css rel=preload as=style><link href=/css/chunk-vendors.cb63319e.css rel=preload as=style><link href=/js/app.945e1d35.js rel=preload as=script><link href=/js/chunk-vendors.d1dab075.js rel=preload as=script><link href=/css/chunk-vendors.cb63319e.css rel=stylesheet><link href=/css/app.398136f5.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.d1dab075.js></script><script src=/js/app.945e1d35.js></script></body></html>

View File

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

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}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long