v2.0.0 更新:

1、SpringBoot从3.1.1升级到3.5.3
    2、JDK从17升级到21并开启虚拟线程
    3、删除RocksDB相关配置,不再使用该缓存方案
    4、修改文件下载方式,使用StreamingResponseBody,支持大文件下载
    5、引入metona-cache-spring-boot-starter,使用此缓存方案
    6、重构在线日志页面及实现方式,不再使用读取日志文件方式,自定义日志拦截器实时获取日志
    7、不再生成自定义日志文件,日志打印从INFO改为DEBUG,打印更详细的内容
This commit is contained in:
2025-07-18 15:29:26 +08:00
parent abfbc181b3
commit 4ce49e1205
13 changed files with 17 additions and 393 deletions

View File

@@ -5,13 +5,12 @@
2. 文件下载、文件上传、在线日志
#### 软件架构
1. Jdk 17
1. Jdk 21
2. Maven 3.6.3
3. SpringBoot 3.1.1
4. SpringBoot Starter Thymeleaf 3.1.1
5. SpringBoot Starter WebSocket 3.1.1
6. RocksDB 8.3.2
7. Hutool Json 5.8.21
3. SpringBoot 3.5.3
4. SpringBoot Starter Thymeleaf 3.5.3
5. SpringBoot Starter WebSocket 3.5.3
7. Hutool 5.8.25
7. AXUI 2.1.1

View File

@@ -10,9 +10,9 @@
</parent>
<groupId>cn.somkit</groupId>
<artifactId>fmt</artifactId>
<version>1.3.0</version>
<version>2.0.0</version>
<name>fmt</name>
<description>fmt</description>
<description>File Manage System for by SpringBoot</description>
<properties>
<java.version>21</java.version>
</properties>

View File

@@ -1,21 +1,12 @@
package cn.somkit.fmt.action;
import cn.metona.cache.Cache;
import cn.somkit.fmt.entity.LoggerMessage;
import cn.somkit.fmt.utils.LoggerQueue;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicBoolean;
@Controller
@RequestMapping("/logging")

View File

@@ -1,53 +0,0 @@
package cn.somkit.fmt.action;
import cn.somkit.fmt.annotation.ApiOperate;
import cn.somkit.fmt.config.FmtConfig;
import cn.somkit.fmt.utils.ParamUtils;
import cn.somkit.fmt.utils.PathUtils;
import cn.somkit.fmt.utils.RocksDBUtils;
import org.rocksdb.RocksDBException;
import org.springframework.stereotype.Controller;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.servlet.ModelAndView;
import java.util.HashMap;
import java.util.Map;
@Controller
@RequestMapping("/system")
public class SystemAction {
@GetMapping("/index")
public ModelAndView index() throws Exception{
Map<String, String> map = new HashMap<>();
map.put("Upload_File_Path", ParamUtils.getUploadPath());
map.put("Temp_File_Path", ParamUtils.getTempFilePath());
map.put("Log_File_Path", ParamUtils.getLogFilePath());
map.put("Max_Read_Length", ParamUtils.getMaxReadLength());
map.put("Read_Interval", ParamUtils.getReadInterval());
ModelAndView mv = new ModelAndView();
mv.setViewName("system");
mv.addObject(FmtConfig.System_Cf_Name, map);
return mv;
}
@PostMapping("/save")
@ResponseBody
@ApiOperate(description = "保存系统设置")
public Map<String, Object> save(@RequestParam Map<String, String> map) throws Exception {
if(map != null && !map.isEmpty()){
map.keySet().forEach(key -> {
try {
if(StringUtils.hasText(map.get(key))){
String value = map.get(key).startsWith("./") ? PathUtils.resolve(map.get(key)) : map.get(key);
RocksDBUtils.put(FmtConfig.System_Cf_Name, key, value);
}
} catch (RocksDBException e) {
throw new RuntimeException(e);
}
});
}
return Map.of("code", 200, "message", "保存成功");
}
}

View File

