mirror of
https://github.com/zfile-dev/zfile.git
synced 2025-04-19 05:34:52 +00:00
Compare commits
140 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
4c914793b0 | ||
|
|
5698cfb2d3 | ||
|
|
3cd5f8f9a7 | ||
|
|
76747771de | ||
|
|
cfacd39210 | ||
|
|
90cd13f2c3 | ||
|
|
018a68246e | ||
|
|
b6a2e3ccb8 | ||
|
|
38b811f8e6 | ||
|
|
6922fa2195 | ||
|
|
4bca6cf7a5 | ||
|
|
c3484426ab | ||
|
|
0455bd366c | ||
|
|
bbe3c053f8 | ||
|
|
f47708f45d | ||
|
|
2e7a7b8cec | ||
|
|
9e067dbce9 | ||
|
|
a4a236e488 | ||
|
|
7d5b0431f5 | ||
|
|
a758c8cc6d | ||
|
|
21a64ec0f3 | ||
|
|
3f241d129a | ||
|
|
fa5f16c61f | ||
|
|
492b22506d | ||
|
|
a12f685340 | ||
|
|
2ee3f3dd66 | ||
|
|
245937e773 | ||
|
|
aef34facbd | ||
|
|
14bb5e15e3 | ||
|
|
12371f06dd | ||
|
|
28e43e968f | ||
|
|
669b413ff0 | ||
|
|
f32e5e8f9e | ||
|
|
3719378614 | ||
|
|
40c759078e | ||
|
|
e37e778e1a | ||
|
|
031607402a | ||
|
|
6c9150466c | ||
|
|
be633ebe1a | ||
|
|
9715cf922a | ||
|
|
f6163c7e19 | ||
|
|
dcc4cb19ad | ||
|
|
ad0ad12c08 | ||
|
|
74c935cdf0 | ||
|
|
1876e692f2 | ||
|
|
f198b34324 | ||
|
|
3095e0c8d9 | ||
|
|
594246127d | ||
|
|
f6c5f7a91b | ||
|
|
2a765fff7e | ||
|
|
28f958878b | ||
|
|
368f3a90eb | ||
|
|
98b14abbfc | ||
|
|
7c04c3d6b8 | ||
|
|
921cb1a115 | ||
|
|
9371968c3b | ||
|
|
47e88849ac | ||
|
|
2f0f41f413 | ||
|
|
7667765abc | ||
|
|
b2a2e69af5 | ||
|
|
7c729a72e2 | ||
|
|
5495abc881 | ||
|
|
797cd4fc06 | ||
|
|
8148d182cf | ||
|
|
7e8cab90d0 | ||
|
|
4d5743dc0b | ||
|
|
1a326cc17d | ||
|
|
cc993d8e65 | ||
|
|
f128882034 | ||
|
|
31dbb902c3 | ||
|
|
c849057aaa | ||
|
|
7b288b795c | ||
|
|
316566d479 | ||
|
|
e01ce28eb8 | ||
|
|
9b7528b61c | ||
|
|
bd22cfd34c | ||
|
|
4aa9839c6b | ||
|
|
5eeea23703 | ||
|
|
6997b15dd0 | ||
|
|
326c954c36 | ||
|
|
ba5801bea2 | ||
|
|
e2b0c29e2d | ||
|
|
845a380a7e | ||
|
|
87229f225e | ||
|
|
de947e510c | ||
|
|
2a367afc37 | ||
|
|
5fb945cebc | ||
|
|
7acedfef38 | ||
|
|
5e198b7ce7 | ||
|
|
c3e7e622e2 | ||
|
|
aec73f5cc7 | ||
|
|
9236f11044 | ||
|
|
02973a3c21 | ||
|
|
e60c64c8fc | ||
|
|
52db0c1515 | ||
|
|
0ab2f3b015 | ||
|
|
dd588fe218 | ||
|
|
dce1b42e8e | ||
|
|
0e9dd7d5a8 | ||
|
|
f5bebd2500 | ||
|
|
6a54150868 | ||
|
|
099c09b625 | ||
|
|
45e117a05a | ||
|
|
14ba1027ae | ||
|
|
04a2ff9542 | ||
|
|
040e92a433 | ||
|
|
c739878890 | ||
|
|
65616e045b | ||
|
|
9aaf1494b1 | ||
|
|
74eaaad72d | ||
|
|
b65ccc95e2 | ||
|
|
e334acd508 | ||
|
|
844cbcc03a | ||
|
|
debaa72938 | ||
|
|
d293105521 | ||
|
|
8e7d4432a3 | ||
|
|
0e6bcbfa11 | ||
|
|
e8122b4ed0 | ||
|
|
b3a0f4585b | ||
|
|
12bae1ef53 | ||
|
|
4d9357b11f | ||
|
|
2aa9ccc389 | ||
|
|
d81d795095 | ||
|
|
9af89ecd8c | ||
|
|
bb381a98b9 | ||
|
|
14828e7f34 | ||
|
|
13c091bcf4 | ||
|
|
6842a31402 | ||
|
|
eb99a3e340 | ||
|
|
403dd4f2e1 | ||
|
|
ff7feedb2f | ||
|
|
2861faeacd | ||
|
|
8532e91386 | ||
|
|
83cb080f35 | ||
|
|
682da819a8 | ||
|
|
0c58869158 | ||
|
|
92396c3631 | ||
|
|
6285633ad4 | ||
|
|
7dadb24727 | ||
|
|
3c278cf176 |
21
LICENSE
Normal file
21
LICENSE
Normal file
@@ -0,0 +1,21 @@
|
||||
MIT License
|
||||
|
||||
Copyright (c) 2019 ZhaoJun
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in all
|
||||
copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
SOFTWARE.
|
||||
105
README.md
105
README.md
@@ -1,50 +1,89 @@
|
||||
# Z-File
|
||||
|
||||

