From 925d4c2ad216a7691f81031fcff17beb0420c327 Mon Sep 17 00:00:00 2001 From: huababa1 <2037205722@qq.com> Date: Mon, 7 Jul 2025 18:09:30 +0800 Subject: [PATCH] =?UTF-8?q?=E3=80=90=E4=BF=AE=E6=94=B9=E3=80=91ps=E5=BC=80?= =?UTF-8?q?=E5=90=AF=E5=85=B3=E9=97=AD=E6=8F=90=E5=8D=87=E6=9D=83=E9=99=90?= =?UTF-8?q?=EF=BC=8C=E5=A2=9E=E5=8A=A0=E6=B3=A8=E5=86=8C=E8=A1=A8=E8=B7=AF?= =?UTF-8?q?=E5=BE=84?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../service/mysql/IMysqlLocalServiceImpl.java | 22 +++-- .../exam/exam/service/ps/PsServiceImpl.java | 2 +- .../example/exam/exam/utils/ps/PsUtil.java | 89 ++++++++++++------- 3 files changed, 75 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java index 3c50053..9ed6c6c 100644 --- a/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/mysql/IMysqlLocalServiceImpl.java @@ -143,7 +143,6 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { if (sqlFileExecuted ) { - Map result = readFilesAsMap(stuFilePath); Map resultStu = readFilesAsMap(fileStu); @@ -1059,6 +1058,16 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { // stmt.executeUpdate(dropDbSql2); + }finally { + //删除临时创建的数据库databaseName + try (Connection conn = DriverManager.getConnection(newDbUrl, user, password); + Statement stmt = conn.createStatement()) { + String dropDbSql = "DROP DATABASE " + databaseName; + stmt.executeUpdate(dropDbSql); + System.out.println("删除临时库"); + } catch (SQLException e) { + e.printStackTrace(); + } } } appendToFile(answerLogPath, "共得分:" + String.format("%.2f", scoreTotal)); @@ -1178,10 +1187,11 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { int index = 1; // 判断表名是否一致 String tableNameCheck = tableName.equalsIgnoreCase(tableNameStu) ? "✔" : "x"; + String tableNameCheckOther = tableName.equalsIgnoreCase(tableNameStu) ? "✅" : "❌"; // 输出 System.out.printf("%02d.【数据表】【%s】【名称】【%s】【%s】\n", index, dbTable, tableName, tableNameCheck); appendToFile(answerLogPath, "%02d.【数据表】【%s】【名称】【%s】【%s】\n", index, dbTable, tableName, tableNameCheck); - judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【数据表】【%s】【名称】【%s】【%s】\n", index, dbTable, tableName, tableNameCheck); + judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【数据表】【%s】【名称】【%s】【%s】\n", index, dbTable, tableName, tableNameCheckOther); // 把Set转成Map,方便通过字段名快速取值 Map> standardMap = convertSetToMap(standardSet); Map> studentMap = convertSetToMap(studentSet); @@ -1193,8 +1203,9 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { String fullName = dbTable + "." + columnName; String nameCheck = stuCol != null ? "✔" : "x"; + String nameCheckOther = stuCol != null ? "✅" : "❌"; System.out.printf("%02d.【字段】【%s】【名称】【%s】【%s】\n", ++index, fullName, columnName, nameCheck); - judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【名称】【%s】【%s】\n", index, fullName, columnName, nameCheck); + judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【名称】【%s】【%s】\n", index, fullName, columnName, nameCheckOther); appendToFile(answerLogPath, "%02d.【字段】【%s】【名称】【%s】【%s】\n", index, fullName, columnName, nameCheck); if (stuCol != null) { @@ -1232,9 +1243,10 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { private static MysqlVo compareField(int index, String fullName, String property, String stdValue, String stuValue, String judgementStr) { MysqlVo mysqlVo=new MysqlVo(); String mark = stdValue.equalsIgnoreCase(stuValue) ? "✔" : "x"; + String markOther = stdValue.equalsIgnoreCase(stuValue) ? "✅" : "❌"; System.out.printf("%02d.【字段】【%s】【%s】【%s】【%s】\n", index + 1, fullName, property, stuValue, mark); appendToFile(answerLogPath, "%02d.【字段】【%s】【%s】【%s】【%s】\n", index + 1, fullName, property, stuValue, mark); - judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【%s】【%s】【%s】\n", index + 1, fullName, property, stuValue, mark); + judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【%s】【%s】【%s】\n", index + 1, fullName, property, stuValue, markOther); mysqlVo.setText(judgementStr); mysqlVo.setIndex(index + 1); return mysqlVo; @@ -1244,7 +1256,7 @@ public class IMysqlLocalServiceImpl implements IMysqlLocalService { MysqlVo mysqlVo=new MysqlVo(); System.out.printf("%02d.【字段】【%s】【%s】【%s】【x】\n", index + 1, fullName, property, stdValue); appendToFile(answerLogPath, "%02d.【字段】【%s】【%s】【%s】【x】\n", index + 1, fullName, property, stdValue); - judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【%s】【%s】【x】\n", index + 1, fullName, property, stdValue); + judgementStr = HtmlAppender.appendHtmlLineMysql(judgementStr, "%02d.【字段】【%s】【%s】【%s】【❌】\n", index + 1, fullName, property, stdValue); mysqlVo.setText(judgementStr); mysqlVo.setIndex(index + 1); return mysqlVo; diff --git a/src/main/java/com/example/exam/exam/service/ps/PsServiceImpl.java b/src/main/java/com/example/exam/exam/service/ps/PsServiceImpl.java index 9117eb9..f30d05d 100644 --- a/src/main/java/com/example/exam/exam/service/ps/PsServiceImpl.java +++ b/src/main/java/com/example/exam/exam/service/ps/PsServiceImpl.java @@ -92,7 +92,7 @@ public class PsServiceImpl implements PsService{ double finalScore = ((totalScore / maxPossibleScore) * score); double finalScoreRatio = Math.round(finalScore * 100.0) / 100.0; // 四舍五入到2位小数 appendToFile(answerLogPath, "最终得分: " + finalScoreRatio); - judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "最终得分: " +finalScoreRatio); +// judgementStr = HtmlAppender.appendHtmlLine(judgementStr, "最终得分: " +finalScoreRatio); sourceAndText.setScore(finalScoreRatio); sourceAndText.setText(judgementStr); return sourceAndText; diff --git a/src/main/java/com/example/exam/exam/utils/ps/PsUtil.java b/src/main/java/com/example/exam/exam/utils/ps/PsUtil.java index a4d4fc0..dffe1e9 100644 --- a/src/main/java/com/example/exam/exam/utils/ps/PsUtil.java +++ b/src/main/java/com/example/exam/exam/utils/ps/PsUtil.java @@ -32,30 +32,42 @@ public class PsUtil { // 尝试读取多个注册表路径获取 Photoshop 路径 public static String findPhotoshopExe() { + // 常见的注册表路径(顺序很重要,优先尝试最常见的) String[] regPaths = { "HKLM\\SOFTWARE\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command", - "HKLM\\SOFTWARE\\WOW6432Node\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command" + "HKLM\\SOFTWARE\\WOW6432Node\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command", + "HKCU\\SOFTWARE\\Classes\\Applications\\Photoshop.exe\\shell\\edit\\command", + "HKLM\\SOFTWARE\\Adobe\\Photoshop", + "HKLM\\SOFTWARE\\WOW6432Node\\Adobe\\Photoshop", + "HKCR\\Photoshop.Image.13\\shell\\edit\\command", + "HKCR\\Photoshop.Image.13\\protocol\\StdFileEditing\\server", + "HKCR\\Photoshop.Image.13\\DefaultIcon", }; for (String path : regPaths) { try { String exePath = queryReg(path); if (exePath != null && !exePath.isEmpty()) { - // 通常 exe 路径后面会跟参数 %1,只取 exe 路径部分 + // 清理掉可能的参数(如 "%1") + exePath = exePath.replaceAll("\"", ""); // 去除引号 int idx = exePath.toLowerCase().indexOf("photoshop.exe"); if (idx != -1) { - exePath = exePath.substring(0, idx + "photoshop.exe".length()); + String psPath = exePath.substring(0, idx + "photoshop.exe".length()); + if (new File(psPath).exists()) { + return psPath; + } } - return exePath; } } catch (Exception e) { - // 忽略异常,继续尝试其他路径 + // 忽略错误,尝试下一个路径 } } - return null; // 没找到 + + return null; // 都没找到 } + public static String runTwoPsdsInOneScript(String psdPath, String jsxTemplatePath, String photoshopExe) throws IOException, InterruptedException { @@ -63,22 +75,32 @@ public class PsUtil { String baseDir = psdFile1.getParent(); String jsxTargetPath = baseDir + File.separator + "run_both_" + System.currentTimeMillis() + ".jsx"; + // 读取 JSX 模板 String jsxTemplate = Files.readString(Paths.get(jsxTemplatePath), StandardCharsets.UTF_8); + // 转义路径 String safePath1 = psdPath.replace("\\", "\\\\").replace("'", "\\'"); - String jsxContent = jsxTemplate - .replace("${inputPath1}", safePath1); + String jsxContent = jsxTemplate.replace("${inputPath1}", safePath1); + // 写入最终 JSX 脚本 Files.writeString(Paths.get(jsxTargetPath), jsxContent, StandardCharsets.UTF_8); - String command = String.format("\"%s\" -r \"%s\"", photoshopExe, jsxTargetPath); - System.out.println("运行 Photoshop 脚本: " + command); + // 构造 PowerShell 提升权限启动 Photoshop 命令 + String powershellCmd = String.format( + "Start-Process -FilePath '%s' -ArgumentList '-r \"%s\"' -Verb RunAs", + photoshopExe, jsxTargetPath + ); - Process process = Runtime.getRuntime().exec(command); + System.out.println("运行 Photoshop 脚本(带权限提升): " + powershellCmd); - // 异步打印输出日志 + // 构造 ProcessBuilder 启动 powershell + ProcessBuilder builder = new ProcessBuilder("powershell.exe", "-Command", powershellCmd); + builder.redirectErrorStream(true); // 合并错误输出 + Process process = builder.start(); + + // 异步读取输出(合并输出流后只需一个线程) new Thread(() -> { - try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) { + try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream(), "GBK"))) { String line; while ((line = br.readLine()) != null) { System.out.println("[PS OUT] " + line); @@ -86,38 +108,41 @@ public class PsUtil { } catch (IOException ignored) {} }).start(); - new Thread(() -> { - try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getErrorStream()))) { - String line; - while ((line = br.readLine()) != null) { - System.err.println("[PS ERR] " + line); - } - } catch (IOException ignored) {} - }).start(); - - // 不使用 waitFor 阻塞,改成轮询判断两个 JSON 文件是否生成 + // 不阻塞 waitFor,轮询等待 JSON 文件 String jsonPath1 = psdPath.replaceAll("(?i)\\.psd$", ".json"); - - int maxWaitSeconds = 60; // 最多等待 60秒,根据实际调整 + int maxWaitSeconds = 60; int waited = 0; - while (!(Files.exists(Paths.get(jsonPath1)))) { - Thread.sleep(1000); // 每秒检查一次 + while (!Files.exists(Paths.get(jsonPath1))) { + Thread.sleep(1000); waited++; if (waited > maxWaitSeconds) { - // 超时,结束进程并抛异常 - process.destroyForcibly(); + // 超时 throw new RuntimeException("等待 Photoshop 生成 JSON 文件超时"); } } - System.out.println("检测到 JSON 文件生成,关闭 Photoshop 进程..."); + System.out.println("检测到 JSON 文件生成,尝试关闭 Photoshop..."); // 手动杀死 Photoshop 进程,确保释放资源 - Process killProcess = Runtime.getRuntime().exec("taskkill /IM Photoshop.exe /F"); - killProcess.waitFor(); + // 构造 PowerShell 提升权限执行 taskkill 命令 + String powershellKillCmd = "Start-Process -FilePath 'taskkill' -ArgumentList '/IM Photoshop.exe /F' -Verb RunAs"; + + // 构造 ProcessBuilder + ProcessBuilder builderKill = new ProcessBuilder("powershell.exe", "-Command", powershellKillCmd); + builderKill.redirectErrorStream(true); // 合并标准输出和错误输出 + + Process processKill = builderKill.start(); + // 等待进程结束 + int exitCode = processKill.waitFor(); + if (exitCode == 0) { + System.out.println("提权关闭 Photoshop 成功"); + } else { + System.err.println("提权关闭 Photoshop 失败,退出码:" + exitCode); + } System.out.println("Photoshop 进程已关闭"); return jsxTargetPath; } + }