1
This commit is contained in:
@@ -1,39 +1,21 @@
|
||||
package com.tashow.erp.controller;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.InputStream;
|
||||
import java.net.URL;
|
||||
import java.net.URLConnection;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Web版本更新控制器
|
||||
* Web版本信息控制器
|
||||
*
|
||||
* @author Claude
|
||||
*/
|
||||
@RestController
|
||||
@RequestMapping("/api/update")
|
||||
public class UpdateController {
|
||||
@Value("${project.version:2.3.6}")
|
||||
@Value("${project.version:2.3.6}")
|
||||
private String currentVersion;
|
||||
@Value("${project.build.time:}")
|
||||
private String buildTime;
|
||||
// 简化:移除与鉴权/版本转发/SQLite 存储相关的依赖
|
||||
|
||||
// 下载进度跟踪
|
||||
private volatile int downloadProgress = 0;
|
||||
private volatile long downloadedBytes = 0;
|
||||
private volatile long totalBytes = 0;
|
||||
private volatile String downloadStatus = "ready"; // ready, downloading, completed, failed, cancelled
|
||||
private volatile String downloadSpeed = "0 KB/s";
|
||||
private volatile long downloadStartTime = 0;
|
||||
private volatile boolean downloadCancelled = false;
|
||||
|
||||
/**
|
||||
* 获取当前版本号
|
||||
@@ -48,415 +30,4 @@ public class UpdateController {
|
||||
result.put("buildTime", buildTime);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 获取下载进度
|
||||
*
|
||||
* @return 下载进度信息
|
||||
*/
|
||||
@GetMapping("/progress")
|
||||
public Map<String, Object> getDownloadProgress() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
result.put("success", true);
|
||||
result.put("progress", downloadProgress);
|
||||
result.put("status", downloadStatus);
|
||||
result.put("downloadedBytes", downloadedBytes);
|
||||
result.put("totalBytes", totalBytes);
|
||||
result.put("downloadSpeed", downloadSpeed);
|
||||
result.put("downloadedMB", String.format("%.1f", downloadedBytes / 1024.0 / 1024.0));
|
||||
result.put("totalMB", String.format("%.1f", totalBytes / 1024.0 / 1024.0));
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 重置下载状态
|
||||
*
|
||||
* @return 重置结果
|
||||
*/
|
||||
@PostMapping("/reset")
|
||||
public Map<String, Object> resetDownloadStatus() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
downloadProgress = 0;
|
||||
downloadedBytes = 0;
|
||||
totalBytes = 0;
|
||||
downloadStatus = "ready";
|
||||
downloadSpeed = "0 KB/s";
|
||||
downloadStartTime = 0;
|
||||
downloadCancelled = false;
|
||||
tempUpdateFilePath = null;
|
||||
|
||||
result.put("success", true);
|
||||
result.put("message", "下载状态已重置");
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 取消下载
|
||||
*
|
||||
* @return 取消结果
|
||||
*/
|
||||
@PostMapping("/cancel")
|
||||
public Map<String, Object> cancelDownload() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
if ("downloading".equals(downloadStatus)) {
|
||||
downloadCancelled = true;
|
||||
downloadStatus = "cancelled";
|
||||
downloadSpeed = "已取消";
|
||||
result.put("success", true);
|
||||
result.put("message", "下载已取消");
|
||||
} else if ("completed".equals(downloadStatus)) {
|
||||
// 下载完成后“稍后更新”:仅关闭弹窗,不触发安装,不改变文件
|
||||
result.put("success", true);
|
||||
result.put("message", "已设置为稍后更新");
|
||||
} else {
|
||||
result.put("success", false);
|
||||
result.put("message", "无效的操作状态");
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 完全清除更新文件和状态
|
||||
*
|
||||
* @return 清除结果
|
||||
*/
|
||||
@PostMapping("/clear")
|
||||
public Map<String, Object> clearUpdateFiles() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (tempUpdateFilePath != null) {
|
||||
try {
|
||||
java.io.File tempFile = new java.io.File(tempUpdateFilePath);
|
||||
if (tempFile.exists()) {
|
||||
tempFile.delete();
|
||||
System.out.println("已删除更新文件: " + tempUpdateFilePath);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("删除临时文件失败: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
// 重置状态
|
||||
downloadProgress = 0;
|
||||
downloadedBytes = 0;
|
||||
totalBytes = 0;
|
||||
downloadStatus = "ready";
|
||||
downloadSpeed = "0 KB/s";
|
||||
downloadCancelled = false;
|
||||
tempUpdateFilePath = null;
|
||||
result.put("success", true);
|
||||
result.put("message", "更新文件和状态已清除");
|
||||
|
||||
return result;
|
||||
}
|
||||
/**
|
||||
* 验证更新文件是否存在
|
||||
*
|
||||
* @return 验证结果
|
||||
*/
|
||||
@GetMapping("/verify-file")
|
||||
public Map<String, Object> verifyUpdateFile() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
boolean fileExists = false;
|
||||
String filePath = "";
|
||||
|
||||
if (tempUpdateFilePath != null) {
|
||||
java.io.File updateFile = new java.io.File(tempUpdateFilePath);
|
||||
fileExists = updateFile.exists();
|
||||
filePath = tempUpdateFilePath;
|
||||
|
||||
if (fileExists) {
|
||||
result.put("fileSize", updateFile.length());
|
||||
result.put("lastModified", new java.util.Date(updateFile.lastModified()));
|
||||
}
|
||||
}
|
||||
|
||||
result.put("success", true);
|
||||
result.put("fileExists", fileExists);
|
||||
result.put("filePath", filePath);
|
||||
result.put("downloadStatus", downloadStatus);
|
||||
|
||||
System.out.println("验证更新文件: " + filePath + ", 存在: " + fileExists);
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", "验证文件失败:" + e.getMessage());
|
||||
result.put("fileExists", false);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 用户确认后执行安装
|
||||
*
|
||||
* @return 安装结果
|
||||
*/
|
||||
@PostMapping("/install")
|
||||
public Map<String, Object> installUpdate() {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
if (tempUpdateFilePath == null || !new java.io.File(tempUpdateFilePath).exists()) {
|
||||
result.put("success", false);
|
||||
result.put("message", "更新文件不存在,请重新下载");
|
||||
return result;
|
||||
}
|
||||
|
||||
try {
|
||||
result.put("success", true);
|
||||
result.put("message", "开始安装更新...");
|
||||
|
||||
// 异步执行安装,避免阻塞响应
|
||||
new Thread(() -> {
|
||||
String updateScript = createUpdateScript(null, tempUpdateFilePath);
|
||||
if (updateScript != null) {
|
||||
executeUpdateAndExit(updateScript);
|
||||
}
|
||||
}).start();
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", "启动安装失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 自动更新:下载、替换、重启
|
||||
*
|
||||
* @return 更新结果
|
||||
*/
|
||||
@PostMapping("/auto-update")
|
||||
public Map<String, Object> autoUpdate(@RequestBody Map<String, String> request) {
|
||||
Map<String, Object> result = new HashMap<>();
|
||||
|
||||
try {
|
||||
String downloadUrl = request.get("downloadUrl");
|
||||
result.put("success", true);
|
||||
result.put("message", "开始自动更新...");
|
||||
result.put("downloadUrl", downloadUrl);
|
||||
String finalDownloadUrl = downloadUrl;
|
||||
new Thread(() -> {
|
||||
|
||||
performUpdate(finalDownloadUrl);
|
||||
}).start();
|
||||
|
||||
} catch (Exception e) {
|
||||
result.put("success", false);
|
||||
result.put("message", "启动更新失败:" + e.getMessage());
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行更新过程
|
||||
*/
|
||||
private void performUpdate(String downloadUrl) {
|
||||
String tempUpdateFile = downloadUpdate(downloadUrl);
|
||||
if (tempUpdateFile == null) {
|
||||
downloadStatus = "failed";
|
||||
return;
|
||||
}
|
||||
|
||||
// 下载完成后不自动重启,等待用户确认
|
||||
downloadStatus = "completed";
|
||||
System.out.println("下载完成,等待用户确认安装...");
|
||||
|
||||
// 将下载文件路径保存,供后续安装使用
|
||||
this.tempUpdateFilePath = tempUpdateFile;
|
||||
}
|
||||
|
||||
private String tempUpdateFilePath = null;
|
||||
|
||||
|
||||
/**
|
||||
* 下载更新文件
|
||||
*/
|
||||
private String downloadUpdate(String downloadUrl) {
|
||||
try {
|
||||
downloadStatus = "downloading";
|
||||
downloadProgress = 0;
|
||||
downloadedBytes = 0;
|
||||
downloadStartTime = System.currentTimeMillis();
|
||||
|
||||
URL url = new URL(downloadUrl);
|
||||
URLConnection connection = url.openConnection();
|
||||
connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36");
|
||||
connection.setConnectTimeout(10000);
|
||||
connection.setReadTimeout(30000);
|
||||
|
||||
// 获取文件大小
|
||||
totalBytes = connection.getContentLength();
|
||||
if (totalBytes <= 0) {
|
||||
totalBytes = 70 * 1024 * 1024; // 默认70MB
|
||||
}
|
||||
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String updateFileName = "erp_update_" + System.currentTimeMillis() + ".exe";
|
||||
String tempUpdatePath = Paths.get(tempDir, updateFileName).toString();
|
||||
|
||||
System.out.println("开始下载更新文件,大小: " + (totalBytes / 1024 / 1024) + "MB");
|
||||
|
||||
try (InputStream inputStream = connection.getInputStream();
|
||||
FileOutputStream outputStream = new FileOutputStream(tempUpdatePath)) {
|
||||
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
long lastSpeedUpdate = System.currentTimeMillis();
|
||||
long lastDownloadedBytes = 0;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
if (downloadCancelled) {
|
||||
System.out.println("下载已取消,停止下载进程");
|
||||
downloadStatus = "cancelled";
|
||||
downloadSpeed = "已取消";
|
||||
outputStream.close();
|
||||
try {
|
||||
java.io.File partialFile = new java.io.File(tempUpdatePath);
|
||||
if (partialFile.exists()) {
|
||||
partialFile.delete();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
System.err.println("删除部分下载文件失败: " + e.getMessage());
|
||||
}
|
||||
return null;
|
||||
}
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
downloadedBytes += bytesRead;
|
||||
|
||||
// 计算下载进度
|
||||
downloadProgress = (int) ((downloadedBytes * 100) / totalBytes);
|
||||
// 每秒计算一次下载速度
|
||||
long currentTime = System.currentTimeMillis();
|
||||
if (currentTime - lastSpeedUpdate >= 1000) {
|
||||
long speedBytes = downloadedBytes - lastDownloadedBytes;
|
||||
double speedKB = speedBytes / 1024.0;
|
||||
|
||||
if (speedKB >= 1024) {
|
||||
downloadSpeed = String.format("%.1f MB/s", speedKB / 1024.0);
|
||||
} else {
|
||||
downloadSpeed = String.format("%.1f KB/s", speedKB);
|
||||
}
|
||||
|
||||
lastSpeedUpdate = currentTime;
|
||||
lastDownloadedBytes = downloadedBytes;
|
||||
|
||||
System.out.println(String.format("下载进度: %d%% (%d/%d MB) 速度: %s",
|
||||
downloadProgress,
|
||||
downloadedBytes / 1024 / 1024,
|
||||
totalBytes / 1024 / 1024,
|
||||
downloadSpeed));
|
||||
}
|
||||
|
||||
// 防止阻塞UI线程
|
||||
if (downloadedBytes % (1024 * 1024) == 0) { // 每MB休息一下
|
||||
Thread.sleep(10);
|
||||
}
|
||||
}
|
||||
|
||||
downloadStatus = "completed";
|
||||
downloadProgress = 100;
|
||||
downloadSpeed = "完成";
|
||||
System.out.println("下载完成: " + (downloadedBytes / 1024 / 1024) + "MB");
|
||||
}
|
||||
|
||||
return tempUpdatePath;
|
||||
} catch (Exception e) {
|
||||
downloadStatus = "failed";
|
||||
downloadSpeed = "失败";
|
||||
System.err.println("下载失败: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建更新脚本
|
||||
*/
|
||||
private String createUpdateScript(String currentExePath, String tempUpdateFile) {
|
||||
try {
|
||||
String tempDir = System.getProperty("java.io.tmpdir");
|
||||
String scriptPath = Paths.get(tempDir, "update_erp.bat").toString();
|
||||
|
||||
File currentDir = new File(System.getProperty("user.dir"));
|
||||
File targetExe = new File(currentDir, "erpClient.exe");
|
||||
String targetPath = targetExe.getAbsolutePath();
|
||||
|
||||
StringBuilder script = new StringBuilder();
|
||||
script.append("@echo off\r\n");
|
||||
script.append("chcp 65001 > nul\r\n");
|
||||
script.append("echo 正在等待程序完全退出...\r\n");
|
||||
script.append("timeout /t 1 /nobreak > nul\r\n");
|
||||
script.append("echo 开始更新程序文件...\r\n");
|
||||
script.append("if exist \"").append(targetPath).append("\" (");
|
||||
script.append(" move \"").append(targetPath).append("\" \"").append(targetPath).append(".backup\"");
|
||||
script.append(" )\r\n");
|
||||
script.append("move \"").append(tempUpdateFile).append("\" \"").append(targetPath).append("\"\r\n");
|
||||
script.append("if exist \"").append(targetPath).append("\" (\r\n");
|
||||
script.append(" echo 更新成功!程序将在1秒后重新启动...\r\n");
|
||||
script.append(" timeout /t 1 /nobreak > nul\r\n");
|
||||
script.append(" start \"\" \"").append(targetPath).append("\"\r\n");
|
||||
script.append(" if exist \"").append(targetPath).append(".backup\" del \"").append(targetPath).append(".backup\"\r\n");
|
||||
script.append(") else (\r\n");
|
||||
script.append(" echo 更新失败!正在恢复原版本...\r\n");
|
||||
script.append(" if exist \"").append(targetPath).append(".backup\" (\r\n");
|
||||
script.append(" move \"").append(targetPath).append(".backup\" \"").append(targetPath).append("\"\r\n");
|
||||
script.append(" echo 已恢复原版本,程序将在1秒后重新启动...\r\n");
|
||||
script.append(" timeout /t 1 /nobreak > nul\r\n");
|
||||
script.append(" start \"\" \"").append(targetPath).append("\"\r\n");
|
||||
script.append(" )\r\n");
|
||||
script.append(")\r\n");
|
||||
script.append("echo 更新操作完成!\r\n");
|
||||
script.append("timeout /t 1 /nobreak > nul\r\n");
|
||||
script.append("(goto) 2>nul & del \"%~f0\" & exit\r\n");
|
||||
|
||||
Files.write(Paths.get(scriptPath), script.toString().getBytes("GBK"));
|
||||
return scriptPath;
|
||||
} catch (Exception e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 执行更新脚本并退出程序
|
||||
*/
|
||||
private void executeUpdateAndExit(String scriptPath) {
|
||||
try {
|
||||
System.out.println("下载完成!正在准备更新...");
|
||||
ProcessBuilder pb = new ProcessBuilder("cmd", "/c", scriptPath);
|
||||
pb.redirectOutput(ProcessBuilder.Redirect.DISCARD);
|
||||
pb.redirectError(ProcessBuilder.Redirect.DISCARD);
|
||||
pb.start();
|
||||
System.out.println("更新程序已启动,当前程序即将退出...");
|
||||
Thread.sleep(1000);
|
||||
Runtime.getRuntime().halt(0);
|
||||
} catch (Exception e) {
|
||||
Runtime.getRuntime().halt(1);
|
||||
}
|
||||
}
|
||||
|
||||
// /**
|
||||
// * 保存跳过的版本
|
||||
// */
|
||||
// @PostMapping("/skip-version")
|
||||
// public Map<String, Object> saveSkippedVersion(@RequestBody Map<String, String> request) {
|
||||
// Map<String, Object> result = new HashMap<>();
|
||||
// try {
|
||||
// saveUpdateInfo("skippedUpdateVersion", request.get("version"));
|
||||
// result.put("success", true);
|
||||
// } catch (Exception e) {
|
||||
// result.put("success", false);
|
||||
// }
|
||||
// return result;
|
||||
// }
|
||||
|
||||
}
|
||||
Reference in New Issue
Block a user