Compare commits

...

16 Commits
0.1 ... 0.2

Author SHA1 Message Date
zhaojun1998
7033fc3fb1 💄 更新页面 2019-12-08 13:35:25 +08:00
zhaojun1998
8758bd8225 🐛 修复 MIMIO 指定名称异常 BUG 2019-12-08 13:34:42 +08:00
zhaojun1998
94290af50c 🐛 修复获取参数时,可能出现的并发修改异常 BUG 2019-12-08 13:34:10 +08:00
zhaojun1998
0200483e22 🐛 修复站点设置无效 BUG 2019-12-08 13:33:47 +08:00
zhaojun1998
8aa497b13b 💄 更新页面 2019-12-08 13:33:05 +08:00
zhaojun1998
1d60395161 🔒 密码加密由 BCrypt 修改为 MD5 2019-12-07 21:59:41 +08:00
zhaojun1998
d4978b0903 💥 新增 MINIO 支持 2019-12-07 21:22:33 +08:00
zhaojun1998
495da58af0 💄 更新样式 2019-12-07 21:22:01 +08:00
zhaojun1998
57f012482c 💥 新增 MINIO 支持 2019-12-07 19:51:09 +08:00
zhaojun1998
22a5e5cfeb 更新前端页面, 增加校验规则 2019-12-03 22:54:29 +08:00
zhaojun1998
fa332df4cf 🐛 修复配置文件 BUG 2019-12-03 22:49:28 +08:00
zhaojun1998
86885c880a Merge remote-tracking branch 'origin/master' 2019-12-03 22:43:12 +08:00
zhaojun1998
9ef217c33c 🐛 修复本地存储 BUG 2019-12-03 22:42:38 +08:00
赵俊
efbd2b441f Update README.md 2019-12-02 22:59:15 +08:00
赵俊
de7d276825 Update README.md 2019-12-02 22:58:50 +08:00
赵俊
428d04d478 Update README.md 2019-12-02 22:53:13 +08:00
26 changed files with 221 additions and 46 deletions

View File

@@ -16,13 +16,53 @@
* 支持在线浏览文本文件, 视频, 图片, 音乐.
* 文件/目录二维码
## 快速开始
安装 JDK 1.8 :
```bash
yum instal -y java # 适用于 Centos 7.x
```
> 其他系统的 JDK 安装教程, 后续我也都会补上. 大家也可执行搜索安装方式, 应该不是很难.
下载项目:
```bash
wget https://github.com/zhaojun1998/zfile/releases/download/0.1/zfile-0.1.jar
```
启动项目:
```bash
java -jar zfile-0.1.jar
## 高级启动
java -jar zfile-0.1.jar --server.port=18777
```
> `--server.port` 为指定端口, 默认为 `8080`
> 其他参数, 后面我会详细补充至文档, 最晚本周六日.
访问地址:
用户前台: http://127.0.0.1:8080/#/main
初始安装: http://127.0.0.1:8080/#/install
管理后台: http://127.0.0.1:8080/#/admin
## 运行环境
* JDK: `1.8`
* 缓存: `caffeine/redis`
* 数据库: `h2/mysql`
## 常见问题
### 缓存
@@ -51,4 +91,4 @@
- 文本预览更换更好用的编辑器
- 后台支持上传、编辑、删除等操作
- API 支持
- 更方便的部署方式
- 更方便的部署方式

View File