|
||||
[](https://www.codacy.com/manual/zhaojun1998/zfile?utm_source=github.com&utm_medium=referral&utm_content=zhaojun1998/zfile&utm_campaign=Badge_Grade)
|
||||

|
||||

|
||||
|
||||
此项目是一个在线文件目录的程序, 支持各种对象存储和本地存储, 使用定位是个人放常用工具下载, 或做公共的文件库. 不会向多账户方向开发.
|
||||
|
||||
前端基于 [h5ai](https://larsjung.de/h5ai/) 的原有功能使用 Vue 重新开发了一遍. 后端采用 SpringBoot, 数据库采用内嵌数据库.
|
||||
|
||||
预览地址: [http://zfile.jun6.net](http://zfile.jun6.net)
|
||||
预览地址: [https://zfile.jun6.net](https://zfile.jun6.net)
|
||||
|
||||
## 系统特色
|
||||
|
||||
* 内存缓存 (免安装)
|
||||
* 内存数据库 (免安装)
|
||||
* 个性化配置
|
||||
* 自定义目录的 header 和 footer 说明文件
|
||||
* 自定义目录的 header 说明文件
|
||||
* 自定义 JS, CSS
|
||||
* 文件夹密码
|
||||
* 支持在线浏览文本文件, 视频, 图片, 音乐.
|
||||
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
|
||||
* 文件/目录二维码
|
||||
* 缓存动态开启, 缓存自动刷新
|
||||
* 全局搜索
|
||||
* 支持 阿里云 OSS, FTP, 华为云 OBS, 本地存储, MINIO, OneDrive 国际/家庭/个人版, OneDrive 世纪互联版, 七牛云 KODO, 腾讯云 COS, 又拍云 USS.
|
||||
|
||||
## 快速开始
|
||||
|
||||
|
||||
安装 JDK 1.8 :
|
||||
安装依赖环境:
|
||||
|
||||
```bash
|
||||
yum instal -y java # 适用于 Centos 7.x
|
||||
```
|
||||
# CentOS系统
|
||||
yum install -y java-1.8.0-openjdk unzip
|
||||
|
||||
> 其他系统的 JDK 安装教程, 后续我也都会补上. 大家也可执行搜索安装方式, 应该不是很难.
|
||||
# Debian/Ubuntu系统
|
||||
apt update
|
||||
apt install -y default-jdk unzip
|
||||
```
|
||||
|
||||
下载项目:
|
||||
|
||||
```bash
|
||||
wget https://github.com/zhaojun1998/zfile/releases/download/0.1/zfile-0.1.jar
|
||||
wget -P ~ https://c.jun6.net/ZFILE/zfile-0.9.war
|
||||
cd ~
|
||||
mkdir zfile && unzip zfile-0.9.war -d zfile && rm -rf zfile-0.9.war
|
||||
chmod +x ~/zfile/bin/*.sh
|
||||
```
|
||||
|
||||
程序的目录结构为:
|
||||
```
|
||||
├── zfile
|
||||
├── META-INF
|
||||
├── WEB-INF
|
||||
└── bin
|
||||
├── start.sh # 启动脚本
|
||||
└── stop.sh # 停止脚本
|
||||
├── restart.sh # 重启脚本
|
||||
```
|
||||
|
||||
启动项目:
|
||||
|
||||
```bash
|
||||
java -jar zfile-0.1.jar
|
||||
|
||||
## 高级启动
|
||||
java -jar zfile-0.1.jar --server.port=18777
|
||||
~/zfile/bin/start.sh
|
||||
```
|
||||
|
||||
> `--server.port` 为指定端口, 默认为 `8080`
|
||||
> 其他参数, 后面我会详细补充至文档, 最晚本周六日.
|
||||
停止项目:
|
||||
|
||||
```bash
|
||||
~/zfile/bin/stop.sh
|
||||
```
|
||||
|
||||
重启项目:
|
||||
|
||||
```bash
|
||||
~/zfile/bin/restart.sh
|
||||
```
|
||||
|
||||
|
||||
修改配置文件:
|
||||
|
||||
```bash
|
||||
vim ~/zfile/WEB-INF/classes/application.yml
|
||||
```
|
||||
|
||||
> 默认启动端口为 8080, 如需请配置文件请编辑上述文件, 修改后重启程序生效.
|
||||
|
||||
访问地址:
|
||||
|
||||
@@ -55,40 +94,58 @@ java -jar zfile-0.1.jar --server.port=18777
|
||||
管理后台: http://127.0.0.1:8080/#/admin
|
||||
|
||||
|
||||
## 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
|
||||
|
||||
|
||||
世纪互联版:
|
||||
|
||||
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
|
||||
|
||||
|
||||
然后分别填写至访问令牌和刷新令牌即可:
|
||||
|
||||

|
||||
|
||||
## 运行环境
|
||||
|
||||
* JDK: `1.8`
|
||||
* 缓存: `caffeine/redis`
|
||||
* 缓存: `caffeine`
|
||||
* 数据库: `h2/mysql`
|
||||
|
||||
## 常见问题
|
||||
|
||||
### 缓存
|
||||
|
||||
缓存默认支持 `caffeine` 和 `redis`, 前者为内存缓存, 无需安装, 但后者相对性能更好.
|
||||
|
||||
### 数据库
|
||||
|
||||
缓存默认支持 `h2` 和 `mysql`, 前者为嵌入式数据库, 无需安装, 但后者相对性能更好.
|
||||
|
||||
|
||||
### 默认路径
|
||||
|
||||
默认 H2 数据库文件地址: `~/.zfile/db/`, `~` 表示用户目录, windows 为 `C:/Users/用户名/`, linux 为 `/home/用户名/`, root 用户为 `/root/`
|
||||
|
||||
|
||||
### 头尾文件和加密文件
|
||||
|
||||
- 目录头部显示文件名为 `header.md`
|
||||
- 目录底部显示文件名为 `footer.md`
|
||||
- 目录需要密码访问, 添加文件 `password.txt` (无法拦截此文件被下载, 但可以改名文件)
|
||||
|
||||
## TODO
|
||||
|
||||
- 全局搜索功能
|
||||
- 文本预览更换更好用的编辑器
|
||||
- 后台支持上传、编辑、删除等操作
|
||||
- API 支持
|
||||
- 更方便的部署方式
|
||||
|
||||
|
||||
## 支持作者
|
||||
|
||||
如果本项目对你有帮助,请作者喝杯咖啡吧。
|
||||
|
||||
|
||||
<img src="http://cdn.jun6.net/alipay.png" width="200" height="312">
|
||||
<img src="http://cdn.jun6.net/wechat.png" width="222" height="300">
|
||||
|
||||
172
pom.xml
172
pom.xml
@@ -12,8 +12,9 @@
|
||||
|
||||
<groupId>im.zhaojun</groupId>
|
||||
<artifactId>zfile</artifactId>
|
||||
<version>0.1</version>
|
||||
<version>0.9</version>
|
||||
<name>zfile</name>
|
||||
<packaging>war</packaging>
|
||||
<description>一个在线的文件浏览系统</description>
|
||||
|
||||
<properties>
|
||||
@@ -21,10 +22,8 @@
|
||||
</properties>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- spring boot 官方相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-web</artifactId>
|
||||
@@ -43,13 +42,25 @@
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-test</artifactId>
|
||||
<scope>test</scope>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-thymeleaf</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 数据库驱动-->
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>io.minio</groupId>
|
||||
<artifactId>minio</artifactId>
|
||||
<version>3.0.10</version>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类 -->
|
||||
@@ -59,80 +70,33 @@
|
||||
<version>4.5.11</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-cache</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.github.ben-manes.caffeine</groupId>
|
||||
<artifactId>caffeine</artifactId>
|
||||
<version>2.7.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 对象存储 API -->
|
||||
<!-- 存储策略相关 API, 对象存储、FTP、 Rest API-->
|
||||
<dependency>
|
||||
<groupId>com.upyun</groupId>
|
||||
<artifactId>java-sdk</artifactId>
|
||||
<version>4.1.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.qiniu</groupId>
|
||||
<artifactId>qiniu-java-sdk</artifactId>
|
||||
<version>7.2.23</version>
|
||||
<groupId>com.amazonaws</groupId>
|
||||
<artifactId>aws-java-sdk-s3</artifactId>
|
||||
<version>1.11.699</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.huaweicloud</groupId>
|
||||
<artifactId>esdk-obs-java</artifactId>
|
||||
<version>3.19.5</version>
|
||||
<groupId>org.apache.httpcomponents</groupId>
|
||||
<artifactId>httpclient</artifactId>
|
||||
<version>4.5.8</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.aliyun.oss</groupId>
|
||||
<artifactId>aliyun-sdk-oss</artifactId>
|
||||
<version>3.5.0</version>
|
||||
</dependency>
|
||||
|
||||
<!-- <dependency>-->
|
||||
<!-- <groupId>org.nuxeo.onedrive</groupId>-->
|
||||
<!-- <artifactId>onedrive-java-client</artifactId>-->
|
||||
<!-- <version>1.0</version>-->
|
||||
<!-- </dependency>-->
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-configuration-processor</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-net</groupId>
|
||||
<artifactId>commons-net</artifactId>
|
||||
<version>3.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.qcloud</groupId>
|
||||
<artifactId>cos_api</artifactId>
|
||||
<version>5.6.3</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.h2database</groupId>
|
||||
<artifactId>h2</artifactId>
|
||||
<scope>runtime</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 其他工具类 -->
|
||||
<dependency>
|
||||
<groupId>org.projectlombok</groupId>
|
||||
<artifactId>lombok</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org</groupId>
|
||||
<artifactId>jaudiotagger</artifactId>
|
||||
<version>2.0.3</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
@@ -142,55 +106,53 @@
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjweaver</artifactId>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
<artifactId>jetcache-starter-redis</artifactId>
|
||||
<version>2.5.14</version>
|
||||
<exclusions>
|
||||
<exclusion>
|
||||
<groupId>com.alicp.jetcache</groupId>
|
||||
<artifactId>jetcache-redis</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>redis.clients</groupId>
|
||||
<artifactId>jedis</artifactId>
|
||||
</exclusion>
|
||||
<exclusion>
|
||||
<groupId>com.esotericsoftware</groupId>
|
||||
<artifactId>kryo</artifactId>
|
||||
</exclusion>
|
||||
</exclusions>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.aspectj</groupId>
|
||||
<artifactId>aspectjrt</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>commons-validator</groupId>
|
||||
<artifactId>commons-validator</artifactId>
|
||||
<version>1.6</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.google.guava</groupId>
|
||||
<artifactId>guava</artifactId>
|
||||
<version>28.1-jre</version>
|
||||
</dependency>
|
||||
|
||||
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
|
||||
<dependency>
|
||||
<groupId>mysql</groupId>
|
||||
<artifactId>mysql-connector-java</artifactId>
|
||||
</dependency>
|
||||
|
||||
|
||||
</dependencies>
|
||||
|
||||
<repositories>
|
||||
<!-- <repository>-->
|
||||
<!-- <id>nuxeo</id>-->
|
||||
<!-- <name>nuxeo</name>-->
|
||||
<!-- <url>http://maven.nuxeo.org/nexus/content/groups/public</url>-->
|
||||
<!-- </repository>-->
|
||||
</repositories>
|
||||
|
||||
<build>
|
||||
<plugins>
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
</plugin>
|
||||
<plugin>
|
||||
<groupId>com.uyoqu.framework</groupId>
|
||||
<artifactId>maven-plugin-starter</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<phase>package</phase>
|
||||
<goals>
|
||||
<goal>bin</goal>
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
<configuration>
|
||||
<jvms>
|
||||
<jvm>-server</jvm>
|
||||
<jvm>-Xmx512m</jvm>
|
||||
<jvm>-Djava.security.egd=file:/dev/./urandom</jvm>
|
||||
</jvms>
|
||||
</configuration>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
|
||||
@@ -1,14 +1,19 @@
|
||||
package im.zhaojun;
|
||||
|
||||
import com.alicp.jetcache.anno.config.EnableCreateCacheAnnotation;
|
||||
import com.alicp.jetcache.anno.config.EnableMethodCache;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
import org.springframework.cache.annotation.EnableCaching;
|
||||
import org.springframework.context.annotation.EnableAspectJAutoProxy;
|
||||
import org.springframework.scheduling.annotation.EnableAsync;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@EnableAsync
|
||||
@SpringBootApplication
|
||||
@EnableCaching
|
||||
@EnableMethodCache(basePackages = "im.zhaojun", proxyTargetClass = true)
|
||||
@EnableCreateCacheAnnotation
|
||||
@EnableAspectJAutoProxy(exposeProxy = true)
|
||||
public class ZfileApplication {
|
||||
|
||||
|
||||
@@ -1,121 +1,54 @@
|
||||
package im.zhaojun.aliyun.service;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.aliyun.oss.OSS;
|
||||
import com.aliyun.oss.OSSClientBuilder;
|
||||
import com.aliyun.oss.model.*;
|
||||
import 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.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
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 im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class AliyunServiceImpl implements FileService {
|
||||
public class AliyunServiceImpl extends AbstractS3FileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(AliyunServiceImpl.class);
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private Long timeout;
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
private static final String SECRET_KEY = "secretKey";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private static final String ENDPOINT_KEY = "endPoint";
|
||||
|
||||
private OSS ossClient;
|
||||
|
||||
private String bucketName;
|
||||
|
||||
private String domain;
|
||||
|
||||
private boolean isPrivate;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ALIYUN);
|
||||
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
|
||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.ALIYUN);
|
||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
||||
|
||||
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
ossClient = new OSSClientBuilder().build(endPoint, accessKey, secretKey);
|
||||
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();
|
||||
|
||||
AccessControlList bucketAcl = ossClient.getBucketAcl(bucketName);
|
||||
CannedAccessControlList cannedAcl = bucketAcl.getCannedACL();
|
||||
isPrivate = "Private".equals(cannedAcl.name());
|
||||
isInitialized = true;
|
||||
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);
|
||||
|
||||
super.s3Client = AmazonS3ClientBuilder.standard()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "oss")).build();
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.ALIYUN.getDescription() + "初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
ObjectListing objectListing =
|
||||
ossClient.listObjects(new ListObjectsRequest(bucketName).withDelimiter("/").withPrefix(path));
|
||||
|
||||
for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(s.getKey().substring(path.length()));
|
||||
fileItemDTO.setSize(s.getSize());
|
||||
fileItemDTO.setTime(s.getLastModified());
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(commonPrefix.substring(path.length(), commonPrefix.length() - 1));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
|
||||
if (isPrivate) {
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
|
||||
URL url = ossClient.generatePresignedUrl(bucketName, path, expirationDate);
|
||||
return URLUtil.complateUrl(domain, url.getFile());
|
||||
} else {
|
||||
return URLUtil.complateUrl(domain, path);
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -124,8 +57,4 @@ public class AliyunServiceImpl implements FileService {
|
||||
return StorageTypeEnum.ALIYUN;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,6 +7,7 @@ import java.lang.annotation.Target;
|
||||
|
||||
/**
|
||||
* 标记注解, 用于在调用前检查是否已存储策略
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Target(ElementType.METHOD)
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
|
||||
@@ -1,13 +1,16 @@
|
||||
package im.zhaojun.common.aspect;
|
||||
|
||||
import im.zhaojun.common.exception.StorageStrategyUninitializedException;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import im.zhaojun.common.util.SpringContextHolder;
|
||||
import org.aspectj.lang.annotation.Aspect;
|
||||
import org.aspectj.lang.annotation.Before;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Aspect
|
||||
@Component
|
||||
public class StorageStrategyInitCheckAspect {
|
||||
@@ -15,11 +18,14 @@ public class StorageStrategyInitCheckAspect {
|
||||
@Before("@annotation(im.zhaojun.common.annotation.CheckStorageStrategyInit)")
|
||||
public void logStart() {
|
||||
SystemConfigService systemConfigService = SpringContextHolder.getBean(SystemConfigService.class);
|
||||
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
|
||||
if (currentStorageStrategy == null) {
|
||||
throw new StorageStrategyUninitializedException("存储策略未初始化");
|
||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
if (currentFileService == null) {
|
||||
throw new StorageStrategyUninitializedException("存储策略尚未初始化, 请联系管理员!");
|
||||
}
|
||||
if (currentFileService.getIsUnInitialized()) {
|
||||
throw new StorageStrategyUninitializedException("存储策略异常, 请联系管理员!");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.io.IOException;
|
||||
|
||||
/**
|
||||
* 开启跨域支持. 一般用于开发环境, 或前后端分离部署时开启.
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class CorsFilter extends GenericFilterBean {
|
||||
|
||||
|
||||
103
src/main/java/im/zhaojun/common/config/GlobalScheduleTask.java
Normal file
103
src/main/java/im/zhaojun/common/config/GlobalScheduleTask.java
Normal file
@@ -0,0 +1,103 @@
|
||||
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.international.service.OneDriveServiceImpl;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.scheduling.annotation.EnableScheduling;
|
||||
import org.springframework.scheduling.annotation.Scheduled;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Arrays;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
@EnableScheduling
|
||||
@Slf4j
|
||||
public class GlobalScheduleTask {
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
@Resource
|
||||
private OneDriveService oneDriveService;
|
||||
|
||||
@Resource
|
||||
private OneDriveChinaService oneDriveChinaService;
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
/**
|
||||
* 项目启动 30 秒后, 每半小时执行一次刷新 OneDrive Token 的定时任务.
|
||||
*/
|
||||
@Scheduled(fixedRate = 1000 * 60 * 30, initialDelay = 1000 * 30)
|
||||
public void autoRefreshOneDriveToken() {
|
||||
|
||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
|
||||
if (!(currentFileService instanceof OneDriveServiceImpl
|
||||
|| currentFileService instanceof OneDriveServiceChinaImpl)) {
|
||||
log.debug("当前启用存储类型, 不是 OneDrive, 跳过自动刷新 AccessToken");
|
||||
return;
|
||||
}
|
||||
|
||||
if (currentFileService.getIsUnInitialized()) {
|
||||
log.debug("当前启用 OneDrive 未初始化成功, 跳过自动刷新 AccessToken");
|
||||
return;
|
||||
}
|
||||
|
||||
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(StorageTypeEnum storageType) {
|
||||
|
||||
OneDriveToken refreshToken;
|
||||
if (Objects.equals(storageType, StorageTypeEnum.ONE_DRIVE_CHINA)) {
|
||||
refreshToken = oneDriveChinaService.getRefreshToken();
|
||||
} else {
|
||||
refreshToken = oneDriveService.getRefreshToken();
|
||||
}
|
||||
|
||||
|
||||
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());
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,7 @@
|
||||
package im.zhaojun.common.config;
|
||||
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import org.springframework.beans.BeansException;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
@@ -9,10 +9,13 @@ import org.springframework.stereotype.Component;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Component
|
||||
public class StorageTypeFactory implements ApplicationContextAware {
|
||||
|
||||
private static Map<String, FileService> storageTypeEnumFileServiceMap;
|
||||
private static Map<String, AbstractFileService> storageTypeEnumFileServiceMap;
|
||||
|
||||
private static ApplicationContext applicationContext;
|
||||
|
||||
@@ -24,15 +27,15 @@ public class StorageTypeFactory implements ApplicationContextAware {
|
||||
applicationContext = act;
|
||||
|
||||
// 获取 Spring 容器中所有 FileService 类型的类
|
||||
storageTypeEnumFileServiceMap = act.getBeansOfType(FileService.class);
|
||||
storageTypeEnumFileServiceMap = act.getBeansOfType(AbstractFileService.class);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取指定存储类型 Service
|
||||
*/
|
||||
public static FileService getStorageTypeService(StorageTypeEnum type) {
|
||||
FileService result = null;
|
||||
for (FileService fileService : storageTypeEnumFileServiceMap.values()) {
|
||||
public static AbstractFileService getStorageTypeService(StorageTypeEnum type) {
|
||||
AbstractFileService result = null;
|
||||
for (AbstractFileService fileService : storageTypeEnumFileServiceMap.values()) {
|
||||
if (fileService.getStorageTypeEnum() == type) {
|
||||
result = fileService;
|
||||
break;
|
||||
|
||||
@@ -5,6 +5,9 @@ import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.format.FormatterRegistry;
|
||||
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
public class WebMvcConfig implements WebMvcConfigurer {
|
||||
|
||||
|
||||
@@ -1,75 +0,0 @@
|
||||
package im.zhaojun.common.config;
|
||||
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
|
||||
import org.springframework.cache.caffeine.CaffeineCacheManager;
|
||||
import org.springframework.cache.interceptor.KeyGenerator;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.data.redis.cache.RedisCacheConfiguration;
|
||||
import org.springframework.data.redis.cache.RedisCacheManager;
|
||||
import org.springframework.data.redis.cache.RedisCacheWriter;
|
||||
import org.springframework.data.redis.connection.RedisConnectionFactory;
|
||||
import org.springframework.data.redis.serializer.GenericJackson2JsonRedisSerializer;
|
||||
import org.springframework.data.redis.serializer.RedisSerializationContext;
|
||||
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* 缓存配置类, 用于根据配置决定使用 redis 缓存还是 caffeine (内存).
|
||||
*/
|
||||
@Configuration
|
||||
public class ZFileCacheConfiguration {
|
||||
|
||||
public static final String CACHE_NAME = "zfile";
|
||||
|
||||
/**
|
||||
* 个性化配置缓存
|
||||
*/
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.cache.type", havingValue = "caffeine")
|
||||
public CaffeineCacheManager caffeineCacheManager() {
|
||||
CaffeineCacheManager caffeineCacheManager = new CaffeineCacheManager();
|
||||
caffeineCacheManager.setCacheNames(Collections.singletonList(CACHE_NAME));
|
||||
return caffeineCacheManager;
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
@ConditionalOnProperty(value = "spring.cache.type", havingValue = "redis")
|
||||
public RedisCacheManager redisCacheManager(RedisConnectionFactory connectionFactory) {
|
||||
RedisCacheWriter redisCacheWriter = RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory);
|
||||
GenericJackson2JsonRedisSerializer jsonRedisSerializer
|
||||
= new GenericJackson2JsonRedisSerializer();
|
||||
RedisSerializationContext.SerializationPair<Object> pair
|
||||
= RedisSerializationContext.SerializationPair.fromSerializer(jsonRedisSerializer);
|
||||
RedisCacheConfiguration defaultCacheConfig=RedisCacheConfiguration.defaultCacheConfig().serializeValuesWith(pair);
|
||||
return new RedisCacheManager(redisCacheWriter, defaultCacheConfig);
|
||||
}
|
||||
|
||||
|
||||
@Bean
|
||||
public KeyGenerator keyGenerator() {
|
||||
return (target, method, params) -> {
|
||||
char separator = ':';
|
||||
StringBuilder strBuilder = new StringBuilder();
|
||||
|
||||
// 类名
|
||||
strBuilder.append(target.getClass().getSimpleName());
|
||||
strBuilder.append(separator);
|
||||
|
||||
// 方法名
|
||||
strBuilder.append(method.getName());
|
||||
strBuilder.append(separator);
|
||||
|
||||
// 参数值
|
||||
for (int i = 0; i < params.length; i++) {
|
||||
if (i == params.length - 1) {
|
||||
strBuilder.append(params[i]);
|
||||
} else {
|
||||
strBuilder.append(params[i]).append(",");
|
||||
}
|
||||
}
|
||||
return strBuilder.toString();
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,9 @@ import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
public class ZFileConfiguration {
|
||||
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
package im.zhaojun.common.controller;
|
||||
|
||||
import im.zhaojun.common.config.StorageTypeFactory;
|
||||
import im.zhaojun.common.model.StorageConfig;
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import im.zhaojun.common.model.dto.StorageStrategyDTO;
|
||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import org.slf4j.Logger;
|
||||
@@ -13,13 +15,18 @@ import org.slf4j.LoggerFactory;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 后台管理
|
||||
* @author zhaojun
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin")
|
||||
@@ -48,6 +55,26 @@ public class AdminController {
|
||||
/**
|
||||
* 更新系统配置
|
||||
*/
|
||||
@PostMapping("/config")
|
||||
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) throws Exception {
|
||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
systemConfigDTO.setId(1);
|
||||
systemConfigService.updateSystemConfig(systemConfigDTO);
|
||||
|
||||
StorageTypeEnum currentStorageStrategy = currentFileService.getStorageTypeEnum();
|
||||
if (!Objects.equals(currentStorageStrategy, systemConfigDTO.getStorageStrategy())) {
|
||||
log.info("已将存储策略由 {} 切换为 {}",
|
||||
currentStorageStrategy.getDescription(),
|
||||
systemConfigDTO.getStorageStrategy().getDescription());
|
||||
refreshStorageStrategy();
|
||||
}
|
||||
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
/**
|
||||
* 修改管理员登陆密码
|
||||
*/
|
||||
@PostMapping("/update-pwd")
|
||||
public ResultBean updatePwd(String username, String password) {
|
||||
systemConfigService.updateUsernameAndPwd(username, password);
|
||||
@@ -55,43 +82,75 @@ public class AdminController {
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新系统配置
|
||||
* 获取指定存储策略的设置
|
||||
* @param storageType 存储策略
|
||||
* @return 所有设置
|
||||
*/
|
||||
@PostMapping("/config")
|
||||
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) {
|
||||
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
|
||||
systemConfigDTO.setId(1);
|
||||
systemConfigService.updateSystemConfig(systemConfigDTO);
|
||||
|
||||
if (!currentStorageStrategy.equals(systemConfigDTO.getStorageStrategy())) {
|
||||
refreshStorageStrategy();
|
||||
}
|
||||
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
|
||||
@GetMapping("/strategy-form")
|
||||
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
|
||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageType);
|
||||
return ResultBean.success(storageConfigList);
|
||||
}
|
||||
|
||||
@GetMapping("/support-strategy")
|
||||
public ResultBean supportStrategy() {
|
||||
List<StorageStrategyDTO> result = new ArrayList<>();
|
||||
StorageTypeEnum[] values = StorageTypeEnum.values();
|
||||
for (StorageTypeEnum value : values) {
|
||||
AbstractFileService storageTypeService = StorageTypeFactory.getStorageTypeService(value);
|
||||
result.add(new StorageStrategyDTO(value.getKey(),
|
||||
value.getDescription(),
|
||||
storageTypeService.getIsInitialized()));
|
||||
}
|
||||
return ResultBean.successData(result);
|
||||
}
|
||||
|
||||
/**
|
||||
* 清理当前启用的存储引擎的缓存
|
||||
* 保存存储策略
|
||||
* @param storageStrategyConfig 保存表单值
|
||||
* @param storageStrategy 所属策略
|
||||
* @return 操作结果
|
||||
* @throws Exception 表单解析出错异常
|
||||
*/
|
||||
@GetMapping("/clear-cache")
|
||||
public ResultBean clearCache() {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.clearCache();
|
||||
return ResultBean.success();
|
||||
@PostMapping("/storage-strategy")
|
||||
public ResultBean save(@RequestParam Map<String, String> storageStrategyConfig, StorageTypeEnum storageStrategy) throws Exception {
|
||||
// 保存设置.
|
||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageStrategy);
|
||||
for (StorageConfig storageConfig : storageConfigList) {
|
||||
String key = storageConfig.getKey();
|
||||
String value = storageStrategyConfig.get(key);
|
||||
storageConfig.setValue(value);
|
||||
}
|
||||
storageConfigService.updateStorageConfig(storageConfigList);
|
||||
|
||||
// 获取当前修改的存储策略 Service, 尝试调用初始化.
|
||||
AbstractFileService updateStorageStrategyService = StorageTypeFactory.getStorageTypeService(storageStrategy);
|
||||
updateStorageStrategyService.init();
|
||||
|
||||
// 如果修改的为当前启用的缓存, 则重新进行缓存.
|
||||
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
if (Objects.equals(storageStrategy, currentStorageStrategy)) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("检测到更新了当前启用的存储策略 {}, 已清理缓存.", currentStorageStrategy);
|
||||
}
|
||||
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.clearFileCache();
|
||||
fileAsyncCacheService.cacheGlobalFile();
|
||||
}
|
||||
|
||||
// 返回是否初始化成功.
|
||||
if (updateStorageStrategyService.getIsInitialized()) {
|
||||
return ResultBean.success();
|
||||
} else {
|
||||
return ResultBean.error("保存成功, 但尝试初始化异常, 请检查设置.");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 更新存储策略
|
||||
*/
|
||||
public void refreshStorageStrategy() {
|
||||
public void refreshStorageStrategy() throws Exception {
|
||||
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
refreshStorageStrategy(storageStrategy);
|
||||
}
|
||||
@@ -99,16 +158,16 @@ public class AdminController {
|
||||
/**
|
||||
* 更新存储策略
|
||||
*/
|
||||
public void refreshStorageStrategy(StorageTypeEnum storageStrategy) {
|
||||
public void refreshStorageStrategy(StorageTypeEnum storageStrategy) throws Exception {
|
||||
if (storageStrategy == null) {
|
||||
log.info("尚未配置存储策略.");
|
||||
} else {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.init();
|
||||
log.info("当前启用存储类型: {}", storageStrategy.getDescription());
|
||||
|
||||
// if 判断是否开启搜索.
|
||||
fileService.clearFileCache();
|
||||
log.info("切换至存储类型: {}", storageStrategy.getDescription());
|
||||
fileAsyncCacheService.cacheGlobalFile();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,81 @@
|
||||
package im.zhaojun.common.controller;
|
||||
|
||||
import im.zhaojun.common.model.dto.CacheConfigDTO;
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
||||
import im.zhaojun.common.service.FileCacheService;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2020/1/11 14:03
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/admin/cache")
|
||||
public class CacheController {
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
private FileAsyncCacheService fileAsyncCacheService;
|
||||
|
||||
@Resource
|
||||
private FileCacheService fileCacheService;
|
||||
|
||||
@PostMapping("/enable")
|
||||
public ResultBean enableCache() throws Exception {
|
||||
fileCacheService.enableCache();
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@PostMapping("/disable")
|
||||
public ResultBean disableCache() throws Exception {
|
||||
fileCacheService.disableCache();
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@GetMapping("/config")
|
||||
public ResultBean cacheConfig() throws Exception {
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
Set<String> cacheKeys = fileService.getCacheKeys();
|
||||
|
||||
CacheConfigDTO cacheConfigDTO = new CacheConfigDTO();
|
||||
cacheConfigDTO.setEnableCache(systemConfigService.getEnableCache());
|
||||
cacheConfigDTO.setCacheFinish(fileAsyncCacheService.isCacheFinish());
|
||||
cacheConfigDTO.setCacheKeys(cacheKeys);
|
||||
cacheConfigDTO.setCacheDirectoryCount(fileAsyncCacheService.getCacheDirectoryCount());
|
||||
cacheConfigDTO.setCacheFileCount(fileAsyncCacheService.getCacheFileCount());
|
||||
return ResultBean.success(cacheConfigDTO);
|
||||
}
|
||||
|
||||
@PostMapping("/refresh")
|
||||
public ResultBean refreshCache(String key) throws Exception {
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.refreshCache(key);
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@PostMapping("/clear")
|
||||
public ResultBean clearCache(String key) throws Exception {
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.clearFileCache();
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@PostMapping("/all")
|
||||
public ResultBean cacheAll() throws Exception {
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.clearFileCache();
|
||||
fileAsyncCacheService.cacheGlobalFile();
|
||||
return ResultBean.success();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
package im.zhaojun.common.controller;
|
||||
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.util.AudioHelper;
|
||||
import im.zhaojun.common.util.HttpUtil;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2020/1/13 21:40
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/common")
|
||||
public class CommonController {
|
||||
|
||||
@GetMapping("/support-strategy")
|
||||
public ResultBean supportStrategy() {
|
||||
return ResultBean.successData(StorageTypeEnum.values());
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件内容, 仅限用于, txt, md, ini 等普通文本文件.
|
||||
* @param url 文件路径
|
||||
* @return 文件内容
|
||||
*/
|
||||
@GetMapping("/content")
|
||||
public ResultBean getContent(String url) {
|
||||
return ResultBean.successData(HttpUtil.getTextContent(url));
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取文件内容, 仅限用于, txt, md, ini 等普通文本文件.
|
||||
* @param url 文件路径
|
||||
* @return 文件内容
|
||||
*/
|
||||
@GetMapping("/content/origin")
|
||||
public String getContentOrigin(String url) {
|
||||
return HttpUtil.getTextContent(url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检测文件是否存在
|
||||
* @param url 文件路径
|
||||
* @return 是否存在
|
||||
*/
|
||||
@GetMapping("/content/exist")
|
||||
public boolean checkFileExist(String url) {
|
||||
return HttpUtil.checkUrlExist(url);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 获取音频文件信息
|
||||
* @param url 文件 URL
|
||||
* @return 音频信息, 标题封面等信息
|
||||
*/
|
||||
@GetMapping("/audio-info")
|
||||
public ResultBean getAudioInfo(String url) throws Exception {
|
||||
return ResultBean.success(AudioHelper.getAudioInfo(url));
|
||||
}
|
||||
}
|
||||
@@ -1,20 +1,18 @@
|
||||
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;
|
||||
import im.zhaojun.common.model.StorageConfig;
|
||||
import im.zhaojun.common.model.constant.ZFileConstant;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import im.zhaojun.common.model.dto.SiteConfigDTO;
|
||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import im.zhaojun.common.service.SystemService;
|
||||
import im.zhaojun.common.util.AudioHelper;
|
||||
import im.zhaojun.common.util.FileComparator;
|
||||
import im.zhaojun.common.util.HttpUtil;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
@@ -29,6 +27,7 @@ import java.util.List;
|
||||
|
||||
/**
|
||||
* 前台文件管理
|
||||
* @author zhaojun
|
||||
*/
|
||||
@RequestMapping("/api")
|
||||
@RestController
|
||||
@@ -41,12 +40,12 @@ public class FileController {
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
private FileAsyncCacheService fileAsyncCacheService;
|
||||
|
||||
/**
|
||||
* 滚动加载每页条数.
|
||||
*/
|
||||
private static final Integer PAGE_SIZE = 20;
|
||||
private static final Integer PAGE_SIZE = 30;
|
||||
|
||||
@CheckStorageStrategyInit
|
||||
@GetMapping("/list")
|
||||
@@ -55,47 +54,22 @@ public class FileController {
|
||||
@RequestParam(defaultValue = "asc") String order,
|
||||
@RequestParam(required = false) String password,
|
||||
@RequestParam(defaultValue = "1") Integer page) throws Exception {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + URLUtil.decode(path) + "/"));
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + path + "/"));
|
||||
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
|
||||
if (!HttpUtil.getTextContent(fileItemDTO.getUrl()).equals(password)) {
|
||||
if (password != null && !"".equals(password)) {
|
||||
return ResultBean.error("密码错误.");
|
||||
}
|
||||
return ResultBean.error("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
|
||||
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())
|
||||
&& !HttpUtil.getTextContent(fileItemDTO.getUrl()).equals(password)) {
|
||||
if (password != null && !"".equals(password)) {
|
||||
return ResultBean.error("密码错误.");
|
||||
}
|
||||
return ResultBean.error("此文件夹需要密码.", ResultBean.REQUIRED_PASSWORD);
|
||||
}
|
||||
}
|
||||
|
||||
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
|
||||
fileItemList.sort(new FileComparator(sortBy, order));
|
||||
filterFileList(fileItemList);
|
||||
|
||||
Integer total = fileItemList.size();
|
||||
Integer totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
|
||||
if (page > totalPage) {
|
||||
return ResultBean.successData(new ArrayList<>());
|
||||
}
|
||||
|
||||
Integer start = (page - 1) * PAGE_SIZE;
|
||||
Integer end = page * PAGE_SIZE;
|
||||
end = end > total ? total : end;
|
||||
List<FileItemDTO> fileSubItem = fileItemList.subList(start, end);
|
||||
return ResultBean.successData(fileSubItem);
|
||||
List<FileItemDTO> sortedPagingData = getSortedPagingData(fileItemList, page);
|
||||
return ResultBean.successData(sortedPagingData);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取文件类容, 仅限用于, txt, md, ini 等普通文本文件.
|
||||
* @param url 文件路径
|
||||
* @return 文件内容
|
||||
*/
|
||||
@CheckStorageStrategyInit
|
||||
@GetMapping("/content")
|
||||
public ResultBean getContent(String url) {
|
||||
return ResultBean.successData(HttpUtil.getTextContent(url));
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取系统配置信息和当前页的标题, 文件头, 文件尾信息
|
||||
@@ -104,45 +78,31 @@ 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);
|
||||
}
|
||||
|
||||
@CheckStorageStrategyInit
|
||||
@GetMapping("/clearCache")
|
||||
public ResultBean clearCache() {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
if (fileService != null) {
|
||||
fileService.clearCache();
|
||||
}
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@CheckStorageStrategyInit
|
||||
@GetMapping("/audioInfo")
|
||||
public ResultBean getAudioInfo(String url) throws Exception {
|
||||
return ResultBean.success(AudioHelper.getAudioInfo(url));
|
||||
}
|
||||
|
||||
@CheckStorageStrategyInit
|
||||
@GetMapping("/search")
|
||||
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name) throws Exception {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name,
|
||||
@RequestParam(defaultValue = "name") String sortBy,
|
||||
@RequestParam(defaultValue = "asc") String order,
|
||||
@RequestParam(defaultValue = "1") Integer page) {
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
|
||||
if (!systemConfigDTO.getSearchEnable()) {
|
||||
if (BooleanUtil.isFalse(systemConfigDTO.getSearchEnable())) {
|
||||
throw new SearchDisableException("搜索功能未开启");
|
||||
}
|
||||
return ResultBean.success(fileService.search(URLUtil.decode(name)));
|
||||
if (!fileAsyncCacheService.isCacheFinish()) {
|
||||
throw new SearchDisableException("搜索功能缓存预热中, 请稍后再试");
|
||||
}
|
||||
List<FileItemDTO> fileItemList = fileService.search(URLUtil.decode(name));
|
||||
List<FileItemDTO> sortedPagingData = getSortedPagingData(fileItemList, page);
|
||||
return ResultBean.successData(sortedPagingData);
|
||||
}
|
||||
|
||||
@GetMapping("/form")
|
||||
public ResultBean getFormByStorageType(String storageType) {
|
||||
StorageTypeEnum storageTypeEnum = StorageTypeEnum.getEnum(storageType);
|
||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageTypeEnum);
|
||||
storageConfigList.forEach(storageConfig -> storageConfig.setValue(null));
|
||||
return ResultBean.success(storageConfigList);
|
||||
}
|
||||
|
||||
/**
|
||||
* 过滤文件列表, 不显示密码, 头部和尾部文件.
|
||||
@@ -153,8 +113,38 @@ 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()));
|
||||
}
|
||||
|
||||
|
||||
private List<FileItemDTO> getSortedPagingData(List<FileItemDTO> fileItemList, Integer page) {
|
||||
// 排序, 先按照文件类型比较, 文件夹在前, 文件在后, 然后根据 sortBy 字段排序, 默认为升序;
|
||||
fileItemList.sort(new FileComparator());
|
||||
filterFileList(fileItemList);
|
||||
|
||||
int total = fileItemList.size();
|
||||
int totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
|
||||
|
||||
if (page > totalPage) {
|
||||
return new ArrayList<>();
|
||||
}
|
||||
|
||||
int start = (page - 1) * PAGE_SIZE;
|
||||
int end = page * PAGE_SIZE;
|
||||
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));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,24 +6,21 @@ import im.zhaojun.common.model.dto.InstallModelDTO;
|
||||
import im.zhaojun.common.model.dto.ResultBean;
|
||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.service.SystemConfigService;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* 系统安装初始化
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Controller
|
||||
@RestController
|
||||
public class InstallController {
|
||||
|
||||
@Resource
|
||||
@@ -36,7 +33,6 @@ public class InstallController {
|
||||
private AdminController adminController;
|
||||
|
||||
@GetMapping("/is-installed")
|
||||
@ResponseBody
|
||||
public ResultBean isInstall() {
|
||||
if (systemConfigService.getCurrentStorageStrategy() == null) {
|
||||
return ResultBean.success();
|
||||
@@ -46,8 +42,7 @@ public class InstallController {
|
||||
|
||||
|
||||
@PostMapping("/install")
|
||||
@ResponseBody
|
||||
public ResultBean install(InstallModelDTO installModelDTO) {
|
||||
public ResultBean install(InstallModelDTO installModelDTO) throws Exception {
|
||||
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
|
||||
|
||||
if (systemConfigDTO.getStorageStrategy() != null) {
|
||||
@@ -76,24 +71,13 @@ public class InstallController {
|
||||
return ResultBean.success();
|
||||
}
|
||||
|
||||
@PostMapping("/storage-strategy")
|
||||
@ResponseBody
|
||||
public ResultBean save(@RequestParam Map<String, String> storageStrategyConfig, StorageTypeEnum storageStrategy) {
|
||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageStrategy);
|
||||
for (StorageConfig storageConfig : storageConfigList) {
|
||||
String key = storageConfig.getKey();
|
||||
String value = storageStrategyConfig.get(key);
|
||||
storageConfig.setValue(value);
|
||||
}
|
||||
storageConfigService.updateStorageConfig(storageConfigList);
|
||||
|
||||
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
if (Objects.equals(storageStrategy, currentStorageStrategy)) {
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
fileService.clearCache();
|
||||
fileService.init();
|
||||
}
|
||||
|
||||
return ResultBean.success();
|
||||
@GetMapping("/form")
|
||||
public ResultBean getFormByStorageType(String storageType) {
|
||||
StorageTypeEnum storageTypeEnum = StorageTypeEnum.getEnum(storageType);
|
||||
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageTypeEnum);
|
||||
storageConfigList.forEach(storageConfig -> storageConfig.setValue(null));
|
||||
return ResultBean.success(storageConfigList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,14 +13,15 @@ import org.springframework.web.bind.annotation.ResponseStatus;
|
||||
|
||||
/**
|
||||
* 全局异常处理器
|
||||
* @author zhaojun
|
||||
*/
|
||||
@ControllerAdvice
|
||||
@ResponseBody
|
||||
public class GlobleExceptionHandler {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(GlobleExceptionHandler.class);
|
||||
|
||||
@ExceptionHandler(SearchDisableException.class)
|
||||
@ResponseBody
|
||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ResultBean searchDisableExceptionHandler(SearchDisableException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -31,6 +32,7 @@ public class GlobleExceptionHandler {
|
||||
|
||||
|
||||
@ExceptionHandler
|
||||
@ResponseBody
|
||||
@ResponseStatus
|
||||
public ResultBean searchDisableExceptionHandler(StorageStrategyUninitializedException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
@@ -39,6 +41,16 @@ public class GlobleExceptionHandler {
|
||||
return ResultBean.error(e.getMessage());
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 不存在的文件异常
|
||||
*/
|
||||
@ExceptionHandler({NotExistFileException.class})
|
||||
@ResponseBody
|
||||
public ResultBean notExistFile(Exception ex) {
|
||||
return ResultBean.error("文件不存在");
|
||||
}
|
||||
|
||||
/**
|
||||
* 捕获 ClientAbortException 异常, 不做任何处理, 防止出现大量堆栈日志输出, 此异常不影响功能.
|
||||
*/
|
||||
@@ -52,6 +64,7 @@ public class GlobleExceptionHandler {
|
||||
}
|
||||
|
||||
@ExceptionHandler
|
||||
@ResponseBody
|
||||
@ResponseStatus(code= HttpStatus.INTERNAL_SERVER_ERROR)
|
||||
public ResultBean searchDisableExceptionHandler(Exception e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
|
||||
@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* 对象存储初始化异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InitializeException extends RuntimeException {
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2020/1/20 22:15
|
||||
*/
|
||||
public class NotExistFileException extends RuntimeException {
|
||||
|
||||
public NotExistFileException() {
|
||||
super();
|
||||
}
|
||||
|
||||
public NotExistFileException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
public NotExistFileException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
public NotExistFileException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
protected NotExistFileException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
|
||||
super(message, cause, enableSuppression, writableStackTrace);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class SearchDisableException extends RuntimeException {
|
||||
|
||||
public SearchDisableException() {
|
||||
|
||||
@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* 存储策略未初始化异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class StorageStrategyUninitializedException extends RuntimeException {
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
|
||||
|
||||
/**
|
||||
* 未知的存储类型异常
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class UnknownStorageTypeException extends RuntimeException {
|
||||
|
||||
|
||||
@@ -3,8 +3,15 @@ package im.zhaojun.common.model;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Entity(name = "STORAGE_CONFIG")
|
||||
@Data
|
||||
public class StorageConfig {
|
||||
@@ -20,6 +27,7 @@ public class StorageConfig {
|
||||
|
||||
private String title;
|
||||
|
||||
@Column(length = 2048)
|
||||
private String value;
|
||||
|
||||
public Integer getId() {
|
||||
|
||||
@@ -2,8 +2,15 @@ package im.zhaojun.common.model;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import javax.persistence.*;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Entity(name = "SYSTEM_CONFIG")
|
||||
@Data
|
||||
public class SystemConfig {
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
package im.zhaojun.common.model.constant;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2019/12/28 18:47
|
||||
*/
|
||||
public class StorageConfigConstant {
|
||||
|
||||
public static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
public static final String SECRET_ID_KEY = "secretId";
|
||||
|
||||
public static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
public static final String SECRET_KEY = "secretKey";
|
||||
|
||||
public static final String ENDPOINT_KEY = "endPoint";
|
||||
|
||||
public static final String BASE_PATH = "base-path";
|
||||
|
||||
public static final String DOMAIN_KEY = "domain";
|
||||
|
||||
public static final String USERNAME_KEY = "username";
|
||||
|
||||
public static final String PASSWORD_KEY = "password";
|
||||
|
||||
public static final String HOST_KEY = "host";
|
||||
|
||||
public static final String PORT_KEY = "port";
|
||||
|
||||
public static final String FILE_PATH_KEY = "filePath";
|
||||
|
||||
public static final String ACCESS_TOKEN_KEY = "accessToken";
|
||||
|
||||
public static final String REFRESH_TOKEN_KEY = "refreshToken";
|
||||
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package im.zhaojun.common.model.constant;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class SystemConfigConstant {
|
||||
|
||||
public static final String SITE_NAME = "siteName";
|
||||
@@ -10,6 +13,8 @@ public class SystemConfigConstant {
|
||||
|
||||
public static final String SEARCH_IGNORE_CASE = "searchIgnoreCase";
|
||||
|
||||
public static final String ENABLE_CACHE = "enableCache";
|
||||
|
||||
public static final String STORAGE_STRATEGY = "storageStrategy";
|
||||
|
||||
public static final String USERNAME = "username";
|
||||
|
||||
@@ -1,5 +1,13 @@
|
||||
package im.zhaojun.common.model.constant;
|
||||
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
public class ZFileConstant {
|
||||
|
||||
public final static String USER_HOME = System.getProperty("user.home");
|
||||
@@ -9,16 +17,21 @@ public class ZFileConstant {
|
||||
/**
|
||||
* 页面头部文件
|
||||
*/
|
||||
public static final String HEADER_FILE_NAME = "header.md";
|
||||
|
||||
/**
|
||||
* 页面尾部文件
|
||||
*/
|
||||
public static final String FOOTER_FILE_NAME = "footer.md";
|
||||
public static String HEADER_FILE_NAME = "header.md";
|
||||
|
||||
/**
|
||||
* 密码文件
|
||||
*/
|
||||
public static final String PASSWORD_FILE_NAME = "password.txt";
|
||||
public static String PASSWORD_FILE_NAME = "password.txt";
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setHeaderFileName(@Value("${zfile.constant.header}") String headerFileName) {
|
||||
ZFileConstant.HEADER_FILE_NAME = headerFileName;
|
||||
}
|
||||
|
||||
@Autowired(required = false)
|
||||
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
|
||||
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,5 +1,8 @@
|
||||
package im.zhaojun.common.model.dto;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class AudioInfoDTO {
|
||||
private String title;
|
||||
private String artist;
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package im.zhaojun.common.model.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2020/1/3 12:39
|
||||
*/
|
||||
@Data
|
||||
public class CacheConfigDTO {
|
||||
private Boolean enableCache;
|
||||
private Boolean cacheFinish;
|
||||
private Set<String> cacheKeys;
|
||||
private Integer cacheDirectoryCount;
|
||||
private Integer cacheFileCount;
|
||||
}
|
||||
@@ -5,6 +5,9 @@ import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import java.io.Serializable;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class FileItemDTO implements Serializable {
|
||||
|
||||
private String name;
|
||||
|
||||
@@ -4,6 +4,9 @@ import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class InstallModelDTO {
|
||||
private String siteName;
|
||||
private StorageTypeEnum storageStrategy;
|
||||
|
||||
@@ -2,6 +2,9 @@ package im.zhaojun.common.model.dto;
|
||||
|
||||
import java.io.Serializable;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class ResultBean implements Serializable {
|
||||
|
||||
private static final long serialVersionUID = -8276264968757808344L;
|
||||
|
||||
@@ -1,50 +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 +
|
||||
'}';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
package im.zhaojun.common.model.dto;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Data;
|
||||
import lombok.NoArgsConstructor;
|
||||
|
||||
/**
|
||||
* @author Zhao Jun
|
||||
*/
|
||||
@Data
|
||||
@AllArgsConstructor
|
||||
@NoArgsConstructor
|
||||
public class StorageStrategyDTO {
|
||||
|
||||
private String key;
|
||||
|
||||
private String description;
|
||||
|
||||
private boolean available;
|
||||
|
||||
}
|
||||
@@ -4,7 +4,15 @@ import com.fasterxml.jackson.annotation.JsonIgnore;
|
||||
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnumSerializerConvert;
|
||||
import lombok.Data;
|
||||
import lombok.ToString;
|
||||
|
||||
/**
|
||||
* 系统设置传输类
|
||||
* @author zhaojun
|
||||
*/
|
||||
@ToString
|
||||
@Data
|
||||
public class SystemConfigDTO {
|
||||
|
||||
@JsonIgnore
|
||||
@@ -28,75 +36,12 @@ public class SystemConfigDTO {
|
||||
|
||||
private String domain;
|
||||
|
||||
public Integer getId() {
|
||||
return id;
|
||||
}
|
||||
private Boolean enableCache;
|
||||
|
||||
public void setId(Integer id) {
|
||||
this.id = id;
|
||||
}
|
||||
private Boolean searchContainEncryptedFile;
|
||||
|
||||
public String getSiteName() {
|
||||
return siteName;
|
||||
}
|
||||
private String customJs;
|
||||
|
||||
public void setSiteName(String siteName) {
|
||||
this.siteName = siteName;
|
||||
}
|
||||
private String customCss;
|
||||
|
||||
public Boolean getInfoEnable() {
|
||||
return infoEnable;
|
||||
}
|
||||
|
||||
public void setInfoEnable(Boolean infoEnable) {
|
||||
this.infoEnable = infoEnable;
|
||||
}
|
||||
|
||||
public Boolean getSearchEnable() {
|
||||
return searchEnable;
|
||||
}
|
||||
|
||||
public void setSearchEnable(Boolean searchEnable) {
|
||||
this.searchEnable = searchEnable;
|
||||
}
|
||||
|
||||
public Boolean getSearchIgnoreCase() {
|
||||
return searchIgnoreCase;
|
||||
}
|
||||
|
||||
public void setSearchIgnoreCase(Boolean searchIgnoreCase) {
|
||||
this.searchIgnoreCase = searchIgnoreCase;
|
||||
}
|
||||
|
||||
public StorageTypeEnum getStorageStrategy() {
|
||||
return storageStrategy;
|
||||
}
|
||||
|
||||
public void setStorageStrategy(StorageTypeEnum storageStrategy) {
|
||||
this.storageStrategy = storageStrategy;
|
||||
}
|
||||
|
||||
public String getUsername() {
|
||||
return username;
|
||||
}
|
||||
|
||||
public void setUsername(String username) {
|
||||
this.username = username;
|
||||
}
|
||||
|
||||
public String getPassword() {
|
||||
return password;
|
||||
}
|
||||
|
||||
public void setPassword(String password) {
|
||||
this.password = password;
|
||||
}
|
||||
|
||||
public String getDomain() {
|
||||
return domain;
|
||||
}
|
||||
|
||||
public void setDomain(String domain) {
|
||||
this.domain = domain;
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,8 @@
|
||||
package im.zhaojun.common.model.enums;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public enum FileTypeEnum {
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,21 +1,33 @@
|
||||
package im.zhaojun.common.model.enums;
|
||||
|
||||
import com.fasterxml.jackson.annotation.JsonFormat;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@JsonFormat(shape = JsonFormat.Shape.OBJECT)
|
||||
public enum StorageTypeEnum {
|
||||
|
||||
/**
|
||||
* 当前系统支持的所有存储策略
|
||||
*/
|
||||
UPYUN("upyun", "又拍云 USS"),
|
||||
QINIU("qiniu", "七牛云 KODO"),
|
||||
HUAWEI("huawei", "华为云 OBS"),
|
||||
ALIYUN("aliyun", "阿里云 OSS"),
|
||||
FTP("ftp", "FTP"),
|
||||
HUAWEI("huawei", "华为云 OBS"),
|
||||
LOCAL("local", "本地存储"),
|
||||
MINIO("minio", "MINIO"),
|
||||
ONE_DRIVE("onedrive", "OneDrive"),
|
||||
ONE_DRIVE_CHINA("onedrive-china", "OneDrive 世纪互联"),
|
||||
QINIU("qiniu", "七牛云 KODO"),
|
||||
TENCENT("tencent", "腾讯云 COS"),
|
||||
MINIO("minio", "MINIO");
|
||||
UPYUN("upyun", "又拍云 USS");
|
||||
|
||||
|
||||
private String key;
|
||||
private String description;
|
||||
|
||||
private static Map<String, StorageTypeEnum> enumMap = new HashMap<>();
|
||||
|
||||
@@ -30,9 +42,6 @@ public enum StorageTypeEnum {
|
||||
this.description = description;
|
||||
}
|
||||
|
||||
private String key;
|
||||
private String description;
|
||||
|
||||
public String getKey() {
|
||||
return key;
|
||||
}
|
||||
@@ -50,7 +59,7 @@ public enum StorageTypeEnum {
|
||||
}
|
||||
|
||||
public static StorageTypeEnum getEnum(String value) {
|
||||
return enumMap.get(value);
|
||||
return enumMap.get(value.toLowerCase());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -3,6 +3,9 @@ package im.zhaojun.common.model.enums;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Converter(autoApply = true)
|
||||
public class StorageTypeEnumConvert implements AttributeConverter<StorageTypeEnum, String> {
|
||||
|
||||
|
||||
@@ -1,11 +1,15 @@
|
||||
package im.zhaojun.common.model.enums;
|
||||
|
||||
import org.springframework.core.convert.converter.Converter;
|
||||
import org.springframework.lang.NonNull;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class StorageTypeEnumDeSerializerConvert implements Converter<String, StorageTypeEnum> {
|
||||
|
||||
@Override
|
||||
public StorageTypeEnum convert(String s) {
|
||||
public StorageTypeEnum convert(@NonNull String s) {
|
||||
return StorageTypeEnum.getEnum(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.SerializerProvider;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class StorageTypeEnumSerializerConvert extends JsonSerializer<StorageTypeEnum> {
|
||||
|
||||
@Override
|
||||
|
||||
@@ -7,9 +7,25 @@ import org.springframework.stereotype.Repository;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Repository
|
||||
public interface StorageConfigRepository extends JpaRepository<StorageConfig, Integer> {
|
||||
|
||||
/**
|
||||
* 根据存储类型找对应的配置信息
|
||||
* @param type 存储类型
|
||||
* @return 此类型所有的配置信息
|
||||
*/
|
||||
List<StorageConfig> findByTypeOrderById(StorageTypeEnum type);
|
||||
|
||||
/**
|
||||
* 根据存储类型找到某个 KEY 的值
|
||||
* @param type 存储类型
|
||||
* @param key KEY
|
||||
* @return KEY 对应的对象
|
||||
*/
|
||||
StorageConfig findByTypeAndKey(StorageTypeEnum type, String key);
|
||||
|
||||
}
|
||||
@@ -4,8 +4,16 @@ import im.zhaojun.common.model.SystemConfig;
|
||||
import org.springframework.data.jpa.repository.JpaRepository;
|
||||
import org.springframework.stereotype.Repository;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Repository
|
||||
public interface SystemConfigRepository extends JpaRepository<SystemConfig, Integer> {
|
||||
|
||||
/**
|
||||
* 查找系统设置中, 某个设置项对应的值
|
||||
* @param key 设置项
|
||||
* @return 设置值
|
||||
*/
|
||||
SystemConfig findByKey(String key);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,10 @@ package im.zhaojun.common.security;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
|
||||
public class MD5PasswordEncoder implements PasswordEncoder {
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class Md5PasswordEncoder implements PasswordEncoder {
|
||||
|
||||
@Override
|
||||
public String encode(CharSequence rawPassword) {
|
||||
@@ -6,6 +6,9 @@ import org.springframework.web.cors.CorsConfiguration;
|
||||
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
|
||||
import org.springframework.web.filter.CorsFilter;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Configuration
|
||||
public class MyCorsFilter {
|
||||
|
||||
|
||||
@@ -12,13 +12,16 @@ import org.springframework.security.config.annotation.web.configuration.EnableWe
|
||||
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import org.springframework.security.crypto.password.PasswordEncoder;
|
||||
import org.springframework.security.web.firewall.HttpFirewall;
|
||||
import org.springframework.security.web.firewall.StrictHttpFirewall;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import java.io.PrintWriter;
|
||||
|
||||
/**
|
||||
* 自定义Security配置类
|
||||
* 自定义 Security 配置类
|
||||
* @author zhaojun
|
||||
*/
|
||||
@EnableWebSecurity
|
||||
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
@@ -97,6 +100,13 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
http.csrf().disable();
|
||||
}
|
||||
|
||||
@Bean
|
||||
public HttpFirewall allowUrlEncodedSlashHttpFirewall() {
|
||||
StrictHttpFirewall firewall = new StrictHttpFirewall();
|
||||
firewall.setAllowUrlEncodedPercent(true);
|
||||
return firewall;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void configure(AuthenticationManagerBuilder web) throws Exception {
|
||||
web.userDetailsService(myUserDetailsServiceImpl()).passwordEncoder(passwordEncoder());
|
||||
@@ -111,11 +121,12 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
|
||||
public void configure(WebSecurity web) {
|
||||
//对于在header里面增加token等类似情况,放行所有OPTIONS请求。
|
||||
web.ignoring().antMatchers(HttpMethod.OPTIONS, "/**");
|
||||
web.httpFirewall(allowUrlEncodedSlashHttpFirewall());
|
||||
}
|
||||
|
||||
@Bean
|
||||
public static PasswordEncoder passwordEncoder() {
|
||||
return new MD5PasswordEncoder();
|
||||
return new Md5PasswordEncoder();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -10,6 +10,9 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class MyUserDetailsServiceImpl implements UserDetailsService {
|
||||
|
||||
@Resource
|
||||
|
||||
244
src/main/java/im/zhaojun/common/service/AbstractFileService.java
Normal file
244
src/main/java/im/zhaojun/common/service/AbstractFileService.java
Normal file
@@ -0,0 +1,244 @@
|
||||
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;
|
||||
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;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.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 {
|
||||
|
||||
private static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-cache:";
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
protected Long timeout;
|
||||
|
||||
protected boolean isInitialized = false;
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
private FileAsyncCacheService fileAsyncCacheService;
|
||||
|
||||
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
|
||||
private Cache<String, List<FileItemDTO>> cache;
|
||||
|
||||
/***
|
||||
* 获取指定路径下的文件及文件夹, 默认缓存 60 分钟,每隔 30 分钟刷新一次.
|
||||
* @param path 文件路径
|
||||
* @return 文件及文件夹列表
|
||||
* @throws Exception 获取文件列表中出现的异常
|
||||
*/
|
||||
@Override
|
||||
@Cached(name = SYSTEM_CONFIG_CACHE_PREFIX,
|
||||
key = "args[0]",
|
||||
cacheType = CacheType.LOCAL, localLimit = 100000, condition = "mvel{bean('systemConfigService').enableCache}")
|
||||
@CacheRefresh(refresh = 30, timeUnit = TimeUnit.MINUTES)
|
||||
public abstract List<FileItemDTO> fileList(String path) throws Exception;
|
||||
|
||||
/**
|
||||
* 清理当前存储策略的缓存
|
||||
* 1. 删除全部缓存
|
||||
* 2. 关闭自动刷新
|
||||
* 3. 重置缓存个数
|
||||
* 4. 标记为当前处于未完成缓存状态
|
||||
*/
|
||||
public void clearFileCache() throws Exception {
|
||||
Set<String> cacheKeys = getCacheKeys();
|
||||
cache.removeAll(cacheKeys);
|
||||
closeCacheAutoRefresh();
|
||||
fileAsyncCacheService.resetCacheCount();
|
||||
fileAsyncCacheService.setCacheFinish(false);
|
||||
}
|
||||
|
||||
/**
|
||||
* 初始化方法, 启动时自动调用实现类的此方法进行初始化.
|
||||
*/
|
||||
@PostConstruct
|
||||
public abstract void init();
|
||||
|
||||
protected boolean testConnection() {
|
||||
boolean flag = true;
|
||||
try {
|
||||
fileList("/");
|
||||
} catch (Exception e) {
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常", e);
|
||||
flag = false;
|
||||
}
|
||||
return flag;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否初始化成功
|
||||
* @return 初始化成功与否
|
||||
*/
|
||||
public boolean getIsUnInitialized() {
|
||||
return !isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取是否初始化成功
|
||||
* @return 初始化成功与否
|
||||
*/
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取存储策略类型
|
||||
* @return 存储策略类型枚举
|
||||
*/
|
||||
public abstract StorageTypeEnum getStorageTypeEnum();
|
||||
|
||||
/**
|
||||
* 搜索文件
|
||||
* @param name 文件名
|
||||
* @return 包含该文件名的所有文件或文件夹
|
||||
*/
|
||||
public List<FileItemDTO> search(String name) {
|
||||
List<FileItemDTO> result = new ArrayList<>();
|
||||
|
||||
boolean searchIgnoreCase = systemConfigService.getSearchIgnoreCase();
|
||||
|
||||
List<FileItemDTO> fileItemList = selectAllFileList();
|
||||
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||
|
||||
boolean testResult;
|
||||
|
||||
if (searchIgnoreCase) {
|
||||
testResult = StrUtil.containsIgnoreCase(fileItemDTO.getName(), name);
|
||||
} else {
|
||||
testResult = fileItemDTO.getName().contains(name);
|
||||
}
|
||||
|
||||
if (testResult) {
|
||||
result.add(fileItemDTO);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 查询所有文件, 仅去缓存中查询.
|
||||
* @return 所有文件
|
||||
*/
|
||||
public List<FileItemDTO> selectAllFileList() {
|
||||
List<FileItemDTO> result = new ArrayList<>();
|
||||
boolean enableCache = systemConfigService.getEnableCache();
|
||||
if (!enableCache) {
|
||||
log.debug("未开启缓存, 不支持查询所有文件.");
|
||||
return null;
|
||||
}
|
||||
String path = "/";
|
||||
|
||||
List<FileItemDTO> fileItemList = cache.get(path);
|
||||
fileItemList = fileItemList == null ? new ArrayList<>() : fileItemList;
|
||||
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
FileItemDTO fileItemDTO = queue.pop();
|
||||
result.add(fileItemDTO);
|
||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
||||
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
||||
List<FileItemDTO> cacheList = cache.get(filePath);
|
||||
if (cacheList != null && isNotEncryptedFolder(cacheList)) {
|
||||
queue.addAll(cacheList);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
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
|
||||
*/
|
||||
public Set<String> getCacheKeys() {
|
||||
if (systemConfigService.getEnableCache() && fileAsyncCacheService.isCacheFinish()) {
|
||||
Set<String> collect = selectAllFileList().stream().map(fileItemDTO -> {
|
||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
||||
return StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
||||
}
|
||||
return null;
|
||||
}).collect(Collectors.toSet());
|
||||
collect.remove(null);
|
||||
collect.add("/");
|
||||
return collect;
|
||||
} else {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 刷新缓存
|
||||
*/
|
||||
public void refreshCache(String key) throws Exception {
|
||||
cache.remove(key);
|
||||
FileService currentFileService = (FileService) AopContext.currentProxy();
|
||||
currentFileService.fileList(key);
|
||||
}
|
||||
|
||||
public void closeCacheAutoRefresh() {
|
||||
cache.config().setRefreshPolicy(null);
|
||||
}
|
||||
|
||||
public void openCacheAutoRefresh() {
|
||||
RefreshPolicy refreshPolicy = RefreshPolicy.newPolicy(30, TimeUnit.MINUTES);
|
||||
cache.config().setRefreshPolicy(refreshPolicy);
|
||||
}
|
||||
|
||||
public abstract FileItemDTO getFileItem(String path);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,127 @@
|
||||
package im.zhaojun.common.service;
|
||||
|
||||
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;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2019/12/26 22:26
|
||||
*/
|
||||
public abstract class AbstractS3FileService extends AbstractFileService {
|
||||
|
||||
@Resource
|
||||
protected StorageConfigService storageConfigService;
|
||||
|
||||
protected String path;
|
||||
|
||||
protected String basePath;
|
||||
|
||||
protected String bucketName;
|
||||
|
||||
protected String domain;
|
||||
|
||||
protected AmazonS3 s3Client;
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) {
|
||||
this.path = path;
|
||||
return s3FileList(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) {
|
||||
this.path = path;
|
||||
return s3ObjectUrl(path);
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取 S3 指定目录下的对象列表
|
||||
* @param path 路径
|
||||
* @return 指定目录下的对象列表
|
||||
*/
|
||||
public List<FileItemDTO> s3FileList(String path) {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
String fullPath = StringUtils.removeFirstSeparator(getFullPath());
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
ObjectListing objectListing = s3Client.listObjects(new ListObjectsRequest(bucketName, fullPath, "", "/", 1000));
|
||||
|
||||
for (S3ObjectSummary s : objectListing.getObjectSummaries()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
if (s.getKey().equals(fullPath)) {
|
||||
continue;
|
||||
}
|
||||
fileItemDTO.setName(s.getKey().substring(fullPath.length()));
|
||||
fileItemDTO.setSize(s.getSize());
|
||||
fileItemDTO.setTime(s.getLastModified());
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
if (Objects.equals(commonPrefix, "/")) {
|
||||
continue;
|
||||
}
|
||||
fileItemDTO.setName(commonPrefix.substring(fullPath.length(), commonPrefix.length() - 1));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取对象的访问链接, 如果指定了域名, 则替换为自定义域名.
|
||||
* @return S3 对象访问地址
|
||||
*/
|
||||
public String s3ObjectUrl(String path) {
|
||||
String fullPath = StringUtils.removeFirstSeparator(StringUtils.removeDuplicateSeparator(basePath + "/" + path));
|
||||
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
|
||||
URL url = s3Client.generatePresignedUrl(bucketName, fullPath, expirationDate);
|
||||
|
||||
String defaultUrl = url.toExternalForm();
|
||||
if (StringUtils.isNotNullOrEmpty(domain)) {
|
||||
defaultUrl = URLUtil.complateUrl(domain, url.getFile());
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
||||
@@ -1,18 +1,39 @@
|
||||
package im.zhaojun.common.service;
|
||||
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
import com.alicp.jetcache.anno.CreateCache;
|
||||
import im.zhaojun.common.config.StorageTypeFactory;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.scheduling.annotation.Async;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class FileAsyncCacheService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FileAsyncCacheService.class);
|
||||
public static final String CACHE_PROCESS_PREFIX = "zfile-process-cache:";
|
||||
|
||||
public static final String CACHE_FILE_COUNT_KEY = "file-count";
|
||||
|
||||
public static final String CACHE_DIRECTORY_COUNT_KEY = "directory-count";
|
||||
|
||||
@CreateCache(name = "SYSTEM_CONFIG_CACHE_PREFIX", cacheType = CacheType.LOCAL)
|
||||
private Cache<String, Integer> cache;
|
||||
|
||||
private boolean cacheFinish;
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
@@ -22,22 +43,98 @@ public class FileAsyncCacheService {
|
||||
StorageTypeEnum storageStrategy = systemConfigService.getCurrentStorageStrategy();
|
||||
|
||||
if (storageStrategy == null) {
|
||||
log.info("尚未配置存储策略. 跳过启动缓存.");
|
||||
log.debug("尚未配置存储策略. 跳过启动缓存.");
|
||||
return;
|
||||
}
|
||||
|
||||
FileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
|
||||
boolean enableCache = systemConfigService.getEnableCache();
|
||||
if (!enableCache) {
|
||||
log.debug("存储策略 {} 未启用缓存, 跳过缓存.", storageStrategy.getDescription());
|
||||
return;
|
||||
}
|
||||
|
||||
AbstractFileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
|
||||
|
||||
if (fileService.getIsUnInitialized()) {
|
||||
log.debug("存储策略 {} 未初始化成功, 跳过缓存.", storageStrategy.getDescription());
|
||||
return;
|
||||
}
|
||||
|
||||
Integer cacheDirectoryCount = cache.get(CACHE_DIRECTORY_COUNT_KEY);
|
||||
if (cacheDirectoryCount == null) {
|
||||
cacheDirectoryCount = 0;
|
||||
}
|
||||
|
||||
Integer cacheFileCount = cache.get(CACHE_FILE_COUNT_KEY);
|
||||
if (cacheFileCount == null) {
|
||||
cacheFileCount = 0;
|
||||
}
|
||||
|
||||
log.info("缓存 {} 所有文件开始", storageStrategy.getDescription());
|
||||
long startTime = System.currentTimeMillis();
|
||||
try {
|
||||
if (fileService.getIsInitialized()) {
|
||||
fileService.selectAllFileList();
|
||||
FileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
List<FileItemDTO> rootFileItems = currentFileService.fileList("/");
|
||||
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(rootFileItems);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
FileItemDTO fileItemDTO = queue.pop();
|
||||
|
||||
if (FileTypeEnum.FOLDER.equals(fileItemDTO.getType())) {
|
||||
cacheDirectoryCount++;
|
||||
}
|
||||
if (FileTypeEnum.FILE.equals(fileItemDTO.getType())) {
|
||||
cacheFileCount++;
|
||||
}
|
||||
|
||||
log.debug("已缓存 {} 个文件夹", cacheDirectoryCount);
|
||||
cache.put(CACHE_DIRECTORY_COUNT_KEY, cacheDirectoryCount);
|
||||
|
||||
log.debug("已缓存 {} 个文件", cacheFileCount);
|
||||
cache.put(CACHE_FILE_COUNT_KEY, cacheFileCount);
|
||||
|
||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
||||
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
||||
|
||||
List<FileItemDTO> fileItems = currentFileService.fileList(filePath);
|
||||
queue.addAll(fileItems);
|
||||
}
|
||||
}
|
||||
cache.put(CACHE_DIRECTORY_COUNT_KEY, cacheDirectoryCount);
|
||||
cache.put(CACHE_FILE_COUNT_KEY, cacheFileCount);
|
||||
} catch (Exception e) {
|
||||
log.error("缓存所有文件失败", e);
|
||||
e.printStackTrace();
|
||||
}
|
||||
long endTime = System.currentTimeMillis();
|
||||
log.info("缓存 {} 所有文件结束, 用时: {} 秒", storageStrategy.getDescription(), ( (endTime - startTime) / 1000 ));
|
||||
log.info("缓存 {} 所有文件结束, 用时: {} 秒, 文件夹共 {} 个, 文件共 {} 个",
|
||||
storageStrategy.getDescription(),
|
||||
( (endTime - startTime) / 1000 ), cacheDirectoryCount, cacheFileCount);
|
||||
cacheFinish = true;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 清理缓存的文件/文件夹数量统计
|
||||
*/
|
||||
public void resetCacheCount() {
|
||||
cache.remove(CACHE_DIRECTORY_COUNT_KEY);
|
||||
cache.remove(CACHE_FILE_COUNT_KEY);
|
||||
}
|
||||
|
||||
public Integer getCacheDirectoryCount() {
|
||||
return ObjectUtil.defaultIfNull(cache.get(CACHE_DIRECTORY_COUNT_KEY), 0);
|
||||
}
|
||||
|
||||
public Integer getCacheFileCount() {
|
||||
return ObjectUtil.defaultIfNull(cache.get(CACHE_FILE_COUNT_KEY), 0);
|
||||
}
|
||||
|
||||
public boolean isCacheFinish() {
|
||||
return cacheFinish;
|
||||
}
|
||||
|
||||
public void setCacheFinish(boolean cacheFinish) {
|
||||
this.cacheFinish = cacheFinish;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,39 @@
|
||||
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 {
|
||||
|
||||
@Resource
|
||||
private SystemConfigService systemConfigService;
|
||||
|
||||
@Resource
|
||||
@Lazy
|
||||
private FileAsyncCacheService fileAsyncCacheService;
|
||||
|
||||
public void enableCache() {
|
||||
systemConfigService.updateCacheEnableConfig(true);
|
||||
|
||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
currentFileService.openCacheAutoRefresh();
|
||||
fileAsyncCacheService.cacheGlobalFile();
|
||||
}
|
||||
|
||||
|
||||
public void disableCache() throws Exception {
|
||||
systemConfigService.updateCacheEnableConfig(false);
|
||||
|
||||
AbstractFileService currentFileService = systemConfigService.getCurrentFileService();
|
||||
currentFileService.clearFileCache();
|
||||
fileAsyncCacheService.resetCacheCount();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,73 +1,27 @@
|
||||
package im.zhaojun.common.service;
|
||||
|
||||
import im.zhaojun.common.config.ZFileCacheConfiguration;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.springframework.aop.framework.AopContext;
|
||||
import org.springframework.cache.annotation.CacheConfig;
|
||||
import org.springframework.cache.annotation.CacheEvict;
|
||||
import org.springframework.cache.annotation.Cacheable;
|
||||
|
||||
import javax.annotation.PostConstruct;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@CacheConfig(cacheNames = ZFileCacheConfiguration.CACHE_NAME, keyGenerator = "keyGenerator")
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public interface FileService {
|
||||
|
||||
@Cacheable
|
||||
/***
|
||||
* 获取指定路径下的文件及文件夹
|
||||
* @param path 文件路径
|
||||
* @return 文件及文件夹列表
|
||||
* @throws Exception 获取文件列表中出现的异常
|
||||
*/
|
||||
List<FileItemDTO> fileList(String path) throws Exception;
|
||||
|
||||
@Cacheable
|
||||
String getDownloadUrl(String path) throws Exception;
|
||||
|
||||
@PostConstruct
|
||||
default void init() {}
|
||||
|
||||
/**
|
||||
* 清除缓存.
|
||||
* 获取文件下载地址
|
||||
* @param path 文件路径
|
||||
* @return 文件下载地址
|
||||
*/
|
||||
@CacheEvict(allEntries = true)
|
||||
default void clearCache() {}
|
||||
String getDownloadUrl(String path);
|
||||
|
||||
default List<FileItemDTO> search(String name) throws Exception {
|
||||
List<FileItemDTO> result = new ArrayList<>();
|
||||
|
||||
List<FileItemDTO> fileItemList = selectAllFileList();
|
||||
for (FileItemDTO fileItemDTO : fileItemList) {
|
||||
if (fileItemDTO.getName().contains(name)) {
|
||||
result.add(fileItemDTO);
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
default List<FileItemDTO> selectAllFileList() throws Exception {
|
||||
List<FileItemDTO> result = new ArrayList<>();
|
||||
|
||||
String path = "/";
|
||||
|
||||
FileService currentFileService = (FileService) AopContext.currentProxy();
|
||||
List<FileItemDTO> fileItemList = currentFileService.fileList(path);
|
||||
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
|
||||
|
||||
while (!queue.isEmpty()) {
|
||||
FileItemDTO fileItemDTO = queue.pop();
|
||||
result.add(fileItemDTO);
|
||||
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
|
||||
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
|
||||
queue.addAll(currentFileService.fileList(filePath));
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
StorageTypeEnum getStorageTypeEnum();
|
||||
|
||||
boolean getIsInitialized();
|
||||
}
|
||||
|
||||
@@ -10,6 +10,9 @@ import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class StorageConfigService {
|
||||
|
||||
@@ -20,6 +23,12 @@ public class StorageConfigService {
|
||||
return storageConfigRepository.findByTypeOrderById(storageTypeEnum);
|
||||
}
|
||||
|
||||
|
||||
public StorageConfig selectByTypeAndKey(StorageTypeEnum storageType, String key) {
|
||||
return storageConfigRepository.findByTypeAndKey(storageType, key);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, StorageConfig> selectStorageConfigMapByKey(StorageTypeEnum storageTypeEnum) {
|
||||
Map<String, StorageConfig> map = new HashMap<>(24);
|
||||
for (StorageConfig storageConfig : selectStorageConfigByType(storageTypeEnum)) {
|
||||
@@ -28,6 +37,7 @@ public class StorageConfigService {
|
||||
return map;
|
||||
}
|
||||
|
||||
|
||||
public void updateStorageConfig(List<StorageConfig> storageConfigList) {
|
||||
storageConfigRepository.saveAll(storageConfigList);
|
||||
}
|
||||
|
||||
@@ -1,126 +1,158 @@
|
||||
package im.zhaojun.common.service;
|
||||
|
||||
import cn.hutool.core.convert.Convert;
|
||||
import cn.hutool.core.util.BooleanUtil;
|
||||
import cn.hutool.crypto.SecureUtil;
|
||||
import com.alicp.jetcache.Cache;
|
||||
import com.alicp.jetcache.anno.CacheType;
|
||||
import com.alicp.jetcache.anno.CreateCache;
|
||||
import im.zhaojun.common.config.StorageTypeFactory;
|
||||
import im.zhaojun.common.model.SystemConfig;
|
||||
import im.zhaojun.common.model.constant.SystemConfigConstant;
|
||||
import im.zhaojun.common.model.dto.SystemConfigDTO;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.repository.SystemConfigRepository;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Slf4j
|
||||
@Service
|
||||
public class SystemConfigService {
|
||||
|
||||
public static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-config-cache:";
|
||||
|
||||
public static final String SYSTEM_CONFIG_CACHE_KEY = "1";
|
||||
|
||||
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
|
||||
private Cache<String, Object> configCache;
|
||||
|
||||
@Resource
|
||||
private SystemConfigRepository systemConfigRepository;
|
||||
|
||||
@Resource
|
||||
private FileCacheService fileCacheService;
|
||||
|
||||
private Class<SystemConfigDTO> systemConfigDTOClass = SystemConfigDTO.class;
|
||||
|
||||
public SystemConfigDTO getSystemConfig() {
|
||||
Object cache = configCache.get(SYSTEM_CONFIG_CACHE_KEY);
|
||||
if (configCache.get(SYSTEM_CONFIG_CACHE_KEY) != null) {
|
||||
return (SystemConfigDTO) cache;
|
||||
}
|
||||
|
||||
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
|
||||
List<SystemConfig> systemConfigList = systemConfigRepository.findAll();
|
||||
|
||||
for (SystemConfig systemConfig : systemConfigList) {
|
||||
switch (systemConfig.getKey()) {
|
||||
case SystemConfigConstant.SITE_NAME:
|
||||
systemConfigDTO.setSiteName(systemConfig.getValue());
|
||||
break;
|
||||
case SystemConfigConstant.INFO_ENABLE:
|
||||
systemConfigDTO.setInfoEnable("true".equals(systemConfig.getValue()));
|
||||
break;
|
||||
case SystemConfigConstant.SEARCH_ENABLE:
|
||||
systemConfigDTO.setSearchEnable("true".equals(systemConfig.getValue()));
|
||||
break;
|
||||
case SystemConfigConstant.SEARCH_IGNORE_CASE:
|
||||
systemConfigDTO.setSearchIgnoreCase("true".equals(systemConfig.getValue()));
|
||||
break;
|
||||
case SystemConfigConstant.STORAGE_STRATEGY:
|
||||
String value = systemConfig.getValue();
|
||||
systemConfigDTO.setStorageStrategy(StorageTypeEnum.getEnum(value));
|
||||
break;
|
||||
case SystemConfigConstant.USERNAME:
|
||||
systemConfigDTO.setUsername(systemConfig.getValue());
|
||||
break;
|
||||
case SystemConfigConstant.PASSWORD:
|
||||
systemConfigDTO.setPassword(systemConfig.getValue());
|
||||
break;
|
||||
case SystemConfigConstant.DOMAIN:
|
||||
systemConfigDTO.setDomain(systemConfig.getValue());
|
||||
break;
|
||||
default:break;
|
||||
String key = systemConfig.getKey();
|
||||
|
||||
try {
|
||||
Field field = systemConfigDTOClass.getDeclaredField(key);
|
||||
if (field != null) {
|
||||
field.setAccessible(true);
|
||||
String strVal = systemConfig.getValue();
|
||||
Object convertVal = Convert.convert(field.getType(), strVal);
|
||||
field.set(systemConfigDTO, convertVal);
|
||||
}
|
||||
} catch (NoSuchFieldException | IllegalAccessException e) {
|
||||
if (log.isDebugEnabled()) {
|
||||
log.debug("通过反射, 将字段 {" + key + "}注入 SystemConfigDTO 时出现异常:", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
configCache.put(SYSTEM_CONFIG_CACHE_KEY, systemConfigDTO);
|
||||
return systemConfigDTO;
|
||||
}
|
||||
|
||||
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) {
|
||||
|
||||
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) throws Exception {
|
||||
List<SystemConfig> systemConfigList = new ArrayList<>();
|
||||
|
||||
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SITE_NAME);
|
||||
systemConfig.setValue(systemConfigDTO.getSiteName());
|
||||
systemConfigList.add(systemConfig);
|
||||
|
||||
SystemConfig domainConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
|
||||
domainConfig.setValue(systemConfigDTO.getDomain());
|
||||
systemConfigList.add(domainConfig);
|
||||
|
||||
SystemConfig infoEnableSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.INFO_ENABLE);
|
||||
infoEnableSystemConfig.setValue(systemConfigDTO.getInfoEnable() ? "true" : "false");
|
||||
systemConfigList.add(infoEnableSystemConfig);
|
||||
|
||||
SystemConfig searchEnableSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SEARCH_ENABLE);
|
||||
searchEnableSystemConfig.setValue(systemConfigDTO.getSearchEnable() ? "true" : "false");
|
||||
systemConfigList.add(searchEnableSystemConfig);
|
||||
|
||||
SystemConfig searchIgnoreCaseSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SEARCH_IGNORE_CASE);
|
||||
searchIgnoreCaseSystemConfig.setValue(systemConfigDTO.getSearchIgnoreCase() ? "true" : "false");
|
||||
systemConfigList.add(searchIgnoreCaseSystemConfig);
|
||||
|
||||
SystemConfig storageStrategySystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.STORAGE_STRATEGY);
|
||||
storageStrategySystemConfig.setValue(systemConfigDTO.getStorageStrategy().getKey());
|
||||
systemConfigList.add(storageStrategySystemConfig);
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getUsername())) {
|
||||
SystemConfig usernameSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
|
||||
usernameSystemConfig.setValue(systemConfigDTO.getUsername());
|
||||
systemConfigList.add(usernameSystemConfig);
|
||||
Field[] fields = systemConfigDTOClass.getDeclaredFields();
|
||||
for (Field field : fields) {
|
||||
String key = field.getName();
|
||||
SystemConfig systemConfig = systemConfigRepository.findByKey(key);
|
||||
if (systemConfig != null) {
|
||||
field.setAccessible(true);
|
||||
Object val = field.get(systemConfigDTO);
|
||||
if (val != null) {
|
||||
systemConfig.setValue(val.toString());
|
||||
systemConfigList.add(systemConfig);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getPassword())) {
|
||||
SystemConfig passwordSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
|
||||
passwordSystemConfig.setValue(systemConfigDTO.getPassword());
|
||||
systemConfigList.add(passwordSystemConfig);
|
||||
}
|
||||
boolean oldEnableCache = getEnableCache();
|
||||
boolean curEnableCache = BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
|
||||
|
||||
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
|
||||
|
||||
systemConfigRepository.saveAll(systemConfigList);
|
||||
|
||||
if (!oldEnableCache && curEnableCache) {
|
||||
log.debug("检测到开启了缓存, 开启预热缓存");
|
||||
fileCacheService.enableCache();
|
||||
}
|
||||
|
||||
if (oldEnableCache && !curEnableCache) {
|
||||
log.debug("检测到关闭了缓存, 正在清理缓存数据及关闭自动刷新");
|
||||
fileCacheService.disableCache();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void updateUsernameAndPwd(String username, String password) {
|
||||
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
|
||||
usernameConfig.setValue(username);
|
||||
systemConfigRepository.save(usernameConfig);
|
||||
|
||||
password = SecureUtil.md5(password);;
|
||||
String encryptionPassword = SecureUtil.md5(password);
|
||||
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
|
||||
systemConfig.setValue(password);
|
||||
systemConfig.setValue(encryptionPassword);
|
||||
|
||||
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
|
||||
|
||||
systemConfigRepository.save(systemConfig);
|
||||
}
|
||||
|
||||
public FileService getCurrentFileService() {
|
||||
|
||||
public void updateCacheEnableConfig(Boolean isEnable) {
|
||||
SystemConfig enableConfig = systemConfigRepository.findByKey(SystemConfigConstant.ENABLE_CACHE);
|
||||
enableConfig.setValue(isEnable.toString());
|
||||
systemConfigRepository.save(enableConfig);
|
||||
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
|
||||
}
|
||||
|
||||
|
||||
public AbstractFileService getCurrentFileService() {
|
||||
StorageTypeEnum storageStrategy = getCurrentStorageStrategy();
|
||||
return StorageTypeFactory.getStorageTypeService(storageStrategy);
|
||||
}
|
||||
|
||||
|
||||
public StorageTypeEnum getCurrentStorageStrategy() {
|
||||
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
||||
return systemConfigDTO.getStorageStrategy();
|
||||
}
|
||||
|
||||
public boolean getEnableCache() {
|
||||
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
||||
return BooleanUtil.isTrue(systemConfigDTO.getEnableCache());
|
||||
}
|
||||
|
||||
public boolean getSearchIgnoreCase() {
|
||||
SystemConfigDTO systemConfigDTO = getSystemConfig();
|
||||
return BooleanUtil.isTrue(systemConfigDTO.getSearchIgnoreCase());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -7,8 +7,12 @@ import im.zhaojun.common.util.HttpUtil;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class SystemService {
|
||||
|
||||
@@ -22,13 +26,11 @@ public class SystemService {
|
||||
public synchronized SiteConfigDTO getConfig(String path) throws Exception {
|
||||
|
||||
SiteConfigDTO siteConfigDTO = new SiteConfigDTO();
|
||||
FileService fileService = systemConfigService.getCurrentFileService();
|
||||
AbstractFileService fileService = systemConfigService.getCurrentFileService();
|
||||
|
||||
List<FileItemDTO> fileItemList = fileService.fileList(path);
|
||||
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()));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,7 +5,11 @@ import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.lang.UUID;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import com.mpatric.mp3agic.*;
|
||||
import com.mpatric.mp3agic.ID3v1;
|
||||
import com.mpatric.mp3agic.ID3v2;
|
||||
import com.mpatric.mp3agic.InvalidDataException;
|
||||
import com.mpatric.mp3agic.Mp3File;
|
||||
import com.mpatric.mp3agic.UnsupportedTagException;
|
||||
import im.zhaojun.common.model.constant.ZFileConstant;
|
||||
import im.zhaojun.common.model.dto.AudioInfoDTO;
|
||||
import org.slf4j.Logger;
|
||||
@@ -18,6 +22,7 @@ import java.net.URL;
|
||||
|
||||
/**
|
||||
* 音频解析工具类
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class AudioHelper {
|
||||
|
||||
@@ -43,7 +48,7 @@ public class AudioHelper {
|
||||
AudioInfoDTO audioInfoDTO = new AudioInfoDTO();
|
||||
audioInfoDTO.setTitle("未知歌曲");
|
||||
audioInfoDTO.setArtist("未知");
|
||||
audioInfoDTO.setCover("/shikwasa/audio.png");
|
||||
audioInfoDTO.setCover("http://c.jun6.net/audio.png");
|
||||
|
||||
Mp3File mp3File = null;
|
||||
try {
|
||||
|
||||
@@ -12,12 +12,17 @@ import java.util.Comparator;
|
||||
* - 默认按照名称排序
|
||||
* - 默认排序为升序
|
||||
* - 按名称排序不区分大小写
|
||||
*
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class FileComparator implements Comparator<FileItemDTO> {
|
||||
|
||||
private String sortBy;
|
||||
private String order;
|
||||
|
||||
public FileComparator() {
|
||||
}
|
||||
|
||||
public FileComparator(String sortBy, String order) {
|
||||
this.sortBy = sortBy;
|
||||
this.order = order;
|
||||
@@ -25,6 +30,14 @@ public class FileComparator implements Comparator<FileItemDTO> {
|
||||
|
||||
@Override
|
||||
public int compare(FileItemDTO o1, FileItemDTO o2) {
|
||||
if (sortBy == null) {
|
||||
sortBy = "name";
|
||||
}
|
||||
|
||||
if (order == null) {
|
||||
order = "asc";
|
||||
}
|
||||
|
||||
FileTypeEnum o1Type = o1.getType();
|
||||
FileTypeEnum o2Type = o2.getType();
|
||||
|
||||
@@ -33,7 +46,7 @@ public class FileComparator implements Comparator<FileItemDTO> {
|
||||
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());
|
||||
default: result = o1.getName().compareToIgnoreCase(o2.getName()); break;
|
||||
}
|
||||
return "asc".equals(order) ? result : -result;
|
||||
}
|
||||
|
||||
@@ -1,14 +1,29 @@
|
||||
package im.zhaojun.common.util;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.web.client.RestClientException;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Slf4j
|
||||
public class HttpUtil {
|
||||
|
||||
public static String getTextContent(String url) {
|
||||
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
|
||||
String result = restTemplate.getForObject(URLUtil.decode(url), String.class);
|
||||
RestTemplate restTemplate = SpringContextHolder.getBean("restTemplate");
|
||||
String result = restTemplate.getForObject(url, String.class);
|
||||
return result == null ? "" : result;
|
||||
}
|
||||
|
||||
public static boolean checkUrlExist(String url) {
|
||||
RestTemplate restTemplate = SpringContextHolder.getBean("restTemplate");
|
||||
try {
|
||||
restTemplate.headForHeaders(url);
|
||||
return true;
|
||||
} catch (RestClientException ignored) {
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -7,8 +7,12 @@ import org.springframework.beans.factory.DisposableBean;
|
||||
import org.springframework.context.ApplicationContext;
|
||||
import org.springframework.context.ApplicationContextAware;
|
||||
import org.springframework.context.annotation.Lazy;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
@Lazy(false)
|
||||
public class SpringContextHolder implements ApplicationContextAware, DisposableBean {
|
||||
@@ -59,7 +63,7 @@ public class SpringContextHolder implements ApplicationContextAware, DisposableB
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
|
||||
public void setApplicationContext(@NonNull ApplicationContext applicationContext) throws BeansException {
|
||||
SpringContextHolder.applicationContext = applicationContext;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,32 +1,58 @@
|
||||
package im.zhaojun.common.util;
|
||||
|
||||
import cn.hutool.core.net.NetUtil;
|
||||
import im.zhaojun.common.exception.InitializeException;
|
||||
import im.zhaojun.common.service.FileAsyncCacheService;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.boot.context.event.ApplicationStartedEvent;
|
||||
import org.springframework.context.ApplicationListener;
|
||||
import org.springframework.context.event.ContextRefreshedEvent;
|
||||
import org.springframework.core.env.Environment;
|
||||
import org.springframework.lang.NonNull;
|
||||
import org.springframework.stereotype.Component;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.LinkedHashSet;
|
||||
|
||||
/**
|
||||
* 项目启动监听器, 当项目启动时, 遍历当前对象存储的所有内容, 添加到缓存中.
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Component
|
||||
public class StartupListener implements ApplicationListener<ContextRefreshedEvent> {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(StartupListener.class);
|
||||
@Slf4j
|
||||
public class StartupListener implements ApplicationListener<ApplicationStartedEvent> {
|
||||
|
||||
@Resource
|
||||
private FileAsyncCacheService fileAsyncCacheService;
|
||||
|
||||
@Resource
|
||||
private Environment environment;
|
||||
|
||||
@Override
|
||||
public void onApplicationEvent(ContextRefreshedEvent event) {
|
||||
public void onApplicationEvent(@NonNull ApplicationStartedEvent event) {
|
||||
printStartInfo();
|
||||
cacheAllFile();
|
||||
}
|
||||
|
||||
private void printStartInfo() {
|
||||
String serverPort = environment.getProperty("server.port", "8080");
|
||||
|
||||
LinkedHashSet<String> localIps = NetUtil.localIps();
|
||||
StringBuilder indexAddr = new StringBuilder();
|
||||
StringBuilder indexAdminAddr = new StringBuilder();
|
||||
for (String localIp : localIps) {
|
||||
String addr = String.format("http://%s:%s", localIp, serverPort);
|
||||
indexAddr.append(addr).append("\t");
|
||||
indexAdminAddr.append(addr).append("/#/admin").append("\t");
|
||||
}
|
||||
log.info("ZFile started at " + indexAddr);
|
||||
log.info("ZFile Admin started at " + indexAdminAddr);
|
||||
}
|
||||
|
||||
private void cacheAllFile() {
|
||||
try {
|
||||
fileAsyncCacheService.cacheGlobalFile();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("缓存异常.", e);
|
||||
throw new InitializeException("初始化缓存异常.", e);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,13 +1,23 @@
|
||||
package im.zhaojun.common.util;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
public class StringUtils {
|
||||
|
||||
|
||||
public static final char DELIMITER = '/';
|
||||
|
||||
public static final String HTTP_PROTOCAL = "http://";
|
||||
|
||||
public static final String HTTPS_PROTOCAL = "https://";
|
||||
|
||||
/**
|
||||
* 移除 URL 中的第一个 '/'
|
||||
* @return 如 path = '/folder1/file1', 返回 'folder1/file1'
|
||||
*/
|
||||
public static String removeFirstSeparator(String path) {
|
||||
if (!"".equals(path) && path.charAt(0) == '/') {
|
||||
if (!"".equals(path) && path.charAt(0) == DELIMITER) {
|
||||
path = path.substring(1);
|
||||
}
|
||||
return path;
|
||||
@@ -18,14 +28,14 @@ public class StringUtils {
|
||||
* @return 如 path = '/folder1/file1/', 返回 '/folder1/file1'
|
||||
*/
|
||||
public static String removeLastSeparator(String path) {
|
||||
if (!"".equals(path) && path.charAt(path.length() - 1) == '/') {
|
||||
if (!"".equals(path) && path.charAt(path.length() - 1) == DELIMITER) {
|
||||
path = path.substring(0, path.length() - 1);
|
||||
}
|
||||
return path;
|
||||
}
|
||||
|
||||
public static String concatUrl(String path, String name) {
|
||||
return removeDuplicateSeparator("/" + path + "/" + name);
|
||||
return removeDuplicateSeparator(DELIMITER + path + DELIMITER + name);
|
||||
}
|
||||
|
||||
|
||||
@@ -36,11 +46,11 @@ public class StringUtils {
|
||||
* @return URL
|
||||
*/
|
||||
public static String concatPath(String domain, String path) {
|
||||
if (path != null && path.length() > 1 && path.charAt(0) != '/') {
|
||||
path = '/' + path;
|
||||
if (path != null && path.length() > 1 && path.charAt(0) != DELIMITER) {
|
||||
path = DELIMITER + path;
|
||||
}
|
||||
|
||||
if (domain.charAt(domain.length() - 1) == '/') {
|
||||
if (domain != null && domain.charAt(domain.length() - 1) == DELIMITER) {
|
||||
domain = domain.substring(0, domain.length() - 2);
|
||||
}
|
||||
|
||||
@@ -54,16 +64,16 @@ public class StringUtils {
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
if (path.indexOf("http://") == 0) {
|
||||
sb.append("http://");
|
||||
} else if (path.indexOf("https://") == 0) {
|
||||
sb.append("http://");
|
||||
if (path.indexOf(HTTP_PROTOCAL) == 0) {
|
||||
sb.append(HTTP_PROTOCAL);
|
||||
} else if (path.indexOf(HTTPS_PROTOCAL) == 0) {
|
||||
sb.append(HTTPS_PROTOCAL);
|
||||
}
|
||||
|
||||
for (int i = sb.length(); i < path.length() - 1; i++) {
|
||||
char current = path.charAt(i);
|
||||
char next = path.charAt(i + 1);
|
||||
if (!(current == '/' && next == '/')) {
|
||||
if (!(current == DELIMITER && next == DELIMITER)) {
|
||||
sb.append(current);
|
||||
}
|
||||
}
|
||||
@@ -75,5 +85,7 @@ public class StringUtils {
|
||||
return s == null || "".equals(s);
|
||||
}
|
||||
|
||||
|
||||
public static boolean isNotNullOrEmpty(String s) {
|
||||
return !isNullOrEmpty(s);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,9 +3,11 @@ package im.zhaojun.ftp.service;
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import cn.hutool.extra.ftp.Ftp;
|
||||
import im.zhaojun.common.model.StorageConfig;
|
||||
import im.zhaojun.common.model.constant.StorageConfigConstant;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
@@ -18,47 +20,44 @@ import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class FtpServiceImpl implements FileService {
|
||||
public class FtpServiceImpl extends AbstractFileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(FtpServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private static final String HOST_KEY = "host";
|
||||
|
||||
private static final String PORT_KEY = "port";
|
||||
|
||||
private static final String USERNAME_KEY = "username";
|
||||
|
||||
private static final String PASSWORD_KEY = "password";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private Ftp ftp;
|
||||
|
||||
private String domain;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.FTP);
|
||||
String host = stringStorageConfigMap.get(HOST_KEY).getValue();
|
||||
String port = stringStorageConfigMap.get(PORT_KEY).getValue();
|
||||
String username = stringStorageConfigMap.get(USERNAME_KEY).getValue();
|
||||
String password = stringStorageConfigMap.get(PASSWORD_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.FTP);
|
||||
String host = stringStorageConfigMap.get(StorageConfigConstant.HOST_KEY).getValue();
|
||||
String port = stringStorageConfigMap.get(StorageConfigConstant.PORT_KEY).getValue();
|
||||
String username = stringStorageConfigMap.get(StorageConfigConstant.USERNAME_KEY).getValue();
|
||||
String password = stringStorageConfigMap.get(StorageConfigConstant.PASSWORD_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||
|
||||
ftp = new Ftp(host, Integer.parseInt(port), username, password);
|
||||
isInitialized = true;
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.FTP.getDescription() + "初始化异常, 已跳过");
|
||||
}
|
||||
if (Objects.isNull(host) || Objects.isNull(port) || Objects.isNull(username) || Objects.isNull(password)) {
|
||||
isInitialized = false;
|
||||
} else {
|
||||
ftp = new Ftp(host, Integer.parseInt(port), username, password);
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
|
||||
} catch (Exception e) {
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -92,9 +91,11 @@ public class FtpServiceImpl implements FileService {
|
||||
return StorageTypeEnum.FTP;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
public FileItemDTO getFileItem(String path) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setUrl(getDownloadUrl(path));
|
||||
return fileItemDTO;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -1,132 +1,60 @@
|
||||
package im.zhaojun.huawei.service;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.obs.services.ObsClient;
|
||||
import com.obs.services.model.*;
|
||||
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.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
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 im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class HuaweiServiceImpl implements FileService {
|
||||
public class HuaweiServiceImpl extends AbstractS3FileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(HuaweiServiceImpl.class);
|
||||
|
||||
private String bucketName;
|
||||
|
||||
private String domain;
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private Long timeout;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
private static final String SECRET_KEY = "secretKey";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private static final String ENDPOINT_KEY = "endPoint";
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private ObsClient obsClient;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.HUAWEI);
|
||||
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
|
||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.HUAWEI);
|
||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
||||
|
||||
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
obsClient = new ObsClient(accessKey, secretKey, endPoint);
|
||||
isInitialized = true;
|
||||
bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||
|
||||
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()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "obs")).build();
|
||||
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.HUAWEI.getDescription() + "初始化异常, 已跳过");
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) throws Exception {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
|
||||
ListObjectsRequest listObjectsRequest = new ListObjectsRequest();
|
||||
listObjectsRequest.setBucketName(bucketName);
|
||||
listObjectsRequest.setDelimiter("/");
|
||||
listObjectsRequest.setPrefix(path);
|
||||
ObjectListing objectListing = obsClient.listObjects(listObjectsRequest);
|
||||
List<ObsObject> objects = objectListing.getObjects();
|
||||
|
||||
for (ObsObject object : objects) {
|
||||
String fileName = object.getObjectKey();
|
||||
ObjectMetadata metadata = object.getMetadata();
|
||||
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(fileName.substring(path.length()));
|
||||
fileItemDTO.setSize(metadata.getContentLength());
|
||||
fileItemDTO.setTime(metadata.getLastModified());
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(commonPrefix.substring(0, commonPrefix.length() - 1));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) throws Exception {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
TemporarySignatureRequest req = new TemporarySignatureRequest(HttpMethodEnum.GET, timeout);
|
||||
req.setBucketName(bucketName);
|
||||
req.setObjectKey(path);
|
||||
TemporarySignatureResponse res = obsClient.createTemporarySignature(req);
|
||||
URL url = new URL(res.getSignedUrl());
|
||||
return URLUtil.complateUrl(domain, url.getFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageTypeEnum getStorageTypeEnum() {
|
||||
return StorageTypeEnum.HUAWEI;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
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;
|
||||
@@ -16,9 +17,11 @@ import org.springframework.web.servlet.HandlerMapping;
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.Date;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Controller
|
||||
public class LocalController {
|
||||
|
||||
@@ -27,17 +30,22 @@ public class LocalController {
|
||||
|
||||
@GetMapping("/file/**")
|
||||
@ResponseBody
|
||||
public ResponseEntity<FileSystemResource> downAttachment(final HttpServletRequest request) throws IOException {
|
||||
public ResponseEntity<FileSystemResource> downAttachment(final HttpServletRequest request) {
|
||||
String path = (String) request.getAttribute(
|
||||
HandlerMapping.PATH_WITHIN_HANDLER_MAPPING_ATTRIBUTE);
|
||||
String bestMatchPattern = (String ) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||
String bestMatchPattern = (String) request.getAttribute(HandlerMapping.BEST_MATCHING_PATTERN_ATTRIBUTE);
|
||||
AntPathMatcher apm = new AntPathMatcher();
|
||||
String filePath = apm.extractPathWithinPattern(bestMatchPattern, path);
|
||||
|
||||
return export(new File(StringUtils.concatPath(localServiceImpl.getFilePath(), URLUtil.decode(filePath))));
|
||||
}
|
||||
|
||||
private ResponseEntity<FileSystemResource> export(File file) throws IOException {
|
||||
private ResponseEntity<FileSystemResource> export(File file) {
|
||||
|
||||
if (!file.exists()) {
|
||||
throw new NotExistFileException();
|
||||
}
|
||||
|
||||
|
||||
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
|
||||
|
||||
|
||||
@@ -1,36 +1,39 @@
|
||||
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;
|
||||
import im.zhaojun.common.model.constant.SystemConfigConstant;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.repository.SystemConfigRepository;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.io.File;
|
||||
import java.net.Inet4Address;
|
||||
import java.net.InetAddress;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class LocalServiceImpl implements FileService {
|
||||
public class LocalServiceImpl extends AbstractFileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(LocalServiceImpl.class);
|
||||
|
||||
private static final String FILE_PATH_KEY = "filePath";
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
@@ -39,22 +42,25 @@ public class LocalServiceImpl implements FileService {
|
||||
|
||||
private String filePath;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.LOCAL);
|
||||
filePath = stringStorageConfigMap.get(FILE_PATH_KEY).getValue();
|
||||
isInitialized = true;
|
||||
filePath = stringStorageConfigMap.get(StorageConfigConstant.FILE_PATH_KEY).getValue();
|
||||
if (Objects.isNull(filePath)) {
|
||||
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
|
||||
isInitialized = false;
|
||||
} else {
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.LOCAL.getDescription() + "初始化异常, 已跳过");
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) throws Exception {
|
||||
public List<FileItemDTO> fileList(String path) {
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
|
||||
String fullPath = StringUtils.concatPath(filePath, path);
|
||||
@@ -82,9 +88,9 @@ public class LocalServiceImpl implements FileService {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) throws Exception {
|
||||
public String getDownloadUrl(String path) {
|
||||
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
|
||||
return StringUtils.removeDuplicateSeparator(usernameConfig.getValue() + "/file/" + path);
|
||||
return URLUtil.encode(StringUtils.removeDuplicateSeparator(usernameConfig.getValue() + "/file/" + path));
|
||||
}
|
||||
|
||||
public String getFilePath() {
|
||||
@@ -100,10 +106,26 @@ public class LocalServiceImpl implements FileService {
|
||||
return StorageTypeEnum.LOCAL;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,109 +1,61 @@
|
||||
package im.zhaojun.minio;
|
||||
|
||||
import com.amazonaws.auth.AWSStaticCredentialsProvider;
|
||||
import com.amazonaws.auth.BasicAWSCredentials;
|
||||
import com.amazonaws.client.builder.AwsClientBuilder;
|
||||
import com.amazonaws.services.s3.AmazonS3ClientBuilder;
|
||||
import im.zhaojun.common.model.StorageConfig;
|
||||
import im.zhaojun.common.model.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
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 im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import io.minio.MinioClient;
|
||||
import io.minio.Result;
|
||||
import io.minio.messages.Item;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class MinIOServiceImpl implements FileService {
|
||||
|
||||
public class MinIOServiceImpl extends AbstractS3FileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(MinIOServiceImpl.class);
|
||||
|
||||
private String bucketName;
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private Long timeout;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
private static final String SECRET_KEY = "secretKey";
|
||||
|
||||
private static final String ENDPOINT_KEY = "endPoint";
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private MinioClient minioClient;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.MINIO);
|
||||
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
|
||||
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
minioClient = new MinioClient(endPoint, accessKey, secretKey);
|
||||
isInitialized = true;
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.MINIO.getDescription() + "初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.MINIO);
|
||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
||||
bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) throws Exception {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
|
||||
Iterable<Result<Item>> iterable = minioClient.listObjects(bucketName, path, false);
|
||||
|
||||
for (Result<Item> itemResult : iterable) {
|
||||
Item item = itemResult.get();
|
||||
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
if (item.isDir()) {
|
||||
fileItemDTO.setName(StringUtils.removeLastSeparator(item.objectName().replaceFirst(path, "")));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
|
||||
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
|
||||
isInitialized = false;
|
||||
} else {
|
||||
fileItemDTO.setName(item.objectName().replaceFirst(path, ""));
|
||||
fileItemDTO.setSize(item.objectSize());
|
||||
fileItemDTO.setTime(item.lastModified());
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
BasicAWSCredentials credentials = new BasicAWSCredentials(accessKey, secretKey);
|
||||
s3Client = AmazonS3ClientBuilder.standard()
|
||||
.withPathStyleAccessEnabled(true)
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "minio")).build();
|
||||
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
fileItemList.add(fileItemDTO);
|
||||
} catch (Exception e) {
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) throws Exception {
|
||||
return minioClient.presignedGetObject(bucketName, path, timeout.intValue());
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public StorageTypeEnum getStorageTypeEnum() {
|
||||
return StorageTypeEnum.MINIO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
* @date 2020/1/12 13:53
|
||||
*/
|
||||
@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();
|
||||
|
||||
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(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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
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;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.Collections;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
* @date 2020/1/18 17:13
|
||||
*/
|
||||
@Configuration
|
||||
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(type, StorageConfigConstant.ACCESS_TOKEN_KEY);
|
||||
|
||||
String tokenValue = String.format("%s %s", "Bearer", accessTokenConfig.getValue());
|
||||
httpRequest.getHeaders().add("Authorization", tokenValue);
|
||||
return clientHttpRequestExecution.execute(httpRequest, bytes);
|
||||
};
|
||||
restTemplate.setInterceptors(Collections.singletonList(interceptor));
|
||||
return restTemplate;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package im.zhaojun.onedrive.common.controller;
|
||||
|
||||
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;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Controller
|
||||
@RequestMapping("/onedirve")
|
||||
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);
|
||||
model.addAttribute("accessToken", oneDriveToken.getAccessToken());
|
||||
model.addAttribute("refreshToken", oneDriveToken.getRefreshToken());
|
||||
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";
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
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 {
|
||||
|
||||
@JSONField(name = "access_token")
|
||||
private String accessToken;
|
||||
|
||||
@JSONField(name = "refresh_token")
|
||||
private String refreshToken;
|
||||
}
|
||||
@@ -0,0 +1,172 @@
|
||||
package im.zhaojun.onedrive.common.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 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.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() {
|
||||
StorageConfig refreshStorageConfig =
|
||||
storageConfigRepository.findByTypeAndKey(StorageTypeEnum.ONE_DRIVE, 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 path) {
|
||||
List<FileItemDTO> result = new ArrayList<>();
|
||||
String nextLink = null;
|
||||
|
||||
do {
|
||||
|
||||
String requestUrl;
|
||||
|
||||
if (nextLink != null) {
|
||||
requestUrl = nextLink;
|
||||
}else if ("/".equalsIgnoreCase(path)) {
|
||||
requestUrl = DRIVER_ROOT_URL;
|
||||
} else {
|
||||
requestUrl = DRIVER_ITEMS_URL;
|
||||
}
|
||||
path = StringUtils.removeLastSeparator(path);
|
||||
|
||||
ResponseEntity<String> responseEntity = oneDriveRestTemplate.getForEntity(requestUrl, String.class, getGraphEndPoint(), path);
|
||||
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();
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
// package im.zhaojun.onedrive.config;
|
||||
//
|
||||
// import org.nuxeo.onedrive.client.*;
|
||||
// import org.springframework.context.annotation.Configuration;
|
||||
//
|
||||
// @Configuration
|
||||
// public class OneDriveConfig {
|
||||
//
|
||||
//
|
||||
// public void a () {
|
||||
// OneDriveAPI api = new OneDriveBasicAPI("YOUR_ACCESS_TOKEN");
|
||||
//
|
||||
// OneDriveFolder folder = new OneDriveFolder(api, "FOLDER_ID");
|
||||
// OneDriveFile file = new OneDriveFile(api, "FILE_ID");
|
||||
// }
|
||||
//
|
||||
// public static void main(String[] args) throws OneDriveAPIException {
|
||||
// OneDriveBasicAPI api = new OneDriveBasicAPI("EwAgA61DBAAUcSSzoTJJsy+XrnQXgAKO5cj4yc8AAQ0ZknDUY8YnwB9aJv7vA9YjiRAVMnKc+rG11fSXLZRAA8Q/CgJaz+OkRN60vaLDfp6KxbmVlob6kxeD/peOUI2eHtk0055Q2+n057tlyVAvGIFl9dvqkItoAthjmybcSkKBZS5h1meWxQ5IOvzSVrdgCKL0NOtTxfh33ZUDsYjvSid6NOX4Bs+pRjvZhQkvqEfGt8KlOL+JoIowmv2I+u09iDmS60BMwSoeK2K3CCLIXxLaiiPYUMsrNk65j4PWEBwBEfyHb6j3lrM/YvwFLq7Y8KJVjrXjFENC7ruja6Ko/cfTMX90yLkUEckpsZ30E6RJHWEHt7jXtNwndDZVknYDZgAACL5pnk17FJfb8AGGxJL1Y0CnAzgkTM2gw+WkFRRDDNzujuW1LQofwZ119HdeANhPrBZ14x32VaPGL1l0RvtR9LCeAN+EogcV5xhVpmCExitaXQB6OkZ6BnXaxLj5TNvFRNeZq0ZfJ3T08clLA1vXHkZhNKgiFDI8xUbahy4r6QpzgoF+0+dz+MA1NzQCQCsRGieS63OD1BKrzRsNxzls5Z9rKzBT6CpWpiaiOg4mmW0yeino/L9zz9Gf5kAJr813bpNr+rH/E8MPd0pZf+6hv37FaVCM7RN1V7CkkCDnRAxwxEK8pDgZhRjZOw7gKutPOiOoTO9ptjh2Jcrds714HitX2HI3RsRY+yyAOcb8XI27m4daSEGCJCuu/TJwXTE4ul54MWsi8MrcDlZN9DOjckiJIqVI8IbvhM+OUAP4FUIfZJJrIVa8WFwxcsMmjlLTxp/I7+JfdvZjJSk3j1yYvbWFviyoSkpQgw2hIDhZxCg083Z6qS467g5H9Uz3fQc+Ss0K0Mud6RcZTU9RqCcp+h92tUc8+gDxQ2NwJsG5vcmSRwf5KHKvsWjt6yK4OHxCpkLYi31eJZtv2EjQGXX1gYyhc/2wQ+cHPvbgBzIfhXetbZKpSxoowAQO/J1i5oRs90h24kjTd4qJd3qspxk1lhZcEC8IkfZXjNgjEQI=");
|
||||
//
|
||||
// OneDriveFolder folder = new OneDriveFolder(api, "PDF");
|
||||
//
|
||||
// for (OneDriveItem.Metadata metadata : OneDriveFolder.getRoot(api)) {
|
||||
// System.out.println(metadata.getName());
|
||||
// if (metadata.isFile()) {
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// // for (OneDriveItem.Metadata search : OneDriveFolder.getRoot(api).search("index.html")) {
|
||||
// // System.out.println(search.getName());
|
||||
// // }
|
||||
//
|
||||
// // OneDriveFile file = new OneDriveFile(api, "key.txt");
|
||||
// // System.out.println(file);
|
||||
// }
|
||||
// }
|
||||
@@ -1,42 +0,0 @@
|
||||
package im.zhaojun.onedrive.controller;
|
||||
|
||||
import cn.hutool.http.HttpRequest;
|
||||
import cn.hutool.http.HttpResponse;
|
||||
import cn.hutool.http.HttpUtil;
|
||||
import org.springframework.http.HttpHeaders;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.stereotype.Controller;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.ResponseBody;
|
||||
import org.springframework.web.client.RestTemplate;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
|
||||
@Controller
|
||||
public class OneDriveController {
|
||||
|
||||
@Resource
|
||||
private RestTemplate restTemplate;
|
||||
|
||||
@GetMapping("/onedirve/callback")
|
||||
@ResponseBody
|
||||
public String onedriveCallback(String code, HttpServletRequest request) {
|
||||
RestTemplate restTemplate = new RestTemplate();
|
||||
HttpHeaders headers = new HttpHeaders();
|
||||
MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
|
||||
headers.setContentType(type);
|
||||
headers.add("Accept", MediaType.APPLICATION_JSON.toString());
|
||||
|
||||
String json = "client_id=04a73532-6c16-4fe4-92e5-f2cd125ed553&redirect_uri=http://localhost:8080/onedirve/callback&client_secret=2gY/t?*Eff6i36TgKTtiG*08/k]@.I4[&code=" + code + "&grant_type=authorization_code";
|
||||
|
||||
HttpRequest post = HttpUtil.createPost("https://login.microsoftonline.com/common/oauth2/v2.0/token");
|
||||
post.body(json, "application/x-www-form-urlencoded");
|
||||
HttpResponse response = post.execute();
|
||||
|
||||
System.out.println(response.body());
|
||||
return response.body();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,83 @@
|
||||
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 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
|
||||
* @date 2020/1/12 13:53
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class OneDriveServiceImpl extends AbstractFileService implements FileService {
|
||||
|
||||
@Resource
|
||||
private GlobalScheduleTask globalScheduleTask;
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
@Resource
|
||||
private OneDriveService oneDriveService;
|
||||
|
||||
@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();
|
||||
|
||||
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 oneDriveService.list(path);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
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;
|
||||
}
|
||||
}
|
||||
@@ -1,130 +1,55 @@
|
||||
package im.zhaojun.qiniu.service;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.qiniu.common.Zone;
|
||||
import com.qiniu.storage.BucketManager;
|
||||
import com.qiniu.storage.Configuration;
|
||||
import com.qiniu.storage.model.FileInfo;
|
||||
import com.qiniu.storage.model.FileListing;
|
||||
import com.qiniu.util.Auth;
|
||||
import 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.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
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 im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class QiniuServiceImpl implements FileService {
|
||||
public class QiniuServiceImpl extends AbstractS3FileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(QiniuServiceImpl.class);
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private Long timeout;
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String ACCESS_KEY = "accessKey";
|
||||
|
||||
private static final String SECRET_KEY = "secretKey";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private BucketManager bucketManager;
|
||||
|
||||
private Auth auth;
|
||||
|
||||
private String bucketName;
|
||||
|
||||
private String domain;
|
||||
|
||||
private boolean isPrivate;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.QINIU);
|
||||
String accessKey = stringStorageConfigMap.get(ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
|
||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.QINIU);
|
||||
String accessKey = stringStorageConfigMap.get(StorageConfigConstant.ACCESS_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(StorageConfigConstant.SECRET_KEY).getValue();
|
||||
String endPoint = stringStorageConfigMap.get(StorageConfigConstant.ENDPOINT_KEY).getValue();
|
||||
|
||||
Configuration cfg = new Configuration(Zone.autoZone());
|
||||
auth = Auth.create(accessKey, secretKey);
|
||||
bucketManager = new BucketManager(auth, cfg);
|
||||
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||
|
||||
isPrivate = bucketManager.getBucketInfo(bucketName).getPrivate() == 1;
|
||||
isInitialized = true;
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.QINIU.getDescription() + "初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
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()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "kodo")).build();
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) throws Exception {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
|
||||
// 每次迭代的长度限制, 最大1000, 推荐值 1000
|
||||
int limit = 1000;
|
||||
// 指定目录分隔符, 列出所有公共前缀(模拟列出目录效果). 缺省值为空字符串
|
||||
String delimiter = "/";
|
||||
// 列举空间文件列表
|
||||
FileListing fileListing = bucketManager.listFilesV2(bucketName, path, "", limit, delimiter);
|
||||
for (FileInfo item : fileListing.items) {
|
||||
String fileKey = item.key;
|
||||
String fileName = fileKey.substring(path.length());
|
||||
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(fileName);
|
||||
fileItemDTO.setSize(item.fsize);
|
||||
fileItemDTO.setTime(new Date(item.putTime / 1000));
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
String[] commonPrefixes = fileListing.commonPrefixes;
|
||||
|
||||
for (String commonPrefix : commonPrefixes) {
|
||||
if ("/".equals(commonPrefix)) {
|
||||
continue;
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(commonPrefix.substring(0, commonPrefix.length() - 1));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemList.add(fileItemDTO);
|
||||
} catch (Exception e) {
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) {
|
||||
String url = URLUtil.complateUrl(domain, path);
|
||||
if (isPrivate) {
|
||||
url = auth.privateDownloadUrl(url, timeout);
|
||||
}
|
||||
return url;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -132,10 +57,4 @@ public class QiniuServiceImpl implements FileService {
|
||||
return StorageTypeEnum.QINIU;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,128 +1,61 @@
|
||||
package im.zhaojun.tencent;
|
||||
|
||||
import cn.hutool.core.util.URLUtil;
|
||||
import com.qcloud.cos.COSClient;
|
||||
import com.qcloud.cos.ClientConfig;
|
||||
import com.qcloud.cos.auth.BasicCOSCredentials;
|
||||
import com.qcloud.cos.auth.COSCredentials;
|
||||
import com.qcloud.cos.model.COSObjectSummary;
|
||||
import com.qcloud.cos.model.ListObjectsRequest;
|
||||
import com.qcloud.cos.model.ObjectListing;
|
||||
import com.qcloud.cos.region.Region;
|
||||
import 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.dto.FileItemDTO;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
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 im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.net.URL;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class TencentServiceImpl implements FileService {
|
||||
public class TencentServiceImpl extends AbstractS3FileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(TencentServiceImpl.class);
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String SECRET_ID_KEY = "secretId";
|
||||
|
||||
private static final String SECRET_KEY = "secretKey";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private static final String ENDPOINT_KEY = "endPoint";
|
||||
|
||||
@Value("${zfile.cache.timeout}")
|
||||
private Long timeout;
|
||||
|
||||
private String bucketName;
|
||||
|
||||
private String domain;
|
||||
|
||||
private COSClient cosClient;
|
||||
|
||||
private boolean isInitialized;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.TENCENT);
|
||||
String secretId = stringStorageConfigMap.get(SECRET_ID_KEY).getValue();
|
||||
String secretKey = stringStorageConfigMap.get(SECRET_KEY).getValue();
|
||||
String regionName = stringStorageConfigMap.get(ENDPOINT_KEY).getValue();
|
||||
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
Map<String, StorageConfig> stringStorageConfigMap = storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.TENCENT);
|
||||
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();
|
||||
bucketName = stringStorageConfigMap.get(StorageConfigConstant.BUCKET_NAME_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||
|
||||
COSCredentials cred = new BasicCOSCredentials(secretId, secretKey);
|
||||
Region region = new Region(regionName);
|
||||
ClientConfig clientConfig = new ClientConfig(region);
|
||||
cosClient = new COSClient(cred, clientConfig);
|
||||
isInitialized = true;
|
||||
if (Objects.isNull(secretId) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
|
||||
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
|
||||
isInitialized = false;
|
||||
} else {
|
||||
BasicAWSCredentials credentials = new BasicAWSCredentials(secretId, secretKey);
|
||||
s3Client = AmazonS3ClientBuilder.standard()
|
||||
.withCredentials(new AWSStaticCredentialsProvider(credentials))
|
||||
.withEndpointConfiguration(new AwsClientBuilder.EndpointConfiguration(endPoint, "cos")).build();
|
||||
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.TENCENT.getDescription() + "初始化异常, 已跳过");
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<FileItemDTO> fileList(String path) {
|
||||
path = StringUtils.removeFirstSeparator(path);
|
||||
|
||||
List<FileItemDTO> fileItemList = new ArrayList<>();
|
||||
ObjectListing objectListing = cosClient.listObjects(new ListObjectsRequest().withBucketName(bucketName).withDelimiter("/").withPrefix(path));
|
||||
for (COSObjectSummary s : objectListing.getObjectSummaries()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(s.getKey().substring(path.length()));
|
||||
fileItemDTO.setSize(s.getSize());
|
||||
fileItemDTO.setTime(s.getLastModified());
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
for (String commonPrefix : objectListing.getCommonPrefixes()) {
|
||||
FileItemDTO fileItemDTO = new FileItemDTO();
|
||||
fileItemDTO.setName(commonPrefix.substring(path.length(), commonPrefix.length() - 1));
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
fileItemDTO.setPath(path);
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
|
||||
return fileItemList;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getDownloadUrl(String path) {
|
||||
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
|
||||
URL url = cosClient.generatePresignedUrl(bucketName, path, expirationDate);
|
||||
return URLUtil.complateUrl(domain, url.getFile());
|
||||
}
|
||||
|
||||
@Override
|
||||
public StorageTypeEnum getStorageTypeEnum() {
|
||||
return StorageTypeEnum.TENCENT;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -1,16 +1,19 @@
|
||||
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;
|
||||
import im.zhaojun.common.model.enums.FileTypeEnum;
|
||||
import im.zhaojun.common.model.enums.StorageTypeEnum;
|
||||
import im.zhaojun.common.service.AbstractFileService;
|
||||
import im.zhaojun.common.service.FileService;
|
||||
import im.zhaojun.common.service.StorageConfigService;
|
||||
import im.zhaojun.common.util.StringUtils;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
@@ -18,42 +21,47 @@ import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
|
||||
/**
|
||||
* @author zhaojun
|
||||
*/
|
||||
@Service
|
||||
public class UpYunServiceImpl implements FileService {
|
||||
@Slf4j
|
||||
public class UpYunServiceImpl extends AbstractFileService implements FileService {
|
||||
|
||||
private static final Logger log = LoggerFactory.getLogger(UpYunServiceImpl.class);
|
||||
private static final String END_MARK = "g2gCZAAEbmV4dGQAA2VvZg";
|
||||
|
||||
@Resource
|
||||
private StorageConfigService storageConfigService;
|
||||
|
||||
private static final String BUCKET_NAME_KEY = "bucket-name";
|
||||
|
||||
private static final String USERNAME_KEY = "username";
|
||||
|
||||
private static final String PASSWORD_KEY = "password";
|
||||
|
||||
private static final String DOMAIN_KEY = "domain";
|
||||
|
||||
private String domain;
|
||||
|
||||
private UpYun upYun;
|
||||
|
||||
private boolean isInitialized;
|
||||
private String basePath;
|
||||
|
||||
@Override
|
||||
public void init() {
|
||||
try {
|
||||
Map<String, StorageConfig> stringStorageConfigMap =
|
||||
storageConfigService.selectStorageConfigMapByKey(StorageTypeEnum.UPYUN);
|
||||
String bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
|
||||
String username = stringStorageConfigMap.get(USERNAME_KEY).getValue();
|
||||
String password = stringStorageConfigMap.get(PASSWORD_KEY).getValue();
|
||||
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
|
||||
upYun = new UpYun(bucketName, username, password);
|
||||
isInitialized = true;
|
||||
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();
|
||||
domain = stringStorageConfigMap.get(StorageConfigConstant.DOMAIN_KEY).getValue();
|
||||
basePath = stringStorageConfigMap.get(StorageConfigConstant.BASE_PATH).getValue();
|
||||
basePath = ObjectUtil.defaultIfNull(basePath, "");
|
||||
|
||||
if (Objects.isNull(bucketName) || Objects.isNull(username) || Objects.isNull(password)) {
|
||||
log.debug("初始化存储策略 [{}] 失败: 参数不完整", getStorageTypeEnum().getDescription());
|
||||
isInitialized = false;
|
||||
} else {
|
||||
upYun = new UpYun(bucketName, username, password);
|
||||
isInitialized = testConnection();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.debug(StorageTypeEnum.UPYUN.getDescription() + "初始化异常, 已跳过");
|
||||
log.debug(getStorageTypeEnum().getDescription() + " 初始化异常, 已跳过");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,7 +74,7 @@ public class UpYunServiceImpl implements FileService {
|
||||
HashMap<String, String> hashMap = new HashMap<>(24);
|
||||
hashMap.put("x-list-iter", nextMark);
|
||||
hashMap.put("x-list-limit", "100");
|
||||
UpYun.FolderItemIter folderItemIter = upYun.readDirIter(URLUtil.encode(path), hashMap);
|
||||
UpYun.FolderItemIter folderItemIter = upYun.readDirIter(URLUtil.encode(basePath + path), hashMap);
|
||||
nextMark = folderItemIter.iter;
|
||||
ArrayList<UpYun.FolderItem> folderItems = folderItemIter.files;
|
||||
if (folderItems != null) {
|
||||
@@ -81,12 +89,12 @@ public class UpYunServiceImpl implements FileService {
|
||||
fileItemDTO.setType(FileTypeEnum.FOLDER);
|
||||
} else {
|
||||
fileItemDTO.setType(FileTypeEnum.FILE);
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
|
||||
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(basePath + path, fileItemDTO.getName())));
|
||||
}
|
||||
fileItemList.add(fileItemDTO);
|
||||
}
|
||||
}
|
||||
} while (!"g2gCZAAEbmV4dGQAA2VvZg".equals(nextMark));
|
||||
} while (!END_MARK.equals(nextMark));
|
||||
return fileItemList;
|
||||
|
||||
}
|
||||
@@ -101,11 +109,23 @@ public class UpYunServiceImpl implements FileService {
|
||||
return StorageTypeEnum.UPYUN;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public boolean getIsInitialized() {
|
||||
return isInitialized;
|
||||
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();
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
@@ -4,5 +4,38 @@
|
||||
"name": "zfile.cache.timeout",
|
||||
"type": "java.lang.Long",
|
||||
"description": "目录缓存过期时间 和 下载地址过期时间. 单位为秒."
|
||||
},
|
||||
{
|
||||
"name": "zfile.constant.header",
|
||||
"type": "java.lang.String",
|
||||
"defaultValue": "header.md",
|
||||
"description": "头部文件 文件名."
|
||||
},
|
||||
{
|
||||
"name": "zfile.constant.password",
|
||||
"type": "java.lang.String",
|
||||
"defaultValue": "password.txt",
|
||||
"description": "密码文件 文件名."
|
||||
},
|
||||
{
|
||||
"name": "zfile.onedirve.clientId",
|
||||
"type": "java.lang.String",
|
||||
"description": "OneDrive ClientId."
|
||||
},
|
||||
{
|
||||
"name": "zfile.onedirve.clientSecret",
|
||||
"type": "java.lang.String",
|
||||
"description": "OneDrive ClientSecret."
|
||||
},
|
||||
{
|
||||
"name": "zfile.onedirve.redirectUri",
|
||||
"type": "java.lang.String",
|
||||
"description": "OneDrive 认证重定向地址."
|
||||
},
|
||||
{
|
||||
"name": "zfile.onedirve.scope",
|
||||
"type": "java.lang.String",
|
||||
"description": "OneDrive 认证权限."
|
||||
}
|
||||
] }
|
||||
]
|
||||
}
|
||||
@@ -1,20 +1,13 @@
|
||||
logging:
|
||||
level:
|
||||
im:
|
||||
zhaojun:
|
||||
common: debug
|
||||
path: ${user.home}/.zfile/logs
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
servlet:
|
||||
context-path: ''
|
||||
|
||||
tomcat:
|
||||
max-threads: 20
|
||||
compression:
|
||||
enabled: true
|
||||
|
||||
spring:
|
||||
cache:
|
||||
type: caffeine
|
||||
# type: redis
|
||||
datasource:
|
||||
# 初始化数据导入
|
||||
data: classpath*:db/data.sql
|
||||
@@ -23,13 +16,13 @@ spring:
|
||||
|
||||
# h2 内存数据库 配置
|
||||
driver-class-name: org.h2.Driver
|
||||
url: jdbc:h2:~/.zfile/db/zfile-demo
|
||||
username: zfile-demo
|
||||
url: jdbc:h2:~/.zfile/db/zfile
|
||||
username: zfile
|
||||
password: 123456
|
||||
|
||||
# MySQL 配置
|
||||
# driver-class-name: com.mysql.jdbc.Driver
|
||||
# url: jdbc:mysql://127.0.0.1:3306/zfile-demo?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
# url: jdbc:mysql://127.0.0.1:3306/zfile?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
|
||||
# username: root
|
||||
# password: 123456
|
||||
jackson:
|
||||
@@ -41,13 +34,33 @@ spring:
|
||||
properties:
|
||||
hibernate:
|
||||
format_sql: false
|
||||
show-sql: true
|
||||
show-sql: false
|
||||
resources:
|
||||
chain:
|
||||
gzipped: true
|
||||
redis:
|
||||
host: 127.0.0.1
|
||||
password: 12345
|
||||
profiles:
|
||||
active: prod
|
||||
zfile:
|
||||
cache:
|
||||
timeout: 300
|
||||
timeout: 300
|
||||
constant:
|
||||
header: header.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
|
||||
areaInCacheName: false
|
||||
local:
|
||||
default:
|
||||
type: caffeine
|
||||
keyConvertor: fastjson
|
||||
@@ -1,43 +1,58 @@
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (1, 'siteName', '站点名称', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (2, 'infoEnable', '是否开启信息框', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (3, 'searchEnable', '是否开启搜索', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (4, 'searchIgnoreCase', '是否搜索时忽略大小写', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (5, 'storageStrategy', '当前启用存储引擎', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (6, 'username', '管理员账号', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (7, 'password', '管理员密码', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`, `VALUE`) VALUES (8, 'domain', '站点域名', null);
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (1, 'siteName', '站点名称');
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (2, 'infoEnable', '是否开启信息框');
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (3, 'searchEnable', '是否开启搜索');
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (4, 'searchIgnoreCase', '是否搜索时忽略大小写');
|
||||
INSERT INTO SYSTEM_CONFIG (`ID`, `k`, `REMARK`) VALUES (5, 'storageStrategy', '当前启用存储引擎');
|
||||
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`, `VALUE`) VALUES (1, 'bucket-name', '云存储服务名称', 'upyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (2, 'username', '操作员名称', 'upyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (3, 'password', '操作员密码', 'upyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (4, 'domain', '加速域名', 'upyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (5, 'accessKey', 'AccessKey', 'qiniu', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (6, 'secretKey', 'SecretKey', 'qiniu', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (7, 'bucket-name', '存储空间名称', 'qiniu', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (8, 'domain', '加速域名', 'qiniu', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (9, 'accessKey', 'AccessKey', 'huawei', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (10, 'secretKey', 'SecretKey', 'huawei', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (11, 'bucket-name', '云存储服务名称', 'huawei', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (12, 'domain', '加速域名', 'huawei', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (13, 'endPoint', '区域', 'huawei', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (14, 'accessKey', 'AccessKey', 'aliyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (15, 'secretKey', 'SecretKey', 'aliyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (16, 'bucket-name', 'Bucket 名称', 'aliyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (17, 'domain', 'Bucket 域名 / CDN 加速域名', 'aliyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (18, 'endPoint', '区域', 'aliyun', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (19, 'filePath', '文件路径', 'local', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (20, 'host', '域名或IP', 'ftp', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (21, 'port', '端口', 'ftp', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (22, 'username', '用户名', 'ftp', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (23, 'password', '密码', 'ftp', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (24, 'domain', '域名', 'ftp', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (25, 'secretId', 'SecretId', 'tencent', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (26, 'secretKey', 'SecretKey', 'tencent', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (27, 'bucket-name', '云存储服务名称', 'tencent', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (28, 'domain', '加速域名', 'tencent', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (29, 'endPoint', '区域', 'tencent', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (30, 'accessKey', 'SecretId', 'minio', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (31, 'secretKey', 'SecretKey', 'minio', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (32, 'endPoint', '服务地址', 'minio', null);
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (33, 'bucket-name', '存储空间名称', 'minio', null);
|
||||
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');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (3, 'password', '操作员密码', 'upyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (4, 'domain', '加速域名', 'upyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (5, 'accessKey', 'AccessKey', 'qiniu');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (6, 'secretKey', 'SecretKey', 'qiniu');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (7, 'bucket-name', '存储空间名称', 'qiniu');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (8, 'domain', '加速域名', 'qiniu');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (9, 'accessKey', 'AccessKey', 'huawei');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (10, 'secretKey', 'SecretKey', 'huawei');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (11, 'bucket-name', '云存储服务名称', 'huawei');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (12, 'domain', '加速域名', 'huawei');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (13, 'endPoint', '区域', 'huawei');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (14, 'accessKey', 'AccessKey', 'aliyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (15, 'secretKey', 'SecretKey', 'aliyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (16, 'bucket-name', 'Bucket 名称', 'aliyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (17, 'domain', 'Bucket 域名 / CDN 加速域名', 'aliyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (18, 'endPoint', '区域', 'aliyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (19, 'filePath', '文件路径', 'local');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (20, 'host', '域名或IP', 'ftp');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (21, 'port', '端口', 'ftp');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (22, 'username', '用户名', 'ftp');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (23, 'password', '密码', 'ftp');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (24, 'domain', '域名', 'ftp');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (25, 'secretId', 'SecretId', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (26, 'secretKey', 'SecretKey', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (27, 'bucket-name', '云存储服务名称', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (28, 'domain', '加速域名', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (29, 'endPoint', '区域', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (30, 'accessKey', 'AccessKey', 'minio');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (31, 'secretKey', 'SecretKey', 'minio');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (32, 'endPoint', '服务地址', 'minio');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (33, 'bucket-name', '存储空间名称', 'minio');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (34, 'base-path', '基路径', 'upyun');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (35, 'base-path', '基路径', 'minio');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (36, 'base-path', '基路径', 'tencent');
|
||||
INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`) VALUES (37, 'endPoint', '区域', 'qiniu');
|
||||
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 (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');
|
||||
100
src/main/resources/logback-spring.xml
Normal file
100
src/main/resources/logback-spring.xml
Normal file
@@ -0,0 +1,100 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
|
||||
<!--
|
||||
scan:当此属性设置为true时,配置文件如果发生改变,将会被重新加载,默认值为true。
|
||||
scanPeriod:设置监测配置文件是否有修改的时间间隔,如果没有给出时间单位,默认单位是毫秒当scan为true时,此属性生效。默认的时间间隔为1分钟。
|
||||
debug:当此属性设置为true时,将打印出logback内部日志信息,实时查看logback运行状态。默认值为false。
|
||||
-->
|
||||
<configuration scan="false" scanPeriod="60 seconds" debug="false">
|
||||
|
||||
<conversionRule conversionWord="clr" converterClass="org.springframework.boot.logging.logback.ColorConverter"/>
|
||||
<conversionRule conversionWord="wex"
|
||||
converterClass="org.springframework.boot.logging.logback.WhitespaceThrowableProxyConverter"/>
|
||||
<conversionRule conversionWord="wEx"
|
||||
converterClass="org.springframework.boot.logging.logback.ExtendedWhitespaceThrowableProxyConverter"/>
|
||||
|
||||
<!-- 定义日志的根目录 -->
|
||||
<property name="LOG_HOME" value="${user.home}/.zfile/logs"/>
|
||||
<!-- 定义日志文件名称 -->
|
||||
<property name="appName" value="zfile"/>
|
||||
|
||||
<!-- ch.qos.logback.core.ConsoleAppender 表示控制台输出 -->
|
||||
<appender name="stdout" class="ch.qos.logback.core.ConsoleAppender">
|
||||
<springProfile name="prod">
|
||||
<filter class="ch.qos.logback.classic.filter.ThresholdFilter">
|
||||
<level>INFO</level>
|
||||
</filter>
|
||||
</springProfile>
|
||||
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>%clr(%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}}){faint} %clr(${LOG_LEVEL_PATTERN:-%5p}) %clr(${PID:- }){magenta} %clr(---){faint} %clr([%15.15t]){faint} %clr(%-40.40logger{39}){cyan} %clr(:){faint} %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!-- 滚动记录文件,先将日志记录到指定文件,当符合某个条件时,将日志记录到其他文件 -->
|
||||
<appender name="appLogAppender" class="ch.qos.logback.core.rolling.RollingFileAppender">
|
||||
<!-- 指定日志文件的名称 -->
|
||||
<file>${LOG_HOME}/${appName}.log</file>
|
||||
|
||||
<!--
|
||||
当发生滚动时,决定 RollingFileAppender 的行为,涉及文件移动和重命名
|
||||
TimeBasedRollingPolicy: 最常用的滚动策略,它根据时间来制定滚动策略,既负责滚动也负责出发滚动。
|
||||
-->
|
||||
<rollingPolicy class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
|
||||
<!--
|
||||
滚动时产生的文件的存放位置及文件名称 %d{yyyy-MM-dd}:按天进行日志滚动
|
||||
%i:当文件大小超过maxFileSize时,按照i进行文件滚动
|
||||
-->
|
||||
<fileNamePattern>${LOG_HOME}/${appName}-%d{yyyy-MM-dd}-%i.log</fileNamePattern>
|
||||
<!--
|
||||
可选节点,控制保留的归档文件的最大数量,超出数量就删除旧文件。假设设置每天滚动,
|
||||
且maxHistory是365,则只保存最近365天的文件,删除之前的旧文件。注意,删除旧文件是,
|
||||
那些为了归档而创建的目录也会被删除。
|
||||
-->
|
||||
<MaxHistory>365</MaxHistory>
|
||||
<!--
|
||||
当日志文件超过maxFileSize指定的大小是,根据上面提到的%i进行日志文件滚动 注意此处配置SizeBasedTriggeringPolicy是无法实现按文件大小进行滚动的,必须配置timeBasedFileNamingAndTriggeringPolicy
|
||||
-->
|
||||
<timeBasedFileNamingAndTriggeringPolicy class="ch.qos.logback.core.rolling.SizeAndTimeBasedFNATP">
|
||||
<maxFileSize>5MB</maxFileSize>
|
||||
</timeBasedFileNamingAndTriggeringPolicy>
|
||||
</rollingPolicy>
|
||||
<!-- 日志输出格式: -->
|
||||
<layout class="ch.qos.logback.classic.PatternLayout">
|
||||
<pattern>%d{${LOG_DATEFORMAT_PATTERN:-yyyy-MM-dd HH:mm:ss.SSS}} ${LOG_LEVEL_PATTERN:-%5p} ${PID:- } --- [%t] %-40.40logger{39} : %m%n${LOG_EXCEPTION_CONVERSION_WORD:-%wEx}</pattern>
|
||||
</layout>
|
||||
</appender>
|
||||
|
||||
<!--
|
||||
logger主要用于存放日志对象,也可以定义日志类型、级别
|
||||
name:表示匹配的logger类型前缀,也就是包的前半部分
|
||||
level:要记录的日志级别,包括 TRACE < DEBUG < INFO < WARN < ERROR
|
||||
additivity:作用在于children-logger是否使用 rootLogger配置的appender进行输出,
|
||||
false:表示只用当前logger的appender-ref,
|
||||
true: 表示当前logger的appender-ref和rootLogger的appender-ref都有效
|
||||
-->
|
||||
|
||||
<!-- jetCache logger -->
|
||||
<logger name="com.alicp" additivity="false" level="debug"/>
|
||||
|
||||
<!-- hibernate logger -->
|
||||
<logger name="org.hibernate.SQL" additivity="false" level="debug"/>
|
||||
|
||||
<springProfile name="dev">
|
||||
<logger name="im.zhaojun" additivity="true" level="debug"/>
|
||||
</springProfile>
|
||||
|
||||
<springProfile name="prod">
|
||||
<logger name="im.zhaojun" additivity="true" level="debug"/>
|
||||
</springProfile>
|
||||
|
||||
<!--
|
||||
root与logger是父子关系,没有特别定义则默认为root,任何一个类只会和一个logger对应,
|
||||
要么是定义的logger,要么是root,判断的关键在于找到这个logger,然后判断这个logger的appender和level。
|
||||
-->
|
||||
<root level="info">
|
||||
<appender-ref ref="stdout"/>
|
||||
<appender-ref ref="appLogAppender"/>
|
||||
</root>
|
||||
|
||||
</configuration>
|
||||
1
src/main/resources/static/css/adminIndex.25eab1c6.css
Normal file
1
src/main/resources/static/css/adminIndex.25eab1c6.css
Normal file
@@ -0,0 +1 @@
|
||||
.el-menu[data-v-0d38e212],.el-row[data-v-0d38e212]{height:100vh}
|
||||
File diff suppressed because one or more lines are too long
1
src/main/resources/static/css/app.22664175.css
Normal file
1
src/main/resources/static/css/app.22664175.css
Normal file
File diff suppressed because one or more lines are too long
1
src/main/resources/static/css/chunk-vendors.39edcc5c.css
Normal file
1
src/main/resources/static/css/chunk-vendors.39edcc5c.css
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
src/main/resources/static/css/install.b4e8b552.css
Normal file
1
src/main/resources/static/css/install.b4e8b552.css
Normal file
@@ -0,0 +1 @@
|
||||
.box-card[data-v-7e472c9a]{padding-top:30px;padding-right:30px;margin:15vh auto;height:65vh;overflow-y:auto}.el-select[data-v-7e472c9a]{width:100%}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.2 KiB After Width: | Height: | Size: 10 KiB |
Binary file not shown.
Binary file not shown.
Binary file not shown.
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 46 KiB |
@@ -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><script src=//at.alicdn.com/t/font_1428963_kk67lnmooll.js></script><title></title><link href=/css/app.16ea04c8.css rel=preload as=style><link href=/css/chunk-vendors.7d475efd.css rel=preload as=style><link href=/js/app.fa7d2b78.js rel=preload as=script><link href=/js/chunk-vendors.e68c4b36.js rel=preload as=script><link href=/css/chunk-vendors.7d475efd.css rel=stylesheet><link href=/css/app.16ea04c8.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.e68c4b36.js></script><script src=/js/app.fa7d2b78.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.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>
|
||||
1
src/main/resources/static/js/adminIndex.456ac23a.js
Normal file
1
src/main/resources/static/js/adminIndex.456ac23a.js
Normal file
@@ -0,0 +1 @@
|
||||
(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}}]);
|
||||
1
src/main/resources/static/js/app.ce8716ec.js
Normal file
1
src/main/resources/static/js/app.ce8716ec.js
Normal file
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
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user