diff --git a/src/main/java/com/ybw/mathapp/Main.java b/src/main/java/com/ybw/mathapp/Main.java deleted file mode 100644 index 637d836..0000000 --- a/src/main/java/com/ybw/mathapp/Main.java +++ /dev/null @@ -1,37 +0,0 @@ -package com.ybw.mathapp; - -import com.ybw.mathapp.entity.QuestionWithOptions; -import com.ybw.mathapp.service.JuniorHighGenerator; -import com.ybw.mathapp.service.MultipleChoiceGenerator; -import com.ybw.mathapp.service.PrimarySchoolGenerator; -import com.ybw.mathapp.service.SeniorHighGenerator; -import java.util.List; - -public class Main { - public static void main(String[] args) { - // 生成小学选择题 - - System.out.println("--- Primary School MCQs ---"); - PrimarySchoolGenerator primaryGen = new PrimarySchoolGenerator(); - MultipleChoiceGenerator primaryMC = new MultipleChoiceGenerator(primaryGen, "小学"); // 传入级别 - List primaryMCQs = primaryMC.generateMultipleChoiceQuestions(10); - primaryMCQs.forEach(q -> System.out.println(q + "\n")); - - // 生成初中选择题 - System.out.println("--- Junior High MCQs ---"); - JuniorHighGenerator juniorGen = new JuniorHighGenerator(); - MultipleChoiceGenerator juniorMC = new MultipleChoiceGenerator(juniorGen, "初中"); // 传入级别 - List juniorMCQs = juniorMC.generateMultipleChoiceQuestions(10); - juniorMCQs.forEach(q -> System.out.println(q + "\n")); - System.out.println(); - - // 生成高中选择题 - System.out.println("--- Senior High MCQs ---"); - SeniorHighGenerator seniorGen = new SeniorHighGenerator(); - MultipleChoiceGenerator seniorMC = new MultipleChoiceGenerator(seniorGen, "高中"); // 传入级别 - List seniorMCQs = seniorMC.generateMultipleChoiceQuestions(10); - seniorMCQs.forEach(q -> System.out.println(q + "\n")); - - - } -} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/config/EmailConfig.java b/src/main/java/com/ybw/mathapp/config/EmailConfig.java index 8331ea5..d4ba5df 100644 --- a/src/main/java/com/ybw/mathapp/config/EmailConfig.java +++ b/src/main/java/com/ybw/mathapp/config/EmailConfig.java @@ -1,18 +1,13 @@ package com.ybw.mathapp.config; public class EmailConfig { + // 发件人邮箱配置(以QQ邮箱为例) public static final String SMTP_HOST = "smtp.qq.com"; public static final String SMTP_PORT = "587"; public static final String SENDER_EMAIL = "1798231811@qq.com"; // 替换为你的邮箱 public static final String SENDER_PASSWORD = "dzmfirotgnlceeae"; // 替换为你的授权码 - // 如果使用Gmail - // public static final String SMTP_HOST = "smtp.gmail.com"; - // public static final String SMTP_PORT = "587"; - // public static final String SENDER_EMAIL = "your_email@gmail.com"; - // public static final String SENDER_PASSWORD = "your_app_password"; - public static final String EMAIL_SUBJECT = "【用户注册】验证码"; public static final int CODE_EXPIRY_MINUTES = 5; } diff --git a/src/main/java/com/ybw/mathapp/entity/QuestionWithOptions.java b/src/main/java/com/ybw/mathapp/entity/QuestionWithOptions.java index fe1c47a..1c822a0 100644 --- a/src/main/java/com/ybw/mathapp/entity/QuestionWithOptions.java +++ b/src/main/java/com/ybw/mathapp/entity/QuestionWithOptions.java @@ -3,43 +3,105 @@ package com.ybw.mathapp.entity; import java.util.List; /** - * 选择题对象,包含题干、选项和正确答案索引。 + * 选择题实体类,用于封装题干、选项列表和正确答案的索引。 * - * @author 你的名字 + * @author 杨博文 * @since 2025 */ public class QuestionWithOptions { - private String questionText; // 题干 - private List options; // 选项列表 - private int correctAnswerIndex; // 正确答案的索引 (0-based) + /** + * 题干文本。 + */ + private String questionText; + /** + * 选项列表。 + */ + private List options; + /** + * 正确答案的索引 (0-based)。 + */ + private int correctAnswerIndex; + + /** + * 构造函数。 + * + * @param questionText 题干文本 + * @param options 选项列表 + * @param correctAnswerIndex 正确答案的索引 (0-based) + * @throws IllegalArgumentException 如果 options 为 null 或索引超出范围 + */ public QuestionWithOptions(String questionText, List options, int correctAnswerIndex) { + if (options == null) { + throw new IllegalArgumentException("选项列表不能为 null"); + } + if (correctAnswerIndex < 0 || correctAnswerIndex >= options.size()) { + throw new IllegalArgumentException("正确答案索引超出选项范围"); + } this.questionText = questionText; this.options = options; this.correctAnswerIndex = correctAnswerIndex; } + /** + * 获取题干文本。 + * + * @return 题干文本 + */ public String getQuestionText() { return questionText; } + /** + * 设置题干文本。 + * + * @param questionText 要设置的题干文本 + */ public void setQuestionText(String questionText) { this.questionText = questionText; } + /** + * 获取选项列表。 + * + * @return 选项列表 + */ public List getOptions() { return options; } + /** + * 设置选项列表。 + * + * @param options 要设置的选项列表 + * @throws IllegalArgumentException 如果 options 为 null + */ public void setOptions(List options) { + if (options == null) { + throw new IllegalArgumentException("选项列表不能为 null"); + } this.options = options; } + /** + * 获取正确答案的索引。 + * + * @return 正确答案的索引 (0-based) + */ public int getCorrectAnswerIndex() { return correctAnswerIndex; } + /** + * 设置正确答案的索引。 + * + * @param correctAnswerIndex 要设置的正确答案索引 (0-based) + * @throws IllegalArgumentException 如果索引超出选项范围 + */ public void setCorrectAnswerIndex(int correctAnswerIndex) { + if (correctAnswerIndex < 0 || correctAnswerIndex >= options.size()) { + throw new IllegalArgumentException("正确答案索引超出选项范围"); + } this.correctAnswerIndex = correctAnswerIndex; } @@ -48,9 +110,10 @@ public class QuestionWithOptions { StringBuilder sb = new StringBuilder(); sb.append("Question: ").append(questionText).append("\n"); for (int i = 0; i < options.size(); i++) { - sb.append("Option ").append((char)('A' + i)).append(": ").append(options.get(i)).append("\n"); + sb.append("Option ").append((char) ('A' + i)).append(": ").append(options.get(i)) + .append("\n"); } - sb.append("Correct Answer: ").append((char)('A' + correctAnswerIndex)); + sb.append("Correct Answer: ").append((char) ('A' + correctAnswerIndex)); return sb.toString(); } -} +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/entity/User.java b/src/main/java/com/ybw/mathapp/entity/User.java index fa07684..b886577 100644 --- a/src/main/java/com/ybw/mathapp/entity/User.java +++ b/src/main/java/com/ybw/mathapp/entity/User.java @@ -12,32 +12,76 @@ package com.ybw.mathapp.entity; */ public class User { - public String getName() { - return name; - } - - /** 用户名,不可修改。 */ + /** + * 用户名,不可修改。 + */ private final String name; - /** 邮箱,不可修改。 */ + /** + * 邮箱,不可修改。 + */ private final String email; - /** 用户密码,不可修改。 */ + /** + * 用户密码,不可修改。 + */ private final String password; - /** 用户当前的学习级别,可以修改。 */ + /** + * 用户当前的学习级别,可以修改。 + */ private String level; /** * 构造一个新的用户对象。 * - * @param email 邮箱,不能为空 用户名,不能为空 + * @param name 用户名,不能为空 + * @param email 邮箱,不能为空 * @param password 用户密码,不能为空 + * @throws IllegalArgumentException 如果 name、email 或 password 为 null 或空字符串 */ public User(String name, String email, String password) { + if (name == null || name.trim().isEmpty()) { + throw new IllegalArgumentException("用户名不能为空"); + } + if (email == null || email.trim().isEmpty()) { + throw new IllegalArgumentException("邮箱不能为空"); + } + if (password == null || password.trim().isEmpty()) { + throw new IllegalArgumentException("密码不能为空"); + } this.name = name; - this.password = password; this.email = email; + this.password = password; + } + + /** + * 从字符串创建用户对象。 + * + *

字符串格式应为 "name,email,password"。 + * + * @param line 包含用户信息的字符串 + * @return 解析成功的用户对象,如果解析失败则返回 null + */ + public static User fromString(String line) { + if (line == null || line.trim().isEmpty()) { + return null; + } + + String[] parts = line.split(",", 3); // 最多分割成3部分 + if (parts.length == 3) { + return new User(parts[0].trim(), parts[1].trim(), parts[2].trim()); + } + return null; + } + + /** + * 获取用户名。 + * + * @return 用户名 + */ + public String getName() { + return name; } /** @@ -59,42 +103,32 @@ public class User { } /** - * 获取用户邮箱。 + * 设置用户的学习级别。 * - * @return 用户邮箱 + * @param newLevel 新的学习级别,支持"小学"、"初中"、"高中" */ - public String getEmail() { - return email; + public void setLevel(String newLevel) { + level = newLevel; } /** - * 设置用户的学习级别。 + * 获取用户邮箱。 * - * @param newLevel 新的学习级别,支持"小学"、"初中"、"高中" + * @return 用户邮箱 */ - public void setLevel(String newLevel) { - level = newLevel; + public String getEmail() { + return email; } /** - * 保存邮箱+密码。 + * 返回用户信息的字符串表示。 + * + *

格式为 "name,email,password"。 * - * @return 邮箱+密码 + * @return 包含用户名、邮箱和密码的字符串 */ @Override public String toString() { return name + "," + email + "," + password; } - - public static User fromString(String line) { - if (line == null || line.trim().isEmpty()) { - return null; - } - - String[] parts = line.split(",", 3); // 最多分割成3部分 - if (parts.length == 3) { - return new User(parts[0].trim(), parts[1].trim(), parts[2].trim()); - } - return null; - } -} +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/service/AdvancedCaculate.java b/src/main/java/com/ybw/mathapp/service/AdvancedCaculate.java index d69d11b..74240b9 100644 --- a/src/main/java/com/ybw/mathapp/service/AdvancedCaculate.java +++ b/src/main/java/com/ybw/mathapp/service/AdvancedCaculate.java @@ -1,21 +1,41 @@ package com.ybw.mathapp.service; -import java.util.*; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.Stack; /** * 扩展的计算类,支持基础四则运算、括号、平方、开根号、三角函数 (sin, cos, tan)。 - * 括号优先级最高。 - * 高级运算符 (平方, 开根号, sin, cos, tan) 优先级高于四则运算。 - * 平方是后置运算符,开根号和三角函数是前置运算符。 - * 例如: "3 + 开根号 16 平方" 解释为 "3 + (sqrt(16))^2" = "3 + 4^2" = "3 + 16" = 19 - * "开根号 ( 4 + 5 ) 平方" 解释为 "(sqrt(4+5))^2" = "sqrt(9)^2" = "3^2" = 9 - * "sin 30 + 5" 解释为 "sin(30) + 5" (假设30是度数) - * 修正:在计算开根号时,若操作数为负数,则抛出 ArithmeticException。 + * + *

运算符优先级定义如下: + *

    + *
  1. 括号 {@code ( )} 优先级最高。
  2. + *
  3. 高级运算符 (平方, 开根号, sin, cos, tan) 优先级高于四则运算。
  4. + *
  5. 平方是后置运算符,开根号和三角函数是前置运算符。
  6. + *
+ * + *

例如: + *

    + *
  • {@code "3 + 开根号 16 平方"} 解释为 {@code "3 + (sqrt(16))^2"} = {@code "3 + 4^2"} = {@code "3 + 16"} = 19
  • + *
  • {@code "开根号 ( 4 + 5 ) 平方"} 解释为 {@code "(sqrt(4+5))^2"} = {@code "sqrt(9)^2"} = {@code "3^2"} = 9
  • + *
  • {@code "sin 30 + 5"} 解释为 {@code "sin(30) + 5"} (假设30是度数)
  • + *
+ * + *

注意: 在计算开根号时,若操作数为负数,则抛出 ArithmeticException。 + * + * @author 杨博文 + * @since 2025 */ public class AdvancedCaculate { - private static final Set OPERATORS = new HashSet<>(Arrays.asList("+", "-", "*", "/")); - private static final Set ADVANCED_OPERATORS = new HashSet<>(Arrays.asList("平方", "开根号", "sin", "cos", "tan")); + private static final Set BASIC_OPERATORS = new HashSet<>( + Arrays.asList("+", "-", "*", "/")); + private static final Set ADVANCED_OPERATORS = new HashSet<>( + Arrays.asList("平方", "开根号", "sin", "cos", "tan")); private static final Map PRECEDENCE = new HashMap<>(); static { @@ -34,51 +54,28 @@ public class AdvancedCaculate { /** * 计算给定表达式的值。 * - * @param expressionTokens 表达式分词列表,例如 ["3", "+", "开根号", "16", "平方"] + *

表达式分词列表例如: ["3", "+", "开根号", "16", "平方"] + * + * @param expressionTokens 表达式的分词列表 * @return 计算结果 - * @throws IllegalArgumentException 如果表达式无效 - * @throws ArithmeticException 如果计算过程中出现错误(如除零、负数开根号) + * @throws IllegalArgumentException 如果表达式无效(例如括号不匹配、操作数不足) + * @throws ArithmeticException 如果计算过程中出现错误(如除零、负数开根号) */ public static double calculate(List expressionTokens) { Stack numberStack = new Stack<>(); Stack operatorStack = new Stack<>(); - for (int i = 0; i < expressionTokens.size(); i++) { - String token = expressionTokens.get(i); - + for (String token : expressionTokens) { if (isNumeric(token)) { numberStack.push(Double.parseDouble(token)); } else if (token.equals("(")) { operatorStack.push(token); } else if (token.equals(")")) { - while (!operatorStack.isEmpty() && !operatorStack.peek().equals("(")) { - processOperator(numberStack, operatorStack.pop()); - } - if (!operatorStack.isEmpty()) { // Pop the "(" - operatorStack.pop(); - } + handleClosingParenthesis(numberStack, operatorStack); } else if (ADVANCED_OPERATORS.contains(token)) { - // 前置运算符 (开根号, sin, cos, tan) 直接入栈 - // 后置运算符 (平方) 需要等待其操作数先计算出来 - // 在标准调度场算法中,后置运算符通常在遇到时立即处理其栈顶的操作数 - // 这里我们可以在遇到 "平方" 时,立即对 numberStack 的顶部元素进行平方操作 - if ("平方".equals(token)) { - if (numberStack.isEmpty()) { - throw new IllegalArgumentException("Invalid expression: '平方' lacks an operand."); - } - double operand = numberStack.pop(); - numberStack.push(Math.pow(operand, 2)); - } else { // "开根号", "sin", "cos", "tan" 是前置运算符 - operatorStack.push(token); - } - } else if (OPERATORS.contains(token)) { - // 处理四则运算符,遵循优先级 - while (!operatorStack.isEmpty() && - !operatorStack.peek().equals("(") && - PRECEDENCE.get(token) <= PRECEDENCE.getOrDefault(operatorStack.peek(), 0)) { - processOperator(numberStack, operatorStack.pop()); - } - operatorStack.push(token); + handleAdvancedOperator(token, numberStack, operatorStack); + } else if (BASIC_OPERATORS.contains(token)) { + handleBasicOperator(token, numberStack, operatorStack); } else { throw new IllegalArgumentException("Unknown token: " + token); } @@ -94,78 +91,149 @@ public class AdvancedCaculate { } if (numberStack.size() != 1 || !operatorStack.isEmpty()) { - throw new IllegalArgumentException("Invalid expression: " + String.join(" ", expressionTokens)); + throw new IllegalArgumentException( + "Invalid expression: " + String.join(" ", expressionTokens)); } - return numberStack.pop(); } + /** + * 处理遇到右括号 ')' 的情况 + */ + private static void handleClosingParenthesis(Stack numberStack, + Stack operatorStack) { + while (!operatorStack.isEmpty() && !operatorStack.peek().equals("(")) { + processOperator(numberStack, operatorStack.pop()); + } + if (!operatorStack.isEmpty()) { // Pop the "(" + operatorStack.pop(); + } else { + throw new IllegalArgumentException("Mismatched parentheses in expression."); + } + } + + /** + * 处理高级运算符(开根号, sin, cos, tan, 平方) + */ + private static void handleAdvancedOperator(String token, Stack numberStack, + Stack operatorStack) { + if ("平方".equals(token)) { + if (numberStack.isEmpty()) { + throw new IllegalArgumentException("Invalid expression: '平方' lacks an operand."); + } + double operand = numberStack.pop(); + numberStack.push(Math.pow(operand, 2)); + } else { // "开根号", "sin", "cos", "tan" 是前置运算符 + operatorStack.push(token); + } + } + + /** + * 处理基础四则运算符(+, -, *, /) + */ + private static void handleBasicOperator(String token, Stack numberStack, + Stack operatorStack) { + // 处理四则运算符,遵循优先级 + while (!operatorStack.isEmpty() && + !operatorStack.peek().equals("(") && + PRECEDENCE.get(token) <= PRECEDENCE.getOrDefault(operatorStack.peek(), 0)) { + processOperator(numberStack, operatorStack.pop()); + } + operatorStack.push(token); + } + /** * 执行一次运算操作。 * * @param numberStack 数字栈 * @param operator 运算符 + * @throws IllegalArgumentException 如果运算符缺少操作数或为未知运算符 + * @throws ArithmeticException 如果计算过程中出现错误(如除零、负数开根号) */ private static void processOperator(Stack numberStack, String operator) { - if (numberStack.size() < 1) { - throw new IllegalArgumentException("Invalid expression: operator '" + operator + "' lacks operand(s)."); + if (numberStack.isEmpty()) { + throw new IllegalArgumentException( + "Invalid expression: operator '" + operator + "' lacks operand(s)."); } if (ADVANCED_OPERATORS.contains(operator)) { - double operand = numberStack.pop(); - switch (operator) { - case "开根号": - if (operand < 0) { - // 抛出异常,让调用者(MultipleChoiceGenerator)处理 - throw new ArithmeticException("Cannot take square root of negative number: " + operand); - } - numberStack.push(Math.sqrt(operand)); - break; - case "sin": - numberStack.push(Math.sin(Math.toRadians(operand))); // 假设输入是度数 - break; - case "cos": - numberStack.push(Math.cos(Math.toRadians(operand))); - break; - case "tan": - // tan(90 + n*180) 会趋向无穷,这里不特别处理,让其返回 Infinity 或 -Infinity - numberStack.push(Math.tan(Math.toRadians(operand))); - break; - default: - throw new IllegalArgumentException("Unknown advanced operator: " + operator); - } - } else if (OPERATORS.contains(operator)) { - if (numberStack.size() < 2) { - throw new IllegalArgumentException("Invalid expression: operator '" + operator + "' lacks operand(s)."); - } - double b = numberStack.pop(); - double a = numberStack.pop(); - double result; - switch (operator) { - case "+": - result = a + b; - break; - case "-": - result = a - b; - break; - case "*": - result = a * b; - break; - case "/": - if (b == 0) { - throw new ArithmeticException("Division by zero"); - } - result = a / b; - break; - default: - throw new IllegalArgumentException("Unknown operator: " + operator); - } - numberStack.push(result); + processAdvancedOperator(numberStack, operator); + } else if (BASIC_OPERATORS.contains(operator)) { + processBasicOperator(numberStack, operator); } else { throw new IllegalArgumentException("Unexpected operator in process: " + operator); } } + /** + * 执行高级运算操作(开根号, sin, cos, tan) + */ + private static void processAdvancedOperator(Stack numberStack, String operator) { + double operand = numberStack.pop(); + double result; + switch (operator) { + case "开根号": + if (operand < 0) { + // 抛出异常,让调用者(MultipleChoiceGenerator)处理 + throw new ArithmeticException("Cannot take square root of negative number: " + operand); + } + result = Math.sqrt(operand); + break; + case "sin": + result = Math.sin(Math.toRadians(operand)); // 假设输入是度数 + break; + case "cos": + result = Math.cos(Math.toRadians(operand)); + break; + case "tan": + // tan(90 + n*180) 会趋向无穷,这里不特别处理,让其返回 Infinity 或 -Infinity + result = Math.tan(Math.toRadians(operand)); + break; + default: + throw new IllegalArgumentException("Unknown advanced operator: " + operator); + } + numberStack.push(result); + } + + /** + * 执行基础四则运算操作(+, -, *, /) + */ + private static void processBasicOperator(Stack numberStack, String operator) { + if (numberStack.size() < 2) { + throw new IllegalArgumentException( + "Invalid expression: operator '" + operator + "' lacks operand(s)."); + } + double b = numberStack.pop(); + double a = numberStack.pop(); + double result; + switch (operator) { + case "+": + result = a + b; + break; + case "-": + result = a - b; + break; + case "*": + result = a * b; + break; + case "/": + if (b == 0) { + throw new ArithmeticException("Division by zero"); + } + result = a / b; + break; + default: + throw new IllegalArgumentException("Unknown operator: " + operator); + } + numberStack.push(result); + } + + /** + * 判断给定字符串是否为数字。 + * + * @param str 待判断的字符串 + * @return 如果是数字则返回 true,否则返回 false + */ public static boolean isNumeric(String str) { if (str == null || str.isEmpty()) { return false; diff --git a/src/main/java/com/ybw/mathapp/service/EmailService.java b/src/main/java/com/ybw/mathapp/service/EmailService.java deleted file mode 100644 index 4728a47..0000000 --- a/src/main/java/com/ybw/mathapp/service/EmailService.java +++ /dev/null @@ -1,149 +0,0 @@ -package com.ybw.mathapp.service; - -import com.ybw.mathapp.config.EmailConfig; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Random; -//import javax.mail.*; -//import javax.mail.internet.*; - -public class EmailService { - private static Map verificationCodes = new HashMap<>(); - - private static class VerificationCodeInfo { - String code; - long timestamp; - - VerificationCodeInfo(String code, long timestamp) { - this.code = code; - this.timestamp = timestamp; - } - } - - public static String generateVerificationCode() { - Random random = new Random(); - int code = 100000 + random.nextInt(900000); - return String.valueOf(code); - } - - public static boolean sendVerificationCode(String recipientEmail, String code) { - /* - try { - // 创建邮件会话 - Properties props = new Properties(); - props.put("mail.smtp.host", EmailConfig.SMTP_HOST); - props.put("mail.smtp.port", EmailConfig.SMTP_PORT); - props.put("mail.smtp.auth", "true"); - props.put("mail.smtp.starttls.enable", "true"); - - // 创建认证器 - Authenticator auth = new Authenticator() { - protected PasswordAuthentication getPasswordAuthentication() { - return new PasswordAuthentication( - EmailConfig.SENDER_EMAIL, - EmailConfig.SENDER_PASSWORD - ); - } - }; - - Session session = Session.getInstance(props, auth); - - // 创建邮件消息 - Message message = new MimeMessage(session); - message.setFrom(new InternetAddress(EmailConfig.SENDER_EMAIL)); - message.setRecipients(Message.RecipientType.TO, - InternetAddress.parse(recipientEmail)); - message.setSubject(EmailConfig.EMAIL_SUBJECT); - - // 创建邮件内容 - String emailContent = createEmailContent(code); - message.setContent(emailContent, "text/html; charset=utf-8"); - - // 发送邮件 - Transport.send(message); - - // 存储验证码信息 - verificationCodes.put(recipientEmail, - new VerificationCodeInfo(code, System.currentTimeMillis())); - - System.out.println("验证码已发送到邮箱: " + recipientEmail); - return true; - - } catch (Exception e) { - System.err.println("发送邮件失败: " + e.getMessage()); - // 在开发环境中,直接返回true用于测试 - verificationCodes.put(recipientEmail, - new VerificationCodeInfo(code, System.currentTimeMillis())); - return true; - } - */ - return true; - } - - private static String createEmailContent(String code) { - return "" + - "" + - "" + - "" + - "" + - "" + - "" + - "

" + - "
" + - "

数学学习软件 - 注册验证码

" + - "
" + - "
" + - "

您好!

" + - "

您正在注册数学学习软件账户,验证码如下:

" + - "
" + code + "
" + - "

验证码有效期为 " + EmailConfig.CODE_EXPIRY_MINUTES + " 分钟,请勿泄露给他人。

" + - "

如果这不是您本人的操作,请忽略此邮件。

" + - "
" + - "" + - "
" + - "" + - ""; - } - - public static boolean verifyCode(String email, String inputCode) { - VerificationCodeInfo codeInfo = verificationCodes.get(email); - if (codeInfo == null) { - return false; - } - - // 检查验证码是否过期 - long currentTime = System.currentTimeMillis(); - if (currentTime - codeInfo.timestamp > EmailConfig.CODE_EXPIRY_MINUTES * 60 * 1000) { - verificationCodes.remove(email); - return false; - } - - return codeInfo.code.equals(inputCode); - } - - public static void cleanupExpiredCodes() { - long currentTime = System.currentTimeMillis(); - Iterator> iterator = - verificationCodes.entrySet().iterator(); - - while (iterator.hasNext()) { - Map.Entry entry = iterator.next(); - if (currentTime - entry.getValue().timestamp > - EmailConfig.CODE_EXPIRY_MINUTES * 60 * 1000) { - iterator.remove(); - } - } - } -} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/service/MultipleChoiceGenerator.java b/src/main/java/com/ybw/mathapp/service/MultipleChoiceGenerator.java index d616ac5..ab31c1a 100644 --- a/src/main/java/com/ybw/mathapp/service/MultipleChoiceGenerator.java +++ b/src/main/java/com/ybw/mathapp/service/MultipleChoiceGenerator.java @@ -9,21 +9,45 @@ import java.util.List; import java.util.Random; import java.util.Set; + /** * 通用选择题生成器,将基础题目生成器的结果转换为带选项的选择题。 - * 确保生成的题目列表中不包含重复的题干。 - * 特别处理:1. 初中题避免负数开根号;2. 小学题选项避免负数。 * - * @author 你的名字 + *

该类确保生成的题目列表中不包含重复的题干。 + * 特殊处理规则: + *

    + *
  • 初中题:在计算过程中避免负数开根号(由 {@link AdvancedCaculate} 抛出异常,此处理捕获并跳过)。
  • + *
  • 小学题:生成的选项避免出现负数。
  • + *
+ * + * @author 杨博文 * @since 2025 */ public class MultipleChoiceGenerator { + /** + * 用于格式化数字的格式化器,保留两位小数。 + */ + private static final DecimalFormat df = new DecimalFormat("#0.00"); + /** + * 基础题目生成器。 + */ private final QuestionGenerator baseGenerator; + /** + * 随机数生成器。 + */ private final Random random = new Random(); - private static final DecimalFormat df = new DecimalFormat("#0.00"); - private final String level; // 记录当前题目类型,用于特殊处理 + /** + * 当前题目类型,用于特殊处理逻辑。 + */ + private final String level; + /** + * 构造一个新的选择题生成器。 + * + * @param baseGenerator 基础题目生成器 + * @param level 题目所属的级别 ("小学", "初中", "高中") + */ public MultipleChoiceGenerator(QuestionGenerator baseGenerator, String level) { this.baseGenerator = baseGenerator; this.level = level; @@ -32,8 +56,8 @@ public class MultipleChoiceGenerator { /** * 生成指定数量的选择题,确保题干不重复。 * - * @param count 题目数量 - * @return 选择题列表 (去重后) + * @param count 要生成的题目数量 + * @return 生成的选择题列表(已去重) */ public List generateMultipleChoiceQuestions(int count) { List mcQuestions = new ArrayList<>(); @@ -42,9 +66,8 @@ public class MultipleChoiceGenerator { while (mcQuestions.size() < count) { String baseQuestion = generateUniqueBaseQuestion(seenQuestionTexts); if (baseQuestion == null) { - // 如果无法生成不重复的基础题目,可能需要退出或处理 - // 例如,如果基础生成器的可能组合用尽了 - break; // 或者抛出异常 + // 如果无法生成不重复的基础题目,可能基础生成器的可能组合已用尽 + break; // 退出循环 } QuestionWithOptions mcq = generateSingleMCQ(baseQuestion); if (mcq != null) { @@ -58,6 +81,9 @@ public class MultipleChoiceGenerator { /** * 生成一个唯一的、未处理过的基础题目。 + * + * @param seenQuestionTexts 已生成题干的集合 + * @return 一个唯一的题干字符串,如果在限定尝试次数内无法找到则返回 null */ private String generateUniqueBaseQuestion(Set seenQuestionTexts) { int attempts = 0; @@ -75,25 +101,34 @@ public class MultipleChoiceGenerator { /** * 从单个基础题目生成选择题对象。 + * + * @param baseQuestion 基础题干字符串,例如 "3 + 5 = ?" + * @return 生成的选择题对象,如果计算或生成选项失败则返回 null */ private QuestionWithOptions generateSingleMCQ(String baseQuestion) { try { + // 从基础题干中提取表达式部分,例如 "3 + 5 = ?" -> "3 + 5" String expression = baseQuestion.substring(0, baseQuestion.lastIndexOf(" =")).trim(); List tokens = tokenizeExpression(expression); + // 计算正确答案 double correctAnswer = AdvancedCaculate.calculate(tokens); + // 生成选项列表 List options = generateOptions(correctAnswer); if (options == null) { - // 无法生成足够的选项 + // 无法生成足够的有效选项 return null; } + // 随机打乱选项顺序 Collections.shuffle(options); + // 找到正确答案在打乱后列表中的索引 int correctIndex = options.indexOf(df.format(correctAnswer)); return new QuestionWithOptions(baseQuestion, options, correctIndex); } catch (ArithmeticException | IllegalArgumentException e) { + // 计算或表达式格式错误,跳过此题 // System.out.println("计算或表达式错误,跳过题目: " + baseQuestion + ", Error: " + e.getMessage()); return null; // 返回 null 表示生成失败 } @@ -101,6 +136,11 @@ public class MultipleChoiceGenerator { /** * 生成选项列表 (正确答案 + 错误答案)。 + * + *

对于小学级别,错误答案不会包含负数。 + * + * @param correctAnswer 正确答案 + * @return 包含正确答案和错误答案的字符串列表,如果无法生成足够选项则返回 null */ private List generateOptions(double correctAnswer) { Set wrongAnswers = new HashSet<>(); @@ -109,12 +149,13 @@ public class MultipleChoiceGenerator { int numWrongOptions = 3; // 假设总共4个选项,需要3个错误答案 while (wrongAnswers.size() < numWrongOptions && attempts < maxAttempts) { - int offset = random.nextInt(20) + 1; + int offset = random.nextInt(20) + 1; // 生成 1-20 的偏移量 if (random.nextBoolean()) { - offset = -offset; + offset = -offset; // 随机正负 } double wrongAnswer = correctAnswer + offset; + // 确保错误答案与正确答案不同,并且对于小学题不为负数 if (Math.abs(df.format(wrongAnswer).compareTo(df.format(correctAnswer))) != 0) { if (!level.equals("小学") || wrongAnswer >= 0) { wrongAnswers.add(wrongAnswer); @@ -128,10 +169,12 @@ public class MultipleChoiceGenerator { return null; // 无法生成足够选项 } + // 将正确答案和错误答案合并 List allAnswers = new ArrayList<>(); allAnswers.add(correctAnswer); allAnswers.addAll(wrongAnswers); + // 格式化所有答案为字符串 List options = new ArrayList<>(); for (Double ans : allAnswers) { options.add(df.format(ans)); @@ -143,6 +186,13 @@ public class MultipleChoiceGenerator { // --- 表达式分词逻辑 --- // 将 "3 + 开根号 ( 4 ) 平方 - sin 30" 分割成 ["3", "+", "开根号", "(", "4", ")", "平方", "-", "sin", "30"] + + /** + * 将表达式字符串分割成标记列表。 + * + * @param expression 表达式字符串 + * @return 标记列表 + */ private List tokenizeExpression(String expression) { List tokens = new ArrayList<>(); int i = 0; @@ -165,8 +215,9 @@ public class MultipleChoiceGenerator { /** * 查找从指定位置开始的下一个 token。 + * * @param expression 表达式字符串 - * @param startPos 起始查找位置 + * @param startPos 起始查找位置 * @return 找到的 token,如果未找到则返回 null */ private String _findNextToken(String expression, int startPos) { @@ -182,7 +233,8 @@ public class MultipleChoiceGenerator { if (Character.isDigit(c) || c == '.') { // 查找连续的数字或小数点 int j = startPos; - while (j < expression.length() && (Character.isDigit(expression.charAt(j)) || expression.charAt(j) == '.')) { + while (j < expression.length() && (Character.isDigit(expression.charAt(j)) + || expression.charAt(j) == '.')) { j++; } return expression.substring(startPos, j); diff --git a/src/main/java/com/ybw/mathapp/service/StartController.java b/src/main/java/com/ybw/mathapp/service/StartController.java deleted file mode 100644 index 00b99cc..0000000 --- a/src/main/java/com/ybw/mathapp/service/StartController.java +++ /dev/null @@ -1,166 +0,0 @@ -package com.ybw.mathapp.service; - -import com.ybw.mathapp.entity.User; -import java.io.IOException; -import java.util.List; -import java.util.Scanner; - -public class StartController { - - private double score; - - public double getScore() { - return score; - } - - public void setScore(double score) { - this.score = score; - } - - public void start() { - Scanner scanner = new Scanner(System.in); - while (true) { - System.out.println("=== 数学学习软件 ==="); - System.out.println("1. 登录"); - System.out.println("2. 注册"); - System.out.print("请选择: "); - - String choice = scanner.nextLine(); - if ("1".equals(choice)) { - if (login()) { - showMainMenu(scanner); - } - } else if ("2".equals(choice)) { - if (register()) { - showMainMenu(scanner); - } - } else { - System.out.println("无效选择,请重新输入!"); - } - } - } - - private boolean login() { - System.out.println("\n=== 用户登录 ==="); - Scanner scanner = new Scanner(System.in); - - System.out.print("请输入邮箱: "); - String email = scanner.nextLine().trim(); - - System.out.print("请输入密码: "); - String password = scanner.nextLine(); - - // 这里应该调用真实的登录逻辑 - System.out.println("登录功能待实现"); - return true; - } - - private boolean register() { - System.out.println("\n=== 用户注册 ==="); - System.out.println("注册功能待实现"); - return true; - } - - private void showMainMenu(Scanner scanner) { - while (true) { - System.out.println("\n=== 主菜单 ==="); - System.out.println("1. 开始练习"); - System.out.println("2. 修改密码"); - System.out.println("3. 退出登录"); - System.out.print("请选择: "); - - String choice = scanner.nextLine(); - if ("1".equals(choice)) { - showLevelSelection(scanner); - } else if ("2".equals(choice)) { - changePassword(scanner); - } else if ("3".equals(choice)) { - System.out.println("退出登录成功!"); - return; - } else { - System.out.println("无效选择,请重新输入!"); - } - } - } - - private void showLevelSelection(Scanner scanner) { - System.out.println("\n=== 选择题目级别 ==="); - System.out.println("1. 小学"); - System.out.println("2. 初中"); - System.out.println("3. 高中"); - System.out.println("4. 返回"); - System.out.print("请选择: "); - - String choice = scanner.nextLine(); - String level = null; - switch (choice) { - case "1": level = "小学"; break; - case "2": level = "初中"; break; - case "3": level = "高中"; break; - case "4": return; - default: - System.out.println("无效选择!"); - return; - } - - showQuestionCount(scanner, level); - } - - private void showQuestionCount(Scanner scanner, String level) { - System.out.println("\n=== 选择题目数量 ==="); - System.out.print("请输入题目数量 (10-30): "); - - try { - int count = Integer.parseInt(scanner.nextLine()); - if (count < 10 || count > 30) { - System.out.println("题目数量必须在10-30之间!"); - return; - } - - startQuiz(level, count); - - } catch (NumberFormatException e) { - System.out.println("请输入有效的数字!"); - } - } - - private void startQuiz(String level, int count) { - System.out.println("\n开始 " + level + " 级别答题,共 " + count + " 题"); - // 这里应该调用题目生成和答题逻辑 - System.out.println("答题功能待实现"); - - // 模拟答题结果 - this.score = 0.8; // 模拟80%的正确率 - System.out.println("答题完成!得分: " + (score * 100) + "%"); - } - - private void changePassword(Scanner scanner) { - System.out.println("\n=== 修改密码 ==="); - System.out.println("修改密码功能待实现"); - } - - public QuestionGenerator createGenerator(String level) { - switch (level) { - case "小学": - return new PrimarySchoolGenerator(); - case "初中": - return new JuniorHighGenerator(); - case "高中": - return new SeniorHighGenerator(); - default: - return null; - } - } - - public boolean isCorrectAnswer(String input, int correctAnswerIndex, List options) { - if (input.equals(String.valueOf(options.get(correctAnswerIndex)))) { - return true; - } else { - return false; - } - } - - public double caculateScore(int rightCount, int totalCount) { - return rightCount / (double) totalCount; - } -} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/util/ChangePassword.java b/src/main/java/com/ybw/mathapp/util/ChangePassword.java index 72af3df..e4872cb 100644 --- a/src/main/java/com/ybw/mathapp/util/ChangePassword.java +++ b/src/main/java/com/ybw/mathapp/util/ChangePassword.java @@ -11,12 +11,40 @@ import java.io.IOException; import java.util.ArrayList; import java.util.List; +/** + * 修改用户密码的工具类。 + * + *

该类提供了一个静态方法来更新用户文件中指定用户的密码。 + * 它通过读取整个文件,找到目标用户,修改其密码,然后将整个内容写回文件来实现。 + * + * @author 杨博文 + * @since 2025 + */ public class ChangePassword { - static final List lines = new ArrayList<>(); - static String userLine = null; - static int userLineNumber = -1; - // 前端接口-修改密码 + /** + * 用于缓存文件所有行内容的列表。 + */ + private static final List lines = new ArrayList<>(); + /** + * 存储找到的用户信息行。 + */ + private static String userLine = null; + /** + * 存储找到的用户行在文件中的行号(从0开始)。 + */ + private static int userLineNumber = -1; + + /** + * 修改指定用户的密码。 + * + *

该方法会读取用户文件,查找与给定用户名匹配的行,更新该行的密码字段, + * 然后将更新后的内容写回文件。 + * + * @param name 要修改密码的用户名 + * @param newPassword 新密码 + * @return 如果修改成功返回 true,否则返回 false + */ public static boolean changePassword(String name, String newPassword) { File file = new File(USER_FILE); if (!file.exists()) { @@ -25,7 +53,10 @@ public class ChangePassword { } // 1. 读取文件,查找用户 - if(!findUserLine(name, file)) { + lines.clear(); // 清空上一次的缓存 + userLine = null; + userLineNumber = -1; + if (!findUserLine(name, file)) { return false; } @@ -38,6 +69,7 @@ public class ChangePassword { // 2. 更新找到的用户行中的密码 String[] parts = userLine.split(","); if (parts.length != 3) { + System.err.println("用户文件中用户 '" + name + "' 的数据格式不正确,无法修改密码。"); return false; } parts[2] = newPassword; // 假设密码是第三个字段 @@ -46,17 +78,24 @@ public class ChangePassword { lines.set(userLineNumber, updatedLine); // 替换列表中的旧行 // 3. 将更新后的内容写回文件 - if(!writeBack(lines, file)) { + if (!writeBack(lines, file)) { return false; } return true; } - public static boolean writeBack(List lines, File file) { + /** + * 将给定的行列表写回指定的文件。 + * + * @param lines 要写入的行列表 + * @param file 目标文件 + * @return 如果写入成功返回 true,否则返回 false + */ + private static boolean writeBack(List lines, File file) { try (BufferedWriter writer = new BufferedWriter(new FileWriter(file))) { - for (String l : lines) { - writer.write(l); + for (String line : lines) { + writer.write(line); writer.newLine(); } } catch (IOException e) { @@ -66,7 +105,17 @@ public class ChangePassword { return true; } - public static boolean findUserLine(String name, File file) { + /** + * 在指定文件中查找包含给定用户名的行。 + * + *

此方法会将文件的所有行读入 {@code lines} 列表,并设置 + * {@code userLine} 和 {@code userLineNumber}。 + * + * @param name 要查找的用户名 + * @param file 要搜索的文件 + * @return 如果读取文件过程无异常则返回 true,否则返回 false + */ + private static boolean findUserLine(String name, File file) { try (BufferedReader reader = new BufferedReader(new FileReader(file))) { String line; int currentLineNum = 0; @@ -74,10 +123,10 @@ public class ChangePassword { lines.add(line); String[] parts = line.split(","); // 假设格式为: username,email,password - if (parts.length >= 3 && parts[0].equals(name)) { + if (parts.length >= 3 && parts[0].trim().equals(name.trim())) { userLine = line; // 找到用户行 userLineNumber = currentLineNum; - break; // 找到后可以退出循环 + // break; // 找到后可以退出循环,但为了读取所有行到 lines,不在此处 break } currentLineNum++; } @@ -87,5 +136,4 @@ public class ChangePassword { } return true; } - -} +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/util/EmailService.java b/src/main/java/com/ybw/mathapp/util/EmailService.java index eba77a8..5a3451d 100644 --- a/src/main/java/com/ybw/mathapp/util/EmailService.java +++ b/src/main/java/com/ybw/mathapp/util/EmailService.java @@ -1,12 +1,6 @@ package com.ybw.mathapp.util; import com.ybw.mathapp.config.EmailConfig; -import java.util.HashMap; -import java.util.Iterator; -import java.util.Map; -import java.util.Map.Entry; -import java.util.Properties; -import java.util.Random; import jakarta.mail.Authenticator; import jakarta.mail.Message; import jakarta.mail.MessagingException; @@ -15,29 +9,50 @@ import jakarta.mail.Session; import jakarta.mail.Transport; import jakarta.mail.internet.InternetAddress; import jakarta.mail.internet.MimeMessage; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.Map.Entry; +import java.util.Properties; +import java.util.Random; +/** + * 邮件服务类,用于发送验证码和验证验证码。 + * + *

该类提供生成验证码、发送邮件、验证验证码以及清理过期验证码的功能。 + * 验证码的有效期由 {@link EmailConfig} 配置。 + * + * @author 杨博文 + * @since 2025 + */ public class EmailService { - private static Map verificationCodes = new HashMap<>(); - // 验证码信息内部类 - private static class VerificationCodeInfo { - String code; - long timestamp; - - VerificationCodeInfo(String code, long timestamp) { - this.code = code; - this.timestamp = timestamp; - } - } + /** + * 存储邮箱地址与验证码信息的映射。 + */ + private static final Map verificationCodes = new HashMap<>(); - // 生成6位随机验证码 + /** + * 生成一个6位的随机数字验证码。 + * + * @return 6位数字验证码字符串 + */ public static String generateVerificationCode() { Random random = new Random(); int code = 100000 + random.nextInt(900000); return String.valueOf(code); } - // 发送真实邮件验证码 + /** + * 发送验证码邮件到指定邮箱。 + * + *

此方法使用 {@link EmailConfig} 中的SMTP配置来发送邮件。 + * 发送成功后,会将验证码和时间戳存储到内存中。 + * + * @param recipientEmail 接收验证码的邮箱地址 + * @param code 要发送的验证码 + * @return 如果邮件发送成功返回 true,否则返回 false + */ public static boolean sendVerificationCode(String recipientEmail, String code) { try { // 创建邮件会话 @@ -89,7 +104,12 @@ public class EmailService { } } - // 创建HTML格式的邮件内容 + /** + * 创建HTML格式的邮件内容。 + * + * @param code 要嵌入到邮件中的验证码 + * @return HTML格式的邮件正文字符串 + */ private static String createEmailContent(String code) { return "" + "" + @@ -100,7 +120,8 @@ public class EmailService { ".container { max-width: 600px; margin: 0 auto; padding: 20px; }" + ".header { background-color: #4CAF50; color: white; padding: 20px; text-align: center; }" + ".content { padding: 20px; background-color: #f9f9f9; margin: 20px 0; }" + - ".code { font-size: 24px; font-weight: bold; color: #4CAF50; text-align: center; padding: 15px; background-color: white; border: 2px dashed #4CAF50; margin: 20px 0; }" + + ".code { font-size: 24px; font-weight: bold; color: #4CAF50; text-align: center; padding: 15px; background-color: white; border: 2px dashed #4CAF50; margin: 20px 0; }" + + ".footer { text-align: center; color: #666; font-size: 12px; }" + "" + "" + @@ -124,7 +145,13 @@ public class EmailService { ""; } - // 前端接口-验证验证码 + /** + * 验证用户输入的验证码是否正确且未过期。 + * + * @param email 发送验证码的邮箱地址 + * @param inputCode 用户输入的验证码 + * @return 如果验证码正确且未过期返回 true,否则返回 false + */ public static boolean verifyCode(String email, String inputCode) { VerificationCodeInfo codeInfo = verificationCodes.get(email); if (codeInfo == null) { @@ -141,7 +168,9 @@ public class EmailService { return codeInfo.code.equals(inputCode); } - // 清理过期的验证码(可选) + /** + * 清理内存中所有已过期的验证码。 + */ public static void cleanupExpiredCodes() { long currentTime = System.currentTimeMillis(); Iterator> iterator = @@ -157,12 +186,13 @@ public class EmailService { } /** - * 前端接口-邮箱格式验证 + * 验证邮箱地址格式是否正确(简单验证)。 + * * @param email 待验证的邮箱地址 - * @return true表示邮箱格式正确,false表示邮箱格式错误 + * @return 如果邮箱格式正确返回 true,否则返回 false */ public static boolean isValidEmail(String email) { - if (email.isEmpty()) { + if (email == null || email.isEmpty()) { System.out.println("邮箱地址不能为空!"); return false; } @@ -173,17 +203,48 @@ public class EmailService { return true; } - // 前端接口-发送验证码 + /** + * 前端接口:发送验证码到指定邮箱。 + * + *

此方法会生成验证码并尝试发送邮件。 + * + * @param email 接收验证码的邮箱地址 + * @return 如果验证码生成并发送邮件成功返回 true,否则返回 false + */ public static boolean sendCode(String email) { - // 发送真实邮件验证码 + // 生成验证码 String verificationCode = EmailService.generateVerificationCode(); - // 验证验证码是否成功发送 + // 尝试发送邮件 if (!EmailService.sendVerificationCode(email, verificationCode)) { + // 如果发送失败,sendVerificationCode 已经打印了错误信息 return false; } return true; } + /** + * 存储验证码及其生成时间的内部类。 + */ + private static class VerificationCodeInfo { + /** + * 验证码字符串。 + */ + String code; + /** + * 验证码生成的时间戳(毫秒)。 + */ + long timestamp; -} + /** + * 构造一个新的验证码信息对象。 + * + * @param code 验证码 + * @param timestamp 生成时间戳 + */ + VerificationCodeInfo(String code, long timestamp) { + this.code = code; + this.timestamp = timestamp; + } + } +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/util/Login.java b/src/main/java/com/ybw/mathapp/util/Login.java index 83f18c0..66a1a7d 100644 --- a/src/main/java/com/ybw/mathapp/util/Login.java +++ b/src/main/java/com/ybw/mathapp/util/Login.java @@ -1,16 +1,32 @@ package com.ybw.mathapp.util; +/** + * 用户登录处理类。 + * + *

该类提供一个静态方法用于验证用户凭据并处理登录逻辑。 + * + * @author 杨博文 + * @since 2025 + */ public class Login { - // 前端接口-登录成功or失败 + /** + * 尝试使用给定的用户名和密码进行登录。 + * + *

此方法通过 {@link LoginFileUtils#validateUser(String, String)} 验证用户凭据。 + * 登录成功或失败时会打印相应的控制台消息。 + * + * @param name 用户名 + * @param password 用户密码 + * @return 如果登录成功返回 true,否则返回 false + */ public static boolean login(String name, String password) { if (LoginFileUtils.validateUser(name, password)) { System.out.println("登录成功!欢迎回来," + name); return true; } else { - System.out.println("邮箱或密码错误!"); + System.out.println("用户名或密码错误!"); return false; } } - -} +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/util/LoginFileUtils.java b/src/main/java/com/ybw/mathapp/util/LoginFileUtils.java index 830fad2..e22d705 100644 --- a/src/main/java/com/ybw/mathapp/util/LoginFileUtils.java +++ b/src/main/java/com/ybw/mathapp/util/LoginFileUtils.java @@ -1,14 +1,38 @@ package com.ybw.mathapp.util; import com.ybw.mathapp.entity.User; -import java.io.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; import java.util.ArrayList; import java.util.List; +/** + * 用户文件操作工具类。 + * + *

该类负责与用户信息文件 ({@code users.txt}) 进行交互, + * 提供读取用户、保存用户、检查用户是否存在以及验证用户登录等功能。 + * + * @author 杨博文 + * @since 2025 + */ public class LoginFileUtils { - static final String USER_FILE = "users.txt"; - // 读取所有用户 + /** + * 用户信息文件的路径。 + */ + public static final String USER_FILE = "users.txt"; + + /** + * 从用户文件中读取所有用户信息。 + * + *

如果文件不存在,将尝试创建一个新文件并返回一个空列表。 + * + * @return 包含所有用户对象的列表 + */ public static List readUsers() { List users = new ArrayList<>(); File file = new File(USER_FILE); @@ -26,7 +50,9 @@ public class LoginFileUtils { String line; while ((line = reader.readLine()) != null) { line = line.trim(); - if (line.isEmpty()) continue; + if (line.isEmpty()) { + continue; + } User user = User.fromString(line); if (user != null) { @@ -39,7 +65,11 @@ public class LoginFileUtils { return users; } - // 保存用户到文件 + /** + * 将一个新用户信息追加保存到用户文件中。 + * + * @param user 要保存的用户对象 + */ public static void saveUser(User user) { try (PrintWriter writer = new PrintWriter(new FileWriter(USER_FILE, true))) { writer.println(user.toString()); @@ -48,7 +78,14 @@ public class LoginFileUtils { } } - // 前端接口-检查邮箱是否已注册 + /** + * 检查指定的邮箱是否已经注册。 + * + *

比较时不区分大小写。 + * + * @param email 要检查的邮箱地址 + * @return 如果邮箱已注册返回 true,否则返回 false + */ public static boolean isEmailRegistered(String email) { List users = readUsers(); for (User user : users) { @@ -59,7 +96,14 @@ public class LoginFileUtils { return false; } - // 前端接口-检查用户名是否已注册 + /** + * 检查指定的用户名是否已经注册。 + * + *

比较时不区分大小写。 + * + * @param name 要检查的用户名 + * @return 如果用户名已注册返回 true,否则返回 false + */ public static boolean isNameRegistered(String name) { List users = readUsers(); for (User user : users) { @@ -70,20 +114,36 @@ public class LoginFileUtils { return false; } - // 前端接口-验证用户登录 + /** + * 验证用户登录凭据。 + * + *

支持使用邮箱或用户名进行登录。比较邮箱/用户名时不区分大小写。 + * + * @param emailOrName 用户输入的邮箱或用户名 + * @param password 用户输入的密码 + * @return 如果凭据有效返回 true,否则返回 false + */ public static boolean validateUser(String emailOrName, String password) { List users = readUsers(); for (User user : users) { if ((user.getEmail().equalsIgnoreCase(emailOrName) - || user.getName().equalsIgnoreCase(emailOrName) ) - && user.getPassword().equals(password)) { + || user.getName().equalsIgnoreCase(emailOrName)) + && user.getPassword().equals(password)) { return true; } } return false; } - // 前端接口-通过邮箱查找用户名 - public static String emailFindName (String email) { + + /** + * 根据邮箱地址查找对应的用户名。 + * + *

比较邮箱时不区分大小写。 + * + * @param email 要查找的邮箱地址 + * @return 如果找到用户则返回其用户名,否则返回 null + */ + public static String emailFindName(String email) { List users = readUsers(); for (User user : users) { if (user.getEmail().equalsIgnoreCase(email)) { @@ -92,4 +152,4 @@ public class LoginFileUtils { } return null; } -} +} \ No newline at end of file diff --git a/src/main/java/com/ybw/mathapp/util/Register.java b/src/main/java/com/ybw/mathapp/util/Register.java index 5085316..02d4e5f 100644 --- a/src/main/java/com/ybw/mathapp/util/Register.java +++ b/src/main/java/com/ybw/mathapp/util/Register.java @@ -3,9 +3,27 @@ package com.ybw.mathapp.util; import com.ybw.mathapp.entity.User; import java.util.regex.Pattern; + +/** + * 用户注册处理类。 + * + *

该类提供用户注册、密码格式验证和两次密码匹配验证等功能。 + * + * @author 杨博文 + * @since 2025 + */ public class Register { - // 前端接口-完成注册 + /** + * 完成用户注册流程。 + * + *

此方法会创建一个新的用户对象并将其保存到用户文件中。 + * + * @param name 用户名 + * @param email 用户邮箱 + * @param password1 用户密码 + * @return 注册成功返回 true(当前实现总是返回 true,即使保存可能失败) + */ public static boolean register(String name, String email, String password1) { User user = new User(name, email, password1); LoginFileUtils.saveUser(user); @@ -14,9 +32,17 @@ public class Register { } /** - * 前端接口-密码格式验证 - * @param password1 第一次输入的密码 - * @return true表示符合要求,false表示不符合 + * 验证密码格式是否符合要求。 + * + *

密码要求: + *

    + *
  • 长度为 6 到 10 个字符
  • + *
  • 只能包含字母和数字
  • + *
  • 必须同时包含至少一个大写字母、一个小写字母和一个数字
  • + *
+ * + * @param password1 待验证的密码 + * @return 如果密码格式符合要求返回 true,否则返回 false */ public static boolean isVaildPassword(String password1) { // 使用正则表达式验证:长度6-10,只包含字母数字,且包含大小写字母和数字 @@ -28,10 +54,11 @@ public class Register { } /** - * 前端接口-两次密码匹配 + * 验证两次输入的密码是否一致。 + * * @param password1 第一次输入的密码 * @param password2 第二次输入的密码 - * @return true表示符合要求,false表示不符合 + * @return 如果两次密码相同返回 true,否则返回 false 并打印错误信息 */ public static boolean isEqualPassword(String password1, String password2) { if (!password1.equals(password2)) { @@ -40,5 +67,4 @@ public class Register { } return true; } - -} +} \ No newline at end of file