JavaM002——System.getProperty("user.dir")获得程序当前路径

本文详细介绍了如何在Java中使用System.getProperty方法获取各种系统属性,包括Java运行环境、操作系统、文件路径等信息,并展示了如何获取当前类的完整路径。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

因为所有在java.io中的类都是将相对路径名解释为起始于用户的当前工作目录,所以应该清楚当前的目录。

可以通过调用System.getProperty("user.dir") 来获得。

/**
获得当前类的完整路径。最后一句
*/
 
package org.outman.dms.server;
 
 
 
import java.net.MalformedURLException;
 
import java.net.URI;
 
import java.net.URISyntaxException;
 
import java.net.URL;
 
 
 
/**
*
java.version          Java 运行时环境版本
java.vendor         Java 运行时环境供应商
java.vendor.url         Java 供应商的 URL
java.vm.specification.version         Java 虚拟机规范版本
java.vm.specification.vendor         Java 虚拟机规范供应商
java.vm.specification.name         Java 虚拟机规范名称
java.vm.version         Java 虚拟机实现版本
java.vm.vendor         Java 虚拟机实现供应商
java.vm.name         Java 虚拟机实现名称
java.specification.version         Java 运行时环境规范版本
java.specification.vendor         Java 运行时环境规范供应商
java.specification.name         Java 运行时环境规范名称
os.name         操作系统的名称
os.arch         操作系统的架构
os.version         操作系统的版本
file.separator         文件分隔符(在 UNIX 系统中是“ / ”)
path.separator         路径分隔符(在 UNIX 系统中是“ : ”)
line.separator         行分隔符(在 UNIX 系统中是“ /n ”)
 
java.home         Java 安装目录
java.class.version         Java 类格式版本号
java.class.path         Java 类路径
java.library.path          加载库时搜索的路径列表
java.io.tmpdir         默认的临时文件路径
java.compiler         要使用的 JIT 编译器的名称
java.ext.dirs         一个或多个扩展目录的路径
user.name         用户的账户名称
user.home         用户的主目录
user.dir
*/
 
public class Test {
 
        public static void main(String[] args) throws MalformedURLException, URISyntaxException {
 
                System.out.println("java.home : "+System.getProperty("java.home"));
 
                System.out.println("java.class.version : "+System.getProperty("java.class.version"));
 
                System.out.println("java.class.path : "+System.getProperty("java.class.path"));
 
                System.out.println("java.library.path : "+System.getProperty("java.library.path"));
 
                System.out.println("java.io.tmpdir : "+System.getProperty("java.io.tmpdir"));
 
                System.out.println("java.compiler : "+System.getProperty("java.compiler"));
 
                System.out.println("java.ext.dirs : "+System.getProperty("java.ext.dirs"));
 
                System.out.println("user.name : "+System.getProperty("user.name"));
 
                System.out.println("user.home : "+System.getProperty("user.home"));
 
                System.out.println("user.dir : "+System.getProperty("user.dir"));
 
                System.out.println("===================");
 
                System.out.println("package: "+Test.class.getPackage().getName());
 
                System.out.println("package: "+Test.class.getPackage().toString());
 
                System.out.println("=========================");
 
                String packName = Test.class.getPackage().getName();
 
                /*URL packurl = new URL(packName);
                System.out.println(packurl.getPath());*/
 
                URI packuri = new URI(packName);
 
                System.out.println(packuri.getPath());
 
                //System.out.println(packuri.toURL().getPath());
 
                System.out.println(packName.replaceAll("//.", "/"));
 
                System.out.println(System.getProperty("user.dir")+"/"+(Test.class.getPackage().getName()).replaceAll("//.", "/")+"/");
 
        }
 
} 

System.getProperty("user.dir")  当前工程路径

(Test.class.getPackage().getName()).replaceAll("//.","/")   当前包路径。

转自https://blog.youkuaiyun.com/zhuhuiby/article/details/8569516