@@ -46,6 +46,11 @@
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.minio</groupId>
<artifactId>minio</artifactId>
<version>3.0.10</version>
</dependency>
<!-- 工具类 -->
<dependency>

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.controller;
import cn.hutool.crypto.SecureUtil;
import im.zhaojun.common.model.StorageConfig;
import im.zhaojun.common.model.dto.InstallModelDTO;
import im.zhaojun.common.model.dto.ResultBean;
@@ -8,7 +9,6 @@ import im.zhaojun.common.model.enums.StorageTypeEnum;
import im.zhaojun.common.service.FileService;
import im.zhaojun.common.service.StorageConfigService;
import im.zhaojun.common.service.SystemConfigService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
@@ -58,7 +58,7 @@ public class InstallController {
StorageTypeEnum storageTypeEnum = installModelDTO.getStorageStrategy();
systemConfigDTO.setStorageStrategy(storageTypeEnum);
systemConfigDTO.setUsername(installModelDTO.getUsername());
systemConfigDTO.setPassword(new BCryptPasswordEncoder().encode(installModelDTO.getPassword()));
systemConfigDTO.setPassword(SecureUtil.md5(installModelDTO.getPassword()));
systemConfigDTO.setDomain(installModelDTO.getDomain());
systemConfigService.updateSystemConfig(systemConfigDTO);

View File

@@ -1,5 +1,7 @@
package im.zhaojun.common.model.dto;
import com.fasterxml.jackson.annotation.JsonProperty;
import java.io.Serializable;
public class SiteConfigDTO implements Serializable {
@@ -10,6 +12,7 @@ public class SiteConfigDTO implements Serializable {
private String footer;
@JsonProperty("viewConfig")
private SystemConfigDTO systemConfigDTO;
public String getHeader() {

View File

@@ -14,7 +14,8 @@ public enum StorageTypeEnum {
ALIYUN("aliyun", "阿里云 OSS"),
FTP("ftp", "FTP"),
LOCAL("local", "本地存储"),
TENCENT("tencent", "腾讯云 COS");
TENCENT("tencent", "腾讯云 COS"),
MINIO("minio", "MINIO");
private static Map<String, StorageTypeEnum> enumMap = new HashMap<>();

View File

@@ -0,0 +1,17 @@
package im.zhaojun.common.security;
import cn.hutool.crypto.SecureUtil;
import org.springframework.security.crypto.password.PasswordEncoder;
public class MD5PasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return SecureUtil.md5(rawPassword.toString());
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return SecureUtil.md5(rawPassword.toString()).equals(encodedPassword);
}
}

View File

@@ -11,7 +11,6 @@ import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import javax.annotation.Resource;
@@ -116,7 +115,7 @@ public class MySecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public static PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
return new MD5PasswordEncoder();
}
}

View File

@@ -1,5 +1,6 @@
package im.zhaojun.common.service;
import cn.hutool.crypto.SecureUtil;
import im.zhaojun.common.config.StorageTypeFactory;
import im.zhaojun.common.model.SystemConfig;
import im.zhaojun.common.model.constant.SystemConfigConstant;
@@ -48,6 +49,9 @@ public class SystemConfigService {
case SystemConfigConstant.PASSWORD:
systemConfigDTO.setPassword(systemConfig.getValue());
break;
case SystemConfigConstant.DOMAIN:
systemConfigDTO.setDomain(systemConfig.getValue());
break;
default:break;
}
}
@@ -102,7 +106,7 @@ public class SystemConfigService {
usernameConfig.setValue(username);
systemConfigRepository.save(usernameConfig);
password = new BCryptPasswordEncoder().encode(password);
password = SecureUtil.md5(password);;
SystemConfig systemConfig = systemConfigRepository.findByKey(SystemConfigConstant.PASSWORD);
systemConfig.setValue(password);

View File

@@ -19,7 +19,7 @@ public class SystemService {
* 构建指定路径下标题, 页头, 页尾
* @param path 路径
*/
public SiteConfigDTO getConfig(String path) throws Exception {
public synchronized SiteConfigDTO getConfig(String path) throws Exception {
SiteConfigDTO siteConfigDTO = new SiteConfigDTO();
FileService fileService = systemConfigService.getCurrentFileService();

View File

@@ -1,12 +1,13 @@
package im.zhaojun.common.util;
import cn.hutool.core.util.URLUtil;
import org.springframework.web.client.RestTemplate;
public class HttpUtil {
public static String getTextContent(String url) {
RestTemplate restTemplate = SpringContextHolder.getBean(RestTemplate.class);
String result = restTemplate.getForObject(url, String.class);
String result = restTemplate.getForObject(URLUtil.decode(url), String.class);
return result == null ? "" : result;
}

View File

@@ -17,7 +17,6 @@ import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.util.Date;
@Controller
@@ -39,18 +38,13 @@ public class LocalController {
}
private ResponseEntity<FileSystemResource> export(File file) throws IOException {
// 获取文件 MIME 类型
String fileMimeType = Files.probeContentType(file.toPath());
MediaType mediaType = MediaType.APPLICATION_OCTET_STREAM;
HttpHeaders headers = new HttpHeaders();
if (fileMimeType == null || "".equals(fileMimeType)) {
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.add("Content-Disposition", "attachment; filename=" + file.getName());
} else {
mediaType = MediaType.parseMediaType(fileMimeType);
}
HttpHeaders headers = new HttpHeaders();
headers.add("Cache-Control", "no-cache, no-store, must-revalidate");
headers.setContentDispositionFormData("attachment", URLUtil.encode(file.getName()));
headers.add("Pragma", "no-cache");
headers.add("Expires", "0");
headers.add("Last-Modified", new Date().toString());

View File

@@ -84,7 +84,7 @@ public class LocalServiceImpl implements FileService {
@Override
public String getDownloadUrl(String path) throws Exception {
SystemConfig usernameConfig = systemConfigRepository.findByKey(SystemConfigConstant.DOMAIN);
return StringUtils.concatPath( usernameConfig.getValue(), "file" + path);
return StringUtils.removeDuplicateSeparator(usernameConfig.getValue() + "/file/" + path);
}
public String getFilePath() {

View File

@@ -0,0 +1,109 @@
package im.zhaojun.minio;
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.enums.StorageTypeEnum;
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;
@Service
public class MinIOServiceImpl 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() + "初始化异常, 已跳过");
}
}
@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);
} 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())));
}
fileItemList.add(fileItemDTO);
}
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

