Compare commits

..

76 Commits
0.2 ... 0.5

Author SHA1 Message Date
zhaojun1998
7e8cab90d0 🔖 升级版本为 0.5 2020-01-05 15:58:46 +08:00
zhaojun1998
4d5743dc0b 💄 更新页面 2020-01-05 15:56:51 +08:00
zhaojun1998
1a326cc17d 💄 更新页面 2020-01-05 15:56:38 +08:00
zhaojun1998
cc993d8e65 优化缓存策略, 开启/关闭缓存后同步控制自动刷新策略 2020-01-05 15:56:17 +08:00
zhaojun1998
f128882034 添加文件获取和判断是否存在接口 2020-01-05 15:54:59 +08:00
zhaojun1998
31dbb902c3 添加文件获取和判断是否存在接口 2020-01-05 15:54:42 +08:00
zhaojun1998
c849057aaa 💄 更新页面 2020-01-03 17:00:15 +08:00
zhaojun1998
7b288b795c 🐛 修复切换缓存时, 出现的异常 BUG 2020-01-03 16:24:53 +08:00
zhaojun1998
316566d479 📝 更新文档, 修复拼写错误 2020-01-03 16:16:05 +08:00
zhaojun1998
e01ce28eb8 💄 更新页面 2020-01-03 15:59:41 +08:00
zhaojun1998
9b7528b61c 💄 更新页面 2020-01-03 15:49:22 +08:00
zhaojun1998
bd22cfd34c 添加检测缓存管理功能 2020-01-03 15:48:42 +08:00
zhaojun1998
4aa9839c6b 🔖 升级版本为 0.4 2020-01-03 15:28:58 +08:00
zhaojun1998
5eeea23703 缓存功能优化, 更高效的管理缓存. 2020-01-03 15:27:45 +08:00
zhaojun1998
6997b15dd0 修复系统设置缓存读取到远程的 BUG 2020-01-02 18:45:19 +08:00
zhaojun1998
326c954c36 💄 更新页面 2020-01-02 18:44:36 +08:00
zhaojun1998
ba5801bea2 🔖 升级版本为 0.3.1 2020-01-02 18:27:30 +08:00
zhaojun1998
e2b0c29e2d 更改日志级别 2020-01-02 18:23:24 +08:00
zhaojun1998
845a380a7e 未开启缓存, 不允许搜索. 2020-01-02 18:22:54 +08:00
zhaojun1998
87229f225e 系统配置添加缓存, 优化性能 2020-01-02 18:20:06 +08:00
zhaojun1998
de947e510c 缓存功能优化, 修改设置后自动修改缓存, 且缓存未完成, 搜索功能暂时禁用. 2020-01-02 18:17:11 +08:00
zhaojun1998
2a367afc37 优化代码, 参数不完整时, 不进行初始化 2020-01-02 18:15:05 +08:00
zhaojun1998
5fb945cebc 🔖 升级版本为 0.3 2020-01-02 14:51:22 +08:00
zhaojun1998
7acedfef38 🎨 修改名称 2020-01-02 14:48:56 +08:00
zhaojun1998
5e198b7ce7 开启 gzip 压缩 2020-01-02 14:48:05 +08:00
zhaojun1998
c3e7e622e2 🎨 缓存修改使用本地 caffeine 2020-01-02 14:46:55 +08:00
zhaojun1998
aec73f5cc7 💄 更新页面 2020-01-02 14:45:21 +08:00
zhaojun1998
9236f11044 优化生产环境配置 2020-01-02 14:40:36 +08:00
zhaojun1998
02973a3c21 更新页面, 支持全局搜索功能 2020-01-01 23:20:12 +08:00
zhaojun1998
e60c64c8fc 📝 更新文档 2019-12-30 22:23:52 +08:00
zhaojun1998
52db0c1515 💄 更新页面 2019-12-29 19:59:48 +08:00
zhaojun1998
0ab2f3b015 移除依赖 2019-12-29 19:58:56 +08:00
zhaojun1998
dd588fe218 🐛 修复某些 S3 协议的存储策略, 生成对象下载地址时, 因重复 encode 造成的 BUG 2019-12-29 19:51:04 +08:00
zhaojun1998
dce1b42e8e 💄 更新页面 2019-12-29 19:14:35 +08:00
zhaojun1998
0e9dd7d5a8 💄 更新页面 2019-12-29 19:14:08 +08:00
zhaojun1998
f5bebd2500 所有存储引擎都支持基路径 2019-12-29 19:10:37 +08:00
zhaojun1998
6a54150868 🏗️ 将缓存框架由 Spring Boot Cache 改为 Alibaba JetCache, 支持缓存自动刷新 2019-12-29 19:09:50 +08:00
zhaojun1998
099c09b625 🎨 抽象基于 S3 API 的存储 2019-12-28 23:49:16 +08:00
zhaojun1998
45e117a05a 腾讯云和七牛云支持基路径 2019-12-28 23:20:56 +08:00
zhaojun1998
14ba1027ae 🎨 修改获取当前存储策略为获取抽象类, 而不是接口 2019-12-28 23:20:26 +08:00
zhaojun1998
04a2ff9542 🐛 修复获取文本内容时的 BUG 2019-12-28 23:20:15 +08:00
zhaojun1998
040e92a433 🎨 抽取 S3 通用 API 2019-12-28 23:19:53 +08:00
zhaojun1998
c739878890 🎨 修改获取当前存储策略为获取抽象类, 而不是接口 2019-12-28 23:19:31 +08:00
zhaojun1998
65616e045b 🎨 优化代码, 将通用方法抽取为抽象类 2019-12-28 23:17:56 +08:00
zhaojun1998
9aaf1494b1 🎨 抽取通用变量 2019-12-28 23:15:34 +08:00
zhaojun1998
74eaaad72d 🐛 修复音乐文件获取封面时包含特殊字符异常的 BUG 2019-12-26 20:19:39 +08:00
zhaojun1998
b65ccc95e2 初始化存储引擎后, 增加测试连接机制 2019-12-25 21:57:22 +08:00
zhaojun1998
e334acd508 🎨 增加启动时显示项目访问地址的功能 2019-12-24 22:11:45 +08:00
zhaojun1998
844cbcc03a 📝 更新文档 2019-12-23 22:11:23 +08:00
zhaojun1998
debaa72938 📝 更新文档 2019-12-21 13:44:05 +08:00
zhaojun1998
d293105521 💩 改善代码, 通过 codacy 校验 2019-12-21 12:31:53 +08:00
zhaojun1998
8e7d4432a3 💩 改善代码, 通过 P3C 校验 2019-12-21 12:08:24 +08:00
zhaojun1998
0e6bcbfa11 接口缓存降级为实现类缓存 2019-12-21 11:06:29 +08:00
zhaojun1998
e8122b4ed0 🗃️ 更新数据库脚本 2019-12-21 11:03:05 +08:00
zhaojun1998
b3a0f4585b 代码优化 2019-12-21 11:01:49 +08:00
zhaojun1998
12bae1ef53 MINIO 添加基路径支持 2019-12-21 11:00:47 +08:00
zhaojun1998
4d9357b11f 🎨 修改文件头, 文件尾, 密码文件的名称为可配置 2019-12-14 22:21:53 +08:00
zhaojun1998
2aa9ccc389 🎨 修改文件头, 文件尾, 密码文件的名称为可配置 2019-12-14 22:01:04 +08:00
zhaojun1998
d81d795095 Merge remote-tracking branch 'origin/master' 2019-12-11 22:40:09 +08:00
zhaojun1998
9af89ecd8c 📝 更新文档 2019-12-11 22:39:30 +08:00
赵俊
bb381a98b9 Create LICENSE 2019-12-10 21:22:32 +08:00
zhaojun1998
14828e7f34 🗃️ 更新数据库文档 2019-12-10 21:11:53 +08:00
zhaojun1998
13c091bcf4 🔖 发布 0.2.1 版 2019-12-09 22:51:12 +08:00
zhaojun1998
6842a31402 💄 更新页面 2019-12-09 22:49:57 +08:00
zhaojun1998
eb99a3e340 UpYun 添加基路径支持 2019-12-09 22:47:43 +08:00
zhaojun1998
403dd4f2e1 优化本地存储, 不适用缓存 2019-12-09 22:46:59 +08:00
zhaojun1998
ff7feedb2f 👽 修改分页条数为每页 30 条 2019-12-09 22:45:19 +08:00
zhaojun1998
2861faeacd 🗃️ 优化数据库脚本 2019-12-09 22:44:41 +08:00
zhaojun1998
8532e91386 🎨 去除无用依赖 2019-12-08 20:36:03 +08:00
zhaojun1998
83cb080f35 🐛 优化文本读取方式, 避免本地存储引发的 BUG 2019-12-08 20:35:23 +08:00
zhaojun1998
682da819a8 🐛 修复本地存储 https 链接拼接错误 BUG 2019-12-08 19:01:50 +08:00
zhaojun1998
0c58869158 💄 更新页面 2019-12-08 19:01:26 +08:00
zhaojun1998
92396c3631 🐛 修复音乐包含特殊字符时,无法获取封面和歌手的 BUG 2019-12-08 18:10:51 +08:00
zhaojun1998
6285633ad4 📝 更新文档 2019-12-08 14:02:19 +08:00
zhaojun1998
7dadb24727 📝 更新文档 2019-12-08 14:00:26 +08:00
zhaojun1998
3c278cf176 🔖 发布 0.2 版本 2019-12-08 13:38:05 +08:00
88 changed files with 1391 additions and 1322 deletions

