diff --git a/src/main/java/neatlogic/module/tenant/api/mailserver/MailServerTestApi.java b/src/main/java/neatlogic/module/tenant/api/mailserver/MailServerTestApi.java
index 69154ee5b16c53d9d5a273ba41b1b5d2b56e5ad2..091a37b619aac3e17841098128eb530272d3fa27 100644
--- a/src/main/java/neatlogic/module/tenant/api/mailserver/MailServerTestApi.java
+++ b/src/main/java/neatlogic/module/tenant/api/mailserver/MailServerTestApi.java
@@ -25,6 +25,8 @@ import neatlogic.framework.restful.core.privateapi.PrivateApiComponentBase;
import neatlogic.framework.util.EmailUtil;
import org.springframework.stereotype.Service;
+import java.util.Collections;
+
/**
* 测试邮件服务器能否正常发送邮件
*
@@ -58,10 +60,11 @@ public class MailServerTestApi extends PrivateApiComponentBase {
@Description(desc = "nmtam.mailservertestapi.getname")
@Override
public Object myDoService(JSONObject jsonObj) throws Exception {
- EmailUtil.sendEmailWithFile(
+ EmailUtil.sendHtmlEmail(
"Test mail",
"Your configured mail server information is available!",
- jsonObj.getString("emailAddress")
+ Collections.singletonList(jsonObj.getString("emailAddress")),
+ null
);
return null;
}
diff --git a/src/main/java/neatlogic/module/tenant/api/util/DownloadLocalFileApi.java b/src/main/java/neatlogic/module/tenant/api/util/DownloadLocalFileApi.java
index d7f28ca9d43a4c598cc413de5bafa0a3427cb3bb..629f9f6859501c805386b36a71a3ab63e385f0df 100644
--- a/src/main/java/neatlogic/module/tenant/api/util/DownloadLocalFileApi.java
+++ b/src/main/java/neatlogic/module/tenant/api/util/DownloadLocalFileApi.java
@@ -37,14 +37,17 @@ import neatlogic.framework.restful.core.privateapi.PrivateBinaryStreamApiCompone
import neatlogic.framework.util.HttpRequestUtil;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
import org.springframework.stereotype.Service;
-import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.File;
import java.io.InputStream;
+import java.util.LinkedHashMap;
import java.util.Objects;
@Service
@@ -52,7 +55,7 @@ import java.util.Objects;
@OperationType(type = OperationTypeEnum.SEARCH)
public class DownloadLocalFileApi extends PrivateBinaryStreamApiComponentBase {
- @Resource
+ @javax.annotation.Resource
private ServerMapper serverMapper;
@Override
@@ -72,66 +75,112 @@ public class DownloadLocalFileApi extends PrivateBinaryStreamApiComponentBase {
@Description(desc = "下载服务器文件")
@Override
public Object myDoService(JSONObject paramObj, HttpServletRequest request, HttpServletResponse response) throws Exception {
+ JSONObject resultObj = new JSONObject(new LinkedHashMap<>());
+ boolean hasServerId = true;
Integer serverId = paramObj.getInteger("serverId");
if (serverId == null) {
+ hasServerId = false;
serverId = Config.SCHEDULE_SERVER_ID;
}
if (Objects.equals(serverId, Config.SCHEDULE_SERVER_ID)) {
String fileName = null;
String path = paramObj.getString("path");
- int index = path.lastIndexOf(File.separator);
+ int index = -1;
+ if (path.contains(File.separator)) {
+ index = path.lastIndexOf(File.separator);
+ } else {
+ index = path.lastIndexOf("/");
+ }
if (index != -1) {
fileName = path.substring(index + 1);
} else {
fileName = path;
}
- fileName += "_serverId" + serverId;
- File file = new File(path);
- if (!file.exists()) {
- throw new ApiRuntimeException("文件不存在");
- }
- if (!file.isFile()) {
- throw new ApiRuntimeException(path + "不是文件");
- }
- if (!path.startsWith("file:")) {
- path = "file:" + path;
+ InputStream in = null;
+ if (path.startsWith("jar:file:")) {
+ String locationPattern = null;
+ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ int index1 = path.lastIndexOf("jar!");
+ if (index1 != -1) {
+ String classpath = path.substring(index1 + 4);
+ locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + classpath;
+ } else {
+ locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "**/" + fileName;
+ }
+ Resource[] resources = resolver.getResources(locationPattern);
+ for (Resource resource : resources) {
+ if (resource.exists()) {
+ if (Objects.equals(resource.getURL().toString(), path)) {
+ if (resource.isReadable()) {
+ in = resource.getInputStream();
+ } else {
+ resultObj.put("message", "没有权限读取" + path + "文件");
+ }
+ break;
+ }
+ }
+ }
+ if (in == null) {
+ resultObj.put("message", "文件不存在");
+ }
+ } else {
+ File file = new File(path);
+ if (file.exists()) {
+ if (file.isFile()) {
+ if (file.canRead()) {
+ if (!path.startsWith("file:")) {
+ path = "file:" + path;
+ }
+ in = FileUtil.getData(path);
+ } else {
+ resultObj.put("message", "没有权限读取" + path + "文件");
+ }
+ } else {
+ resultObj.put("message", path + "不是文件");
+ }
+ } else {
+ resultObj.put("message", "文件不存在");
+ }
}
- ServletOutputStream os;
- InputStream in;
- in = FileUtil.getData(path);
if (in != null) {
+ if (!hasServerId) {
+ fileName += "_serverId" + serverId;
+ }
response.setContentType("application/octet-stream");
response.setHeader("Content-Disposition", " attachment; filename=\"" + neatlogic.framework.util.FileUtil.getEncodedFileName(fileName) + "\"");
- os = response.getOutputStream();
+ ServletOutputStream os = response.getOutputStream();
IOUtils.copyLarge(in, os);
os.flush();
os.close();
in.close();
}
} else {
- String host = null;
TenantContext.get().setUseMasterDatabase(true);
ServerClusterVo serverClusterVo = serverMapper.getServerByServerId(serverId);
- if (serverClusterVo != null) {
- host = serverClusterVo.getHost();
- }
TenantContext.get().setUseMasterDatabase(false);
- if (StringUtils.isNotBlank(host)) {
- ServletOutputStream os = response.getOutputStream();
- String url = host + request.getRequestURI();
- HttpRequestUtil httpRequestUtil = HttpRequestUtil.download(url, "POST", os)
- .setPayload(paramObj.toJSONString())
- .setAuthType(AuthenticateType.BUILDIN)
- .setConnectTimeout(5000)
- .setReadTimeout(5000)
- .sendRequest();
- String error = httpRequestUtil.getError();
- if (StringUtils.isNotBlank(error)) {
- throw new ApiRuntimeException(error);
+ if (serverClusterVo != null) {
+ String host = serverClusterVo.getHost();
+ if (StringUtils.isNotBlank(host)) {
+ ServletOutputStream os = response.getOutputStream();
+ String url = host + request.getRequestURI();
+ HttpRequestUtil httpRequestUtil = HttpRequestUtil.download(url, "POST", os)
+ .setPayload(paramObj.toJSONString())
+ .setAuthType(AuthenticateType.BUILDIN)
+ .setConnectTimeout(5000)
+ .setReadTimeout(5000)
+ .sendRequest();
+ String error = httpRequestUtil.getError();
+ if (StringUtils.isNotBlank(error)) {
+ throw new ApiRuntimeException(error);
+ }
+ } else {
+ resultObj.put("message", "serverId为" + serverId + "的应用服务器的`server_status`表中对应数据没有配置host");
}
+ } else {
+ resultObj.put("message", "找不到serverId为" + serverId + "的应用服务器");
}
}
- return null;
+ return resultObj;
}
@Override
diff --git a/src/main/java/neatlogic/module/tenant/api/util/GetServerInfoApi.java b/src/main/java/neatlogic/module/tenant/api/util/GetServerInfoApi.java
index 8fbb4ca1eae190fdd86d7f15cd176128fffef1c6..7145900a98126b011ff26488fb6904d3cbb4e21d 100644
--- a/src/main/java/neatlogic/module/tenant/api/util/GetServerInfoApi.java
+++ b/src/main/java/neatlogic/module/tenant/api/util/GetServerInfoApi.java
@@ -88,36 +88,41 @@ public class GetServerInfoApi extends PrivateApiComponentBase {
JSONArray array = new JSONArray();
array.addAll(args);
resultObj.put("命令行参数", array);
+ resultObj.put("Java虚拟机的系统属性", System.getProperties());
+ resultObj.put("操作系统的环境变量", System.getenv());
resultObj.put("serverId", serverId);
} else {
- String host = null;
TenantContext.get().setUseMasterDatabase(true);
ServerClusterVo serverClusterVo = serverMapper.getServerByServerId(serverId);
- if (serverClusterVo != null) {
- host = serverClusterVo.getHost();
- }
TenantContext.get().setUseMasterDatabase(false);
- if (StringUtils.isNotBlank(host)) {
- HttpServletRequest request = RequestContext.get().getRequest();
- String url = host + request.getRequestURI();
- HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
- .setPayload(paramObj.toJSONString())
- .setAuthType(AuthenticateType.BUILDIN)
- .setConnectTimeout(5000)
- .setReadTimeout(5000)
- .sendRequest();
- String error = httpRequestUtil.getError();
- if (StringUtils.isNotBlank(error)) {
- throw new ApiRuntimeException(error);
- }
- JSONObject resultJson = httpRequestUtil.getResultJson();
- if (MapUtils.isNotEmpty(resultJson)) {
- String status = resultJson.getString("Status");
- if (!"OK".equals(status)) {
- throw new RuntimeException(resultJson.getString("Message"));
+ if (serverClusterVo != null) {
+ String host = serverClusterVo.getHost();
+ if (StringUtils.isNotBlank(host)) {
+ HttpServletRequest request = RequestContext.get().getRequest();
+ String url = host + request.getRequestURI();
+ HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
+ .setPayload(paramObj.toJSONString())
+ .setAuthType(AuthenticateType.BUILDIN)
+ .setConnectTimeout(5000)
+ .setReadTimeout(5000)
+ .sendRequest();
+ String error = httpRequestUtil.getError();
+ if (StringUtils.isNotBlank(error)) {
+ throw new ApiRuntimeException(error);
+ }
+ JSONObject resultJson = httpRequestUtil.getResultJson();
+ if (MapUtils.isNotEmpty(resultJson)) {
+ String status = resultJson.getString("Status");
+ if (!"OK".equals(status)) {
+ throw new RuntimeException(resultJson.getString("Message"));
+ }
+ resultObj = resultJson.getJSONObject("Return");
}
- resultObj = resultJson.getJSONObject("Return");
+ } else {
+ resultObj.put("message", "serverId为" + serverId + "的应用服务器的`server_status`表中对应数据没有配置host");
}
+ } else {
+ resultObj.put("message", "找不到serverId为" + serverId + "的应用服务器");
}
}
return resultObj;
diff --git a/src/main/java/neatlogic/module/tenant/api/util/RefreshConfigApi.java b/src/main/java/neatlogic/module/tenant/api/util/RefreshConfigApi.java
index d41b9aa05884bb0ebc788f6d744178f85e86d90d..7433b4bab4031329d20d8dea0c3bab15c9a679b9 100644
--- a/src/main/java/neatlogic/module/tenant/api/util/RefreshConfigApi.java
+++ b/src/main/java/neatlogic/module/tenant/api/util/RefreshConfigApi.java
@@ -82,34 +82,37 @@ public class RefreshConfigApi extends PrivateApiComponentBase {
resultObj.put("config", prop);
resultObj.put("serverId", serverId);
} else {
- String host = null;
TenantContext.get().setUseMasterDatabase(true);
ServerClusterVo serverClusterVo = serverMapper.getServerByServerId(serverId);
- if (serverClusterVo != null) {
- host = serverClusterVo.getHost();
- }
TenantContext.get().setUseMasterDatabase(false);
- if (StringUtils.isNotBlank(host)) {
- HttpServletRequest request = RequestContext.get().getRequest();
- String url = host + request.getRequestURI();
- HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
- .setPayload(paramObj.toJSONString())
- .setAuthType(AuthenticateType.BUILDIN)
- .setConnectTimeout(5000)
- .setReadTimeout(5000)
- .sendRequest();
- String error = httpRequestUtil.getError();
- if (StringUtils.isNotBlank(error)) {
- throw new ApiRuntimeException(error);
- }
- JSONObject resultJson = httpRequestUtil.getResultJson();
- if (MapUtils.isNotEmpty(resultJson)) {
- String status = resultJson.getString("Status");
- if (!"OK".equals(status)) {
- throw new RuntimeException(resultJson.getString("Message"));
+ if (serverClusterVo != null) {
+ String host = serverClusterVo.getHost();
+ if (StringUtils.isNotBlank(host)) {
+ HttpServletRequest request = RequestContext.get().getRequest();
+ String url = host + request.getRequestURI();
+ HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
+ .setPayload(paramObj.toJSONString())
+ .setAuthType(AuthenticateType.BUILDIN)
+ .setConnectTimeout(5000)
+ .setReadTimeout(5000)
+ .sendRequest();
+ String error = httpRequestUtil.getError();
+ if (StringUtils.isNotBlank(error)) {
+ throw new ApiRuntimeException(error);
+ }
+ JSONObject resultJson = httpRequestUtil.getResultJson();
+ if (MapUtils.isNotEmpty(resultJson)) {
+ String status = resultJson.getString("Status");
+ if (!"OK".equals(status)) {
+ throw new RuntimeException(resultJson.getString("Message"));
+ }
+ resultObj = resultJson.getJSONObject("Return");
}
- resultObj = resultJson.getJSONObject("Return");
+ } else {
+ resultObj.put("message", "serverId为" + serverId + "的应用服务器的`server_status`表中对应数据没有配置host");
}
+ } else {
+ resultObj.put("message", "找不到serverId为" + serverId + "的应用服务器");
}
}
return resultObj;
diff --git a/src/main/java/neatlogic/module/tenant/api/util/SearchLocalFilePathApi.java b/src/main/java/neatlogic/module/tenant/api/util/SearchLocalFilePathApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..59d7fd56ceab4eee95be74148d0e0f3f1f5c2e62
--- /dev/null
+++ b/src/main/java/neatlogic/module/tenant/api/util/SearchLocalFilePathApi.java
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package neatlogic.module.tenant.api.util;
+
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import neatlogic.framework.asynchronization.threadlocal.RequestContext;
+import neatlogic.framework.asynchronization.threadlocal.TenantContext;
+import neatlogic.framework.auth.core.AuthAction;
+import neatlogic.framework.auth.label.ADMIN;
+import neatlogic.framework.common.config.Config;
+import neatlogic.framework.common.constvalue.ApiParamType;
+import neatlogic.framework.exception.core.ApiRuntimeException;
+import neatlogic.framework.heartbeat.dao.mapper.ServerMapper;
+import neatlogic.framework.heartbeat.dto.ServerClusterVo;
+import neatlogic.framework.integration.authentication.enums.AuthenticateType;
+import neatlogic.framework.restful.annotation.Description;
+import neatlogic.framework.restful.annotation.Input;
+import neatlogic.framework.restful.annotation.OperationType;
+import neatlogic.framework.restful.annotation.Param;
+import neatlogic.framework.restful.constvalue.OperationTypeEnum;
+import neatlogic.framework.restful.core.privateapi.PrivateApiComponentBase;
+import neatlogic.framework.util.HttpRequestUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.stereotype.Service;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+@Service
+@AuthAction(action = ADMIN.class)
+@OperationType(type = OperationTypeEnum.OPERATE)
+public class SearchLocalFilePathApi extends PrivateApiComponentBase {
+
+ @Autowired
+ private ServerMapper serverMapper;
+
+ @Override
+ public String getName() {
+ return "查询服务器文件路径";
+ }
+
+ @Input({
+ @Param(name = "serverId", type = ApiParamType.INTEGER, desc = "服务器ID"),
+ @Param(name = "fileName", type = ApiParamType.STRING, isRequired = true, desc = "文件名"),
+ @Param(name = "scanPathList", type = ApiParamType.JSONARRAY, desc = "扫描路径列表", help = "默认只扫描类路径,如果需要扫描其他路径,就在这里添加,但不可以从\"/\"根目录开始扫描")
+ })
+ @Description(desc = "查询服务器文件路径")
+ @Override
+ public Object myDoService(JSONObject paramObj) throws Exception {
+ JSONObject resultObj = new JSONObject(new LinkedHashMap<>());
+ Integer serverId = paramObj.getInteger("serverId");
+ if (serverId == null) {
+ serverId = Config.SCHEDULE_SERVER_ID;
+ }
+ if (Objects.equals(serverId, Config.SCHEDULE_SERVER_ID)) {
+ String fileName = paramObj.getString("fileName");
+ JSONArray scanPathList = paramObj.getJSONArray("scanPathList");
+ ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
+ JSONArray resultList = new JSONArray();
+ {
+ long startTime = System.currentTimeMillis();
+ JSONObject jsonObj = new JSONObject(new LinkedHashMap<>());
+ JSONArray filePathList = new JSONArray();
+ JSONArray otherPathList = new JSONArray();
+ String locationPattern = ResourcePatternResolver.CLASSPATH_ALL_URL_PREFIX + "**/" + fileName;
+ Resource[] resources = resolver.getResources(locationPattern);
+ for (Resource resource : resources) {
+ if (resource.exists()) {
+ if (resource.isFile()) {
+ File file = resource.getFile();
+ JSONObject pathObj = new JSONObject();
+ pathObj.put("path", file.getPath());
+ pathObj.put("canRead", file.canRead());
+ pathObj.put("canWrite", file.canWrite());
+ pathObj.put("isHidden", file.isHidden());
+ pathObj.put("length", file.length());
+ filePathList.add(pathObj);
+ } else {
+ JSONObject pathObj = new JSONObject();
+ pathObj.put("path", resource.getURL().toString());
+ pathObj.put("canRead", resource.isReadable());
+ otherPathList.add(pathObj);
+ }
+ }
+ }
+ jsonObj.put("locationPattern", locationPattern);
+ jsonObj.put("timeCost", (System.currentTimeMillis() - startTime));
+ jsonObj.put("filePathList", filePathList);
+ if (CollectionUtils.isNotEmpty(otherPathList)) {
+ jsonObj.put("otherPathList", otherPathList);
+ }
+ resultList.add(jsonObj);
+ }
+ {
+ if (CollectionUtils.isNotEmpty(scanPathList)) {
+ for (int i = 0; i < scanPathList.size(); i++) {
+ String scanPath = scanPathList.getString(i);
+ if (Objects.equals(scanPath, "/")) {
+ String locationPattern = "file:" + "/**/" + fileName;
+ JSONObject jsonObj = new JSONObject(new LinkedHashMap<>());
+ jsonObj.put("locationPattern", locationPattern);
+ jsonObj.put("message", "不可以从根目录开始扫描");
+ resultList.add(jsonObj);
+ } else {
+ long startTime = System.currentTimeMillis();
+ JSONObject jsonObj = new JSONObject(new LinkedHashMap<>());
+ JSONArray filePathList = new JSONArray();
+ JSONArray otherPathList = new JSONArray();
+ String locationPattern = "file:" + scanPath + "/**/" + fileName;
+ Resource[] resources = resolver.getResources(locationPattern);
+ for (Resource resource : resources) {
+ if (resource.exists()) {
+ if (resource.isFile()) {
+ File file = resource.getFile();
+ JSONObject pathObj = new JSONObject();
+ pathObj.put("path", file.getPath());
+ pathObj.put("canRead", file.canRead());
+ pathObj.put("canWrite", file.canWrite());
+ pathObj.put("isHidden", file.isHidden());
+ pathObj.put("length", file.length());
+ filePathList.add(pathObj);
+ } else {
+ JSONObject pathObj = new JSONObject();
+ pathObj.put("path", resource.getURL().toString());
+ pathObj.put("canRead", resource.isReadable());
+ otherPathList.add(pathObj);
+ }
+ }
+ }
+ jsonObj.put("locationPattern", locationPattern);
+ jsonObj.put("timeCost", (System.currentTimeMillis() - startTime));
+ jsonObj.put("filePathList", filePathList);
+ if (CollectionUtils.isNotEmpty(otherPathList)) {
+ jsonObj.put("otherPathList", otherPathList);
+ }
+ resultList.add(jsonObj);
+ }
+ }
+ }
+ }
+ resultObj.put("tbodyList", resultList);
+ resultObj.put("serverId", serverId);
+ } else {
+ TenantContext.get().setUseMasterDatabase(true);
+ ServerClusterVo serverClusterVo = serverMapper.getServerByServerId(serverId);
+ TenantContext.get().setUseMasterDatabase(false);
+ if (serverClusterVo != null) {
+ String host = serverClusterVo.getHost();
+ if (StringUtils.isNotBlank(host)) {
+ HttpServletRequest request = RequestContext.get().getRequest();
+ String url = host + request.getRequestURI();
+ HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
+ .setPayload(paramObj.toJSONString())
+ .setAuthType(AuthenticateType.BUILDIN)
+ .setConnectTimeout(5000)
+ .setReadTimeout(5000)
+ .sendRequest();
+ String error = httpRequestUtil.getError();
+ if (StringUtils.isNotBlank(error)) {
+ throw new ApiRuntimeException(error);
+ }
+ JSONObject resultJson = httpRequestUtil.getResultJson();
+ if (MapUtils.isNotEmpty(resultJson)) {
+ String status = resultJson.getString("Status");
+ if (!"OK".equals(status)) {
+ throw new RuntimeException(resultJson.getString("Message"));
+ }
+ resultObj = resultJson.getJSONObject("Return");
+ }
+ } else {
+ resultObj.put("message", "serverId为" + serverId + "的应用服务器的`server_status`表中对应数据没有配置host");
+ }
+ } else {
+ resultObj.put("message", "找不到serverId为" + serverId + "的应用服务器");
+ }
+ }
+ return resultObj;
+ }
+
+ @Override
+ public String getToken() {
+ return "util/localfile/path/search";
+ }
+}
diff --git a/src/main/java/neatlogic/module/tenant/api/util/UpdateLocalFileApi.java b/src/main/java/neatlogic/module/tenant/api/util/UpdateLocalFileApi.java
new file mode 100644
index 0000000000000000000000000000000000000000..db7c72d42d41934ef0de7246efb6d5c0d41761bf
--- /dev/null
+++ b/src/main/java/neatlogic/module/tenant/api/util/UpdateLocalFileApi.java
@@ -0,0 +1,164 @@
+/*
+ * Copyright (C) 2025 深圳极向量科技有限公司 All Rights Reserved.
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+package neatlogic.module.tenant.api.util;
+
+import com.alibaba.fastjson.JSONObject;
+import neatlogic.framework.asynchronization.threadlocal.RequestContext;
+import neatlogic.framework.asynchronization.threadlocal.TenantContext;
+import neatlogic.framework.auth.core.AuthAction;
+import neatlogic.framework.auth.label.ADMIN;
+import neatlogic.framework.common.config.Config;
+import neatlogic.framework.common.constvalue.ApiParamType;
+import neatlogic.framework.exception.core.ApiRuntimeException;
+import neatlogic.framework.exception.file.FileStorageMediumHandlerNotFoundException;
+import neatlogic.framework.file.core.FileStorageMediumFactory;
+import neatlogic.framework.file.core.IFileStorageHandler;
+import neatlogic.framework.file.dao.mapper.FileMapper;
+import neatlogic.framework.file.dto.FileVo;
+import neatlogic.framework.heartbeat.dao.mapper.ServerMapper;
+import neatlogic.framework.heartbeat.dto.ServerClusterVo;
+import neatlogic.framework.integration.authentication.enums.AuthenticateType;
+import neatlogic.framework.restful.annotation.Description;
+import neatlogic.framework.restful.annotation.Input;
+import neatlogic.framework.restful.annotation.OperationType;
+import neatlogic.framework.restful.annotation.Param;
+import neatlogic.framework.restful.constvalue.OperationTypeEnum;
+import neatlogic.framework.restful.core.privateapi.PrivateApiComponentBase;
+import neatlogic.framework.util.HttpRequestUtil;
+import org.apache.commons.collections4.MapUtils;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import java.io.File;
+import java.io.InputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+import java.util.LinkedHashMap;
+import java.util.Objects;
+
+@Service
+@AuthAction(action = ADMIN.class)
+@OperationType(type = OperationTypeEnum.OPERATE)
+public class UpdateLocalFileApi extends PrivateApiComponentBase {
+
+ @Resource
+ private ServerMapper serverMapper;
+
+ @Resource
+ private FileMapper fileMapper;
+
+ @Override
+ public String getName() {
+ return "更新服务器文件";
+ }
+
+ @Input({
+ @Param(name = "serverId", type = ApiParamType.INTEGER, desc = "服务器ID"),
+ @Param(name = "fileId", type = ApiParamType.LONG, isRequired = true, desc = "附件ID"),
+ @Param(name = "path", type = ApiParamType.STRING, isRequired = true, desc = "需要更新的文件路径")
+ })
+ @Description(desc = "更新服务器文件")
+ @Override
+ public Object myDoService(JSONObject paramObj) throws Exception {
+ JSONObject resultObj = new JSONObject(new LinkedHashMap<>());
+ Integer serverId = paramObj.getInteger("serverId");
+ if (serverId == null) {
+ serverId = Config.SCHEDULE_SERVER_ID;
+ }
+ if (Objects.equals(serverId, Config.SCHEDULE_SERVER_ID)) {
+ Long fileId = paramObj.getLong("fileId");
+ String path = paramObj.getString("path");
+ FileVo fileVo = fileMapper.getFileById(fileId);
+ String filePath = fileVo.getPath();
+ String[] split = filePath.split(":", 2);
+ IFileStorageHandler handler = FileStorageMediumFactory.getHandler(split[0].toUpperCase());
+ if (handler == null) {
+ throw new FileStorageMediumHandlerNotFoundException(split[0]);
+ }
+ try (InputStream inputStream = handler.getData(filePath)) {
+ Path targetPath = Paths.get(path);
+ File file = targetPath.toFile();
+ resultObj.put("path", file.getPath());
+ if (file.exists()) {
+ resultObj.put("文件是否已存在", "是");
+ long length = Files.copy(inputStream, targetPath, StandardCopyOption.REPLACE_EXISTING);
+ resultObj.put("操作类型", "覆盖");
+ resultObj.put("文件大小", length);
+ } else {
+ if (!file.getParentFile().exists()) {
+ file.getParentFile().mkdirs();
+ }
+ resultObj.put("文件是否已存在", "否");
+ long length = Files.copy(inputStream, targetPath);
+ resultObj.put("操作类型", "新增");
+ resultObj.put("文件大小", length);
+ }
+ }
+ resultObj.put("serverId", serverId);
+ } else {
+ TenantContext.get().setUseMasterDatabase(true);
+ ServerClusterVo serverClusterVo = serverMapper.getServerByServerId(serverId);
+ TenantContext.get().setUseMasterDatabase(false);
+ if (serverClusterVo != null) {
+ String host = serverClusterVo.getHost();
+ if (StringUtils.isNotBlank(host)) {
+ HttpServletRequest request = RequestContext.get().getRequest();
+ String url = host + request.getRequestURI();
+ HttpRequestUtil httpRequestUtil = HttpRequestUtil.post(url)
+ .setPayload(paramObj.toJSONString())
+ .setAuthType(AuthenticateType.BUILDIN)
+ .setConnectTimeout(5000)
+ .setReadTimeout(5000)
+ .sendRequest();
+ String error = httpRequestUtil.getError();
+ if (StringUtils.isNotBlank(error)) {
+ throw new ApiRuntimeException(error);
+ }
+ JSONObject resultJson = httpRequestUtil.getResultJson();
+ if (MapUtils.isNotEmpty(resultJson)) {
+ String status = resultJson.getString("Status");
+ if (!"OK".equals(status)) {
+ throw new RuntimeException(resultJson.getString("Message"));
+ }
+ resultObj = resultJson.getJSONObject("Return");
+ }
+ } else {
+ resultObj.put("message", "serverId为" + serverId + "的应用服务器的`server_status`表中对应数据没有配置host");
+ }
+ } else {
+ resultObj.put("message", "找不到serverId为" + serverId + "的应用服务器");
+ }
+ }
+ return resultObj;
+ }
+
+ @Override
+ public String getToken() {
+ return "util/localfile/update";
+ }
+
+ @Override
+ public int needAudit() {
+ return 1;
+ }
+
+}