You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
MathSystem2/src/main/java/com/example/mathsystemtogether/RegisterController.java

328 lines
11 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

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<String> 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<String> 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<String> 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<String> 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);
}
}