21
LICENSE Normal file
View 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.

View File

@@ -1,10 +1,15 @@
# Z-File
![https://img.shields.io/badge/license-MIT-blue.svg?style=flat-square](https://img.shields.io/badge/license-MIT-blue.svg?longCache=true&style=flat-square)
[![Codacy Badge](https://api.codacy.com/project/badge/Grade/70b793267f7941d58cbd93f50c9a8e0a)](https://www.codacy.com/manual/zhaojun1998/zfile?utm_source=github.com&utm_medium=referral&utm_content=zhaojun1998/zfile&utm_campaign=Badge_Grade)
![https://img.shields.io/badge/springboot-2.0.6-orange.svg?style=flat-square](https://img.shields.io/badge/springboot-2.0.6-yellow.svg?longCache=true&style=popout-square)
![GitHub tag (latest SemVer)](https://img.shields.io/github/tag/zhaojun1998/zfile.svg?style=flat-square)
此项目是一个在线文件目录的程序, 支持各种对象存储和本地存储, 使用定位是个人放常用工具下载, 或做公共的文件库. 不会向多账户方向开发.
前端基于 [h5ai](https://larsjung.de/h5ai/) 的原有功能使用 Vue 重新开发了一遍. 后端采用 SpringBoot, 数据库采用内嵌数据库.
预览地址: [http://zfile.jun6.net](http://zfile.jun6.net)
预览地址: [https://zfile.jun6.net](https://zfile.jun6.net)
## 系统特色
@@ -13,37 +18,50 @@
* 个性化配置
* 自定义目录的 header 和 footer 说明文件
* 文件夹密码
* 支持在线浏览文本文件, 视频, 图片, 音乐.
* 支持在线浏览文本文件, 视频, 图片, 音乐. (支持 FLV 和 HLS)
* 文件/目录二维码
* 缓存动态开启, 缓存自动刷新
* 全局搜索
## 快速开始
安装 JDK 1.8 :
```bash
yum instal -y java # 适用于 Centos 7.x
yum install -y java # 适用于 Centos 7.x
```
> 其他系统的 JDK 安装教程, 后续我也都会补上. 大家也可执行搜索安装方式, 应该不是很难.
下载项目:
```bash
wget https://github.com/zhaojun1998/zfile/releases/download/0.1/zfile-0.1.jar
wget https://github.com/zhaojun1998/zfile/releases/download/0.5/zfile-0.5.jar
```
启动项目:
```bash
java -jar zfile-0.1.jar
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar
## 高级启动
java -jar zfile-0.1.jar --server.port=18777
java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar --server.port=18777
## 后台运行
nohup java -Djava.security.egd=file:/dev/./urandom -jar zfile-0.5.jar &
```
> `--server.port` 为指定端口, 默认为 `8080`
> 其他参数, 后面我会详细补充至文档, 最晚本周六日.
> 系统使用的是内置配置文件, 默认配置请参考: [application.yml](https://github.com/zhaojun1998/zfile/blob/master/src/main/resources/application.yml)
> **可下载此文件放置与 jar 包同目录, 此时会以外部配置文件为准, 推荐适用此方式!.**
> 所有参数都可在命令行启动时, 以类似 `--server.port=18777` 的方式强制执行, 此方式的优先级最高.
> *指定 `-Djava.security.egd=file:/dev/./urandom` 是为了防止在 Linux 环境中, 生成首次登陆生成 sessionId 取系统随机数过慢的问题.*
重要参数:
- `server.port` 为指定端口, 默认为 `8080`
- `logging.path` 为日志文件存放路径, 默认为 `${user.home}/.zfile/logs`
- `spring.datasource` 下配置了 `h2``mysql` 两种数据库的支持, 默认采用 `h2`.
- `spring.cache.type` 为指定缓存方式, 默认为 `caffeine`, 即内存缓存, 无需安装, 支持切换为 `redis`, 但需配置 `spring.redis.host``spring.redis.password` 参数后才可使用.
访问地址:
@@ -55,20 +73,14 @@ java -jar zfile-0.1.jar --server.port=18777
管理后台: http://127.0.0.1:8080/#/admin
## 运行环境
* JDK: `1.8`
* 缓存: `caffeine/redis`
* 缓存: `caffeine`
* 数据库: `h2/mysql`
## 常见问题
### 缓存
缓存默认支持 `caffeine``redis`, 前者为内存缓存, 无需安装, 但后者相对性能更好.
### 数据库
缓存默认支持 `h2``mysql`, 前者为嵌入式数据库, 无需安装, 但后者相对性能更好.
@@ -87,7 +99,6 @@ java -jar zfile-0.1.jar --server.port=18777
## TODO
- 全局搜索功能
- 文本预览更换更好用的编辑器
- 后台支持上传、编辑、删除等操作
- API 支持

133
pom.xml
View File

@@ -12,7 +12,7 @@
<groupId>im.zhaojun</groupId>
<artifactId>zfile</artifactId>
<version>0.1</version>
<version>0.5</version>
<name>zfile</name>
<description>一个在线的文件浏览系统</description>
@@ -21,10 +21,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 +41,21 @@
</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>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 +65,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,49 +101,13 @@
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<groupId>com.alicp.jetcache</groupId>
<artifactId>jetcache-starter-redis</artifactId>
<version>2.5.14</version>
</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>

View File

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

View File

@@ -1,121 +1,55 @@
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();
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();
if (Objects.isNull(accessKey) || Objects.isNull(secretKey) || Objects.isNull(endPoint) || Objects.isNull(bucketName)) {
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();
}
bucketName = stringStorageConfigMap.get(BUCKET_NAME_KEY).getValue();
domain = stringStorageConfigMap.get(DOMAIN_KEY).getValue();
ossClient = new OSSClientBuilder().build(endPoint, accessKey, secretKey);
AccessControlList bucketAcl = ossClient.getBucketAcl(bucketName);
CannedAccessControlList cannedAcl = bucketAcl.getCannedACL();
isPrivate = "Private".equals(cannedAcl.name());
isInitialized = true;
} catch (Exception e) {
log.debug(StorageTypeEnum.ALIYUN.getDescription() + "初始化异常, 已跳过");
}
}
@Override
public List<FileItemDTO> fileList(String path) {
path = StringUtils.removeFirstSeparator(path);
List<FileItemDTO> fileItemList = new ArrayList<>();
ObjectListing objectListing =
ossClient.listObjects(new ListObjectsRequest(bucketName).withDelimiter("/").withPrefix(path));
for (OSSObjectSummary s : objectListing.getObjectSummaries()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(s.getKey().substring(path.length()));
fileItemDTO.setSize(s.getSize());
fileItemDTO.setTime(s.getLastModified());
fileItemDTO.setType(FileTypeEnum.FILE);
fileItemDTO.setPath(path);
fileItemDTO.setUrl(getDownloadUrl(StringUtils.concatUrl(path, fileItemDTO.getName())));
fileItemList.add(fileItemDTO);
}
for (String commonPrefix : objectListing.getCommonPrefixes()) {
FileItemDTO fileItemDTO = new FileItemDTO();
fileItemDTO.setName(commonPrefix.substring(path.length(), commonPrefix.length() - 1));
fileItemDTO.setType(FileTypeEnum.FOLDER);
fileItemDTO.setPath(path);
fileItemList.add(fileItemDTO);
}
return fileItemList;
}
@Override
public String getDownloadUrl(String path) {
path = StringUtils.removeFirstSeparator(path);
if (isPrivate) {
Date expirationDate = new Date(System.currentTimeMillis() + timeout * 1000);
URL url = ossClient.generatePresignedUrl(bucketName, path, expirationDate);
return URLUtil.complateUrl(domain, url.getFile());
} else {
return URLUtil.complateUrl(domain, path);
log.debug(getStorageTypeEnum().getDescription() + "初始化异常, 已跳过");
}
}
@@ -124,8 +58,4 @@ public class AliyunServiceImpl implements FileService {
return StorageTypeEnum.ALIYUN;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -7,6 +7,7 @@ import java.lang.annotation.Target;
/**
* 标记注解, 用于在调用前检查是否已存储策略
* @author zhaojun
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)

View File

@@ -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("存储策略异常, 请联系管理员!");
}
}
}

View File

@@ -14,6 +14,7 @@ import java.io.IOException;
/**
* 开启跨域支持. 一般用于开发环境, 或前后端分离部署时开启.
* @author zhaojun
*/
public class CorsFilter extends GenericFilterBean {

View File

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

View File

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

View File

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

View File

@@ -7,6 +7,9 @@ import org.springframework.web.client.RestTemplate;
import java.nio.charset.StandardCharsets;
/**
* @author zhaojun
*/
@Configuration
public class ZFileConfiguration {

View File

@@ -1,11 +1,12 @@
package im.zhaojun.common.controller;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.CacheConfigDTO;
import im.zhaojun.common.model.dto.ResultBean;
import im.zhaojun.common.model.dto.SystemConfigDTO;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.FileAsyncCacheService;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import org.slf4j.Logger;
@@ -17,9 +18,11 @@ import org.springframework.web.bind.annotation.RestController;
import javax.annotation.Resource;
import java.util.List;
import java.util.Set;
/**
* 后台管理
* @author zhaojun
*/
@RestController
@RequestMapping("/admin")
@@ -45,20 +48,11 @@ public class AdminController {
return ResultBean.success(systemConfigDTO);
}
/**
* 更新系统配置
*/
@PostMapping("/update-pwd")
public ResultBean updatePwd(String username, String password) {
systemConfigService.updateUsernameAndPwd(username, password);
return ResultBean.success();
}
/**
* 更新系统配置
*/
@PostMapping("/config")
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) {
public ResultBean updateConfig(SystemConfigDTO systemConfigDTO) throws Exception {
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
systemConfigDTO.setId(1);
@@ -71,23 +65,61 @@ public class AdminController {
return ResultBean.success();
}
/**
* 修改管理员登陆密码
*/
@PostMapping("/update-pwd")
public ResultBean updatePwd(String username, String password) {
systemConfigService.updateUsernameAndPwd(username, password);
return ResultBean.success();
}
/**
* 获取指定存储引擎的设置
* @param storageType 存储引擎
* @return 所有设置
*/
@GetMapping("/strategy-form")
public ResultBean getFormByStorageType(StorageTypeEnum storageType) {
List<StorageConfig> storageConfigList = storageConfigService.selectStorageConfigByType(storageType);
return ResultBean.success(storageConfigList);
}
/**
* 清理当前启用的存储引擎的缓存
*/
@GetMapping("/clear-cache")
public ResultBean clearCache() {
FileService fileService = systemConfigService.getCurrentFileService();
@GetMapping("/cache/config")
public ResultBean cacheConfig() throws Exception {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
Set<String> cacheKeys = fileService.getCacheKeys();
CacheConfigDTO cacheConfigDTO = new CacheConfigDTO();
cacheConfigDTO.setEnableCache(systemConfigService.getEnableCache());
cacheConfigDTO.setCacheFinish(fileAsyncCacheService.isCacheFinish());
cacheConfigDTO.setCacheKeys(cacheKeys);
return ResultBean.success(cacheConfigDTO);
}
@PostMapping("/cache/refresh")
public ResultBean refreshCache(String key) throws Exception {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
fileService.refreshCache(key);
return ResultBean.success();
}
@PostMapping("/cache/clear")
public ResultBean clearCache(String key) throws Exception {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
fileService.clearCache();
return ResultBean.success();
}
@PostMapping("/cache/all")
public ResultBean cacheAll() throws Exception {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
fileService.clearCache();
fileAsyncCacheService.cacheGlobalFile();
return ResultBean.success();
}
/**
* 更新存储策略
*/
@@ -103,7 +135,7 @@ public class AdminController {
if (storageStrategy == null) {
log.info("尚未配置存储策略.");
} else {
FileService fileService = systemConfigService.getCurrentFileService();
AbstractFileService fileService = systemConfigService.getCurrentFileService();
fileService.init();
log.info("当前启用存储类型: {}", storageStrategy.getDescription());
@@ -111,4 +143,5 @@ public class AdminController {
fileAsyncCacheService.cacheGlobalFile();
}
}
}

View File

@@ -10,7 +10,8 @@ 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.AbstractFileService;
import im.zhaojun.common.service.FileAsyncCacheService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import im.zhaojun.common.service.SystemService;
@@ -29,6 +30,7 @@ import java.util.List;
/**
* 前台文件管理
* @author zhaojun
*/
@RequestMapping("/api")
@RestController
@@ -43,10 +45,13 @@ public class FileController {
@Resource
private StorageConfigService storageConfigService;
@Resource
private FileAsyncCacheService fileAsyncCacheService;
/**
* 滚动加载每页条数.
*/
private static final Integer PAGE_SIZE = 20;
private static final Integer PAGE_SIZE = 30;
@CheckStorageStrategyInit
@GetMapping("/list")
@@ -55,16 +60,15 @@ public class FileController {
@RequestParam(defaultValue = "asc") String order,
@RequestParam(required = false) String password,
@RequestParam(defaultValue = "1") Integer page) throws Exception {
FileService fileService = systemConfigService.getCurrentFileService();
AbstractFileService fileService = systemConfigService.getCurrentFileService();
List<FileItemDTO> fileItemList = fileService.fileList(StringUtils.removeDuplicateSeparator("/" + URLUtil.decode(path) + "/"));
for (FileItemDTO fileItemDTO : fileItemList) {
if (ZFileConstant.PASSWORD_FILE_NAME.equals(fileItemDTO.getName())) {
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);
}
}
@@ -72,17 +76,17 @@ public class FileController {
fileItemList.sort(new FileComparator(sortBy, order));
filterFileList(fileItemList);
Integer total = fileItemList.size();
Integer totalPage = (total + PAGE_SIZE - 1) / PAGE_SIZE;
int total = fileItemList.size();
int 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);
int start = (page - 1) * PAGE_SIZE;
int end = page * PAGE_SIZE;
end = Math.min(end, total);
List<FileItemDTO> fileSubItem = new ArrayList<>(fileItemList.subList(start, end));
return ResultBean.successData(fileSubItem);
}
@@ -91,12 +95,32 @@ public class FileController {
* @param url 文件路径
* @return 文件内容
*/
@CheckStorageStrategyInit
@GetMapping("/content")
public ResultBean getContent(String url) {
return ResultBean.successData(HttpUtil.getTextContent(url));
}
/**
* 获取文件类容, 仅限用于, txt, md, ini 等普通文本文件.
* @param url 文件路径
* @return 文件内容
*/
@GetMapping("/content/origin")
public String getContentOrigin(String url) {
return HttpUtil.getTextContent(url);
}
/**
* 检测文件是否存在
* @param url 文件路径
* @return 是否存在
*/
@GetMapping("/content/exist")
public boolean checkFileExist(String url) {
return HttpUtil.checkUrlExist(url);
}
/**
* 获取系统配置信息和当前页的标题, 文件头, 文件尾信息
* @param path 路径
@@ -111,8 +135,8 @@ public class FileController {
@CheckStorageStrategyInit
@GetMapping("/clearCache")
public ResultBean clearCache() {
FileService fileService = systemConfigService.getCurrentFileService();
public ResultBean clearCache() throws Exception {
AbstractFileService fileService = systemConfigService.getCurrentFileService();
if (fileService != null) {
fileService.clearCache();
}
@@ -128,11 +152,14 @@ public class FileController {
@CheckStorageStrategyInit
@GetMapping("/search")
public ResultBean search(@RequestParam(value = "name", defaultValue = "/") String name) throws Exception {
FileService fileService = systemConfigService.getCurrentFileService();
AbstractFileService fileService = systemConfigService.getCurrentFileService();
SystemConfigDTO systemConfigDTO = systemConfigService.getSystemConfig();
if (!systemConfigDTO.getSearchEnable()) {
throw new SearchDisableException("搜索功能未开启");
}
if (!fileAsyncCacheService.isCacheFinish()) {
throw new SearchDisableException("搜索功能缓存预热中, 请稍后再试");
}
return ResultBean.success(fileService.search(URLUtil.decode(name)));
}

View File

@@ -6,7 +6,8 @@ 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.AbstractFileService;
import im.zhaojun.common.service.FileAsyncCacheService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import org.springframework.stereotype.Controller;
@@ -22,6 +23,7 @@ import java.util.Objects;
/**
* 系统安装初始化
* @author zhaojun
*/
@Controller
public class InstallController {
@@ -35,6 +37,9 @@ public class InstallController {
@Resource
private AdminController adminController;
@Resource
private FileAsyncCacheService fileAsyncCacheService;
@GetMapping("/is-installed")
@ResponseBody
public ResultBean isInstall() {
@@ -47,7 +52,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) {
@@ -78,7 +83,7 @@ public class InstallController {
@PostMapping("/storage-strategy")
@ResponseBody
public ResultBean save(@RequestParam Map<String, String> storageStrategyConfig, StorageTypeEnum storageStrategy) {
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();
@@ -89,8 +94,12 @@ public class InstallController {
StorageTypeEnum currentStorageStrategy = systemConfigService.getCurrentStorageStrategy();
if (Objects.equals(storageStrategy, currentStorageStrategy)) {
FileService fileService = systemConfigService.getCurrentFileService();
AbstractFileService fileService = systemConfigService.getCurrentFileService();
fileService.clearCache();
if (systemConfigService.getEnableCache()) {
fileAsyncCacheService.cacheGlobalFile();
}
fileService.init();
}

View File

@@ -13,6 +13,7 @@ import org.springframework.web.bind.annotation.ResponseStatus;
/**
* 全局异常处理器
* @author zhaojun
*/
@ControllerAdvice
@ResponseBody

View File

@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
/**
* 对象存储初始化异常
* @author zhaojun
*/
public class InitializeException extends RuntimeException {

View File

@@ -1,5 +1,8 @@
package im.zhaojun.common.exception;
/**
* @author zhaojun
*/
public class SearchDisableException extends RuntimeException {
public SearchDisableException() {

View File

@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
/**
* 存储策略未初始化异常
* @author zhaojun
*/
public class StorageStrategyUninitializedException extends RuntimeException {

View File

@@ -2,6 +2,7 @@ package im.zhaojun.common.exception;
/**
* 未知的存储类型异常
* @author zhaojun
*/
public class UnknownStorageTypeException extends RuntimeException {

View File

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

View File

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

View File

@@ -0,0 +1,33 @@
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";
}

View File

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

View File

@@ -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,31 @@ public class ZFileConstant {
/**
* 页面头部文件
*/
public static final String HEADER_FILE_NAME = "header.md";
public static String HEADER_FILE_NAME = "header.md";
/**
* 页面尾部文件
*/
public static final String FOOTER_FILE_NAME = "footer.md";
public static String FOOTER_FILE_NAME = "footer.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 setFooterFileName(@Value("${zfile.constant.footer}") String footerFileName) {
ZFileConstant.FOOTER_FILE_NAME = footerFileName;
}
@Autowired(required = false)
public void setPasswordFileName(@Value("${zfile.constant.password}") String passwordFileName) {
ZFileConstant.PASSWORD_FILE_NAME = passwordFileName;
}
}

View File

@@ -1,5 +1,8 @@
package im.zhaojun.common.model.dto;
/**
* @author zhaojun
*/
public class AudioInfoDTO {
private String title;
private String artist;

View File

@@ -0,0 +1,16 @@
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;
}

View File

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

View File

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

View File

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

View File

@@ -4,6 +4,9 @@ import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
/**
* @author zhaojun
*/
public class SiteConfigDTO implements Serializable {
private static final long serialVersionUID = 8811196207046121740L;

View File

@@ -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,5 @@ public class SystemConfigDTO {
private String domain;
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getSiteName() {
return siteName;
}
public void setSiteName(String siteName) {
this.siteName = siteName;
}
public Boolean getInfoEnable() {
return infoEnable;
}
public void setInfoEnable(Boolean infoEnable) {
this.infoEnable = infoEnable;
}
public Boolean getSearchEnable() {
return searchEnable;
}
public void setSearchEnable(Boolean searchEnable) {
this.searchEnable = searchEnable;
}
public Boolean getSearchIgnoreCase() {
return searchIgnoreCase;
}
public void setSearchIgnoreCase(Boolean searchIgnoreCase) {
this.searchIgnoreCase = searchIgnoreCase;
}
public StorageTypeEnum getStorageStrategy() {
return storageStrategy;
}
public void setStorageStrategy(StorageTypeEnum storageStrategy) {
this.storageStrategy = storageStrategy;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public String getDomain() {
return domain;
}
public void setDomain(String domain) {
this.domain = domain;
}
private Boolean enableCache;
}

View File

@@ -1,5 +1,8 @@
package im.zhaojun.common.model.enums;
/**
* @author zhaojun
*/
public enum FileTypeEnum {
/**

View File

@@ -3,6 +3,9 @@ package im.zhaojun.common.model.enums;
import java.util.HashMap;
import java.util.Map;
/**
* @author zhaojun
*/
public enum StorageTypeEnum {
/**
@@ -17,6 +20,9 @@ public enum StorageTypeEnum {
TENCENT("tencent", "腾讯云 COS"),
MINIO("minio", "MINIO");
private String key;
private String description;
private static Map<String, StorageTypeEnum> enumMap = new HashMap<>();
static {
@@ -30,9 +36,6 @@ public enum StorageTypeEnum {
this.description = description;
}
private String key;
private String description;
public String getKey() {
return key;
}

View File

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

View File

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

View File

@@ -6,6 +6,9 @@ import com.fasterxml.jackson.databind.SerializerProvider;
import java.io.IOException;
/**
* @author zhaojun
*/
public class StorageTypeEnumSerializerConvert extends JsonSerializer<StorageTypeEnum> {
@Override

View File

@@ -7,9 +7,17 @@ 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);
}

View File

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

View File

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

View File

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

View File

@@ -18,7 +18,8 @@ import javax.servlet.http.HttpServletResponse;
import java.io.PrintWriter;
/**
* 自定义Security配置类
* 自定义 Security 配置类
* @author zhaojun
*/
@EnableWebSecurity
public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@@ -115,7 +116,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public static PasswordEncoder passwordEncoder() {
return new MD5PasswordEncoder();
return new Md5PasswordEncoder();
}
}

View File

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

View File

@@ -0,0 +1,194 @@
package im.zhaojun.common.service;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.RefreshPolicy;
import com.alicp.jetcache.anno.CacheRefresh;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.Cached;
import com.alicp.jetcache.anno.CreateCache;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.util.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Value;
import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
/**
* @author zhaojun
* @date 2019/12/28 19:27
*/
@Slf4j
public abstract class AbstractFileService implements FileService {
public static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-cache:";
@Value("${zfile.cache.timeout}")
protected Long timeout;
protected boolean isInitialized;
@Resource
private SystemConfigService systemConfigService;
@Resource
private FileAsyncCacheService fileAsyncCacheService;
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
private Cache<String, List<FileItemDTO>> cache;
/***
* 获取指定路径下的文件及文件夹, 默认缓存 60 分钟,每隔 30 分钟刷新一次.
* @param path 文件路径
* @return 文件及文件夹列表
* @throws Exception 获取文件列表中出现的异常
*/
@Override
@Cached(name = SYSTEM_CONFIG_CACHE_PREFIX,
key = "args[0]",
cacheType = CacheType.LOCAL, localLimit = 100000, condition = "mvel{bean('systemConfigService').enableCache}")
@CacheRefresh(refresh = 30, timeUnit = TimeUnit.MINUTES)
public abstract List<FileItemDTO> fileList(String path) throws Exception;
/**
* 清理当前存储引擎的缓存
*/
public void clearCache() throws Exception {
Set<String> cacheKeys = getCacheKeys();
cache.removeAll(cacheKeys);
closeCacheAutoRefresh();
fileAsyncCacheService.setCacheFinish(false);
}
/**
* 初始化方法, 启动时自动调用实现类的此方法进行初始化.
*/
@PostConstruct
public abstract void init();
protected boolean testConnection() {
boolean flag = true;
try {
fileList("/");
} catch (Exception e) {
log.debug(getStorageTypeEnum().getDescription() + "初始化异常", e);
flag = false;
}
return flag;
}
/**
* 获取是否初始化成功
* @return 初始化成功与否
*/
public boolean getIsUnInitialized() {
return !isInitialized;
}
/**
* 获取存储引擎类型
* @return 存储引擎类型枚举
*/
public abstract StorageTypeEnum getStorageTypeEnum();
/**
* 搜索文件
* @param name 文件名
* @return 包含该文件名的所有文件或文件夹
* @throws Exception 搜索过程出现的异常
*/
public List<FileItemDTO> search(String name) throws Exception {
List<FileItemDTO> result = new ArrayList<>();
List<FileItemDTO> fileItemList = selectAllFileList();
for (FileItemDTO fileItemDTO : fileItemList) {
if (fileItemDTO.getName().contains(name)) {
result.add(fileItemDTO);
}
}
return result;
}
/**
* 查询所有文件, 仅去缓存中查询.
* @return 所有文件
*/
public List<FileItemDTO> selectAllFileList() throws Exception {
List<FileItemDTO> result = new ArrayList<>();
boolean enableCache = systemConfigService.getEnableCache();
if (!enableCache) {
log.debug("未开启缓存, 不支持查询所有文件.");
return null;
}
String path = "/";
List<FileItemDTO> fileItemList = cache.get(path);
fileItemList = fileItemList == null ? new ArrayList<>() : fileItemList;
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
while (!queue.isEmpty()) {
FileItemDTO fileItemDTO = queue.pop();
result.add(fileItemDTO);
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
List<FileItemDTO> cacheList = cache.get(filePath);
if (cacheList != null) {
queue.addAll(cacheList);
}
}
}
return result;
}
/**
* 获取所有缓存的 Key, 仅当开启缓存, 且缓存完成时, 可获取.
* @return 所有缓存的 Key
* @throws Exception 可能出现的异常
*/
public Set<String> getCacheKeys() throws Exception {
if (systemConfigService.getEnableCache() && fileAsyncCacheService.isCacheFinish()) {
Set<String> collect = selectAllFileList().stream().map(fileItemDTO -> {
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
return StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
}
return null;
}).collect(Collectors.toSet());
collect.remove(null);
collect.add("/");
return collect;
} else {
return Collections.emptySet();
}
}
/**
* 刷新缓存
*/
public void refreshCache(String key) throws Exception {
cache.remove(key);
FileService currentFileService = (FileService) AopContext.currentProxy();
currentFileService.fileList(key);
}
public void closeCacheAutoRefresh() {
cache.config().setRefreshPolicy(null);
}
public void openCacheAutoRefresh() {
RefreshPolicy refreshPolicy = RefreshPolicy.newPolicy(1, TimeUnit.MINUTES);
cache.config().setRefreshPolicy(refreshPolicy);
}
}

View File

@@ -0,0 +1,111 @@
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.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;
/**
* @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();
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);
}
}

View File

@@ -1,18 +1,26 @@
package im.zhaojun.common.service;
import im.zhaojun.common.config.StorageTypeFactory;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import 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);
private boolean cacheFinish;
@Resource
private SystemConfigService systemConfigService;
@@ -26,12 +34,35 @@ public class FileAsyncCacheService {
return;
}
FileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
boolean enableCache = systemConfigService.getEnableCache();
if (!enableCache) {
log.info("未开启缓存, 跳过启动缓存");
return;
}
AbstractFileService fileService = StorageTypeFactory.getStorageTypeService(storageStrategy);
if (fileService.getIsUnInitialized()) {
log.info("存储引擎 {} 未初始化成功, 跳过启动缓存.", storageStrategy.getDescription());
return;
}
log.info("缓存 {} 所有文件开始", storageStrategy.getDescription());
long startTime = System.currentTimeMillis();
try {
if (fileService.getIsInitialized()) {
fileService.selectAllFileList();
String path = "/";
FileService currentFileService = systemConfigService.getCurrentFileService();
List<FileItemDTO> fileItemList = currentFileService.fileList(path);
ArrayDeque<FileItemDTO> queue = new ArrayDeque<>(fileItemList);
while (!queue.isEmpty()) {
FileItemDTO fileItemDTO = queue.pop();
if (fileItemDTO.getType() == FileTypeEnum.FOLDER) {
String filePath = StringUtils.removeDuplicateSeparator("/" + fileItemDTO.getPath() + "/" + fileItemDTO.getName() + "/");
queue.addAll(currentFileService.fileList(filePath));
}
}
} catch (Exception e) {
log.error("缓存所有文件失败", e);
@@ -39,5 +70,15 @@ public class FileAsyncCacheService {
}
long endTime = System.currentTimeMillis();
log.info("缓存 {} 所有文件结束, 用时: {} 秒", storageStrategy.getDescription(), ( (endTime - startTime) / 1000 ));
cacheFinish = true;
}
public boolean isCacheFinish() {
return cacheFinish;
}
public void setCacheFinish(boolean cacheFinish) {
this.cacheFinish = cacheFinish;
}
}

View File

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

View File

@@ -10,6 +10,9 @@ import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* @author zhaojun
*/
@Service
public class StorageConfigService {

View File

@@ -1,6 +1,9 @@
package im.zhaojun.common.service;
import cn.hutool.crypto.SecureUtil;
import com.alicp.jetcache.Cache;
import com.alicp.jetcache.anno.CacheType;
import com.alicp.jetcache.anno.CreateCache;
import im.zhaojun.common.config.StorageTypeFactory;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.SystemConfigConstant;
@@ -8,20 +11,39 @@ 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.util.ArrayList;
import java.util.List;
/**
* @author zhaojun
*/
@Slf4j
@Service
public class SystemConfigService {
public static final String SYSTEM_CONFIG_CACHE_PREFIX = "zfile-config-cache:";
public static final String SYSTEM_CONFIG_CACHE_KEY = "1";
@CreateCache(name = SYSTEM_CONFIG_CACHE_PREFIX, cacheType = CacheType.LOCAL)
private Cache<String, Object> configCache;
@Resource
private SystemConfigRepository systemConfigRepository;
@Resource
private FileAsyncCacheService fileAsyncCacheService;
public SystemConfigDTO getSystemConfig() {
Object cache = configCache.get(SYSTEM_CONFIG_CACHE_KEY);
if (configCache.get(SYSTEM_CONFIG_CACHE_KEY) != null) {
return (SystemConfigDTO) cache;
}
SystemConfigDTO systemConfigDTO = new SystemConfigDTO();
List<SystemConfig> systemConfigList = systemConfigRepository.findAll();
@@ -52,14 +74,19 @@ public class SystemConfigService {
case SystemConfigConstant.DOMAIN:
systemConfigDTO.setDomain(systemConfig.getValue());
break;
case SystemConfigConstant.ENABLE_CACHE:
systemConfigDTO.setEnableCache("true".equals(systemConfig.getValue()));
break;
default:break;
}
}
configCache.put(SYSTEM_CONFIG_CACHE_KEY, systemConfigDTO);
return systemConfigDTO;
}
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) {
public void updateSystemConfig(SystemConfigDTO systemConfigDTO) throws Exception {
List<SystemConfig> systemConfigList = new ArrayList<>();
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.SITE_NAME);
@@ -82,23 +109,45 @@ public class SystemConfigService {
searchIgnoreCaseSystemConfig.setValue(systemConfigDTO.getSearchIgnoreCase() ? "true" : "false");
systemConfigList.add(searchIgnoreCaseSystemConfig);
boolean oldEnableCache = getEnableCache();
Boolean curEnableCache = systemConfigDTO.getEnableCache();
SystemConfig enableCacheSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.ENABLE_CACHE);
enableCacheSystemConfig.setValue(systemConfigDTO.getEnableCache() ? "true" : "false");
systemConfigList.add(enableCacheSystemConfig);
SystemConfig storageStrategySystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.STORAGE_STRATEGY);
storageStrategySystemConfig.setValue(systemConfigDTO.getStorageStrategy().getKey());
systemConfigList.add(storageStrategySystemConfig);
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getUsername())) {
if (StringUtils.isNotNullOrEmpty(systemConfigDTO.getUsername())) {
SystemConfig usernameSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.USERNAME);
usernameSystemConfig.setValue(systemConfigDTO.getUsername());
systemConfigList.add(usernameSystemConfig);
}
if (!StringUtils.isNullOrEmpty(systemConfigDTO.getPassword())) {
if (StringUtils.isNotNullOrEmpty(systemConfigDTO.getPassword())) {
SystemConfig passwordSystemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
passwordSystemConfig.setValue(systemConfigDTO.getPassword());
systemConfigList.add(passwordSystemConfig);
}
configCache.remove(SYSTEM_CONFIG_CACHE_KEY);
systemConfigRepository.saveAll(systemConfigList);
AbstractFileService currentFileService = getCurrentFileService();
if (!oldEnableCache && curEnableCache) {
log.debug("检测到开启了缓存, 开启预热缓存");
currentFileService.openCacheAutoRefresh();
fileAsyncCacheService.cacheGlobalFile();
}
if (oldEnableCache && !curEnableCache) {
log.debug("检测到关闭了缓存, 正在清理缓存数据及关闭自动刷新");
currentFileService.clearCache();
}
}
public void updateUsernameAndPwd(String username, String password) {
@@ -106,14 +155,16 @@ public class SystemConfigService {
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 AbstractFileService getCurrentFileService() {
StorageTypeEnum storageStrategy = getCurrentStorageStrategy();
return StorageTypeFactory.getStorageTypeService(storageStrategy);
}
@@ -123,4 +174,9 @@ public class SystemConfigService {
return systemConfigDTO.getStorageStrategy();
}
public boolean getEnableCache() {
SystemConfigDTO systemConfigDTO = getSystemConfig();
return systemConfigDTO.getEnableCache();
}
}

View File

@@ -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,9 +26,9 @@ 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()));

View File

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

View File

@@ -12,6 +12,8 @@ import java.util.Comparator;
* - 默认按照名称排序
* - 默认排序为升序
* - 按名称排序不区分大小写
*
* @author zhaojun
*/
public class FileComparator implements Comparator<FileItemDTO> {
@@ -33,7 +35,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;
}

View File

@@ -1,14 +1,28 @@
package im.zhaojun.common.util;
import cn.hutool.core.util.URLUtil;
import org.springframework.web.client.RestClientException;
import org.springframework.web.client.RestTemplate;
/**
* @author zhaojun
*/
public class HttpUtil {
public static String getTextContent(String url) {
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
String result = restTemplate.getForObject(URLUtil.decode(url), String.class);
String result = restTemplate.getForObject(url, String.class);
return result == null ? "" : result;
}
public static boolean checkUrlExist(String url) {
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
try {
restTemplate.headForHeaders(url);
return true;
} catch (RestClientException e) {
e.printStackTrace();
}
return false;
}
}

View File

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

View File

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

View File

@@ -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.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);
}
}

View File

@@ -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 = true;
} else {
ftp = new Ftp(host, Integer.parseInt(port), username, password);
isInitialized = testConnection();
}
} catch (Exception e) {
log.debug(getStorageTypeEnum().getDescription() + "初始化异常, 已跳过");
}
}
@Override
@@ -91,10 +90,4 @@ public class FtpServiceImpl implements FileService {
public StorageTypeEnum getStorageTypeEnum() {
return StorageTypeEnum.FTP;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,132 +1,59 @@
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)) {
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;
}
}

View File

@@ -16,9 +16,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,7 +29,7 @@ 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);
@@ -37,7 +39,7 @@ public class LocalController {
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) {
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;

View File

@@ -2,35 +2,36 @@ package im.zhaojun.local.service;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.StorageConfigConstant;
import im.zhaojun.common.model.constant.SystemConfigConstant;
import im.zhaojun.common.model.dto.FileItemDTO;
import im.zhaojun.common.model.enums.FileTypeEnum;
import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.repository.SystemConfigRepository;
import im.zhaojun.common.service.AbstractFileService;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.util.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.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 +40,24 @@ 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)) {
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,7 +85,7 @@ 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);
}
@@ -100,10 +103,4 @@ public class LocalServiceImpl implements FileService {
return StorageTypeEnum.LOCAL;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,109 +1,59 @@
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)) {
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()
.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;
}
}

View File

@@ -3,31 +3,21 @@ 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;
/**
* @author zhaojun
*/
@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");

View File

@@ -1,130 +1,54 @@
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)) {
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 +56,4 @@ public class QiniuServiceImpl implements FileService {
return StorageTypeEnum.QINIU;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -1,128 +1,60 @@
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)) {
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;
}
}

View File

@@ -1,11 +1,14 @@
package im.zhaojun.upyun.service;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.URLUtil;
import com.UpYun;
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,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 {
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)) {
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,4 @@ public class UpYunServiceImpl implements FileService {
return StorageTypeEnum.UPYUN;
}
@Override
public boolean getIsInitialized() {
return isInitialized;
}
}

View File

@@ -4,5 +4,24 @@
"name": "zfile.cache.timeout",
"type": "java.lang.Long",
"description": "目录缓存过期时间 和 下载地址过期时间. 单位为秒."
},
{
"name": "zfile.constant.header",
"type": "java.lang.String",
"defaultValue": "header.md",
"description": "头部文件 文件名."
},
{
"name": "zfile.constant.footer",
"type": "java.lang.String",
"defaultValue": "footer.md",
"description": "尾部文件 文件名."
},
{
"name": "zfile.constant.password",
"type": "java.lang.String",
"defaultValue": "password.txt",
"description": "密码文件 文件名."
}
] }
]
}

