diff --git a/src/main/java/com/mathquiz/Main.java b/src/main/java/com/mathquiz/Main.java deleted file mode 100644 index e69de29..0000000 diff --git a/src/main/java/com/mathquiz/model/ChoiceQuestion.java b/src/main/java/com/mathquiz/model/ChoiceQuestion.java deleted file mode 100644 index e3dcb16..0000000 --- a/src/main/java/com/mathquiz/model/ChoiceQuestion.java +++ /dev/null @@ -1,141 +0,0 @@ -package com.mathquiz.model; - -import java.util.List; -import java.util.Objects; -import java.util.UUID; - -/** - * 选择题模型类 - * 表示一道完整的数学选择题,包含题干、选项、正确答案等信息 - */ -public class ChoiceQuestion { - - /** - * 题目唯一ID(UUID生成) - */ - private String questionId; - - /** - * 所属学段(小学 / 初中 / 高中) - */ - private Grade grade; - - /** - * 题干内容,例如:"2 + 3 × (4 - 1) = ?" - */ - private String questionContent; - - /** - * 选项列表,固定4个选项,顺序已随机打乱 - * 格式示例:["11", "10", "13", "9"] - */ - private List options; - - /** - * 正确答案标识,取值为 "A"、"B"、"C" 或 "D" - */ - private String correctAnswer; - - // ---------------- 构造函数 ---------------- - - /** - * 默认构造函数(用于 JSON 反序列化) - */ - public ChoiceQuestion() {} - - /** - * 全参构造函数 - */ - public ChoiceQuestion(String questionId, Grade grade, String questionContent, - List options, String correctAnswer) { - this.questionId = questionId; - this.grade = grade; - this.questionContent = questionContent; - this.options = options; - this.correctAnswer = correctAnswer; - } - - // ---------------- 静态工厂方法 ---------------- - - /** - * 创建一道新题目,自动分配 UUID 作为 questionId - * - * @param grade 年级 - * @param questionContent 题干 - * @param options 4个选项(顺序应已打乱) - * @param correctAnswer 正确答案("A"-"D") - * @return 新的 ChoiceQuestion 实例 - */ - public static ChoiceQuestion of(Grade grade, String questionContent, - List options, String correctAnswer) { - return new ChoiceQuestion(UUID.randomUUID().toString(), grade, questionContent, options, correctAnswer); - } - - // ---------------- Getter & Setter ---------------- - - public String getQuestionId() { - return questionId; - } - - public void setQuestionId(String questionId) { - this.questionId = questionId; - } - - public Grade getGrade() { - return grade; - } - - public void setGrade(Grade grade) { - this.grade = grade; - } - - public String getQuestionContent() { - return questionContent; - } - - public void setQuestionContent(String questionContent) { - this.questionContent = questionContent; - } - - public List getOptions() { - return options; - } - - public void setOptions(List options) { - this.options = options; - } - - public String getCorrectAnswer() { - return correctAnswer; - } - - public void setCorrectAnswer(String correctAnswer) { - this.correctAnswer = correctAnswer; - } - - // ---------------- Object 方法 ---------------- - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - ChoiceQuestion that = (ChoiceQuestion) o; - return Objects.equals(questionId, that.questionId); - } - - @Override - public int hashCode() { - return Objects.hash(questionId); - } - - @Override - public String toString() { - return "ChoiceQuestion{" + - "questionId='" + questionId + '\'' + - ", grade=" + grade + - ", questionContent='" + questionContent + '\'' + - ", options=" + options + - ", correctAnswer='" + correctAnswer + '\'' + - '}'; - } -} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/model/Grade.java b/src/main/java/com/mathquiz/model/Grade.java deleted file mode 100644 index ede720f..0000000 --- a/src/main/java/com/mathquiz/model/Grade.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.mathquiz.model; - -/** - * 年级枚举,表示小学、初中、高中三个学段 - */ - -public enum Grade { - PRIMARY("小学", 1), - JUNIOR("初中", 2), - SENIOR("高中", 3); - - private final String displayName; - private final int level; - - Grade(String displayName, int level) { - this.displayName = displayName; - this.level = level; - } - - public String getDisplayName() { - return displayName; - } - - public int getLevel() { - return level; - } -} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/model/User.java b/src/main/java/com/mathquiz/model/User.java deleted file mode 100644 index d519167..0000000 --- a/src/main/java/com/mathquiz/model/User.java +++ /dev/null @@ -1,52 +0,0 @@ -package com.mathquiz.model; - -/** - * 用户类 - */ - -public class User { - private String name; - private String email; - private String encryptedPwd; - private Grade grade; - - public User() {} - - public User(String email, String encryptedPwd) { - this.email = email; - this.encryptedPwd = encryptedPwd; - } - - // Getter & Setter - public java.lang.String getName() { - return name; - } - - public void setName(java.lang.String name) { - this.name = name; - } - - public java.lang.String getEmail() { - return email; - } - - public void setEmail(java.lang.String email) { - this.email = email; - } - - public java.lang.String getEncryptedPwd() { - return encryptedPwd; - } - - public void setEncryptedPwd(java.lang.String encryptedPwd) { - this.encryptedPwd = encryptedPwd; - } - - public Grade getGrade() { - return grade; - } - - public void setGrade(Grade grade) { - this.grade = grade; - } -} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/GradeSelectPanel.java b/src/main/java/com/mathquiz/ui/GradeSelectPanel.java new file mode 100644 index 0000000..f210860 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/GradeSelectPanel.java @@ -0,0 +1,58 @@ +package com.mathquiz.ui; + +import com.mathquiz.model.Grade; +import com.mathquiz.service.QuizService; +import javafx.geometry.Insets; +import javafx.scene.control.Button; +import javafx.scene.control.TextInputDialog; +import javafx.scene.layout.VBox; + +public class GradeSelectPanel extends VBox { + + public GradeSelectPanel(MainWindow mainWindow) { + setPadding(new Insets(20)); + setSpacing(20); + + getChildren().addAll( + new Button("小学") {{ + setOnAction(e -> startQuiz(mainWindow, Grade.PRIMARY)); + }}, + new Button("初中") {{ + setOnAction(e -> startQuiz(mainWindow, Grade.JUNIOR)); + }}, + new Button("高中") {{ + setOnAction(e -> startQuiz(mainWindow, Grade.SENIOR)); + }}, + new Button("修改密码") {{ + setOnAction(e -> mainWindow.showPasswordModifyPanel()); + }} + ); + } + + private void startQuiz(MainWindow mainWindow, Grade grade) { + TextInputDialog dialog = new TextInputDialog("20"); + dialog.setTitle("题目数量"); + dialog.setHeaderText("请输入题目数量(10-30)"); + dialog.setContentText("数量:"); + + dialog.showAndWait().ifPresent(input -> { + try { + int count = Integer.parseInt(input); + if (count < 10 || count > 30) { + throw new NumberFormatException(); + } + + // 创建 QuizService(未来可注入) + QuizService quizService = new QuizService(grade, mainWindow.getFileIOService()); + var questions = quizService.generateQuestions( + mainWindow.getCurrentUser().getEmail(), count + ); + + mainWindow.showQuizPanel(questions, quizService); + + } catch (NumberFormatException e) { + new Alert(Alert.AlertType.ERROR, "请输入10-30之间的整数").showAndWait(); + } + }); + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/LoginPanel.java b/src/main/java/com/mathquiz/ui/LoginPanel.java new file mode 100644 index 0000000..5c06144 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/LoginPanel.java @@ -0,0 +1,44 @@ +package com.mathquiz.ui; + +import com.mathquiz.model.User; +import javafx.geometry.Insets; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; + +public class LoginPanel extends VBox { + + private final TextField emailField = new TextField(); + private final PasswordField pwdField = new PasswordField(); + + public LoginPanel(MainWindow mainWindow) { + setPadding(new Insets(20)); + setSpacing(10); + + getChildren().addAll( + new Label("登录"), + new Label("邮箱:"), + emailField, + new Label("密码:"), + pwdField, + new Button("登录") {{ + setOnAction(e -> loginAction(mainWindow)); + }}, + new Hyperlink("没有账号?去注册") {{ + setOnAction(e -> mainWindow.showRegisterPanel()); + }} + ); + } + + private void loginAction(MainWindow mainWindow) { + String email = emailField.getText().trim(); + String password = pwdField.getText(); + + User user = mainWindow.getUserService().login(email, password); + if (user != null) { + mainWindow.setCurrentUser(user); + mainWindow.showGradeSelectPanel(); + } else { + new Alert(Alert.AlertType.ERROR, "邮箱或密码错误").showAndWait(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/MainWindow.java b/src/main/java/com/mathquiz/ui/MainWindow.java new file mode 100644 index 0000000..52875e9 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/MainWindow.java @@ -0,0 +1,77 @@ +package com.mathquiz.ui; + +import com.mathquiz.model.User; +import com.mathquiz.service.*; +import javafx.scene.layout.BorderPane; +import javafx.stage.Stage; + +/** + * 主窗口控制器,持有所有服务引用和当前用户状态 + * 所有 UI 面板通过此窗口切换 + */ +public class MainWindow extends BorderPane { + + // 服务层引用(便于后期替换实现) + private final UserService userService; + private final FileIOService fileIOService; + private User currentUser; + + public MainWindow(Stage primaryStage) { + // 初始化服务(未来可替换为 DI 容器) + this.fileIOService = new FileIOService(); + this.userService = new UserService(fileIOService); + + // 默认显示登录页 + showLoginPanel(); + } + + // ---------------- 公共方法:面板切换 ---------------- + + public void showPanel(javafx.scene.layout.Pane panel) { + this.setCenter(panel); + } + + public void showLoginPanel() { + showPanel(new LoginPanel(this)); + } + + public void showRegisterPanel() { + showPanel(new RegisterPanel(this)); + } + + public void showPasswordModifyPanel() { + if (currentUser != null) { + showPanel(new PasswordModifyPanel(this, currentUser.getEmail())); + } + } + + public void showGradeSelectPanel() { + showPanel(new GradeSelectPanel(this)); + } + + public void showQuizPanel(java.util.List questions, QuizService quizService) { + showPanel(new QuizPanel(this, questions, quizService)); + } + + public void showResultPanel(int score, Runnable onContinue) { + showPanel(new ResultPanel(this, score, onContinue)); + } + + // ---------------- Getter ---------------- + + public UserService getUserService() { + return userService; + } + + public FileIOService getFileIOService() { + return fileIOService; + } + + public User getCurrentUser() { + return currentUser; + } + + public void setCurrentUser(User user) { + this.currentUser = user; + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/PasswordModifyPanel.java b/src/main/java/com/mathquiz/ui/PasswordModifyPanel.java new file mode 100644 index 0000000..bea9dd0 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/PasswordModifyPanel.java @@ -0,0 +1,46 @@ +package com.mathquiz.ui; + +import javafx.geometry.Insets; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; + +public class PasswordModifyPanel extends VBox { + + private final String email; + private final PasswordField oldPwdField = new PasswordField(); + private final PasswordField newPwd1Field = new PasswordField(); + private final PasswordField newPwd2Field = new PasswordField(); + + public PasswordModifyPanel(MainWindow mainWindow, String email) { + this.email = email; + setPadding(new Insets(20)); + setSpacing(10); + + getChildren().addAll( + new Label("修改密码"), + new Label("原密码:"), + oldPwdField, + new Label("新密码(6-10位,含大小写+数字):"), + newPwd1Field, + new Label("确认新密码:"), + newPwd2Field, + new Button("确认修改") {{ + setOnAction(e -> changePassword(mainWindow)); + }}, + new Button("返回") {{ + setOnAction(e -> mainWindow.showGradeSelectPanel()); + }} + ); + } + + private void changePassword(MainWindow mainWindow) { + boolean success = mainWindow.getUserService() + .changePassword(email, oldPwdField.getText(), newPwd1Field.getText(), newPwd2Field.getText()); + if (success) { + new Alert(Alert.AlertType.INFORMATION, "密码修改成功!").showAndWait(); + mainWindow.showGradeSelectPanel(); + } else { + new Alert(Alert.AlertType.ERROR, "原密码错误或新密码不符合要求").showAndWait(); + } + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/QuizPanel.java b/src/main/java/com/mathquiz/ui/QuizPanel.java new file mode 100644 index 0000000..9100c25 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/QuizPanel.java @@ -0,0 +1,67 @@ +package com.mathquiz.ui; + +import com.mathquiz.model.ChoiceQuestion; +import com.mathquiz.service.QuizService; +import javafx.geometry.Insets; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; + +import java.util.ArrayList; +import java.util.List; + +public class QuizPanel extends VBox { + + private final List questions; + private final List userAnswers = new ArrayList<>(); + private final QuizService quizService; + private final MainWindow mainWindow; + private int currentIndex = 0; + + public QuizPanel(MainWindow mainWindow, List questions, QuizService quizService) { + this.mainWindow = mainWindow; + this.questions = questions; + this.quizService = quizService; + setPadding(new Insets(20)); + showQuestion(currentIndex); + } + + private void showQuestion(int index) { + getChildren().clear(); + ChoiceQuestion q = questions.get(index); + + getChildren().add(new Label("第 " + (index + 1) + " 题 / " + questions.size())); + getChildren().add(new Label(q.getQuestionContent())); + + ToggleGroup group = new ToggleGroup(); + for (int i = 0; i < 4; i++) { + RadioButton rb = new RadioButton( + (char)('A' + i) + ". " + q.getOptions().get(i) + ); + rb.setToggleGroup(group); + getChildren().add(rb); + } + + Button submitBtn = new Button("提交"); + submitBtn.setOnAction(e -> { + RadioButton selected = (RadioButton) group.getSelectedToggle(); + if (selected != null) { + String answer = selected.getText().substring(0, 1); // "A" + userAnswers.add(answer); + + if (index + 1 < questions.size()) { + showQuestion(index + 1); + } else { + int score = quizService.calculateScore(questions, userAnswers); + Runnable onContinue = () -> { + quizService.savePaper(mainWindow.getCurrentUser().getEmail(), questions); + }; + mainWindow.showResultPanel(score, onContinue); + } + } else { + new Alert(Alert.AlertType.WARNING, "请选择一个选项").showAndWait(); + } + }); + + getChildren().add(submitBtn); + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/RegisterPanel.java b/src/main/java/com/mathquiz/ui/RegisterPanel.java new file mode 100644 index 0000000..27ae653 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/RegisterPanel.java @@ -0,0 +1,80 @@ +package com.mathquiz.ui; + +import com.mathquiz.util.EmailUtil; +import javafx.geometry.Insets; +import javafx.scene.control.*; +import javafx.scene.layout.VBox; + +/** + * 注册面板 + */ +public class RegisterPanel extends VBox { + + private final TextField emailField = new TextField(); + private final TextField codeField = new TextField(); + private final PasswordField pwd1Field = new PasswordField(); + private final PasswordField pwd2Field = new PasswordField(); + + public RegisterPanel(MainWindow mainWindow) { + setPadding(new Insets(20)); + setSpacing(10); + + getChildren().addAll( + new Label("注册"), + new Label("邮箱:"), + emailField, + new Button("发送注册码") {{ + setOnAction(e -> sendCodeAction(mainWindow)); + }}, + new Label("注册码:"), + codeField, + new Label("密码(6-10位,含大小写+数字):"), + pwd1Field, + new Label("确认密码:"), + pwd2Field, + new Button("完成注册") {{ + setOnAction(e -> registerAction(mainWindow)); + }}, + new Hyperlink("已有账号?去登录") {{ + setOnAction(e -> mainWindow.showLoginPanel()); + }} + ); + } + + private void sendCodeAction(MainWindow mainWindow) { + String email = emailField.getText().trim(); + if (email.isEmpty() || !EmailUtil.isValidEmail(email)) { + showAlert("请输入有效的邮箱地址"); + return; + } + // 调用服务层 + boolean sent = mainWindow.getUserService().sendRegistrationCode(email); + if (sent) { + showAlert("注册码已发送(模拟)"); + } + } + + private void registerAction(MainWindow mainWindow) { + String email = emailField.getText().trim(); + String code = codeField.getText().trim(); + String pwd1 = pwd1Field.getText(); + String pwd2 = pwd2Field.getText(); + + if (!mainWindow.getUserService().verifyCode(email, code)) { + showAlert("注册码错误"); + return; + } + + boolean success = mainWindow.getUserService().setPassword(email, pwd1, pwd2); + if (success) { + showAlert("注册成功!"); + mainWindow.showGradeSelectPanel(); + } else { + showAlert("密码不符合要求(6-10位,含大小写字母和数字)"); + } + } + + private void showAlert(String message) { + new Alert(Alert.AlertType.INFORMATION, message).showAndWait(); + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/ui/ResultPanel.java b/src/main/java/com/mathquiz/ui/ResultPanel.java new file mode 100644 index 0000000..b94f202 --- /dev/null +++ b/src/main/java/com/mathquiz/ui/ResultPanel.java @@ -0,0 +1,32 @@ +package com.mathquiz.ui; + +import javafx.geometry.Insets; +import javafx.scene.control.Alert; +import javafx.scene.control.Button; +import javafx.scene.control.Label; +import javafx.scene.layout.VBox; + +public class ResultPanel extends VBox { + + public ResultPanel(MainWindow mainWindow, int score, Runnable onContinue) { + setPadding(new Insets(20)); + setSpacing(20); + + getChildren().addAll( + new Label("答题结束!"), + new Label("您的得分: " + score + " 分"), + new Button("继续做题") {{ + setOnAction(e -> { + onContinue.run(); // 保存试卷 + mainWindow.showGradeSelectPanel(); + }); + }}, + new Button("退出") {{ + setOnAction(e -> { + mainWindow.setCurrentUser(null); + mainWindow.showLoginPanel(); + }); + }} + ); + } +} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/util/EmailUtil.java b/src/main/java/com/mathquiz/util/EmailUtil.java deleted file mode 100644 index ff915ac..0000000 --- a/src/main/java/com/mathquiz/util/EmailUtil.java +++ /dev/null @@ -1,109 +0,0 @@ -package com.util; - -/** - * 邮件工具类 - * 用于发送注册码邮件(可选功能) - * 注意:当前项目需求中,注册码是直接显示在界面上的, - * 不需要发送邮件,所以这个类暂时保留为空实现。 - * 如果将来需要发送邮件,可以使用JavaMail库实现。 - */ -public class EmailUtil { - - /** - * 发送注册码邮件(预留接口) - * @param toEmail 收件人邮箱 - * @param registrationCode 注册码 - * @return true表示发送成功 - */ - public static boolean sendRegistrationCode(String toEmail, String registrationCode) { - // TODO: 暂不实现邮件发送功能 - // 原因:项目需求是直接在界面显示注册码,不需要发邮件 - - System.out.println("【模拟】发送注册码邮件"); - System.out.println("收件人: " + toEmail); - System.out.println("注册码: " + registrationCode); - - return true; - } - - /** - * 发送密码重置邮件(预留接口) - * @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); - } -} - -/* - * 如果将来需要真正实现邮件发送,可以参考以下代码: - * - * 1. 在pom.xml添加依赖: - * - * javax.mail - * javax.mail-api - * 1.6.2 - * - * - * com.sun.mail - * javax.mail - * 1.6.2 - * - * - * 2. 实现代码示例: - * - * import javax.mail.*; - * import javax.mail.internet.*; - * import java.util.Properties; - * - * public static boolean sendEmail(String toEmail, String subject, String content) { - * try { - * Properties props = new Properties(); - * props.put("mail.smtp.auth", "true"); - * props.put("mail.smtp.starttls.enable", "true"); - * props.put("mail.smtp.host", "smtp.qq.com"); - * props.put("mail.smtp.port", "587"); - * - * Session session = Session.getInstance(props, new Authenticator() { - * protected PasswordAuthentication getPasswordAuthentication() { - * return new PasswordAuthentication("your-email@qq.com", "your-password"); - * } - * }); - * - * Message message = new MimeMessage(session); - * message.setFrom(new InternetAddress("your-email@qq.com")); - * message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); - * message.setSubject(subject); - * message.setText(content); - * - * Transport.send(message); - * return true; - * } catch (Exception e) { - * e.printStackTrace(); - * return false; - * } - * } - */ \ No newline at end of file diff --git a/src/main/java/com/mathquiz/util/FileUtils.java b/src/main/java/com/mathquiz/util/FileUtils.java deleted file mode 100644 index d4daf9e..0000000 --- a/src/main/java/com/mathquiz/util/FileUtils.java +++ /dev/null @@ -1,111 +0,0 @@ -package com.util; - -import java.io.*; -import java.nio.charset.StandardCharsets; -import java.nio.file.*; - -/** - * 文件操作工具类 - * 提供文件读写、目录创建等常用操作 - */ -public class FileUtils { - - /** - * 读取文件内容为字符串 - * @param filePath 文件路径 - * @return 文件内容 - * @throws IOException 读取失败时抛出 - */ - public static String readFileToString(String filePath) throws IOException { - return Files.readString(Paths.get(filePath), StandardCharsets.UTF_8); - } - - /** - * 写入字符串到文件 - * @param filePath 文件路径 - * @param content 要写入的内容 - * @throws IOException 写入失败时抛出 - */ - public static void writeStringToFile(String filePath, String content) throws IOException { - Files.writeString(Paths.get(filePath), content, StandardCharsets.UTF_8); - } - - /** - * 创建目录(如果不存在) - * @param dirPath 目录路径 - * @throws IOException 创建失败时抛出 - */ - public static void createDirectoryIfNotExists(String dirPath) throws IOException { - Path path = Paths.get(dirPath); - if (!Files.exists(path)) { - Files.createDirectories(path); - } - } - - /** - * 检查文件是否存在 - * @param filePath 文件路径 - * @return true表示存在 - */ - public static boolean exists(String filePath) { - return Files.exists(Paths.get(filePath)); - } - - /** - * 删除文件 - * @param filePath 文件路径 - * @return true表示删除成功 - */ - public static boolean deleteFile(String filePath) { - try { - return Files.deleteIfExists(Paths.get(filePath)); - } catch (IOException e) { - e.printStackTrace(); - return false; - } - } - - /** - * 获取目录下所有文件 - * @param dirPath 目录路径 - * @return 文件数组 - */ - public static File[] listFiles(String dirPath) { - File dir = new File(dirPath); - if (dir.exists() && dir.isDirectory()) { - return dir.listFiles(); - } - return new File[0]; - } - - /** - * 追加内容到文件末尾 - * @param filePath 文件路径 - * @param content 要追加的内容 - * @throws IOException 追加失败时抛出 - */ - public static void appendToFile(String filePath, String content) throws IOException { - Files.writeString(Paths.get(filePath), content, StandardCharsets.UTF_8, - StandardOpenOption.CREATE, StandardOpenOption.APPEND); - } - - /** - * 复制文件 - * @param sourcePath 源文件路径 - * @param targetPath 目标文件路径 - * @throws IOException 复制失败时抛出 - */ - public static void copyFile(String sourcePath, String targetPath) throws IOException { - Files.copy(Paths.get(sourcePath), Paths.get(targetPath), StandardCopyOption.REPLACE_EXISTING); - } - - /** - * 获取文件大小(字节) - * @param filePath 文件路径 - * @return 文件大小 - * @throws IOException 获取失败时抛出 - */ - public static long getFileSize(String filePath) throws IOException { - return Files.size(Paths.get(filePath)); - } -} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/util/PasswordValidator.java b/src/main/java/com/mathquiz/util/PasswordValidator.java deleted file mode 100644 index 40a26b5..0000000 --- a/src/main/java/com/mathquiz/util/PasswordValidator.java +++ /dev/null @@ -1,102 +0,0 @@ -package com.util; - -import java.security.MessageDigest; -import java.security.NoSuchAlgorithmException; - -/** - * 密码验证和加密工具类 - * 提供密码格式验证、加密、匹配等功能 - */ -public class PasswordValidator { - - /** - * 验证密码格式:6-10位,包含字母和数字 - * @param password 待验证的密码 - * @return true表示格式正确 - */ - public static boolean isValid(String password) { - if (password == null || password.length() < 6 || password.length() > 10) { - return false; - } - - boolean hasLetter = password.matches("^(?=.*[a-z])(?=.*[A-Z]).*$"); - boolean hasDigit = password.matches(".*\\d.*"); - - return hasLetter && hasDigit; - } - - /** - * 使用SHA-256加密密码 - * @param password 明文密码 - * @return 加密后的密码(16进制字符串) - */ - public static String encrypt(String password) { - try { - MessageDigest digest = MessageDigest.getInstance("SHA-256"); - byte[] hash = digest.digest(password.getBytes()); - StringBuilder hexString = new StringBuilder(); - - for (byte b : hash) { - String hex = Integer.toHexString(0xff & b); - if (hex.length() == 1) { - hexString.append('0'); - } - hexString.append(hex); - } - - return hexString.toString(); - } catch (NoSuchAlgorithmException e) { - throw new RuntimeException("SHA-256算法不可用", e); - } - } - - /** - * 验证密码是否匹配 - * @param plainPassword 明文密码 - * @param encryptedPassword 加密后的密码 - * @return true表示匹配 - */ - public static boolean matches(String plainPassword, String encryptedPassword) { - return encrypt(plainPassword).equals(encryptedPassword); - } - - /** - * 生成6-10位随机注册码(包含字母和数字) - * @return 注册码 - */ - public static String generateRegistrationCode() { - String chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"; - int length = 6 + (int) (Math.random() * 5); // 6-10位 - - StringBuilder code = new StringBuilder(); - - // 确保至少有一个字母 - code.append(chars.charAt((int) (Math.random() * 52))); - // 确保至少有一个数字 - code.append(chars.charAt(52 + (int) (Math.random() * 10))); - - // 填充剩余字符 - for (int i = 2; i < length; i++) { - code.append(chars.charAt((int) (Math.random() * chars.length()))); - } - - // 打乱字符顺序 - return shuffleString(code.toString()); - } - - /** - * 打乱字符串 - * @param str 原字符串 - * @return 打乱后的字符串 - */ - private static String shuffleString(String str) { - char[] chars = str.toCharArray(); - for (int i = chars.length - 1; i > 0; i--) { - int j = (int) (Math.random() * (i + 1)); - char temp = chars[i]; - chars[i] = chars[j]; - chars[j] = temp; - } - return new String(chars); - } -} \ No newline at end of file diff --git a/src/main/java/com/mathquiz/util/RandomUtils.java b/src/main/java/com/mathquiz/util/RandomUtils.java deleted file mode 100644 index c7351b9..0000000 --- a/src/main/java/com/mathquiz/util/RandomUtils.java +++ /dev/null @@ -1,69 +0,0 @@ -package com.util; - -import java.util.Collections; -import java.util.List; -import java.util.Random; - -//各种随机数生成 -public class RandomUtils { - private static final Random random = new Random(); - - - //生成[min, max]范围内的随机整数(包含边界) - public static int nextInt(int min, int max) { - if (min > max) { - throw new IllegalArgumentException("min不能大于max"); - } - return min + random.nextInt(max - min + 1); - } - - - //从数组中随机选择一个元素(模板类) - public static T randomChoice(T[] array) { - if (array == null || array.length == 0) { - throw new IllegalArgumentException("数组不能为空"); - } - return array[random.nextInt(array.length)]; - } - - - //从列表中随机选择一个元素 - public static T randomChoice(List list) { - if (list == null || list.isEmpty()) { - throw new IllegalArgumentException("列表不能为空"); - } - return list.get(random.nextInt(list.size())); - } - - /** - * 打乱列表顺序 - * @param list 要打乱的列表 - */ - public static void shuffle(List list) { - Collections.shuffle(list, random); - } - - - //生成指定范围内的随机双精度浮点数 - public static double nextDouble(double min, double max) { - if (min > max) { - throw new IllegalArgumentException("min不能大于max"); - } - return min + (max - min) * random.nextDouble(); - } - - - //生成随机布尔值 - public static boolean nextBoolean() { - return random.nextBoolean(); - } - - //按概率返回true(题目生成概率) - //示例:probability(0.7) 有70%概率返回true - public static boolean probability(double probability) { - if (probability < 0.0 || probability > 1.0) { - throw new IllegalArgumentException("概率必须在0.0-1.0之间"); - } - return random.nextDouble() < probability; - } -} \ No newline at end of file