@@ -1,41 +0,0 @@
package cn.somkit.fmt.config;
import cn.somkit.fmt.utils.PathUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;
/**
* 系统参数配置
*/
@Component
public class FmtConfig {
public static String System_Cf_Name = "system";
public static String Upload_File_Path = "./data/files";
public static String Temp_File_Path = "./data/files/temp";
@Value("${somkit.upload.path}")
public void setUpload_File_Path(String upload_file_path) {
if(StringUtils.hasText(upload_file_path)){
//如果使用相对路径,转换为绝对路径
if(upload_file_path.startsWith("./")){
upload_file_path = PathUtils.resolve(upload_file_path);
}
Upload_File_Path = upload_file_path;
}
}
@Value("${somkit.upload.temp-path}")
public void setTemp_File_Path(String temp_file_path) {
if(StringUtils.hasText(temp_file_path)){
//如果使用相对路径,转换为绝对路径
if(temp_file_path.startsWith("./")){
temp_file_path = PathUtils.resolve(temp_file_path);
}
Temp_File_Path = temp_file_path;
}
}
}

View File

@@ -1,63 +0,0 @@
package cn.somkit.fmt.utils;
import cn.somkit.fmt.config.FmtConfig;
import cn.somkit.fmt.config.LogSocketConfig;
import org.springframework.util.StringUtils;
public class ParamUtils {
public static String getUploadPath() throws Exception {
String path = RocksDBUtils.get(FmtConfig.System_Cf_Name, "Upload_File_Path");
if(StringUtils.hasText(path)){
return path;
} else {
path = FmtConfig.Upload_File_Path;
RocksDBUtils.put(FmtConfig.System_Cf_Name, "Upload_File_Path", path);
return path;
}
}
public static String getTempFilePath() throws Exception {
String path = RocksDBUtils.get(FmtConfig.System_Cf_Name, "Temp_File_Path");
if(StringUtils.hasText(path)){
return path;
} else {
path = FmtConfig.Temp_File_Path;
RocksDBUtils.put(FmtConfig.System_Cf_Name, "Temp_File_Path", path);
return path;
}
}
public static String getLogFilePath() throws Exception {
String path = RocksDBUtils.get(FmtConfig.System_Cf_Name, "Log_File_Path");
if(StringUtils.hasText(path)){
return path;
} else {
path = LogSocketConfig.Log_File_Path;
RocksDBUtils.put(FmtConfig.System_Cf_Name, "Log_File_Path", path);
return path;
}
}
public static String getMaxReadLength() throws Exception {
String path = RocksDBUtils.get(FmtConfig.System_Cf_Name, "Max_Read_Length");
if(StringUtils.hasText(path)){
return path;
} else {
path = LogSocketConfig.Max_Read_Length;
RocksDBUtils.put(FmtConfig.System_Cf_Name, "Max_Read_Length", path);
return path;
}
}
public static String getReadInterval() throws Exception {
String path = RocksDBUtils.get(FmtConfig.System_Cf_Name, "Read_Interval");
if(StringUtils.hasText(path)){
return path;
} else {
path = LogSocketConfig.Read_Interval;
RocksDBUtils.put(FmtConfig.System_Cf_Name, "Read_Interval", path);
return path;
}
}
}

View File

@@ -1,53 +0,0 @@
package cn.somkit.fmt.utils;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
/**
* 路径工具类
*/
public class PathUtils {
/**
* 解析相对路径为绝对路径
* @param relativePath 相对路径
* @return 绝对路径
*/
public static String resolve(String relativePath) {
if(relativePath.startsWith("./")){
relativePath = relativePath.replace("./", "");
}
// 获取当前工作目录的Path对象
Path currentWorkingDirectory = Paths.get("").toAbsolutePath();
// 使用相对路径创建Path对象
Path relativePathObject = Paths.get(relativePath);
// 解析相对路径,补全为绝对路径
Path absolutePath = currentWorkingDirectory.resolve(relativePathObject);
return absolutePath.toString();
}
/**
* 创建文件夹
* @param directoryPath 文件夹路径
*/
public static void directory(String directoryPath){
// 使用Paths.get()方法创建Path对象
Path dirPath = Paths.get(directoryPath);
// 检查文件夹是否存在
if (Files.notExists(dirPath)) {
try {
// 如果不存在,则创建文件夹及其所有必需的父目录
Files.createDirectories(dirPath);
System.out.println("Directory created: " + dirPath);
} catch (IOException e) {
// 如果创建过程中出现异常,打印错误信息
System.err.println("Failed to create directory: " + dirPath);
e.printStackTrace();
}
} else {
System.out.println("Directory already exists: " + dirPath);
}
}
}