@@ -23,13 +23,13 @@ spring:
# h2 内存数据库 配置
driver-class-name: org.h2.Driver
url: jdbc:h2:~/.zfile/db/zfile
username: zfile
url: jdbc:h2:~/.zfile/db/zfile-demo
username: zfile-demo
password: 123456
# MySQL 配置
# driver-class-name: com.mysql.jdbc.Driver
# url: jdbc:mysql://127.0.0.1:3306/zfile?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
# url: jdbc:mysql://127.0.0.1:3306/zfile-demo?characterEncoding=utf8&serverTimezone=Asia/Shanghai&useSSL=false
# username: root
# password: 123456
jackson:
@@ -50,6 +50,4 @@ spring:
password: 12345
zfile:
cache:
timeout: 300
timeout: 300

View File

@@ -36,4 +36,8 @@ INSERT INTO STORAGE_CONFIG (`ID`, `k`, `TITLE`, `TYPE`, `VALUE`) VALUES (25, 'se
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 (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);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1 +1 @@
<!DOCTYPE html><html lang=en><head><meta charset=utf-8><meta http-equiv=X-UA-Compatible content="IE=edge"><meta name=viewport content="width=device-width,initial-scale=1"><link rel=icon href=/favicon.ico><script src=//at.alicdn.com/t/font_1428963_kk67lnmooll.js></script><title></title><link href=/css/app.a5e07919.css rel=preload as=style><link href=/css/chunk-vendors.2f37471b.css rel=preload as=style><link href=/js/app.07eaa8c9.js rel=preload as=script><link href=/js/chunk-vendors.06c4a2a1.js rel=preload as=script><link href=/css/chunk-vendors.2f37471b.css rel=stylesheet><link href=/css/app.a5e07919.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.06c4a2a1.js></script><script src=/js/app.07eaa8c9.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><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>

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