userList = new ArrayList<>(usersByEmail.values());
+ oos.writeObject(userList);
+ System.out.println("成功保存 " + userList.size() + " 个用户数据");
+ } catch (IOException e) {
+ System.err.println("保存用户数据失败: " + e.getMessage());
+ JOptionPane.showMessageDialog(null,
+ "用户数据保存失败: " + e.getMessage(),
+ "错误",
+ JOptionPane.ERROR_MESSAGE);
+ }
}
private void addUser(String username, String email, String password) {
@@ -265,6 +517,17 @@ class UserManager {
usersByUsername.put(username, user);
}
+ // 在UserManager类中添加新的updatePasswordByUsername方法
+ public boolean updatePasswordByUsername(String username, String oldPassword, String newPassword) {
+ User user = usersByUsername.get(username);
+ if (user != null && user.getPassword().equals(oldPassword)) {
+ user.setPassword(newPassword);
+ saveUsersToFile(); // 保存更改到文件
+ return true;
+ }
+ return false;
+ }
+
public boolean registerUser(String username, String email, String password) {
if (usersByEmail.containsKey(email) || usersByUsername.containsKey(username)) {
return false;
@@ -273,11 +536,12 @@ class UserManager {
User user = new User(username, email, password);
usersByEmail.put(email, user);
usersByUsername.put(username, user);
+ saveUsersToFile(); // 保存新用户到文件
return true;
}
- public User login(String email, String password) {
- User user = usersByEmail.get(email);
+ public User login(String username, String password) {
+ User user = usersByUsername.get(username);
if (user != null && user.getPassword().equals(password)) {
return user;
}
@@ -288,6 +552,7 @@ class UserManager {
User user = usersByEmail.get(email);
if (user != null && user.getPassword().equals(oldPassword)) {
user.setPassword(newPassword);
+ saveUsersToFile(); // 保存更改到文件
return true;
}
return false;
@@ -369,9 +634,9 @@ public class MathLearningApp {
gbc.gridwidth = 1;
gbc.gridy = 2; gbc.gridx = 0;
- JLabel emailLabel = new JLabel("邮箱:");
- emailLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
- panel.add(emailLabel, gbc);
+ JLabel usernameLabel = new JLabel("用户名:");
+ usernameLabel.setFont(new Font("微软雅黑", Font.BOLD, 14));
+ panel.add(usernameLabel, gbc);
gbc.gridx = 1;
emailField = new JTextField(20);
@@ -407,7 +672,7 @@ public class MathLearningApp {
// 添加测试账号提示
gbc.gridy = 5;
- JLabel testAccountLabel = new JLabel("测试账号: test@test.com / Test123", JLabel.CENTER);
+ JLabel testAccountLabel = new JLabel("测试账号: 测试用户 / Test123", JLabel.CENTER);
testAccountLabel.setFont(new Font("微软雅黑", Font.ITALIC, 12));
testAccountLabel.setForeground(Color.GRAY);
panel.add(testAccountLabel, gbc);
@@ -532,22 +797,29 @@ public class MathLearningApp {
gbc.gridx = 0; gbc.gridy = 0; gbc.gridwidth = 2;
panel.add(titleLabel, gbc);
+ // 添加密码要求说明
+ JLabel requirementLabel = new JLabel("密码要求:6-10位,包含大小写字母和数字", JLabel.CENTER);
+ requirementLabel.setFont(new Font("微软雅黑", Font.ITALIC, 12));
+ requirementLabel.setForeground(Color.RED);
+ gbc.gridy = 1; gbc.gridwidth = 2;
+ panel.add(requirementLabel, gbc);
+
gbc.gridwidth = 1;
- gbc.gridy = 1; gbc.gridx = 0;
+ gbc.gridy = 2; gbc.gridx = 0;
panel.add(new JLabel("密码:"), gbc);
gbc.gridx = 1;
JPasswordField setPasswordField = new JPasswordField(20);
panel.add(setPasswordField, gbc);
- gbc.gridy = 2; gbc.gridx = 0;
+ gbc.gridy = 3; gbc.gridx = 0;
panel.add(new JLabel("确认密码:"), gbc);
gbc.gridx = 1;
JPasswordField confirmSetPasswordField = new JPasswordField(20);
panel.add(confirmSetPasswordField, gbc);
- gbc.gridy = 3; gbc.gridx = 0; gbc.gridwidth = 2;
+ gbc.gridy = 4; gbc.gridx = 0; gbc.gridwidth = 2;
JButton setPasswordButton = createStyledButton("设置密码", new Color(60, 179, 113));
setPasswordButton.addActionListener(e -> {
String password = new String(setPasswordField.getPassword());
@@ -620,7 +892,7 @@ public class MathLearningApp {
gbc.gridy = 1;
panel.add(countField, gbc);
- JLabel hintLabel = new JLabel("(建议5-20题)", JLabel.CENTER);
+ JLabel hintLabel = new JLabel("(建议10-30题)", JLabel.CENTER);
hintLabel.setFont(new Font("微软雅黑", Font.ITALIC, 12));
hintLabel.setForeground(Color.GRAY);
gbc.gridy = 2;
@@ -630,11 +902,11 @@ public class MathLearningApp {
startButton.addActionListener(e -> {
try {
int count = Integer.parseInt(countField.getText());
- if (count > 0 && count <= 50) {
+ if (count >= 10 && count <= 30) {
generateExamQuestions(count);
cardLayout.show(mainPanel, "Exam");
} else {
- JOptionPane.showMessageDialog(panel, "请输入1-50之间的有效题目数量");
+ JOptionPane.showMessageDialog(panel, "请输入10-30之间的有效题目数量");
}
} catch (NumberFormatException ex) {
JOptionPane.showMessageDialog(panel, "请输入有效的数字");
@@ -726,7 +998,7 @@ public class MathLearningApp {
gbc.gridwidth = 1;
gbc.gridy = 1; gbc.gridx = 0;
- panel.add(new JLabel("邮箱:"), gbc);
+ panel.add(new JLabel("用户名:"), gbc);
gbc.gridx = 1;
JTextField changePasswordEmailField = new JTextField(20);
@@ -754,57 +1026,66 @@ public class MathLearningApp {
panel.add(confirmNewPasswordField, gbc);
gbc.gridy = 5; gbc.gridx = 0; gbc.gridwidth = 2;
- JPanel buttonPanel = new JPanel(new FlowLayout());
-
- JButton changeButton = createStyledButton("修改密码", new Color(60, 179, 113));
- changeButton.addActionListener(e -> {
- String email = changePasswordEmailField.getText();
+ JButton changePasswordButton = createStyledButton("修改密码", new Color(218, 165, 32));
+ changePasswordButton.addActionListener(e -> {
+ String username = changePasswordEmailField.getText();
String oldPassword = new String(oldPasswordField.getPassword());
String newPassword = new String(newPasswordField.getPassword());
- String confirmPassword = new String(confirmNewPasswordField.getPassword());
+ String confirmNewPassword = new String(confirmNewPasswordField.getPassword());
- if (validatePassword(newPassword, confirmPassword)) {
- if (userManager.updatePassword(email, oldPassword, newPassword)) {
- JOptionPane.showMessageDialog(panel, "密码修改成功");
- cardLayout.show(mainPanel, "Login");
- } else {
- JOptionPane.showMessageDialog(panel, "邮箱或原密码错误");
- }
+ if (username.isEmpty() || oldPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
+ JOptionPane.showMessageDialog(panel, "请填写所有信息");
+ return;
+ }
+
+ if (!newPassword.equals(confirmNewPassword)) {
+ JOptionPane.showMessageDialog(panel, "新密码和确认密码不匹配");
+ return;
+ }
+
+ if (!validatePasswordFormat(newPassword)) {
+ JOptionPane.showMessageDialog(panel, "密码必须是6-10位,包含大小写字母和数字");
+ return;
+ }
+
+ if (userManager.updatePasswordByUsername(username, oldPassword, newPassword)) {
+ JOptionPane.showMessageDialog(panel, "密码修改成功");
+ cardLayout.show(mainPanel, "Login");
+ } else {
+ JOptionPane.showMessageDialog(panel, "用户名或原密码错误");
}
});
- buttonPanel.add(changeButton);
+ panel.add(changePasswordButton, gbc);
- JButton backButton = createStyledButton("返回", new Color(169, 169, 169));
+ gbc.gridy = 6;
+ JButton backButton = createStyledButton("返回登录", new Color(169, 169, 169));
backButton.addActionListener(e -> cardLayout.show(mainPanel, "Login"));
- buttonPanel.add(backButton);
-
- panel.add(buttonPanel, gbc);
+ panel.add(backButton, gbc);
mainPanel.add(panel, "ChangePassword");
}
// 事件处理方法
private void handleLogin() {
- String email = emailField.getText();
+ String username = emailField.getText();
String password = new String(passwordField.getPassword());
- if (email.isEmpty() || password.isEmpty()) {
- JOptionPane.showMessageDialog(mainPanel, "请填写邮箱和密码");
+ if (username.isEmpty() || password.isEmpty()) {
+ JOptionPane.showMessageDialog(mainPanel, "请填写用户名和密码");
return;
}
- currentUser = userManager.login(email, password);
+ currentUser = userManager.login(username, password);
if (currentUser != null) {
welcomeLabel.setText("欢迎, " + currentUser.getUsername() + "!");
JOptionPane.showMessageDialog(mainPanel, "登录成功!");
cardLayout.show(mainPanel, "LevelSelection");
} else {
- JOptionPane.showMessageDialog(mainPanel, "邮箱或密码错误");
+ JOptionPane.showMessageDialog(mainPanel, "用户名或密码错误");
}
}
private void startExam(String level) {
- // 保存当前选择的级别
mainPanel.putClientProperty("currentLevel", level);
cardLayout.show(mainPanel, "QuestionCount");
}
@@ -839,6 +1120,9 @@ public class MathLearningApp {
currentQuestionIndex = 0;
score = 0;
+
+ // 开始考试时重置选项状态
+ resetOptionButtons();
displayCurrentQuestion();
}
@@ -851,7 +1135,22 @@ public class MathLearningApp {
String[] options = question.getOptions();
for (int i = 0; i < 4; i++) {
optionButtons[i].setText((char)('A' + i) + ". " + options[i]);
- optionButtons[i].setSelected(false);
+ }
+
+ // 重置选项状态
+ resetOptionButtons();
+ }
+ }
+
+ private void resetOptionButtons() {
+ if (optionGroup != null) {
+ optionGroup.clearSelection();
+ }
+ if (optionButtons != null) {
+ for (JRadioButton button : optionButtons) {
+ if (button != null) {
+ button.setSelected(false);
+ }
}
}
}
@@ -885,25 +1184,23 @@ public class MathLearningApp {
}
private void showScore() {
- // 计算百分制得分
int totalQuestions = currentExam.size();
int percentScore = (int) Math.round((double) score / totalQuestions * 100);
- // 根据得分设置不同的颜色和评语
String comment;
Color color;
if (percentScore >= 90) {
comment = "优秀!";
- color = new Color(0, 128, 0); // 绿色
+ color = new Color(0, 128, 0);
} else if (percentScore >= 80) {
comment = "良好!";
- color = new Color(0, 100, 0); // 深绿色
+ color = new Color(0, 100, 0);
} else if (percentScore >= 60) {
comment = "及格!";
- color = new Color(218, 165, 32); // 金色
+ color = new Color(218, 165, 32);
} else {
comment = "加油!";
- color = new Color(220, 20, 60); // 红色
+ color = new Color(220, 20, 60);
}
scoreLabel.setText("" +
@@ -923,7 +1220,6 @@ public class MathLearningApp {
button.setBorder(BorderFactory.createEmptyBorder(10, 20, 10, 20));
button.setCursor(new Cursor(Cursor.HAND_CURSOR));
- // 添加鼠标悬停效果
button.addMouseListener(new java.awt.event.MouseAdapter() {
public void mouseEntered(java.awt.event.MouseEvent evt) {
button.setBackground(color.darker());
@@ -973,6 +1269,10 @@ public class MathLearningApp {
return false;
}
+ return validatePasswordFormat(password);
+ }
+
+ private boolean validatePasswordFormat(String password) {
if (password.length() < 6 || password.length() > 10) {
JOptionPane.showMessageDialog(mainPanel, "密码长度应为6-10位");
return false;
@@ -999,7 +1299,6 @@ public class MathLearningApp {
}
public static void main(String[] args) {
- // 设置界面风格
try {
UIManager.setLookAndFeel(UIManager.getLookAndFeel());
} catch (Exception e) {
--
2.34.1
From 7a4920060c75946abebb3b21526bb71a03ab623a Mon Sep 17 00:00:00 2001
From: ZHW <1941286652@qq.com>
Date: Sun, 12 Oct 2025 13:10:44 +0800
Subject: [PATCH 5/5] final
---
README.md | 2 -
doc/README.md | 188 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 188 insertions(+), 2 deletions(-)
delete mode 100644 README.md
create mode 100644 doc/README.md
diff --git a/README.md b/README.md
deleted file mode 100644
index 8101d5a..0000000
--- a/README.md
+++ /dev/null
@@ -1,2 +0,0 @@
-# mathlearningapp
-
diff --git a/doc/README.md b/doc/README.md
new file mode 100644
index 0000000..f6bc7fe
--- /dev/null
+++ b/doc/README.md
@@ -0,0 +1,188 @@
+# mathlearningapp
+
+# mathlearningapp
+
+# 数学学习软件 - 版本演进文档
+
+## 项目概述
+
+数学学习软件是一个基于Java Swing开发的桌面应用程序,旨在为不同学习阶段(小学、初中、高中)的学生提供数学题目练习和测试功能。软件采用模块化设计,包含用户管理、题目生成、答题测试等核心功能。
+
+## 版本演进历史
+
+### 版本1.0 - 基础版本
+
+#### 核心功能
+- **用户管理**:邮箱注册、登录、密码修改
+- **题目生成**:小学、初中、高中三个级别的题目生成器
+- **答题系统**:选择题形式,支持自定义题目数量
+- **成绩统计**:显示得分和正确率
+
+#### 技术特点
+- 使用CardLayout实现多面板切换
+- 基础的用户验证系统
+- 简单的题目生成算法
+
+#### 主要类结构
+```
+User - 用户类
+Question - 题目类
+QuestionGenerator - 题目生成器抽象类
+PrimaryQuestionGenerator - 小学题目生成器
+JuniorQuestionGenerator - 初中题目生成器
+SeniorQuestionGenerator - 高中题目生成器
+UserManager - 用户管理类
+MathLearningApp - 主应用程序类
+```
+
+### 版本2.0 - 功能增强版
+
+#### 新增功能
+- **用户名系统**:引入用户名概念,不再仅依赖邮箱
+- **界面美化**:改进UI设计,添加颜色和样式
+- **验证码系统**:注册时发送验证码
+- **欢迎界面**:登录后显示个性化欢迎信息
+
+#### 技术改进
+- 改进的用户管理,支持用户名和邮箱双重索引
+- 增强的题目生成逻辑
+- 更友好的用户界面
+
+### 版本3.0 - 算法优化版
+
+#### 核心改进
+- **题目生成优化**:
+ - 小学:操作数数量扩展为1-5个
+ - 初中:支持混合运算和平方/开方运算
+ - 高中:三角函数使用特殊角度,确保结果合理
+- **表达式计算**:引入JavaScript引擎计算复杂表达式
+- **输入验证**:题目数量限制为10-30题
+
+#### 技术升级
+- 更健壮的题目生成算法
+- 改进的错误处理机制
+- 优化的用户交互体验
+
+### 版本4.0 - 企业级版本
+
+#### 重大改进
+- **数据持久化**:用户数据序列化保存到文件
+- **表达式计算器**:自定义表达式计算引擎
+- **包管理**:添加com.hnu包结构
+- **代码重构**:大幅优化代码结构和算法
+
+#### 新增特性
+- **文件存储**:用户数据自动保存和加载
+- **高级计算**:支持括号和运算优先级
+- **健壮性提升**:完善的异常处理和输入验证
+
+## 核心功能详解
+
+### 1. 用户管理系统
+
+#### 版本演进
+- **1.0**:基于邮箱的简单用户管理
+- **2.0**:引入用户名系统,双重索引
+- **4.0**:数据持久化,文件存储
+
+#### 功能特性
+- 用户注册(邮箱验证)
+- 用户登录
+- 密码修改
+- 数据持久化(4.0+)
+
+### 2. 题目生成系统
+
+#### 小学题目
+- **运算符**:+、-、*、/
+- **特点**:支持括号,2-4个操作数
+- **演进**:从简单运算到支持复杂表达式
+
+#### 初中题目
+- **类型**:基本运算、平方、开方
+- **特点**:混合运算,确保完全平方数
+- **演进**:算法优化,结果更合理
+
+#### 高中题目
+- **类型**:三角函数、复合表达式
+- **特点**:使用特殊角度,避免极端值
+- **演进**:从简单三角函数到复合表达式
+
+### 3. 答题与评分系统
+
+#### 答题流程
+1. 选择学习阶段
+2. 输入题目数量
+3. 逐题作答
+4. 查看成绩
+
+#### 评分机制
+- 实时计分
+- 百分比显示
+- 成绩评级(优秀、良好、及格、加油)
+
+## 技术架构
+
+### 设计模式应用
+- **工厂模式**:题目生成器
+- **单例模式**:用户管理
+- **策略模式**:不同级别的题目生成
+
+### 核心算法
+
+#### 表达式计算(版本4.0)
+```java
+// 支持括号和运算优先级
+public static double calculate(String expression) {
+ // 递归处理括号
+ // 先乘除后加减
+ // 完善的错误处理
+}
+```
+
+#### 题目生成
+```java
+// 确保题目多样性和合理性
+public Question generateQuestion() {
+ // 操作数数量随机
+ // 运算符随机选择
+ // 错误答案生成算法
+ // 选项随机排序
+}
+```
+
+## 部署与使用
+
+### 环境要求
+- Java 8+
+- 支持Swing的Java环境
+
+### 运行方式
+```bash
+javac MathLearningApp.java
+java MathLearningApp
+```
+
+### 测试账户
+- 用户名:测试用户
+- 密码:Test123
+
+## 版本对比总结
+
+| 特性 | 1.0 | 2.0 | 3.0 | 4.0 |
+|------|-----|-----|-----|-----|
+| 用户管理 | 基础 | 增强 | 增强 | 持久化 |
+| 题目生成 | 简单 | 改进 | 优化 | 高级 |
+| 界面设计 | 基础 | 美化 | 优化 | 专业 |
+| 数据存储 | 内存 | 内存 | 内存 | 文件 |
+| 计算能力 | 基础 | 基础 | 引擎 | 自定义 |
+| 代码结构 | 简单 | 模块化 | 优化 | 企业级 |
+
+## 未来发展建议
+
+1. **数据库集成**:替换文件存储为数据库
+2. **网络功能**:添加在线排名和题目分享
+3. **移动端**:开发Android和iOS版本
+4. **AI辅助**:集成智能题目推荐
+5. **多媒体**:添加题目解析视频功能
+
--
2.34.1