View File

@@ -1,20 +1,19 @@
logging:
level:
im:
zhaojun:
common: debug
zhaojun: info
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 +22,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:
@@ -45,9 +44,19 @@ spring:
resources:
chain:
gzipped: true
redis:
host: 127.0.0.1
password: 12345
zfile:
cache:
timeout: 300
timeout: 300
constant:
header: header.md
footer: footer.md
password: password.txt
jetcache:
statIntervalMinutes: 0
areaInCacheName: false
local:
default:
type: caffeine
keyConvertor: fastjson
defaultExpireInMillis: 3600000

View File

@@ -1,43 +1,52 @@
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 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', 'SecretId', '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');

View File

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

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
.box-card[data-v-621306e1]{padding-top:30px;padding-right:30px;margin:15vh auto;height:65vh;overflow-y:auto}.el-select[data-v-621306e1]{width:100%}

File diff suppressed because one or more lines are too long

Before

Width:  |  Height:  |  Size: 46 KiB

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><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.67225c93.css rel=prefetch><link href=/css/install.39da241e.css rel=prefetch><link href=/js/adminIndex.57637329.js rel=prefetch><link href=/js/dplayer.acc587f7.js rel=prefetch><link href=/js/install.3ac7201f.js rel=prefetch><link href=/css/app.46f70347.css rel=preload as=style><link href=/css/chunk-vendors.b9a3d604.css rel=preload as=style><link href=/js/app.362c49b5.js rel=preload as=script><link href=/js/chunk-vendors.10f10391.js rel=preload as=script><link href=/css/chunk-vendors.b9a3d604.css rel=stylesheet><link href=/css/app.46f70347.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.10f10391.js></script><script src=/js/app.362c49b5.js></script></body></html>

