From b82ae44e0e20f588d5326db02455f03346d4a3d9 Mon Sep 17 00:00:00 2001 From: lsbp <2803234009@qq.com> Date: Wed, 8 Oct 2025 19:49:26 +0800 Subject: [PATCH 1/5] =?UTF-8?q?=E6=AD=A3=E5=BC=8F=E7=89=881.0.1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 75 +++++++++------ src/main/java/com/pair/MathQuiz/Main.java | 4 - .../java/com/pair/service/FileIOService.java | 5 +- .../java/com/pair/service/QuizService.java | 25 +++-- .../java/com/pair/service/UserService.java | 50 +--------- .../java/com/pair/ui/GradeSelectPanel.java | 7 -- src/main/java/com/pair/ui/MainWindow.java | 7 +- src/main/java/com/pair/ui/ResultPage.java | 1 + .../pair/util/AsyncRegistrationHelper.java | 16 ++-- src/main/java/com/pair/util/EmailUtil.java | 35 +------ .../java/com/pair/util/PasswordValidator.java | 95 ------------------- 11 files changed, 79 insertions(+), 241 deletions(-) delete mode 100644 src/main/java/com/pair/MathQuiz/Main.java delete mode 100644 src/main/java/com/pair/ui/GradeSelectPanel.java diff --git a/pom.xml b/pom.xml index 0bb799d..0ba7047 100644 --- a/pom.xml +++ b/pom.xml @@ -5,6 +5,14 @@ http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 + + + org.springframework.boot + spring-boot-starter-parent + 3.1.12 + + + com.mathquiz MathQuizApp 1.04 @@ -13,22 +21,29 @@ Math Quiz Application 小初高数学学习软件- JavaFX版本 - jitpack.io - https://jitpack.io + https://jitpack.io + UTF-8 21 21 21.0.2 + 3.1.12 + + + 1.5.13 + 2.2 + 6.0.22 + com.google.code.gson gson @@ -56,25 +71,28 @@ ${javafx.version} - - com.sun.mail javax.mail 1.6.2 - com.sun.activation javax.activation 1.2.0 - + + + org.springframework.boot + spring-boot-starter + + + org.apache.maven.plugins maven-compiler-plugin @@ -86,6 +104,7 @@ + org.apache.maven.plugins maven-resources-plugin @@ -101,41 +120,39 @@ 3.6.1 - copy-dependencies - package + copy-javafx-dependencies + compile copy-dependencies - ${project.build.directory}/dependencies - false - false - true + org.openjfx + ${project.build.directory}/javafx-libs - - org.codehaus.mojo - exec-maven-plugin - 3.1.0 + org.springframework.boot + spring-boot-maven-plugin + ${spring-boot.maven.plugin.version} - - com.pair.Test - - - --add-modules - javafx.controls,javafx.fxml,javafx.graphics,javafx.base - + com.pair.Test + + + --module-path ${project.build.directory}/javafx-libs --add-modules javafx.controls,javafx.fxml,javafx.graphics,javafx.base + --add-modules javafx.controls,javafx.fxml,javafx.graphics,javafx.base + + + + + repackage + + + - - - - - - + \ No newline at end of file diff --git a/src/main/java/com/pair/MathQuiz/Main.java b/src/main/java/com/pair/MathQuiz/Main.java deleted file mode 100644 index f94bf8e..0000000 --- a/src/main/java/com/pair/MathQuiz/Main.java +++ /dev/null @@ -1,4 +0,0 @@ -package com.pair.MathQuiz; - -public class Main { -} diff --git a/src/main/java/com/pair/service/FileIOService.java b/src/main/java/com/pair/service/FileIOService.java index d420587..ed0b0a6 100644 --- a/src/main/java/com/pair/service/FileIOService.java +++ b/src/main/java/com/pair/service/FileIOService.java @@ -21,7 +21,6 @@ import java.util.*; public class FileIOService { private static final String DATA_DIR = AppDataDirectory.getFullPath("data"); - private static final String USERS_DIR = AppDataDirectory.getFullPath("data/users"); private static final String HISTORY_DIR = AppDataDirectory.getFullPath("data/history"); private static final String REGISTRATION_CODES_FILE = AppDataDirectory.getFullPath("data/registration_codes.json"); @@ -41,7 +40,6 @@ public class FileIOService { public void initDataDirectory() throws IOException { FileUtils.createDirectoryIfNotExists(DATA_DIR); - FileUtils.createDirectoryIfNotExists(USERS_DIR); FileUtils.createDirectoryIfNotExists(HISTORY_DIR); FileUtils.ensureFileExists(REGISTRATION_CODES_FILE); @@ -139,8 +137,9 @@ public class FileIOService { // ==================== 答题历史操作 ==================== public void saveQuizHistory(QuizHistory history) throws IOException { + String filename = HISTORY_DIR + "/" + - sanitizeFilename(history.getUsername()) + "_" + + sanitizeFilename(history.getUsername()) + "/" + System.currentTimeMillis() + ".txt"; StringBuilder content = new StringBuilder(); diff --git a/src/main/java/com/pair/service/QuizService.java b/src/main/java/com/pair/service/QuizService.java index 917c91d..ea350f9 100644 --- a/src/main/java/com/pair/service/QuizService.java +++ b/src/main/java/com/pair/service/QuizService.java @@ -20,14 +20,6 @@ public class QuizService { // ==================== 构造方法 ==================== - public QuizService() throws IOException { - this.fileIOService = new FileIOService(); - this.userService = new UserService(fileIOService); - this.currentQuestions = new ArrayList<>(); - this.userAnswers = new ArrayList<>(); - this.currentQuestionIndex = 0; - } - public QuizService(FileIOService fileIOService, UserService userService) { this.fileIOService = fileIOService; this.userService = userService; @@ -408,20 +400,27 @@ public class QuizService { // ==================== 数据持久化 ==================== - public void saveQuizHistory(User user) throws IOException { + public void saveQuizHistory() { QuizResult result = calculateResult(); QuizHistory history = new QuizHistory( - user.getUsername(), + userService.getCurrentUser().getUsername(), new Date(), currentQuestions, userAnswers, result.getScore() ); + try { + fileIOService.saveQuizHistory(history); + } catch (IOException e) { + System.err.println(e); + } - fileIOService.saveQuizHistory(history); - - userService.updateUserStatistics(user, result.getScore()); + try { + userService.updateUserStatistics(userService.getCurrentUser(), result.getScore()); + } catch (IOException e) { + System.err.println(e); + } System.out.println("✓ 答题记录已保存"); } diff --git a/src/main/java/com/pair/service/UserService.java b/src/main/java/com/pair/service/UserService.java index b5e50fa..f9961b2 100644 --- a/src/main/java/com/pair/service/UserService.java +++ b/src/main/java/com/pair/service/UserService.java @@ -1,7 +1,9 @@ package com.pair.service; +import com.pair.model.ChoiceQuestion; import com.pair.model.Grade; +import com.pair.model.QuizHistory; import com.pair.model.User; import com.pair.util.EmailUtil; import com.pair.util.FileUtils; @@ -495,23 +497,6 @@ public class UserService { // ==================== 业务逻辑方法=================== -// /** -// * 从用户名提取真实姓名 -// */ -// public String getRealName(User user) { -// if (user == null || user.getUsername() == null) { -// return ""; -// } -// -// String username = user.getUsername(); -// int dashIndex = username.indexOf('-'); -// -// if (dashIndex > 0 && dashIndex < username.length() - 1) { -// return username.substring(dashIndex + 1); -// } -// -// return username; -// } /** * 获取学段中文名称 @@ -550,35 +535,4 @@ public class UserService { return sb.toString(); } - // ==================== 验证工具方法 ==================== - -// private boolean validateUsername(String username) { -// if (username == null || username.trim().isEmpty()) { -// return false; -// } -// -// Matcher matcher = USERNAME_PATTERN.matcher(username); -// return matcher.matches(); -// } - -// private boolean validateEmail(String email) { -// if (email == null || email.trim().isEmpty()) { -// return false; -// } -// -// Matcher matcher = EMAIL_PATTERN.matcher(email); -// return matcher.matches(); -// } - -// private Grade extractGradeFromUsername(String username) { -// if (username.startsWith("小学-")) { -// return Grade.ELEMENTARY; -// } else if (username.startsWith("初中-")) { -// return Grade.MIDDLE; -// } else if (username.startsWith("高中-")) { -// return Grade.HIGH; -// } -// -// throw new IllegalArgumentException("无法识别的学段"); -// } } \ No newline at end of file diff --git a/src/main/java/com/pair/ui/GradeSelectPanel.java b/src/main/java/com/pair/ui/GradeSelectPanel.java deleted file mode 100644 index 83c9d8c..0000000 --- a/src/main/java/com/pair/ui/GradeSelectPanel.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.pair.ui; - -import javafx.scene.layout.VBox; - -public class GradeSelectPanel extends VBox { - -} \ No newline at end of file diff --git a/src/main/java/com/pair/ui/MainWindow.java b/src/main/java/com/pair/ui/MainWindow.java index f44a851..884c90c 100644 --- a/src/main/java/com/pair/ui/MainWindow.java +++ b/src/main/java/com/pair/ui/MainWindow.java @@ -2,6 +2,7 @@ package com.pair.ui; import com.pair.model.User; +import com.pair.service.FileIOService; import com.pair.service.QuizService; import com.pair.service.UserService; import com.pair.util.AsyncRegistrationHelper; @@ -15,8 +16,8 @@ import javafx.stage.Stage; import java.io.IOException; public class MainWindow extends BorderPane { - private final UserService userService = new UserService(); - private final QuizService quizService = new QuizService(); + private final UserService userService; + private final QuizService quizService; private User currentUser; private final Stage primaryStage; @@ -24,6 +25,8 @@ public class MainWindow extends BorderPane { public MainWindow(Stage primaryStage) throws IOException { this.primaryStage = primaryStage; + this.userService = new UserService(); + this.quizService = new QuizService(new FileIOService(), userService); showStartPage(); } diff --git a/src/main/java/com/pair/ui/ResultPage.java b/src/main/java/com/pair/ui/ResultPage.java index c82b922..1874219 100644 --- a/src/main/java/com/pair/ui/ResultPage.java +++ b/src/main/java/com/pair/ui/ResultPage.java @@ -52,6 +52,7 @@ public class ResultPage extends NavigablePanel { public void updateResult() { QuizResult result = quizService.calculateResult(); + quizService.saveQuizHistory(); resultLabel.setText(result.toString()); gradeLabel.setText(quizService.getGrade(result)); } diff --git a/src/main/java/com/pair/util/AsyncRegistrationHelper.java b/src/main/java/com/pair/util/AsyncRegistrationHelper.java index b854424..03488d1 100644 --- a/src/main/java/com/pair/util/AsyncRegistrationHelper.java +++ b/src/main/java/com/pair/util/AsyncRegistrationHelper.java @@ -4,6 +4,7 @@ package com.pair.util; import com.pair.service.UserService; import javafx.application.Platform; import javafx.concurrent.Task; +import javafx.concurrent.WorkerStateEvent; import java.io.IOException; import java.util.function.Consumer; @@ -51,13 +52,16 @@ public class AsyncRegistrationHelper { }).start(); }); - task.setOnFailed(e -> { + task.setOnFailed((WorkerStateEvent e) -> { Throwable ex = task.getException(); - String msg = switch (ex) { - case IllegalArgumentException iae -> iae.getMessage(); - case IOException ioe -> "系统错误:" + ioe.getMessage(); - default -> "发送失败,请检查网络或稍后重试"; - }; + String msg; + if (ex instanceof IllegalArgumentException iae) { + msg = iae.getMessage(); + } else if (ex instanceof IOException ioe) { + msg = "系统错误:" + ioe.getMessage(); + } else { + msg = "发送失败,请检查网络或稍后重试"; + } onFailure.accept(msg); Platform.runLater(onComplete); }); diff --git a/src/main/java/com/pair/util/EmailUtil.java b/src/main/java/com/pair/util/EmailUtil.java index c9df9e0..5766db5 100644 --- a/src/main/java/com/pair/util/EmailUtil.java +++ b/src/main/java/com/pair/util/EmailUtil.java @@ -61,6 +61,7 @@ public class EmailUtil { return new PasswordAuthentication(SENDER_EMAIL, SENDER_PASSWORD); } }); + session.setDebug(true); // 3. 创建邮件 Message message = new MimeMessage(session); @@ -88,38 +89,4 @@ public class EmailUtil { } - /** - * 发送密码重置邮件(预留接口) - * - * @param toEmail 收件人邮箱 - * @param newPassword 新密码 - * @return true表示发送成功 - */ - public static boolean sendPasswordReset(String toEmail, String newPassword) { - // TODO: 将来如果需要"找回密码"功能,可以在这里实现 - - System.out.println("【模拟】发送密码重置邮件"); - System.out.println("收件人: " + toEmail); - System.out.println("新密码: " + newPassword); - - return true; - } - } - - /** - * 验证邮箱格式 - * @param email 邮箱地址 - * @return true表示格式正确 - */ -// public static boolean isValidEmail(String email) { -// if (email == null || email.trim().isEmpty()) { -// return false; -// } -// -// // 简单的邮箱格式验证 -// String emailRegex = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"; -// return email.matches(emailRegex); -// } -//} - diff --git a/src/main/java/com/pair/util/PasswordValidator.java b/src/main/java/com/pair/util/PasswordValidator.java index b183fbf..cd0d972 100644 --- a/src/main/java/com/pair/util/PasswordValidator.java +++ b/src/main/java/com/pair/util/PasswordValidator.java @@ -144,99 +144,4 @@ public class PasswordValidator { return RandomUtils.shuffleString(code.toString()); } -// /** -// * 生成固定长度的随机密码 -// * -// * @param length 密码长度 -// * @param includeSpecialChars 是否包含特殊字符 -// * @return 随机密码 -// */ -// public static String generateRandomPassword(int length, boolean includeSpecialChars) { -// if (length < MIN_LENGTH) { -// throw new IllegalArgumentException("密码长度不能少于 " + MIN_LENGTH); -// } -// -// String chars = ALL_CHARS; -// if (includeSpecialChars) { -// chars += "!@#$%^&*()_+-=[]{}"; -// } -// -// StringBuilder password = new StringBuilder(length); -// -// // 确保至少包含一个字母和一个数字 -// password.append(UPPERCASE.charAt(random.nextInt(UPPERCASE.length()))); -// password.append(DIGITS.charAt(random.nextInt(DIGITS.length()))); -// -// // 填充剩余字符 -// for (int i = 2; i < length; i++) { -// password.append(chars.charAt(random.nextInt(chars.length()))); -// } -// -// return shuffleString(password.toString()); -// } - - // ==================== 工具方法 ==================== -// -// /** -// * 打乱字符串(使用 Fisher-Yates 算法) -// * -// * @param str 原字符串 -// * @return 打乱后的字符串 -// */ -// private static String shuffleString(String str) { -// if (str == null || str.length() <= 1) { -// return str; -// } -// -// char[] chars = str.toCharArray(); -// -// for (int i = chars.length - 1; i > 0; i--) { -// int j = random.nextInt(i + 1); -// -// // 交换 -// char temp = chars[i]; -// chars[i] = chars[j]; -// chars[j] = temp; -// } -// -// return new String(chars); -// } - -// /** -// * 检查密码是否包含常见弱密码 -// * -// * @param password 密码 -// * @return true表示是弱密码 -// */ -// public static boolean isWeakPassword(String password) { -// if (password == null) { -// return true; -// } -// -// String lowerPassword = password.toLowerCase(); -// -// // 常见弱密码列表 -// String[] weakPasswords = { -// "123456", "password", "123456789", "12345678", "12345", -// "111111", "1234567", "sunshine", "qwerty", "iloveyou", -// "princess", "admin", "welcome", "666666", "abc123", -// "football", "123123", "monkey", "654321", "!@#$%^&*", -// "charlie", "aa123456", "donald", "password1", "qwerty123" -// }; -// -// for (String weak : weakPasswords) { -// if (lowerPassword.equals(weak) || lowerPassword.contains(weak)) { -// return true; -// } -// } -// -// // 检查是否是连续数字或字母 -// if (password.matches("^(\\d)\\1+$") || // 全是相同数字 -// password.matches("^(.)\\1+$") || // 全是相同字符 -// password.matches("^(0123456789|123456789|987654321|abcdefghij|qwertyuiop).*")) { // 连续字符 -// return true; -// } -// -// return false; -// } } \ No newline at end of file -- 2.34.1 From 7c3b83f78938019456b3a2b01ca1eb64a30130e8 Mon Sep 17 00:00:00 2001 From: lsbp <2803234009@qq.com> Date: Wed, 8 Oct 2025 23:36:21 +0800 Subject: [PATCH 2/5] =?UTF-8?q?UI=E4=BF=AE=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .idea/workspace.xml | 22 +- src/main/java/com/pair/ui/InfGenPage.java | 123 ++----- src/main/java/com/pair/ui/LoginPage.java | 30 +- src/main/java/com/pair/ui/MainWindow.java | 1 - src/main/java/com/pair/ui/NavigablePanel.java | 10 +- .../java/com/pair/ui/PasswordModifyPage.java | 24 +- src/main/java/com/pair/ui/QuizPage.java | 320 +++++++----------- src/main/java/com/pair/ui/RegisterPage.java | 31 +- src/main/java/com/pair/ui/ResultPage.java | 41 +-- src/main/java/com/pair/ui/StartPage.java | 26 +- src/main/java/com/pair/ui/StyleHelper.java | 26 ++ src/main/java/com/pair/ui/UIConstants.java | 116 ++++--- 12 files changed, 317 insertions(+), 453 deletions(-) create mode 100644 src/main/java/com/pair/ui/StyleHelper.java diff --git a/.idea/workspace.xml b/.idea/workspace.xml index 6851aea..4b04394 100644 --- a/.idea/workspace.xml +++ b/.idea/workspace.xml @@ -10,17 +10,18 @@ - - + - - - - + - + + + + + +