package com.example.mathsystemtogether; import javafx.fxml.FXML; import javafx.fxml.FXMLLoader; import javafx.scene.Scene; import javafx.scene.control.*; import javafx.stage.Stage; import javafx.collections.FXCollections; import javafx.collections.ObservableList; import java.util.*; import java.util.regex.Pattern; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; import java.nio.file.StandardOpenOption; /** * 注册控制器 */ public class RegisterController { @FXML private TextField usernameField; @FXML private PasswordField passwordField; @FXML private PasswordField confirmPasswordField; @FXML private TextField emailField; @FXML private TextField verificationCodeField; @FXML private Button sendCodeButton; @FXML private Button registerButton; @FXML private Button backToLoginButton; @FXML private ComboBox levelComboBox; @FXML private Label statusLabel; // 验证码相关 private String generatedCode; private long codeGenerationTime; private static final int CODE_VALIDITY_MINUTES = 5; private static final String EMAIL_REGEX = "^[A-Za-z0-9+_.-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}$"; private static final Pattern EMAIL_PATTERN = Pattern.compile(EMAIL_REGEX); // 密码强度验证正则表达式 private static final String PASSWORD_REGEX = "^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).+$"; private static final Pattern PASSWORD_PATTERN = Pattern.compile(PASSWORD_REGEX); // 用户数据文件路径 private static final String USER_DATA_FILE = "user_data.txt"; // 邮件服务 private EmailService emailService; @FXML public void initialize() { setupLevelComboBox(); // 初始化时禁用注册按钮 registerButton.setDisable(true); // 初始化邮件服务 emailService = new EmailService(); // 检查邮件服务配置 if (!emailService.isAvailable()) { showStatus("⚠️ 邮件服务未配置,请检查mail.properties文件", true); } } private void setupLevelComboBox() { ObservableList levels = FXCollections.observableArrayList("小学", "初中", "高中"); levelComboBox.setItems(levels); levelComboBox.setValue("小学"); } @FXML private void handleSendCode() { String email = emailField.getText().trim(); if (email.isEmpty()) { showStatus("请输入邮箱地址", true); return; } if (!isValidEmail(email)) { showStatus("请输入有效的邮箱地址", true); return; } // 检查邮件服务是否可用 if (!emailService.isAvailable()) { showStatus("❌ 邮件服务不可用,请检查配置", true); return; } // 生成6位数字验证码 generatedCode = emailService.generateVerificationCode(); codeGenerationTime = System.currentTimeMillis(); // 发送真实邮件 showStatus("📤 正在发送验证码到邮箱:" + email + ",请稍候...", false); // 在后台线程中发送邮件 new Thread(() -> { boolean success = emailService.sendVerificationCode(email, generatedCode); javafx.application.Platform.runLater(() -> { if (success) { showStatus("✅ 验证码已发送到邮箱:" + email + ",请查收邮件", false); // 启用注册按钮 registerButton.setDisable(false); } else { showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试", true); // 显示验证码用于调试(仅开发环境) showStatus("❌ 邮件发送失败,请检查邮箱地址或稍后重试。验证码:" + generatedCode + "(调试用)", true); } }); }).start(); // 禁用发送按钮60秒 sendCodeButton.setDisable(true); sendCodeButton.setText("60秒后可重发"); // 启动倒计时 startCountdown(); } @FXML private void handleRegister() { String username = usernameField.getText().trim(); String password = passwordField.getText(); String confirmPassword = confirmPasswordField.getText(); String email = emailField.getText().trim(); String verificationCode = verificationCodeField.getText().trim(); String level = levelComboBox.getValue(); // 验证输入 if (username.isEmpty() || password.isEmpty() || confirmPassword.isEmpty() || email.isEmpty() || verificationCode.isEmpty()) { showStatus("请填写所有字段", true); return; } if (username.length() < 3) { showStatus("用户名至少需要3个字符", true); return; } if (password.length() < 6) { showStatus("密码至少需要6个字符", true); return; } if (!isValidPassword(password)) { showStatus("密码必须包含大小写字母和数字", true); return; } if (!password.equals(confirmPassword)) { showStatus("两次输入的密码不一致", true); return; } if (!isValidEmail(email)) { showStatus("请输入有效的邮箱地址", true); return; } // 验证验证码 if (!verifyCode(verificationCode)) { showStatus("验证码错误或已过期", true); return; } // 检查用户名是否已存在 if (isUserExists(username)) { showStatus("用户名已存在,请选择其他用户名", true); return; } // 检查邮箱是否已注册 if (isEmailExists(email)) { showStatus("该邮箱已被注册", true); return; } // 保存用户信息 if (saveUserData(username, password, email, level)) { showStatus("注册成功!正在跳转到登录界面...", false); // 延迟跳转到登录界面 Timer timer = new Timer(); timer.schedule(new TimerTask() { @Override public void run() { javafx.application.Platform.runLater(() -> { handleBackToLogin(); }); } }, 2000); } else { showStatus("注册失败,请重试", true); } } @FXML private void handleBackToLogin() { try { // 关闭当前窗口 Stage currentStage = (Stage) backToLoginButton.getScene().getWindow(); currentStage.close(); // 打开登录界面 FXMLLoader loader = new FXMLLoader(getClass().getResource("exam-view.fxml")); Scene scene = new Scene(loader.load(), 900, 900); Stage loginStage = new Stage(); loginStage.setTitle("数学考试系统 - 登录"); loginStage.setScene(scene); loginStage.setResizable(true); loginStage.show(); } catch (Exception e) { showStatus("跳转失败:" + e.getMessage(), true); } } private boolean verifyCode(String inputCode) { if (generatedCode == null) { return false; } // 检查验证码是否过期 long currentTime = System.currentTimeMillis(); long elapsedMinutes = (currentTime - codeGenerationTime) / (1000 * 60); if (elapsedMinutes > CODE_VALIDITY_MINUTES) { return false; } return generatedCode.equals(inputCode); } private boolean isValidEmail(String email) { return EMAIL_PATTERN.matcher(email).matches(); } /** * 验证密码强度 * 密码必须包含至少一个小写字母、一个大写字母和一个数字 */ private boolean isValidPassword(String password) { return PASSWORD_PATTERN.matcher(password).matches(); } private boolean isUserExists(String username) { try { if (!Files.exists(Paths.get(USER_DATA_FILE))) { return false; } List lines = Files.readAllLines(Paths.get(USER_DATA_FILE)); for (String line : lines) { if (line.startsWith(username + "|")) { return true; } } } catch (IOException e) { System.err.println("检查用户存在性时出错:" + e.getMessage()); } return false; } private boolean isEmailExists(String email) { try { if (!Files.exists(Paths.get(USER_DATA_FILE))) { return false; } List lines = Files.readAllLines(Paths.get(USER_DATA_FILE)); for (String line : lines) { String[] parts = line.split("\\|"); if (parts.length >= 3 && parts[2].equals(email)) { return true; } } } catch (IOException e) { System.err.println("检查邮箱存在性时出错:" + e.getMessage()); } return false; } private boolean saveUserData(String username, String password, String email, String level) { try { String userData = username + "|" + password + "|" + email + "|" + level + "|" + System.currentTimeMillis() + "\n"; Files.write(Paths.get(USER_DATA_FILE), userData.getBytes(), StandardOpenOption.CREATE, StandardOpenOption.APPEND); return true; } catch (IOException e) { System.err.println("保存用户数据时出错:" + e.getMessage()); return false; } } private void showStatus(String message, boolean isError) { statusLabel.setText(message); if (isError) { statusLabel.setStyle("-fx-text-fill: #DC143C; -fx-font-weight: bold; -fx-font-size: 14;"); } else { statusLabel.setStyle("-fx-text-fill: #228B22; -fx-font-weight: bold; -fx-font-size: 14;"); } } private void startCountdown() { Timer timer = new Timer(); timer.schedule(new TimerTask() { int countdown = 60; @Override public void run() { javafx.application.Platform.runLater(() -> { if (countdown > 0) { sendCodeButton.setText(countdown + "秒后可重发"); countdown--; } else { sendCodeButton.setDisable(false); sendCodeButton.setText("📤 发送验证码"); timer.cancel(); } }); } }, 0, 1000); } }