View File

@@ -1,5 +1,5 @@
chcp 65001
SET JAR=D:/fmt/fmt-1.3.0.jar
SET JAR=D:/fmt/fmt-2.0.0.jar
SET JAR_CONFIG=D:/fmt/config/
SET JAR_LIB=D:/fmt/lib/
java -Dfile.encoding=utf-8 -jar %JAR% --spring.config.location=%JAR_CONFIG% --spring.lib.location=%JAR_LIB%

View File

@@ -1,8 +1,8 @@
#!/bin/bash
JAR=/home/deploy/fmt/fmt-1.3.0.jar
JAR=/home/deploy/fmt/fmt-2.0.0.jar
JAR_CONFIG=/home/deploy/fmt/config/
JAR_LIB=/home/deploy/fmt/lib/
JAVA_HOME=/usr/local/jdk-17.0.7
JAVA_HOME=/usr/local/jdk-21
JAVA=$JAVA_HOME/bin/java
nohup $JAVA -jar $JAR --spring.config.location=$JAR_CONFIG --spring.lib.location=$JAR_LIB -Djava.ext.dirs=$JAVA_HOME/lib &
tail -f nohup.out

View File

@@ -43,10 +43,6 @@
<a th:href="@{/logging/index}" target="_blank" class="ax-text">在线日志</a>
<span class="ax-line"></span>
</div>
<div class="ax-item">
<a th:href="@{/system/index}" class="ax-text">系统设置</a>
<span class="ax-line"></span>
</div>
</div>
</div>
</header>

View File

