mirror of
https://gitee.com/dromara/Jpom.git
synced 2024-11-29 18:38:32 +08:00
🐞 fix(server): 分发文件使用文件中心或者静态文件上传至节点使用实际文件名
This commit is contained in:
parent
d7cc7d40ba
commit
6cbbe721e8
@ -9,6 +9,7 @@
|
||||
3. 【all】优化 解析 HTTP `Accept-Language` 请求头支持多语言最高优先级
|
||||
4. 【server】修复 页面未刷新情况下打开弹窗次数过多不能提示窗口层级太低(感谢[@lin_yeqi](https://gitee.com/lin_yeqi) [Gitee issues IAEBUZ](https://gitee.com/dromara/Jpom/issues/IAEBUZ) )
|
||||
5. 【server】优化 分发日志现在关联数据信息(感谢[@pumpkinor](https://gitee.com/pumpkinor) [Gitee issues IAF7IV](https://gitee.com/dromara/Jpom/issues/IAF7IV) )
|
||||
6. 【server】优化 分发文件使用文件中心或者静态文件上传至节点使用实际文件名(感谢[@pumpkinor](https://gitee.com/pumpkinor) [Gitee issues IAF7GD](https://gitee.com/dromara/Jpom/issues/IAF7GD) )
|
||||
|
||||
------
|
||||
|
||||
|
@ -17,6 +17,7 @@ import cn.hutool.core.io.NioUtil;
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.CharsetUtil;
|
||||
import cn.hutool.core.util.IdUtil;
|
||||
import cn.hutool.core.util.ReUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
import lombok.Lombok;
|
||||
@ -232,4 +233,15 @@ public class FileUtils {
|
||||
FileUtil.del(src);
|
||||
}
|
||||
}
|
||||
|
||||
public static String safeFileName(String name1, String extName, String defaultName){
|
||||
// 需要考虑文件名中存在非法字符 [\s\\/:\*\?\"<>\|]
|
||||
String name = ReUtil.replaceAll(name1, "[\\s\\\\/:\\*\\?\\\"<>\\|]", "");
|
||||
if (StrUtil.isEmpty(name)) {
|
||||
name = defaultName;
|
||||
} else if (!StrUtil.endWith(name, StrUtil.DOT + extName)) {
|
||||
name += StrUtil.DOT + extName;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
@ -556,7 +556,7 @@ public class ReleaseManage {
|
||||
//
|
||||
Set<Integer> progressRangeList = ConcurrentHashMap.newKeySet((int) Math.floor((float) 100 / buildExtConfig.getLogReduceProgressRatio()));
|
||||
int finalI = i;
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, startPath,
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, file.getName(), startPath,
|
||||
projectId, false, last ? afterOpt : AfterOpt.No, nodeModel, false,
|
||||
this.buildExtraModule.getProjectUploadCloseFirst(), (total, progressSize) -> {
|
||||
double progressPercentage = Math.floor(((float) progressSize / total) * 100);
|
||||
@ -604,7 +604,7 @@ public class ReleaseManage {
|
||||
JsonMessage<String> jsonMessage = BuildUtil.loadDirPackage(this.buildExtraModule.getId(), this.getRealBuildNumberId(), this.resultFile, tarGz, (unZip, zipFile) -> {
|
||||
String name = zipFile.getName();
|
||||
Set<Integer> progressRangeList = ConcurrentHashMap.newKeySet((int) Math.floor((float) 100 / buildExtConfig.getLogReduceProgressRatio()));
|
||||
return OutGivingRun.fileUpload(zipFile,
|
||||
return OutGivingRun.fileUpload(zipFile, zipFile.getName(),
|
||||
this.buildExtraModule.getProjectSecondaryDirectory(),
|
||||
projectId,
|
||||
unZip,
|
||||
|
@ -55,6 +55,7 @@ import org.dromara.jpom.service.node.ProjectInfoCacheService;
|
||||
import org.dromara.jpom.service.outgiving.DbOutGivingLogService;
|
||||
import org.dromara.jpom.service.outgiving.OutGivingServer;
|
||||
import org.dromara.jpom.system.ServerConfig;
|
||||
import org.dromara.jpom.util.FileUtils;
|
||||
import org.dromara.jpom.util.StringUtil;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
@ -302,7 +303,7 @@ public class OutGivingProjectController extends BaseServerController {
|
||||
File file = FileUtil.file(serverConfig.getUserTempPath(), ServerConst.OUTGIVING_FILE, id);
|
||||
FileUtil.mkdir(file);
|
||||
File downloadFile = HttpUtil.downloadFileFromUrl(url, file);
|
||||
this.startTask(outGivingModel, downloadFile, autoUnzip, stripComponents, selectProject, true);
|
||||
this.startTask(outGivingModel, downloadFile, null, autoUnzip, stripComponents, selectProject, true);
|
||||
return JsonMessage.success(I18nMessageUtil.get("i18n.download_success_and_distribute.ae94"));
|
||||
}
|
||||
|
||||
@ -392,7 +393,8 @@ public class OutGivingProjectController extends BaseServerController {
|
||||
outGivingServer.updateById(outGivingModel);
|
||||
File storageSavePath = serverConfig.fileStorageSavePath();
|
||||
File file = FileUtil.file(storageSavePath, storageModel.getPath());
|
||||
this.startTask(outGivingModel, file, autoUnzip, stripComponents, selectProject, false);
|
||||
String fileName = FileUtils.safeFileName(storageModel.getName(), storageModel.getExtName(), "file-storage." + storageModel.getExtName());
|
||||
this.startTask(outGivingModel, file, fileName, autoUnzip, stripComponents, selectProject, false);
|
||||
return JsonMessage.success(I18nMessageUtil.get("i18n.start_distribution_exclamation.9fc2"));
|
||||
}
|
||||
|
||||
@ -426,7 +428,8 @@ public class OutGivingProjectController extends BaseServerController {
|
||||
outGivingServer.updateById(outGivingModel);
|
||||
|
||||
File file = FileUtil.file(storageModel.getAbsolutePath());
|
||||
this.startTask(outGivingModel, file, autoUnzip, stripComponents, selectProject, false);
|
||||
String fileName = FileUtils.safeFileName(storageModel.getName(), storageModel.getExtName(), "file-storage." + storageModel.getExtName());
|
||||
this.startTask(outGivingModel, file, fileName, autoUnzip, stripComponents, selectProject, false);
|
||||
return JsonMessage.success(I18nMessageUtil.get("i18n.start_distribution_exclamation.9fc2"));
|
||||
}
|
||||
|
||||
@ -439,7 +442,7 @@ public class OutGivingProjectController extends BaseServerController {
|
||||
* @param stripComponents 剔除目录
|
||||
* @param selectProject 选择指定项目
|
||||
*/
|
||||
private void startTask(OutGivingModel outGivingModel, File file, String autoUnzip,
|
||||
private void startTask(OutGivingModel outGivingModel, File file, String fileName, String autoUnzip,
|
||||
String stripComponents,
|
||||
String selectProject,
|
||||
boolean deleteFile) {
|
||||
@ -454,6 +457,7 @@ public class OutGivingProjectController extends BaseServerController {
|
||||
.id(outGivingModel.getId())
|
||||
.file(file)
|
||||
.userModel(getUser())
|
||||
.fileName(fileName)
|
||||
.unzip(unzip)
|
||||
.mode(outGivingModel.getMode())
|
||||
.modeData(outGivingModel.getModeData())
|
||||
|
@ -86,17 +86,6 @@ public abstract class BaseDownloadApiController extends BaseJpomController {
|
||||
return new long[]{fromPos, downloadSize};
|
||||
}
|
||||
|
||||
protected String convertName(String name1, String extName, String defaultName) {
|
||||
// 需要考虑文件名中存在非法字符
|
||||
String name = ReUtil.replaceAll(name1, "[\\s\\\\/:\\*\\?\\\"<>\\|]", "");
|
||||
if (StrUtil.isEmpty(name)) {
|
||||
name = defaultName;
|
||||
} else if (!StrUtil.endWith(name, StrUtil.DOT + extName)) {
|
||||
name += StrUtil.DOT + extName;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
public void download(File file, long fileSize, String name, long[] resolveRange, HttpServletResponse response) throws IOException {
|
||||
Assert.state(FileUtil.isFile(file), I18nMessageUtil.get("i18n.file_does_not_exist_anymore.2fab"));
|
||||
String contentType = ObjectUtil.defaultIfNull(FileUtil.getMimeType(name), "application/octet-stream");
|
||||
|
@ -27,6 +27,7 @@ import org.dromara.jpom.func.files.service.FileStorageService;
|
||||
import org.dromara.jpom.model.user.UserModel;
|
||||
import org.dromara.jpom.service.user.TriggerTokenLogServer;
|
||||
import org.dromara.jpom.system.ServerConfig;
|
||||
import org.dromara.jpom.util.FileUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -131,7 +132,7 @@ public class FileStorageApiController extends BaseDownloadApiController {
|
||||
File storageSavePath = serverConfig.fileStorageSavePath();
|
||||
File fileStorageFile = FileUtil.file(storageSavePath, storageModel.getPath());
|
||||
// 需要考虑文件名中存在非法字符
|
||||
String name = this.convertName(storageModel.getName(), storageModel.getExtName(), fileStorageFile.getName());
|
||||
String name = FileUtils.safeFileName(storageModel.getName(), storageModel.getExtName(), fileStorageFile.getName());
|
||||
// 解析断点续传相关信息
|
||||
long fileSize = FileUtil.size(fileStorageFile);
|
||||
long[] resolveRange = this.resolveRange(request, fileSize, storageModel.getId(), storageModel.getName(), response);
|
||||
|
@ -19,6 +19,7 @@ import org.dromara.jpom.func.files.model.StaticFileStorageModel;
|
||||
import org.dromara.jpom.func.files.service.StaticFileStorageService;
|
||||
import org.dromara.jpom.model.user.UserModel;
|
||||
import org.dromara.jpom.service.user.TriggerTokenLogServer;
|
||||
import org.dromara.jpom.util.FileUtils;
|
||||
import org.springframework.http.MediaType;
|
||||
import org.springframework.util.Assert;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
@ -64,7 +65,7 @@ public class StaticFileStorageApiController extends BaseDownloadApiController {
|
||||
Assert.notNull(userModel, I18nMessageUtil.get("i18n.token_invalid_or_expired.cb96"));
|
||||
File file = FileUtil.file(storageModel.getAbsolutePath());
|
||||
// 需要考虑文件名中存在非法字符
|
||||
String name = this.convertName(storageModel.getName(), storageModel.getExtName(), file.getName());
|
||||
String name = FileUtils.safeFileName(storageModel.getName(), storageModel.getExtName(), file.getName());
|
||||
// 解析断点续传相关信息
|
||||
long fileSize = FileUtil.size(file);
|
||||
long[] resolveRange = this.resolveRange(request, fileSize, storageModel.getId(), storageModel.getName(), response);
|
||||
|
@ -14,6 +14,7 @@ import cn.hutool.core.date.SystemClock;
|
||||
import cn.hutool.core.io.FileUtil;
|
||||
import cn.hutool.core.util.EnumUtil;
|
||||
import cn.hutool.core.util.ObjectUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.extra.spring.SpringUtil;
|
||||
import cn.keepbx.jpom.model.JsonMessage;
|
||||
import com.alibaba.fastjson2.JSONObject;
|
||||
@ -50,6 +51,7 @@ public class OutGivingItemRun implements Callable<OutGivingNodeProject.Status> {
|
||||
private final String secondaryDirectory;
|
||||
private final Boolean closeFirst;
|
||||
private int stripComponents;
|
||||
private String fileName;
|
||||
|
||||
public OutGivingItemRun(OutGivingModel item,
|
||||
OutGivingNodeProject outGivingNodeProject,
|
||||
@ -76,6 +78,7 @@ public class OutGivingItemRun implements Callable<OutGivingNodeProject.Status> {
|
||||
OutGivingNodeProject.Status result;
|
||||
long time = SystemClock.now();
|
||||
String fileSize = FileUtil.readableFileSize(file);
|
||||
this.fileName = StrUtil.emptyToDefault(this.fileName, this.file.getName());
|
||||
try {
|
||||
if (this.outGivingNodeProject.getDisabled() != null && this.outGivingNodeProject.getDisabled()) {
|
||||
// 禁用
|
||||
@ -84,7 +87,7 @@ public class OutGivingItemRun implements Callable<OutGivingNodeProject.Status> {
|
||||
}
|
||||
this.updateStatus(this.outGivingId, OutGivingNodeProject.Status.Ing, I18nMessageUtil.get("i18n.start_distribution.bce5"));
|
||||
//
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, this.secondaryDirectory,
|
||||
JsonMessage<String> jsonMessage = OutGivingRun.fileUpload(file, this.fileName, this.secondaryDirectory,
|
||||
this.outGivingNodeProject.getProjectId(),
|
||||
unzip,
|
||||
afterOpt,
|
||||
|
@ -80,6 +80,7 @@ public class OutGivingRun {
|
||||
private UserModel userModel;
|
||||
private boolean unzip;
|
||||
private int stripComponents;
|
||||
private String fileName;
|
||||
/**
|
||||
* 分发方式
|
||||
* upload: "手动上传",
|
||||
@ -195,6 +196,7 @@ public class OutGivingRun {
|
||||
final OutGivingNodeProject outGivingNodeProject = outGivingNodeProjects.get(nowIndex);
|
||||
final OutGivingItemRun outGivingRun = new OutGivingItemRun(item, outGivingNodeProject, file, unzip, sleepTime);
|
||||
outGivingRun.setStripComponents(stripComponents);
|
||||
outGivingRun.setFileName(fileName);
|
||||
OutGivingNodeProject.Status status = outGivingRun.call();
|
||||
if (status != OutGivingNodeProject.Status.Ok) {
|
||||
if (afterOpt == AfterOpt.Order_Must_Restart) {
|
||||
@ -221,6 +223,7 @@ public class OutGivingRun {
|
||||
for (final OutGivingNodeProject outGivingNodeProject : outGivingNodeProjects) {
|
||||
final OutGivingItemRun outGivingItemRun = new OutGivingItemRun(item, outGivingNodeProject, file, unzip, null);
|
||||
outGivingItemRun.setStripComponents(stripComponents);
|
||||
outGivingItemRun.setFileName(fileName);
|
||||
syncFinisher.addWorker(() -> {
|
||||
try {
|
||||
statusList.add(outGivingItemRun.call());
|
||||
@ -378,14 +381,14 @@ public class OutGivingRun {
|
||||
* @param closeFirst 保存项目文件前先关闭项目
|
||||
* @return json
|
||||
*/
|
||||
public static JsonMessage<String> fileUpload(File file, String levelName, String projectId,
|
||||
public static JsonMessage<String> fileUpload(File file, String fileName, String levelName, String projectId,
|
||||
boolean unzip,
|
||||
AfterOpt afterOpt,
|
||||
NodeModel nodeModel,
|
||||
boolean clearOld,
|
||||
Boolean closeFirst,
|
||||
BiConsumer<Long, Long> streamProgress) {
|
||||
return fileUpload(file, levelName, projectId, unzip, afterOpt, nodeModel, clearOld, null, closeFirst, streamProgress);
|
||||
return fileUpload(file, fileName, levelName, projectId, unzip, afterOpt, nodeModel, clearOld, null, closeFirst, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -402,7 +405,7 @@ public class OutGivingRun {
|
||||
* @param closeFirst 保存项目文件前先关闭项目
|
||||
* @return json
|
||||
*/
|
||||
public static JsonMessage<String> fileUpload(File file, String levelName, String projectId,
|
||||
public static JsonMessage<String> fileUpload(File file, String fileName, String levelName, String projectId,
|
||||
boolean unzip,
|
||||
AfterOpt afterOpt,
|
||||
NodeModel nodeModel,
|
||||
@ -410,7 +413,7 @@ public class OutGivingRun {
|
||||
Integer sleepTime,
|
||||
Boolean closeFirst,
|
||||
BiConsumer<Long, Long> streamProgress) {
|
||||
return fileUpload(file, levelName, projectId, unzip, afterOpt, nodeModel, clearOld, sleepTime, closeFirst, 0, streamProgress);
|
||||
return fileUpload(file, fileName, levelName, projectId, unzip, afterOpt, nodeModel, clearOld, sleepTime, closeFirst, 0, streamProgress);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -427,7 +430,10 @@ public class OutGivingRun {
|
||||
* @param closeFirst 保存项目文件前先关闭项目
|
||||
* @return json
|
||||
*/
|
||||
public static JsonMessage<String> fileUpload(File file, String levelName, String projectId,
|
||||
public static JsonMessage<String> fileUpload(File file,
|
||||
String fileName,
|
||||
String levelName,
|
||||
String projectId,
|
||||
boolean unzip,
|
||||
AfterOpt afterOpt,
|
||||
NodeModel nodeModel,
|
||||
@ -457,6 +463,7 @@ public class OutGivingRun {
|
||||
data.put("closeFirst", closeFirst);
|
||||
try {
|
||||
return NodeForward.requestSharding(nodeModel, NodeUrl.Manage_File_Upload_Sharding, data, file,
|
||||
fileName,
|
||||
sliceData -> {
|
||||
sliceData.putAll(data);
|
||||
return NodeForward.request(nodeModel, NodeUrl.Manage_File_Sharding_Merge, sliceData);
|
||||
|
@ -1768,6 +1768,7 @@
|
||||
"i18n_9ee9d48699": "Modification is not supported after creation",
|
||||
"i18n_9f01272a10": " legal risk",
|
||||
"i18n_9f0de3800b": "Please fill in the warehouse name.",
|
||||
"i18n_9f4a0d67c6": "It is recommended not to have blank spaces, tables, other blanks, \\,/,:, *,?, _ # # _,<,>, \\, in the file name| Waiting for special characters",
|
||||
"i18n_9f52492fbc": "For configuration details, please refer to the configuration example.",
|
||||
"i18n_9f6090c819": "The incoming parameters are: buildId, buildName, type, statusMsg, triggerTime",
|
||||
"i18n_9f6fa346d8": "Please enter an SSH name",
|
||||
|
@ -1768,6 +1768,7 @@
|
||||
"i18n_9ee9d48699": "创建后不支持修改",
|
||||
"i18n_9f01272a10": " 法律风险",
|
||||
"i18n_9f0de3800b": "请填写仓库名称",
|
||||
"i18n_9f4a0d67c6": "文件名建议不要出现空白、制表、其他空白、\\、/、:、*、?、_##_、<、>、\\、| 等特殊字符",
|
||||
"i18n_9f52492fbc": "配置详情请参考配置示例",
|
||||
"i18n_9f6090c819": "传入参数有:buildId、buildName、type、statusMsg、triggerTime",
|
||||
"i18n_9f6fa346d8": "请输入 SSH 名称",
|
||||
|
@ -1768,6 +1768,7 @@
|
||||
"i18n_9ee9d48699":"創建後不支持修改",
|
||||
"i18n_9f01272a10":" 法律風險",
|
||||
"i18n_9f0de3800b":"請填寫倉庫名稱",
|
||||
"i18n_9f4a0d67c6":"文件名建議不要出現空白、製表、其他空白、\\、/、:、*、?、_##_、<、>、\\、| 等特殊字符",
|
||||
"i18n_9f52492fbc":"配置詳情請參考配置示例",
|
||||
"i18n_9f6090c819":"傳入參數有:buildId、buildName、type、statusMsg、triggerTime",
|
||||
"i18n_9f6fa346d8":"請輸入 SSH 名稱",
|
||||
|
@ -1768,6 +1768,7 @@
|
||||
"i18n_9ee9d48699":"建立後不支援修改",
|
||||
"i18n_9f01272a10":" 法律風險",
|
||||
"i18n_9f0de3800b":"請填寫倉庫名稱",
|
||||
"i18n_9f4a0d67c6":"檔名建議不要出現空白、製表、其他空白、\\、/、:、*、?、_##_、<、>、\\、| 等特殊字元",
|
||||
"i18n_9f52492fbc":"配置詳情請參考配置示例",
|
||||
"i18n_9f6090c819":"傳入引數有:buildId、buildName、type、statusMsg、triggerTime",
|
||||
"i18n_9f6fa346d8":"請輸入 SSH 名稱",
|
||||
|
@ -217,6 +217,8 @@
|
||||
<a-form ref="editForm" :rules="rules" :model="temp" :label-col="{ span: 4 }" :wrapper-col="{ span: 20 }">
|
||||
<a-form-item :label="$t('i18n_29139c2a1a')" name="name">
|
||||
<a-input v-model:value="temp.name" :placeholder="$t('i18n_29139c2a1a')" />
|
||||
<!-- [\s\\/:\*\?\"<>\|] -->
|
||||
<template #help>{{ $t('i18n_9f4a0d67c6') }}</template>
|
||||
</a-form-item>
|
||||
<a-form-item :label="$t('i18n_824607be6b')" name="keepDay">
|
||||
<a-input-number
|
||||
|
Loading…
Reference in New Issue
Block a user