package com.example.demo.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.thread.ThreadFactoryBuilder; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.dao.entity.WExecuteHost; import com.example.demo.dao.entity.WHostProcess; import com.example.demo.dao.entity.WPersonalHost; import com.example.demo.dao.mapper.WExecuteHostMapper; import com.example.demo.request.ProcessRequest; import com.example.demo.service.WExecuteHostService; import com.example.demo.service.WHostProcessService; import com.example.demo.service.WPersonalHostService; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.PreDestroy; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @Service public class WExecuteHostServiceImpl extends ServiceImpl<WExecuteHostMapper, WExecuteHost> implements WExecuteHostService { @Autowired private WPersonalHostService wPersonalHostService; @Autowired private WHostProcessService wHostProcessService; @Data private static class UserSession { private Process cmdProcess; private volatile boolean isProcessRunning; private String sessionId; private String logFilePath; private final Queue<String> logBuffer = new ConcurrentLinkedQueue<>(); private static final int BATCH_SIZE = 50; // 批量写入阈值 // 命令执行状态锁 private final AtomicBoolean isExecuting = new AtomicBoolean(false); } private final Map<String, UserSession> userSessions = new ConcurrentHashMap<>(); private final SimpMessagingTemplate messagingTemplate; // 异步日志写入线程池 private static final ExecutorService LOG_WRITER_POOL = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNamePrefix("log-writer-").build()); // 日志刷新调度器 private static final ScheduledExecutorService LOG_FLUSH_SCHEDULER = Executors.newSingleThreadScheduledExecutor(); public WExecuteHostServiceImpl(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; startLogFlushService(); } // 初始化日志刷新服务 private void startLogFlushService() { LOG_FLUSH_SCHEDULER.scheduleAtFixedRate(() -> { userSessions.values().forEach(session -> { if (!session.getLogBuffer().isEmpty()) { List<String> batch = CollUtil.newArrayList(session.getLogBuffer()); session.getLogBuffer().clear(); asyncWriteLog(session.getLogFilePath(), String.join("\n", batch)); } }); }, 0, 1, TimeUnit.SECONDS); } @Override public void executeCommand(String command, String host, String userId) { // 0. ABORT命令特殊处理(优先处理终止请求) if ("ABORT".equalsIgnoreCase(command)) { handleAbort(userId); return; } // 1. 权限校验 if (!validateUserHost(userId, host)) { sendError("无权访问该主机", userId); return; } // 2. 检查用户当前会话状态 UserSession session = userSessions.get(userId); if (session != null && session.isExecuting.get()) { sendError("已有命令执行中,请等待完成或使用ABORT终止", userId); return; } // 3. 创建新会话(带原子状态检查) session = userSessions.computeIfAbsent(userId, key -> { UserSession newSession = createNewSession(userId, host); if (newSession != null) { newSession.isExecuting.set(true); // 标记为执行中 } return newSession; }); if (session == null) return; // 4. 写入日志并执行命令 try { // 确保获得执行锁 if (!session.isExecuting.compareAndSet(true, true)) { sendError("命令执行冲突,请重试", userId); return; } session.getLogBuffer().offer("——————————————— " + DateUtil.now() + " ———————————————"); // 发送命令到进程 IoUtil.write(session.getCmdProcess().getOutputStream(), Charset.forName("gbk"), true, command + "\n"); } catch (Exception e) { session.isExecuting.set(false); // 发生异常时释放锁 sendError("命令发送失败: " + e.getMessage(), userId); } } @Override public Boolean isCommandExecuting(String userId) { UserSession session = userSessions.get(userId); return session != null && session.isExecuting.get(); } @Override public void handleAbort(String userId) { UserSession session = userSessions.get(userId); if (session == null || session.getCmdProcess() == null) { sendError("没有活动的命令进程", userId); return; } try { long pid = session.getCmdProcess().pid(); System.out.println("Attempting to kill process with PID: " + pid); // 使用 taskkill 命令终止进程 ProcessBuilder taskKill = new ProcessBuilder("taskkill", "/F", "/T", "/PID", String.valueOf(pid)); Process killProcess = taskKill.start(); // 等待命令执行完成 int exitCode = killProcess.waitFor(); System.out.println("taskkill exit code: " + exitCode); if (exitCode == 0) { // 进程终止成功 session.isExecuting.set(false); cleanupSession(userId); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "✔️" + "进程已通过 taskkill 终止 (PID: " + pid + ")"); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, ""); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, System.getProperty("user.dir") + ">"); } else { // 进程终止失败 sendError("终止进程失败,错误码: " + exitCode, userId); } } catch (IOException | InterruptedException e) { System.err.println("Error killing process: " + e.getMessage()); sendError("终止进程失败: " + e.getMessage(), userId); } } @Override public String startProcess(ProcessRequest processRequest) { try { // 数据库表新增数据 String p13 = processRequest.getP13().trim(); String processName = processRequest.getProcessName().trim(); String productNumber = processRequest.getProductNumber().trim(); String executeHost = processRequest.getExecuteHost().trim(); String department = processRequest.getDepartment().trim(); String version = processRequest.getVersion().trim(); if (StrUtil.isEmpty(p13) || StrUtil.isEmpty(processName) || StrUtil.isEmpty(productNumber) || StrUtil.isEmpty(executeHost) || StrUtil.isEmpty(department) || StrUtil.isEmpty(version)) { return "新增进程失败。"; } WHostProcess wHostProcess = new WHostProcess(); wHostProcess.setP13(p13); wHostProcess.setProcessName(processName); wHostProcess.setProductNumber(productNumber); wHostProcess.setHost(executeHost); wHostProcess.setPid(null); wHostProcess.setDepartment(department); wHostProcess.setState("离线"); wHostProcess.setVersion(version); wHostProcess.setBeginTime(new Date()); boolean saveResult = wHostProcessService.save(wHostProcess); if (saveResult) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper .eq(WPersonalHost::getExecuteHost, processRequest.getExecuteHost()) .eq(WPersonalHost::getSharedHost, processRequest.getSharedHost()); WPersonalHost wPersonalHost = wPersonalHostService.getOne(queryWrapper); // 执行py启动命令 //todo 后续动态 String pythonEXEPath = "D:\\miniforge\\envs" + File.separator + p13 + File.separator + "python" + wPersonalHost.getPythonEnv() + File.separator + "python.exe"; String mainPyPath = System.getProperty("user.dir") + File.separator + "python-package" + File.separator + executeHost + File.separator + p13 + File.separator + "test" + File.separator + "main.py"; executeCommand(pythonEXEPath + " " + mainPyPath, processRequest.getExecuteHost(), processRequest.getP13()); return "正在启动项目..."; } } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return "新增进程失败。"; } private boolean validateUserHost(String userId, String executeHost) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(WPersonalHost::getP13, userId) .eq(WPersonalHost::getExecuteHost, executeHost) .eq(WPersonalHost::getState, "在线"); return wPersonalHostService.getOne(queryWrapper) != null; } private UserSession createNewSession(String userId, String executeHost) { try { UserSession session = new UserSession(); session.setSessionId(UUID.randomUUID().toString()); session.setLogFilePath(initLogFile(userId, executeHost)); // 启动CMD进程(带唯一标题) ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/k", "title " + generateUniqueTitle(userId)); session.setCmdProcess(pb.redirectErrorStream(true).start()); // 启动输出监听线程 startOutputThread(session, userId); return session; } catch (IOException e) { sendError("进程启动失败: " + e.getMessage(), userId); return null; } } private String initLogFile(String userId, String executeHost) { // 1. 构建基础路径(使用File.separator) String baseDir = FileUtil.normalize( System.getProperty("user.dir") + File.separator + "command-log"); // 2. 构建安全路径(统一使用File.separator) String safePath = FileUtil.normalize( baseDir + File.separator + userId + File.separator + executeHost + File.separator + "项目名称"); // 3. 安全校验(现在路径分隔符一致) if (!safePath.startsWith(baseDir)) { throw new SecurityException("非法日志路径: " + safePath); } // 4. 创建目录(自动处理路径分隔符) FileUtil.mkdir(safePath); // 5. 生成日志文件 String logFileName = DateUtil.today() + ".log"; return FileUtil.touch(safePath + File.separator + logFileName).getAbsolutePath(); } private void startOutputThread(UserSession session, String userId) { new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(session.getCmdProcess().getInputStream(), "GBK"))) { String line; while ((line = reader.readLine()) != null) { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, line); session.getLogBuffer().offer(line); } } catch (Exception e) { sendError("输出流异常: " + e.getMessage(), userId); } finally { session.isExecuting.set(false); // 命令结束释放锁 cleanupSession(userId); // 通知前端命令执行结束 messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "⏹ 该命令执行已结束"); } }).start(); } private void asyncWriteLog(String logFilePath, String content) { CompletableFuture.runAsync(() -> { try { // 替换掉日志文件中没用的信息,如多余的路径信息 String currentDir = System.getProperty("user.dir"); String escapedDir = currentDir.replace("\\", "\\\\"); String regex = "(?m)^\\s*" + escapedDir + ">(?!\\S)\\s*"; // 创建 Pattern 和 Matcher 对象 Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); // 检查是否存在匹配的模式 if (matcher.find()) { // 如果存在匹配,则进行替换 String cleaned = content.replaceAll(regex, ""); FileUtil.appendString(cleaned + System.lineSeparator(), logFilePath, "GBK"); } else { FileUtil.appendString(content + System.lineSeparator(), logFilePath, "GBK"); } } catch (Exception e) { System.err.println("日志写入失败: " + e.getMessage()); } }, LOG_WRITER_POOL); } private void cleanupSession(String userId) { UserSession session = userSessions.remove(userId); if (session != null) { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } // 强制将剩余日志写入文件(新增代码) if (!session.getLogBuffer().isEmpty()) { asyncWriteLog(session.getLogFilePath(), String.join("\n", session.getLogBuffer())); session.getLogBuffer().clear(); } } catch (Exception ignored) { } } } @PreDestroy public void cleanup() { LOG_FLUSH_SCHEDULER.shutdown(); LOG_WRITER_POOL.shutdown(); userSessions.forEach((userId, session) -> { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } } catch (Exception ignored) { } }); userSessions.clear(); } /** * 发送错误日志 */ private void sendError(String message, String userId) { try { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "❌" + message); } catch (Exception ignored) { } } /** * 生成cmd窗口唯一id */ private String generateUniqueTitle(String userId) { return "CMD_SESSION_" + userId + "_" + System.currentTimeMillis(); } } 仔细阅读我的代码,现在有个bug,我执行下面的main.py文件,会报错请输入你的名字: 发生未知错误: EOF when reading a line import random import sys from datetime import datetime def generate_random_number(min_val=1, max_val=100): """ 生成一个指定范围内的随机整数 参数: min_val (int): 最小值,默认为1 max_val (int): 最大值,默认为100 返回: int: 随机生成的整数 """ return random.randint(min_val, max_val) def check_even_odd(number): """ 检查一个数字是奇数还是偶数 参数: number (int): 要检查的数字 返回: str: "偶数" 或 "奇数" """ return "偶数" if number % 2 == 0 else "奇数" def greet_user(name): """ 向用户问好 参数: name (str): 用户名 """ print(f"你好, {name}! 当前时间是: {datetime.now().strftime('%Y-%m-%d %H:%M:%S')}") def main(): """ 主函数 """ print("欢迎使用随机数生成器!") try: user_name = input("请输入你的名字: ") greet_user(user_name) count = int(input("你想生成多少个随机数? (1-10): ")) if count < 1 or count > 10: print("请输入1到10之间的数字!") return for i in range(count): num = generate_random_number() print(f"随机数 #{i+1}: {num} ({check_even_odd(num)})") print("感谢使用!") except ValueError: print("错误: 请输入有效的数字!") except KeyboardInterrupt: print("\n程序被用户中断") except Exception as e: print(f"发生未知错误: {e}") if __name__ == "__main__": main()
06-18
我现在有多个服务,a是前端,b是java后端,还有很多个小java客户端。我的小客户端是部署在多台电脑上的,使用websocket执行代码,我现在想要的是过去小客户端的所有websocket要用b进行一个中转,即a<=>b<=>小客户端。 这是我的a的代码: import { Client } from '@stomp/stompjs'; import SockJS from 'sockjs-client'; // npm remove stompjs // npm install @stomp/stompjs sockjs-client --save export default { connect() { return new Promise((resolve, reject) => { const socket = new SockJS('http://10.228.73.15:31001/websocket'); const stompClient = new Client({ webSocketFactory: () => socket, debug: () => { // 禁用调试输出,或根据需要处理 }, reconnectDelay: 5000, heartbeatIncoming: 4000, heartbeatOutgoing: 4000, }); stompClient.onConnect = (frame) => { console.log('Connected:', frame); resolve(stompClient); // 连接成功后立即订阅个人主题 // stompClient.subscribe(`/topic/commandOutput/${userId}`, (message) => { // console.log(1,message) // }); }; stompClient.onStompError = (error) => { console.error('Connection error:', error); reject(error); }; stompClient.activate(); }); } };<template> <div> <span style="display: flex; justify-content: center; margin-bottom: 8px"> <img alt="Vue logo" src="../assets/logo.png" style="width: 90px;"> </span> <span style="display: flex; justify-content: center; margin-bottom: 8px"> 当前登录用户: <input v-model="userId" placeholder="请输入p13" @keyup.enter="connectWebSocket"> <button @click="connectWebSocket" style="margin-left: 10px;">登录</button> </span> <span style="display: flex; justify-content: center"> <input ref="commandInput" v-model="currentCommand" style="width: 600px" placeholder="输入任意命令(如:ipconfig / dir)" :disabled="isExecuting" @keyup.enter="sendCommand" > <button @click="sendCommand" style="margin-left: 10px;" :disabled="isExecuting">执行命令</button> <button @click="abortCommand" style="margin-left: 10px; background: #ff4d4f" :disabled="!isExecuting" > 中止命令 </button> </span> <div style="display: flex"> <div style="margin-top: 20px; width: 30%;"> <h3 style="text-align: center">已执行命令</h3> <div style="height: 482px; overflow-y: auto; background: #f8f8f8;"> <div v-for="(msg, index) in messages" :key="index" style="margin-top: 8px; margin-left: 8px; border-radius: 4px; overflow-y: auto;" > {{ msg }} </div> </div> </div> <div style="padding: 20px; width: 70%"> <h3 style="text-align: center">实时命令输出</h3> <pre ref="outputPre" style="background: #282c34; color: #fff; padding: 15px; border-radius: 4px; height: 450px; overflow-y: auto" > {{ currentOutput }} </pre> </div> </div> </div> </template> <script> import websocket from '@/utils/websocket' export default { name: 'HelloWorld', props: { msg: String }, data() { return { currentCommand: '', messages: [], currentOutput: '', stompClient: null, index: 1, userId: '', isExecuting: false // 控制命令是否正在执行 }; }, methods: { async connectWebSocket() { alert("登录成功"); try { this.stompClient = await websocket.connect(this.userId); this.$nextTick(() => { this.$refs.commandInput.focus(); // 命令结束后重新聚焦到输入框 }); const subscription = this.stompClient.subscribe(`/topic/commandOutput/${this.userId}`, (message) => { const output = message.body; if (output.startsWith("⏹")) { this.isExecuting = false; // 命令执行结束,允许用户继续输入 this.$nextTick(() => { this.$refs.commandInput.focus(); // 命令结束后重新聚焦到输入框 }); return; } this.currentOutput += output.trim() + '\n'; this.$nextTick(() => { if (this.$refs.outputPre) { this.$refs.outputPre.scrollTop = this.$refs.outputPre.scrollHeight; } }); }); this.stompClient.onDisconnect = () => { subscription.unsubscribe(); }; // 检查命令执行状态 await this.checkCommandStatus(); } catch (error) { console.error('WebSocket连接失败:', error); } }, async checkCommandStatus() { try { const response = await fetch(`/win/status/${this.userId}`); if (!response.ok) { console.error('无法获取命令状态'); return; } this.isExecuting = await response.json(); // 更新前端状态 if (this.isExecuting) { alert("上一个命令尚未完成,请等待或中止命令!"); } } catch (error) { console.error('检查命令状态时出错:', error); } }, sendCommand() { if (this.userId === '') { alert("请输入当前登录用户"); return; } this.isExecuting = true; if (this.currentCommand.trim() && this.stompClient) { // 删除 currentOutput 的最后一个非空行 if (this.currentOutput) { let lastNewLineIndex = this.currentOutput.lastIndexOf('\n'); let lastNonEmptyIndex = -1; // 从后往前遍历,找到最后一个非空行的起始位置 for (let i = this.currentOutput.length - 1; i >= 0; i--) { if (this.currentOutput[i] === '\n') { // 如果当前字符是换行符,并且之前的字符不是空白字符,则记录位置 if (lastNewLineIndex !== -1 && i < lastNewLineIndex) { lastNonEmptyIndex = lastNewLineIndex; break; } lastNewLineIndex = i; } else if (this.currentOutput[i].trim() !== '') { // 找到非空字符,更新 lastNewLineIndex lastNewLineIndex = i; } } // 如果找到了非空行,则删除它 if (lastNonEmptyIndex !== -1) { const nextNewLineIndex = this.currentOutput.indexOf('\n', lastNonEmptyIndex); if (nextNewLineIndex === -1) { this.currentOutput = this.currentOutput.substring(0, lastNonEmptyIndex); } else { this.currentOutput = this.currentOutput.substring(0, lastNonEmptyIndex) + this.currentOutput.substring(nextNewLineIndex); } } // 删除最后一个空行 if (this.currentOutput.endsWith('\n')) { this.currentOutput = this.currentOutput.substring(0, this.currentOutput.length - 1); } } // 发送命令 this.stompClient.publish({ destination: '/app/executeCommand', body: JSON.stringify({ command: this.currentCommand.trim(), //todo 之后改为动态 host: '10.228.73.15', userId: this.userId }), }); this.messages.push(this.index + '. ' + this.currentCommand); this.index += 1; this.currentCommand = ''; } }, async abortCommand() { if (this.stompClient) { const response = await fetch(`/win/handleAbort/${this.userId}`); if (response){ this.messages.push("已发送中止命令"); } } }, onTabChange(key, type) { this[type] = key; }, }, beforeDestroy() { if (this.stompClient) { this.stompClient.deactivate(); } } } </script> <style scoped> pre { white-space: pre-line; background-color: #f4f4f4; padding: 10px; border: 1px solid #ddd; } </style> 这是我的小客户端的代码: package com.example.demo.config; import org.springframework.context.annotation.Configuration; import org.springframework.messaging.simp.config.MessageBrokerRegistry; import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; import org.springframework.web.socket.config.annotation.StompEndpointRegistry; import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; @Configuration @EnableWebSocketMessageBroker public class WebSocketConfig implements WebSocketMessageBrokerConfigurer { @Override public void configureMessageBroker(MessageBrokerRegistry config) { config.enableSimpleBroker("/topic"); config.setApplicationDestinationPrefixes("/app"); } @Override public void registerStompEndpoints(StompEndpointRegistry registry) { registry.addEndpoint("/websocket") .setAllowedOriginPatterns("*") .withSockJS(); } }package com.example.demo.service.impl; import cn.hutool.core.collection.CollUtil; import cn.hutool.core.date.DateUtil; import cn.hutool.core.io.FileUtil; import cn.hutool.core.io.IoUtil; import cn.hutool.core.lang.UUID; import cn.hutool.core.thread.ThreadFactoryBuilder; import cn.hutool.core.util.StrUtil; import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl; import com.example.demo.dao.entity.WExecuteHost; import com.example.demo.dao.entity.WHostProcess; import com.example.demo.dao.entity.WPersonalHost; import com.example.demo.dao.mapper.WExecuteHostMapper; import com.example.demo.request.ProcessRequest; import com.example.demo.service.WExecuteHostService; import com.example.demo.service.WHostProcessService; import com.example.demo.service.WPersonalHostService; import lombok.Data; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.messaging.simp.SimpMessagingTemplate; import org.springframework.stereotype.Service; import org.springframework.transaction.interceptor.TransactionAspectSupport; import javax.annotation.PreDestroy; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Date; import java.util.List; import java.util.Map; import java.util.Queue; import java.util.concurrent.CompletableFuture; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.regex.Matcher; import java.util.regex.Pattern; @Service public class WExecuteHostServiceImpl extends ServiceImpl<WExecuteHostMapper, WExecuteHost> implements WExecuteHostService { @Autowired private WPersonalHostService wPersonalHostService; @Autowired private WHostProcessService wHostProcessService; @Data private static class UserSession { private Process cmdProcess; private volatile boolean isProcessRunning; private String sessionId; private String logFilePath; private final Queue<String> logBuffer = new ConcurrentLinkedQueue<>(); private static final int BATCH_SIZE = 50; // 批量写入阈值 // 命令执行状态锁 private final AtomicBoolean isExecuting = new AtomicBoolean(false); } private final Map<String, UserSession> userSessions = new ConcurrentHashMap<>(); private final SimpMessagingTemplate messagingTemplate; // 异步日志写入线程池 private static final ExecutorService LOG_WRITER_POOL = Executors.newCachedThreadPool( new ThreadFactoryBuilder().setNamePrefix("log-writer-").build()); // 日志刷新调度器 private static final ScheduledExecutorService LOG_FLUSH_SCHEDULER = Executors.newSingleThreadScheduledExecutor(); public WExecuteHostServiceImpl(SimpMessagingTemplate messagingTemplate) { this.messagingTemplate = messagingTemplate; startLogFlushService(); } // 初始化日志刷新服务 private void startLogFlushService() { LOG_FLUSH_SCHEDULER.scheduleAtFixedRate(() -> { userSessions.values().forEach(session -> { if (!session.getLogBuffer().isEmpty()) { List<String> batch = CollUtil.newArrayList(session.getLogBuffer()); session.getLogBuffer().clear(); asyncWriteLog(session.getLogFilePath(), String.join("\n", batch)); } }); }, 0, 1, TimeUnit.SECONDS); } @Override public void executeCommand(String command, String host, String userId) { // 0. ABORT命令特殊处理(优先处理终止请求) if ("ABORT".equalsIgnoreCase(command)) { handleAbort(userId); return; } // 1. 权限校验 if (!validateUserHost(userId, host)) { sendError("无权访问该主机", userId); return; } // 2. 检查用户当前会话状态 UserSession session = userSessions.get(userId); if (session != null && session.isExecuting.get()) { sendError("已有命令执行中,请等待完成或使用ABORT终止", userId); return; } // 3. 创建新会话(带原子状态检查) session = userSessions.computeIfAbsent(userId, key -> { UserSession newSession = createNewSession(userId, host); if (newSession != null) { newSession.isExecuting.set(true); // 标记为执行中 } return newSession; }); if (session == null) return; // 4. 写入日志并执行命令 try { // 确保获得执行锁 if (!session.isExecuting.compareAndSet(true, true)) { sendError("命令执行冲突,请重试", userId); return; } session.getLogBuffer().offer("——————————————— " + DateUtil.now() + " ———————————————"); // 发送命令到进程 IoUtil.write(session.getCmdProcess().getOutputStream(), Charset.forName("GBK"), true, command + "\n"); } catch (Exception e) { session.isExecuting.set(false); // 发生异常时释放锁 sendError("命令发送失败: " + e.getMessage(), userId); } } @Override public Boolean isCommandExecuting(String userId) { UserSession session = userSessions.get(userId); return session != null && session.isExecuting.get(); } @Override public void handleAbort(String userId) { UserSession session = userSessions.get(userId); if (session == null || session.getCmdProcess() == null) { sendError("没有活动的命令进程", userId); return; } try { long pid = session.getCmdProcess().pid(); System.out.println("Attempting to kill process with PID: " + pid); // 使用 taskkill 命令终止进程 ProcessBuilder taskKill = new ProcessBuilder("taskkill", "/F", "/T", "/PID", String.valueOf(pid)); Process killProcess = taskKill.start(); // 等待命令执行完成 int exitCode = killProcess.waitFor(); System.out.println("taskkill exit code: " + exitCode); if (exitCode == 0) { // 进程终止成功 session.isExecuting.set(false); cleanupSession(userId); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "✔️" + "进程已通过 taskkill 终止 (PID: " + pid + ")"); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, ""); messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, System.getProperty("user.dir") + ">"); } else { // 进程终止失败 sendError("终止进程失败,错误码: " + exitCode, userId); } } catch (IOException | InterruptedException e) { System.err.println("Error killing process: " + e.getMessage()); sendError("终止进程失败: " + e.getMessage(), userId); } } @Override public String startProcess(ProcessRequest processRequest) { try { // 数据库表新增数据 String id = processRequest.getId(); String p13 = processRequest.getP13().trim(); String processName = processRequest.getProcessName().trim(); String productNumber = processRequest.getProductNumber().trim(); String executeHost = processRequest.getExecuteHost().trim(); String department = processRequest.getDepartment().trim(); String version = processRequest.getVersion().trim(); String type = processRequest.getType(); boolean saveOrUpdateResult; if (type.equals("新增")) { // 判断产品编号是否唯一 LambdaQueryWrapper<WHostProcess> processWrapper = new LambdaQueryWrapper<>(); processWrapper.eq(WHostProcess::getProductNumber, productNumber); WHostProcess process = wHostProcessService.getOne(processWrapper); if (process != null) { return "该产品编号已被他人使用,请使用其他的产品编号。"; } if (StrUtil.isEmpty(p13) || StrUtil.isEmpty(processName) || StrUtil.isEmpty(productNumber) || StrUtil.isEmpty(executeHost) || StrUtil.isEmpty(department) || StrUtil.isEmpty(version)) { return "新增进程失败。"; } WHostProcess wHostProcess = new WHostProcess(); wHostProcess.setP13(p13); wHostProcess.setProcessName(processName); wHostProcess.setProductNumber(productNumber); wHostProcess.setHost(executeHost); wHostProcess.setDepartment(department); wHostProcess.setState("离线"); wHostProcess.setVersion(version); wHostProcess.setBeginTime(new Date()); saveOrUpdateResult = wHostProcessService.save(wHostProcess); } else { // 执行更新操作 WHostProcess wHostProcess = wHostProcessService.getById(id); // 判断产品编号是否唯一 if (!wHostProcess.getProductNumber().equals(productNumber)) { LambdaQueryWrapper<WHostProcess> processWrapper = new LambdaQueryWrapper<>(); processWrapper.eq(WHostProcess::getProductNumber, productNumber); WHostProcess process = wHostProcessService.getOne(processWrapper); if (process != null) { return "该产品编号已被他人使用,请使用其他的产品编号。"; } } wHostProcess.setProcessName(processName); wHostProcess.setProductNumber(productNumber); wHostProcess.setHost(executeHost); wHostProcess.setDepartment(department); wHostProcess.setState("离线"); wHostProcess.setVersion(version); wHostProcess.setUpdateTime(new Date()); saveOrUpdateResult = wHostProcessService.updateById(wHostProcess); } if (saveOrUpdateResult) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper .eq(WPersonalHost::getExecuteHost, processRequest.getExecuteHost()) .eq(WPersonalHost::getSharedHost, processRequest.getSharedHost()); WPersonalHost wPersonalHost = wPersonalHostService.getOne(queryWrapper); // 执行py启动命令 //todo 后续动态 String pythonEXEPath = "D:\\miniforge\\envs" + File.separator + p13 + File.separator + p13 + "_python" + wPersonalHost.getPythonEnv() + File.separator + "python.exe -u"; String mainPyPath = System.getProperty("user.dir") + File.separator + "python-package" + File.separator + executeHost + File.separator + p13 + File.separator + "test" + File.separator + "main.py"; this.executeCommand(pythonEXEPath + " " + mainPyPath, processRequest.getExecuteHost(), processRequest.getP13()); return "正在启动项目..."; } } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); } return "新增进程失败。"; } @Override public String stopProcess(ProcessRequest processRequest) { try { //todo 后续动态 String account = "fangpeiyuan"; Integer pid = processRequest.getPid(); LambdaQueryWrapper<WHostProcess> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper .eq(WHostProcess::getP13, account) .eq(WHostProcess::getPid, pid); WHostProcess wHostProcess = wHostProcessService.getOne(queryWrapper); if (wHostProcess == null) { return "当前进程终止失败,请联系管理员!"; } // 执行终止命令并获取返回值 Process process = Runtime.getRuntime().exec( "taskkill /F /PID \"" + pid + "\""); int exitCode = process.waitFor(); if (exitCode == 0) { wHostProcess.setState("离线"); wHostProcess.setPid(null); wHostProcess.setUpdateTime(DateUtil.date()); wHostProcessService.updateById(wHostProcess); return "进程终止成功。"; } else { // 获取错误流信息(可选) BufferedReader errorReader = new BufferedReader( new InputStreamReader(process.getErrorStream())); String errorLine; StringBuilder errorMessage = new StringBuilder(); while ((errorLine = errorReader.readLine()) != null) { errorMessage.append(errorLine).append("\n"); } return "进程终止失败,错误码: " + exitCode + (errorMessage.length() > 0 ? ",错误信息: " + errorMessage : ""); } } catch (Exception e) { e.printStackTrace(); TransactionAspectSupport.currentTransactionStatus().setRollbackOnly(); return "当前进程终止失败: " + e.getMessage(); } } private boolean validateUserHost(String userId, String executeHost) { LambdaQueryWrapper<WPersonalHost> queryWrapper = new LambdaQueryWrapper<>(); queryWrapper.eq(WPersonalHost::getP13, userId) .eq(WPersonalHost::getExecuteHost, executeHost) .eq(WPersonalHost::getState, "在线"); return wPersonalHostService.getOne(queryWrapper) != null; } private UserSession createNewSession(String userId, String executeHost) { try { UserSession session = new UserSession(); session.setSessionId(UUID.randomUUID().toString()); session.setLogFilePath(initLogFile(userId, executeHost)); // 启动CMD进程(带唯一标题) ProcessBuilder pb = new ProcessBuilder("cmd.exe", "/k", "title " + generateUniqueTitle(userId)); session.setCmdProcess(pb.redirectErrorStream(true).start()); // 启动输出监听线程 startOutputThread(session, userId); return session; } catch (IOException e) { sendError("进程启动失败: " + e.getMessage(), userId); return null; } } private String initLogFile(String userId, String executeHost) { // 1. 构建基础路径(使用File.separator) String baseDir = FileUtil.normalize( System.getProperty("user.dir") + File.separator + "command-log"); // 2. 构建安全路径(统一使用File.separator) String safePath = FileUtil.normalize( baseDir + File.separator + userId + File.separator + executeHost + File.separator + "项目名称"); // 3. 安全校验(现在路径分隔符一致) if (!safePath.startsWith(baseDir)) { throw new SecurityException("非法日志路径: " + safePath); } // 4. 创建目录(自动处理路径分隔符) FileUtil.mkdir(safePath); // 5. 生成日志文件 String logFileName = DateUtil.today() + ".log"; return FileUtil.touch(safePath + File.separator + logFileName).getAbsolutePath(); } private void startOutputThread(UserSession session, String userId) { new Thread(() -> { try (BufferedReader reader = new BufferedReader( new InputStreamReader(session.getCmdProcess().getInputStream(), Charset.forName("GBK")))) { String line; while ((line = reader.readLine()) != null) { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, line); session.getLogBuffer().offer(line); } } catch (Exception e) { sendError("输出流异常: " + e.getMessage(), userId); } finally { session.isExecuting.set(false); // 命令结束释放锁 cleanupSession(userId); // 通知前端命令执行结束 messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "⏹ 该命令执行已结束"); } }).start(); } private void asyncWriteLog(String logFilePath, String content) { CompletableFuture.runAsync(() -> { try { // 替换掉日志文件中没用的信息,如多余的路径信息 String currentDir = System.getProperty("user.dir"); String escapedDir = currentDir.replace("\\", "\\\\"); String regex = "(?m)^\\s*" + escapedDir + ">(?!\\S)\\s*"; // 创建 Pattern 和 Matcher 对象 Pattern pattern = Pattern.compile(regex); Matcher matcher = pattern.matcher(content); // 检查是否存在匹配的模式 if (matcher.find()) { // 如果存在匹配,则进行替换 String cleaned = content.replaceAll(regex, ""); FileUtil.appendString(cleaned + System.lineSeparator(), logFilePath, Charset.forName("GBK")); } else { FileUtil.appendString(content + System.lineSeparator(), logFilePath, Charset.forName("GBK")); } } catch (Exception e) { System.err.println("日志写入失败: " + e.getMessage()); } }, LOG_WRITER_POOL); } private void cleanupSession(String userId) { UserSession session = userSessions.remove(userId); if (session != null) { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } // 强制将剩余日志写入文件(新增代码) if (!session.getLogBuffer().isEmpty()) { asyncWriteLog(session.getLogFilePath(), String.join("\n", session.getLogBuffer())); session.getLogBuffer().clear(); } } catch (Exception ignored) { } } } @PreDestroy public void cleanup() { LOG_FLUSH_SCHEDULER.shutdown(); LOG_WRITER_POOL.shutdown(); userSessions.forEach((userId, session) -> { try { if (session.getCmdProcess() != null) { session.getCmdProcess().destroyForcibly(); } } catch (Exception ignored) { } }); userSessions.clear(); } /** * 发送错误日志 */ private void sendError(String message, String userId) { try { messagingTemplate.convertAndSend("/topic/commandOutput/" + userId, "❌" + message); } catch (Exception ignored) { } } /** * 生成cmd窗口唯一id */ private String generateUniqueTitle(String userId) { return "CMD_SESSION_" + userId + "_" + System.currentTimeMillis(); } } 请参考这两个,帮我实现b作为中转需要的代码,以及a和小客户端需要修改的东西,不要什么心跳检测等复杂的东西,先简单实现,但是代码要给全
06-22
package com.Ls.erp.util; import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; import java.io.*; import java.nio.file.Files; import java.nio.file.attribute.BasicFileAttributes; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Calendar; import java.util.Date; import java.util.List; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; @Component public class DatabaseBackupScheduler { // 配置参数(根据实际情况修改) private static final String DB_HOST = "localhost"; private static final String DB_PORT = "3306"; private static final String DB_USER = "root"; private static final String DB_PASSWORD = "000000"; private static final String DATABASE_NAME = "erp"; private static final String BACKUP_DIR = "D://2023-02-23ERP测试//2025-08-01//数据库备份查询"; // 替换为实际备份目录 private static final int RETENTION_DAYS = 15; // 保留最近15天的备份 private static final String MYSQLDUMP_PATH = getMysqldumpPath(); @PostConstruct public void init() { startScheduledBackup(); } private static String getMysqldumpPath() { String os = System.getProperty("os.name").toLowerCase(); if (os.contains("win")) { return "C:\\Program Files\\MySQL\\MySQL Server 5.7\\bin\\mysqldump.exe"; } else { return "/usr/bin/mysqldump"; } } private static void startScheduledBackup() { ScheduledExecutorService scheduler = Executors.newScheduledThreadPool(1); // 计算首次执行时间 Calendar now = Calendar.getInstance(); Calendar nextBackupTime = calculateNextBackupTime(now); // 计算初始延迟(毫秒) long initialDelay = nextBackupTime.getTimeInMillis() - now.getTimeInMillis(); // 每天执行一次(24小时) long period = 24 * 60 * 60 * 1000; scheduler.scheduleAtFixedRate( DatabaseBackupScheduler::performBackup, initialDelay, period, TimeUnit.MILLISECONDS ); System.out.println("数据库备份任务已启动。首次备份时间: " + nextBackupTime.getTime()); System.out.println("备份目录: " + BACKUP_DIR); System.out.println("备份保留天数: " + RETENTION_DAYS + "天"); } private static Calendar calculateNextBackupTime(Calendar currentTime) { Calendar nextTime = (Calendar) currentTime.clone(); // 设置备份时间点(12:00 和 17:30) List<Calendar> backupTimes = new ArrayList<>(); Calendar noon = Calendar.getInstance(); noon.set(Calendar.HOUR_OF_DAY, 12); noon.set(Calendar.MINUTE, 0); noon.set(Calendar.SECOND, 0); Calendar evening = Calendar.getInstance(); evening.set(Calendar.HOUR_OF_DAY, 14); evening.set(Calendar.MINUTE, 25); evening.set(Calendar.SECOND, 0); backupTimes.add(noon); backupTimes.add(evening); // 找到下一个最近的备份时间 for (Calendar time : backupTimes) { if (time.after(currentTime)) { return time; } } // 如果今天所有时间点都已过,返回明天的第一个时间点 Calendar firstTime = backupTimes.get(0); firstTime.add(Calendar.DAY_OF_MONTH, 1); return firstTime; } private static void performBackup() { try { // 创建备份目录(如果不存在) File backupDir = new File(BACKUP_DIR); if (!backupDir.exists() && !backupDir.mkdirs()) { System.err.println("无法创建备份目录: " + BACKUP_DIR); return; } // 生成带时间戳的文件名 String timeStamp = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date()); String fileName = String.format("%s_%s.sql", DATABASE_NAME, timeStamp); String backupPath = BACKUP_DIR + File.separator + fileName; // 构建备份命令 List<String> command = new ArrayList<>(); command.add(MYSQLDUMP_PATH); command.add("--host=" + DB_HOST); command.add("--port=" + DB_PORT); command.add("--user=" + DB_USER); command.add("--password=" + DB_PASSWORD); command.add("--databases"); command.add(DATABASE_NAME); command.add("--result-file=" + backupPath); command.add("--skip-lock-tables"); command.add("--single-transaction"); command.add("--routines"); // 备份存储过程和函数 command.add("--events"); // 备份事件 command.add("--triggers"); // 备份触发器 // 添加以下关键参数 command.add("--default-character-set=utf8mb4"); command.add("--hex-blob"); // 处理二进制字段 command.add("--skip-comments"); // 避免注释导致问题 command.add("--no-tablespaces"); // 避免权限问题 command.add("--verbose"); // 显示更多信息 // 执行备份命令 ProcessBuilder processBuilder = new ProcessBuilder(command); // 关键修复:使用标准输出重定向 File backupFile = new File(backupPath); processBuilder.redirectOutput(backupFile); // 正确重定向输出到文件 processBuilder.redirectErrorStream(true); // 合并错误流到输出流 System.out.println("[" + new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(new Date()) + "] 开始备份数据库: " + DATABASE_NAME); Process process = processBuilder.start(); // 读取命令输出 try (BufferedReader reader = new BufferedReader( new InputStreamReader(process.getInputStream()))) { String line; while ((line = reader.readLine()) != null) { System.out.println("[MYSQLDUMP] " + line); } } int exitCode = process.waitFor(); if (exitCode == 0) { long fileSizeKB = backupFile.length() / 1024; System.out.println("✅ 数据库备份成功: " + backupPath); System.out.println("📁 备份文件大小: " + fileSizeKB + " KB"); // 验证备份文件 if (isBackupValid(backupFile)) { System.out.println("🔍 备份文件验证通过"); } else { System.err.println("⚠️ 备份文件验证失败,可能存在数据丢失"); } // 清理旧备份 cleanOldBackups(); } else { System.err.println("❌ 数据库备份失败,退出码: " + exitCode); // 记录详细错误信息 try (BufferedReader errorReader = new BufferedReader( new InputStreamReader(process.getErrorStream()))) { String errorLine; while ((errorLine = errorReader.readLine()) != null) { System.err.println("[MYSQLDUMP ERROR] " + errorLine); } } catch (IOException e) { System.err.println("无法读取错误流: " + e.getMessage()); } } } catch (IOException | InterruptedException e) { System.err.println("⚠️ 备份过程中发生错误: " + e.getMessage()); e.printStackTrace(); } } // 新增方法:验证备份文件完整性 private static boolean isBackupValid(File backupFile) { try (BufferedReader reader = new BufferedReader(new FileReader(backupFile))) { boolean hasCreateTable = false; boolean hasInsert = false; boolean hasEndMarker = false; String line; int lineCount = 0; while ((line = reader.readLine()) != null) { lineCount++; // 检查关键结构 if (line.startsWith("CREATE TABLE")) hasCreateTable = true; if (line.startsWith("INSERT INTO")) hasInsert = true; if (line.contains("Dump completed")) hasEndMarker = true; // 检查错误信息 if (line.contains("ERROR") || line.contains("failed")) { System.err.println("备份文件中发现错误: " + line); return false; } } // 基本完整性检查 if (lineCount < 100) { System.err.println("备份文件行数不足: " + lineCount); return false; } if (!hasCreateTable) { System.err.println("缺少CREATE TABLE语句"); return false; } if (!hasInsert) { System.err.println("缺少INSERT INTO语句"); return false; } return hasEndMarker; } catch (IOException e) { System.err.println("验证备份文件时出错: " + e.getMessage()); return false; } } private static void cleanOldBackups() { File backupDir = new File(BACKUP_DIR); if (!backupDir.exists() || !backupDir.isDirectory()) { return; } // 计算截止时间(当前时间减去保留天数) long cutoff = System.currentTimeMillis() - TimeUnit.DAYS.toMillis(RETENTION_DAYS); // 获取所有备份文件 File[] backupFiles = backupDir.listFiles((dir, name) -> name.startsWith(DATABASE_NAME + "_") && name.endsWith(".sql") ); if (backupFiles == null || backupFiles.length == 0) { return; } int deletedCount = 0; for (File backup : backupFiles) { try { // 获取文件的创建时间 BasicFileAttributes attrs = Files.readAttributes( backup.toPath(), BasicFileAttributes.class ); // 如果文件创建时间早于截止时间,则删除 if (attrs.creationTime().toMillis() < cutoff) { if (backup.delete()) { System.out.println("♻️ 已清理旧备份: " + backup.getName()); deletedCount++; } else { System.err.println("⚠️ 无法删除旧备份: " + backup.getName()); } } } catch (IOException e) { System.err.println("⚠️ 检查备份文件时出错: " + backup.getName() + " - " + e.getMessage()); } } System.out.println("🧹 清理完成: 共删除 " + deletedCount + " 个旧备份"); } } 我可以在Java里面去做这个事情吗,我需要的mysql、里面的erp库进行数据与结构的保存,我使用这个好像可以保存erp里面的时间但是存在问题,保存的erp.sql,文件大小是16000KB我手动去mysql里面对erp进行保存,sql文件大小是28430KB还有我去运行erp里面的数据,全部是报错的,我代码存在什么问题吗
最新发布
08-02
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值