@@ -1,150 +0,0 @@
<!DOCTYPE html>
<html lang="zh-CN" xmlns:th="https://www.thymeleaf.org">
<head>
<meta name="viewport" content="width=device-width,initial-scale=1.0,maximum-scale=1.0,user-scalable=no" />
<meta name="apple-mobile-web-app-capable" content="yes" />
<meta name="apple-mobile-web-app-status-bar-style" content="black" />
<meta name="apple-touch-fullscreen" content="yes"/>
<meta name="format-detection" content="email=no" />
<meta name="wap-font-scale" content="no" />
<meta name="viewport" content="user-scalable=no, width=device-width" />
<meta content="telephone=no" name="format-detection" />
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>系统设置</title>
<link th:href="@{/axui-v2.1.1/css/ax.css}" rel="stylesheet" type="text/css" >
<link th:href="@{/axui-v2.1.1/css/ax-response.css}" rel="stylesheet" type="text/css" >
</head>
<body>
<header class="ax-header">
<div class="ax-row">
<div class="ax-col">
<a th:href="@{/download/index}" class="ax-logo">
<img th:src="@{/common/images/logo.png}" alt="File Management"/>
</a>
</div>
<div class="ax-nav">
<div class="ax-item">
<a th:href="@{/download/index}" class="ax-text">文件列表</a>
<span class="ax-line"></span>
</div>
<div class="ax-item">
<a th:href="@{/upload/index}" class="ax-text">文件上传</a>
<span class="ax-line"></span>
</div>
<div class="ax-item">
<a th:href="@{/logging/index}" class="ax-text">在线日志</a>
<span class="ax-line"></span>
</div>
<div class="ax-item ax-selected">
<a th:href="@{/system/index}" class="ax-text">系统设置</a>
<span class="ax-line"></span>
</div>
</div>
</div>
</header>
<div class="ax-space-header"></div>
<div id="app" class="ax-border ax-margin">
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label">上传文件存放地址:</div>
<div class="ax-form-con">
<div class="ax-form-input">
<input name="Upload_File_Path" th:value="${system.Upload_File_Path}" type="text">
</div>
</div>
<span class="ax-form-txt ax-color-ignore">相对路径以“./”开头,绝对路径填写完整目录</span>
</div>
</div>
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label">临时文件存放地址:</div>
<div class="ax-form-con">
<div class="ax-form-input">
<input name="Temp_File_Path" th:value="${system.Temp_File_Path}" type="text">
</div>
</div>
<span class="ax-form-txt ax-color-ignore">相对路径以“./”开头,绝对路径填写完整目录</span>
</div>
</div>
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label">日志文件地址:</div>
<div class="ax-form-con">
<div class="ax-form-input">
<input name="Log_File_Path" th:value="${system.Log_File_Path}" type="text">
</div>
</div>
<span class="ax-form-txt ax-color-ignore">相对路径以“./”开头,绝对路径填写完整目录</span>
</div>
</div>
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label">最大读取展示行数:</div>
<div class="ax-form-con">
<div class="ax-form-input">
<div class="ax-amount" axAmount>
<input name="Max_Read_Length" th:value="${system.Max_Read_Length}" type="text">
<a href="#" decrease><i class="ax-iconfont ax-icon-minus"></i></a>
<a href="#" increase><i class="ax-iconfont ax-icon-plus"></i></a>
</div>
</div>
</div>
<span class="ax-form-txt ax-color-ignore">在线日志文件最大读取行数,建议设置较大值以提高性能</span>
</div>
</div>
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label">读取间隔时间(毫秒)</div>
<div class="ax-form-con">
<div class="ax-form-input">
<div class="ax-amount" axAmount>
<input name="Read_Interval" th:value="${system.Read_Interval}" type="text">
<a href="#" decrease><i class="ax-iconfont ax-icon-minus"></i></a>
<a href="#" increase><i class="ax-iconfont ax-icon-plus"></i></a>
</div>
</div>
</div>
<span class="ax-form-txt ax-color-ignore">在线日志文件读取间隔时间,建议设置较小值以提高性能</span>
</div>
</div>
<div class="ax-break-md"></div>
<div class="ax-form-group">
<div class="ax-flex-row">
<div class="ax-form-label"></div>
<div class="ax-flex-block">
<div class="ax-form-input">
<button type="button" id="saveSystemSetting" class="ax-btn ax-primary ax-full">保存系统设置</button>
</div>
</div>
</div>
</div>
<div class="ax-break-md"></div>
</div>
<script th:src="@{/axui-v2.1.1/js/ax.js}" type="text/javascript" charset="utf-8"></script>
<script th:src="@{/common/js/basic.js}" type="text/javascript" charset="utf-8"></script>
<script type="text/javascript" th:inline="javascript" charset="utf-8">
window.onload = () => {
document.getElementById("saveSystemSetting").onclick = () => {
const options = {
url: Fmt.ctx() + '/system/save',
data: Fmt.utils.serialize('#app', 'json'),
method: 'post'
};
Fmt.axios(options).then((result) => {
console.log(result);
new axMessage({content: result.message, result: 'success', iconShow: true}).show();
}).catch((err) => {
console.log(err);
new axMessage({content: err, result: 'error', iconShow: true}).show();
});
}
}
</script>
</body>
</html>

View File

@@ -36,10 +36,6 @@
<a th:href="@{/logging/index}" target="_blank" class="ax-text">在线日志</a>
<span class="ax-line"></span>
</div>
<div class="ax-item">
<a th:href="@{/system/index}" class="ax-text">系统设置</a>
<span class="ax-line"></span>
</div>
</div>
</div>
</header>

View File

@@ -17,11 +17,13 @@
上传文件格式新增支持js、css、html、vsdx、dmp、7z、ppt、pptx
AxUI的axAjax方法timeout默认值改为6000000
```
> v1.3.0
> v2.0.0
```
修改RocksDB文件目录配置使其支持使用相对路径
修改上传文件目录配置,使其支持使用相对路径
新增临时文件存放地址配置,支持相对路径
新增系统设置页面,支持在线配置上传文件地址、日志文件地址等参数
SpringBoot从3.1.1升级到3.5.3
JDK从17升级到21并开启虚拟线程
删除RocksDB相关配置不再使用该缓存方案
修改文件下载方式使用StreamingResponseBody支持大文件下载
引入metona-cache-spring-boot-starter使用此缓存方案
重构在线日志页面及实现方式,不再使用读取日志文件方式,自定义日志拦截器实时获取日志
不再生成自定义日志文件日志打印从INFO改为DEBUG打印更详细的内容
```