View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["adminIndex"],{"7bf3":function(t,e,a){"use strict";var s=a("ed6d"),i=a.n(s);i.a},adf4:function(t,e,a){"use strict";a.r(e);var s=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:12}},[a("keep-alive",{attrs:{exclude:"CacheManager"}},[a("router-view")],1)],1)],1)},i=[],n={name:"Index",data:function(){return{active:"/admin/storage"}}},l=n,o=(a("7bf3"),a("2877")),r=Object(o["a"])(l,s,i,!1,null,"4fea46ab",null);e["default"]=r.exports},ed6d:function(t,e,a){}}]);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1 @@
(window["webpackJsonp"]=window["webpackJsonp"]||[]).push([["install"],{4904:function(e,t,a){"use strict";var r=a("dfa0"),o=a.n(r);o.a},dfa0:function(e,t,a){},f8a7:function(e,t,a){"use strict";a.r(t);var r=function(){var e=this,t=e.$createElement,a=e._self._c||t;return a("el-row",{attrs:{gutter:20}},[a("el-col",{attrs:{span:8,offset:8}},[a("el-card",{staticClass:"box-card",attrs:{"align-center":"",shadow:"always"}},[a("el-form",{ref:"form",attrs:{rules:e.rules,model:e.form,"label-width":"auto","status-icon":!0}},[a("el-form-item",{attrs:{label:"站点名称",prop:"siteName"}},[a("el-input",{model:{value:e.form.siteName,callback:function(t){e.$set(e.form,"siteName",t)},expression:"form.siteName"}})],1),a("el-form-item",{attrs:{label:"管理员账号",prop:"username"}},[a("el-input",{model:{value:e.form.username,callback:function(t){e.$set(e.form,"username","string"===typeof t?t.trim():t)},expression:"form.username"}})],1),a("el-form-item",{attrs:{label:"管理员密码",prop:"password"}},[a("el-input",{model:{value:e.form.password,callback:function(t){e.$set(e.form,"password","string"===typeof t?t.trim():t)},expression:"form.password"}})],1),a("el-form-item",{attrs:{label:"站点地址/域名",prop:"domain"}},[a("el-input",{model:{value:e.form.domain,callback:function(t){e.$set(e.form,"domain","string"===typeof t?t.trim():t)},expression:"form.domain"}})],1),a("el-form-item",{attrs:{label:"存储策略"}},[a("el-select",{attrs:{placeholder:"请选择存储策略"},model:{value:e.form.storageStrategy,callback:function(t){e.$set(e.form,"storageStrategy",t)},expression:"form.storageStrategy"}},[a("el-option",{attrs:{label:"阿里云 OSS",value:"aliyun"}}),a("el-option",{attrs:{label:"腾讯云 COS",value:"tencent"}}),a("el-option",{attrs:{label:"华为云 OBS",value:"huawei"}}),a("el-option",{attrs:{label:"七牛云 KODO",value:"qiniu"}}),a("el-option",{attrs:{label:"又拍云 USS",value:"upyun"}}),a("el-option",{attrs:{label:"FTP",value:"ftp"}}),a("el-option",{attrs:{label:"本地存储",value:"local"}}),a("el-option",{attrs:{label:"minio",value:"minio"}})],1)],1),e._l(e.storageStrategyForm,(function(t){return a("el-form-item",{key:t.title,attrs:{label:t.title}},["endPoint"===t.key&&e.region.hasOwnProperty(e.form.storageStrategy)?a("el-select",{model:{value:e.form.storageStrategyConfig.endPoint,callback:function(t){e.$set(e.form.storageStrategyConfig,"endPoint",t)},expression:"form.storageStrategyConfig.endPoint"}},e._l(e.region[e.form.storageStrategy],(function(e){return a("el-option",{key:e.name,attrs:{label:e.name,value:e.val}})})),1):a("el-input",{model:{value:e.form.storageStrategyConfig[t.key],callback:function(a){e.$set(e.form.storageStrategyConfig,t.key,"string"===typeof a?a.trim():a)},expression:"form.storageStrategyConfig[item.key]"}})],1)})),a("el-form-item",[a("el-button",{attrs:{type:"primary"},on:{click:function(t){return e.submitForm("form")}}},[e._v("确认")])],1)],2)],1)],1)],1)},o=[],n=a("4328"),s=a.n(n),i=a("245d"),l={name:"Install",data:function(){return{active:1,form:{siteName:"",storageStrategy:"",username:"",password:"",domain:window.location.protocol+"//"+window.location.host,storageStrategyConfig:{endPoint:""}},storageStrategyForm:[],region:i["a"],rules:{siteName:[{required:!0,message:"请输入站点名称",trigger:"change"}],username:[{required:!0,message:"请输入管理员账号",trigger:"change"}],password:[{required:!0,message:"请输入管理员密码",trigger:"change"}],domain:[{required:!0,type:"url",message:"请输入正确的域名, 需以 http:// 或 https:// 开头",trigger:"change"}]}}},watch:{"form.storageStrategy":function(e){var t=this;this.$http.get("api/form",{params:{storageType:e}}).then((function(e){t.form.storageStrategyConfig.endPoint=null,t.storageStrategyForm=e.data.data}))}},methods:{submitForm:function(e){var t=this;this.$refs[e].validate((function(e){if(!e)return!1;var a=t;t.$http.post("install",s.a.stringify(t.form)).then((function(e){var r=e.data;t.$message({message:r.msg,type:0===r.code?"success":"error",duration:1500,onClose:function(){a.$router.push("/main")}})}))}))}},created:function(){var e=this;this.$http.get("is-installed").then((function(t){var a=t.data;0!==a.code&&e.$router.push("/main")}))}},m=l,u=(a("4904"),a("2877")),f=Object(u["a"])(m,r,o,!1,null,"621306e1",null);t["default"]=f.exports}}]);