javadoc的补全

wanglirong_branch
hnu202326010328 7 months ago committed by hnu202326010318
parent 7fcd5cfb96
commit 47aca1462c

@ -1,9 +1,21 @@
package com.mathgenerator;
/**
* JavaFX fat JAR
*
* <p>
* 使 Maven Shade Plugin JavaFX
* "fat JAR"
* <p>
* {@code main} {@link MainApplication#main(String[])}
* JavaFX
*/
public class Launcher {
/**
*
*
* @param args
*/
public static void main(String[] args) {
MainApplication.main(args);
}

@ -4,39 +4,56 @@ import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.image.Image; // 1. 导入 Image 类
import javafx.scene.image.Image;
import javafx.stage.Stage;
import java.io.IOException;
/**
* JavaFX
* <p>
* {@link Application} JavaFX
* (Stage) (LoginView.fxml)
*
*/
public class MainApplication extends Application {
/**
* JavaFX
* <p>
* JavaFX
*
* @param primaryStage JavaFX
* @throws IOException FXML I/O
*/
@Override
public void start(Stage primaryStage) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/com/mathgenerator/view/LoginView.fxml"));
Scene scene = new Scene(root);
// 确保样式表被加载
scene.getStylesheets().add(getClass().getResource("/com/mathgenerator/styles/styles.css").toExternalForm());
primaryStage.setTitle("中小学数学学习软件");
// --- 核心修改在这里 ---
// 2. 加载图标文件
try {
Image appIcon = new Image(getClass().getResourceAsStream("/com/mathgenerator/images/icon.png"));
// 3. 将图标设置到程序窗口
primaryStage.getIcons().add(appIcon);
} catch (Exception e) {
System.err.println("错误:无法加载应用程序图标!请检查 'icon.png' 是否在 images 文件夹中。");
e.printStackTrace();
}
// --- 修改结束 ---
primaryStage.setScene(scene);
primaryStage.setResizable(false);
primaryStage.show();
}
/**
* main
* <p>
* Java {@link #launch(String...)} JavaFX
*
* @param args
*/
public static void main(String[] args) {
launch(args);
}

@ -13,6 +13,10 @@ import javafx.scene.control.PasswordField;
import javafx.stage.Stage;
import java.io.IOException;
/**
* (ChangePasswordView.fxml) FXML
*
*/
public class ChangePasswordController {
private final UserService userService = new UserService();
@ -26,48 +30,50 @@ public class ChangePasswordController {
@FXML private Label statusLabel;
/**
*
*
* FXML
*
* @param user User
*/
public void initData(User user) {
this.currentUser = user;
}
/**
*
*
*
* @param event ActionEvent
*/
@FXML
private void handleConfirmAction(ActionEvent event) {
// 1. 获取输入
String oldPassword = oldPasswordField.getText();
String newPassword = newPasswordField.getText();
String confirmNewPassword = confirmNewPasswordField.getText();
// 2. 输入校验
if (oldPassword.isEmpty() || newPassword.isEmpty() || confirmNewPassword.isEmpty()) {
showStatusMessage("所有密码字段都不能为空!", true);
return;
}
if (!newPassword.equals(confirmNewPassword)) {
showStatusMessage("两次输入的新密码不匹配!", true);
return;
}
// 新增校验:新密码不能与当前密码相同
if (oldPassword.equals(newPassword)) {
showStatusMessage("新密码不能与当前密码相同!", true);
return;
}
if (!UserService.isPasswordValid(newPassword)) {
showStatusMessage("新密码格式错误必须为6-10位且包含大小写字母和数字。", true);
return;
}
// 3. 调用后端服务修改密码
boolean success = userService.changePassword(
currentUser.username(),
oldPassword,
newPassword
);
// 4. 更新UI反馈
if (success) {
showStatusMessage("密码修改成功!请返回主菜单。", true);
@ -78,7 +84,10 @@ public class ChangePasswordController {
}
/**
*
* (statusLabel)
*
* @param message
* @param hasContent
*/
private void showStatusMessage(String message, boolean hasContent) {
statusLabel.setText(message);
@ -86,8 +95,9 @@ public class ChangePasswordController {
}
/**
*
* @param hasContent
* CSS
*
* @param hasContent true
*/
private void updateStatusLabelStyle(boolean hasContent) {
if (hasContent) {
@ -106,7 +116,10 @@ public class ChangePasswordController {
}
/**
*
*
*
*
* @param event ActionEvent
*/
@FXML
private void handleBackAction(ActionEvent event) {

@ -16,6 +16,11 @@ import javafx.stage.Stage;
import java.io.IOException;
import java.util.Optional;
import com.mathgenerator.util.ValidationUtils;
/**
* (LoginView.fxml) FXML
*
*/
public class LoginController {
// 依赖注入后端服务
@ -38,8 +43,10 @@ public class LoginController {
private Label statusLabel;
/**
*
* @param event
*
*
*
* @param event ActionEvent
*/
@FXML
private void handleLoginButtonAction(ActionEvent event) {
@ -69,8 +76,10 @@ public class LoginController {
}
/**
*
* @param event
*
*
*
* @param event ActionEvent
*/
@FXML
private void handleRegisterButtonAction(ActionEvent event) {
@ -78,8 +87,10 @@ public class LoginController {
}
/**
*
* @param user
*
* MainMenuController
*
* @param user User
*/
private void loadMainMenu(User user) {
try {
@ -104,8 +115,9 @@ public class LoginController {
}
/**
*
* @param fxmlPath FXML
*
*
* @param fxmlPath FXML
*/
private void loadScene(String fxmlPath) {
try {

@ -13,6 +13,11 @@ import javafx.scene.control.TextField;
import javafx.stage.Stage;
import java.io.IOException;
/**
* (MainMenuView.fxml) FXML
*
*/
public class MainMenuController {
private User currentUser;
@ -23,8 +28,9 @@ public class MainMenuController {
@FXML private Button logoutButton;
/**
*
* @param user
*
*
* @param user
*/
public void initData(User user) {
this.currentUser = user;
@ -33,21 +39,41 @@ public class MainMenuController {
clearStatus();
}
/**
*
*
* @param event
*/
@FXML
private void handlePrimaryAction(ActionEvent event) {
startQuiz(Level.PRIMARY);
}
/**
*
*
* @param event
*/
@FXML
private void handleJuniorHighAction(ActionEvent event) {
startQuiz(Level.JUNIOR_HIGH);
}
/**
*
*
* @param event
*/
@FXML
private void handleSeniorHighAction(ActionEvent event) {
startQuiz(Level.SENIOR_HIGH);
}
/**
*
*
* @param event
*/
@FXML
private void handleChangePasswordAction(ActionEvent event) {
try {
@ -71,6 +97,11 @@ public class MainMenuController {
}
}
/**
* 退
*
* @param event
*/
@FXML
private void handleLogoutAction(ActionEvent event) {
// 跳转回登录界面
@ -78,8 +109,10 @@ public class MainMenuController {
}
/**
*
* @param level
*
*
*
* @param level
*/
private void startQuiz(Level level) {
try {
@ -90,17 +123,14 @@ public class MainMenuController {
setErrorStatus("请输入题目数量!");
return;
}
int count = Integer.parseInt(countText);
// 修改范围检查从1-50改为10-30
if (count < 10 || count > 30) {
setErrorStatus("题目数量必须在 10 到 30 之间!");
return;
}
// 清除状态信息
clearStatus();
// 加载答题界面,并传递数据
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mathgenerator/view/QuizView.fxml"));
Parent root = loader.load();
@ -121,7 +151,9 @@ public class MainMenuController {
}
/**
*
*
*
* @param message
*/
private void setErrorStatus(String message) {
statusLabel.setText(message);
@ -129,13 +161,18 @@ public class MainMenuController {
}
/**
*
*
*/
private void clearStatus() {
statusLabel.setText("");
statusLabel.getStyleClass().clear();
}
/**
*
*
* @param fxmlPath FXML
*/
private void loadScene(String fxmlPath) {
try {
Stage stage = (Stage) logoutButton.getScene().getWindow();

@ -21,18 +21,18 @@ import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
/**
* (QuizView.fxml) FXML
*
*/
public class QuizController {
// --- 后端服务 ---
private final PaperService paperService;
// --- 答题状态 ---
private User currentUser;
private List<ChoiceQuestion> questions;
private List<Integer> userAnswers = new ArrayList<>();
private int currentQuestionIndex = 0;
// --- FXML 控件 ---
@FXML private Label questionNumberLabel;
@FXML private ProgressBar progressBar;
@FXML private Label questionTextLabel;
@ -42,34 +42,32 @@ public class QuizController {
@FXML private Label statusLabel;
/**
*
*
* PaperService
*/
public QuizController() {
// 这是依赖注入的一种简化形式,在真实项目中会使用框架管理
FileManager fileManager = new FileManager();
MixedDifficultyStrategy strategy = new MixedDifficultyStrategy();
this.paperService = new PaperService(fileManager, strategy);
}
/**
*
*
*
* @param user
* @param level
* @param questionCount
*/
public void initData(User user, Level level, int questionCount) {
this.currentUser = user;
// 1. 调用后端服务生成题目
this.questions = paperService.createPaper(user, questionCount, level);
// --- 核心修改在这里 ---
// 2. 立即调用后端服务,在后台自动保存生成的试卷
paperService.savePaper(user.username(), this.questions);
// 3. 正常显示第一道题
displayCurrentQuestion();
}
/**
* (ABCD)
*
*
*/
private void displayCurrentQuestion() {
ChoiceQuestion currentQuestion = questions.get(currentQuestionIndex);
@ -79,17 +77,13 @@ public class QuizController {
questionTextLabel.setText(currentQuestion.questionText());
List<RadioButton> radioButtons = List.of(option1, option2, option3, option4);
String[] prefixes = {"A. ", "B. ", "C. ", "D. "}; // 定义选项前缀
String[] prefixes = {"A. ", "B. ", "C. ", "D. "};
for (int i = 0; i < radioButtons.size(); i++) {
// 将前缀和选项文本结合起来
radioButtons.get(i).setText(prefixes[i] + currentQuestion.options().get(i));
}
optionsGroup.selectToggle(null); // 清除上一次的选择
// 清除状态提示并更新样式
statusLabel.setText("");
updateStatusLabelStyle(false); // 隐藏状态框
optionsGroup.selectToggle(null);
updateStatusLabelStyle(false);
if (currentQuestionIndex == questions.size() - 1) {
submitButton.setText("完成答题");
@ -97,48 +91,45 @@ public class QuizController {
}
/**
*
*
*
*
* @param event
*/
@FXML
private void handleSubmitButtonAction(ActionEvent event) {
RadioButton selectedRadioButton = (RadioButton) optionsGroup.getSelectedToggle();
if (selectedRadioButton == null) {
statusLabel.setText("请选择一个答案!");
updateStatusLabelStyle(true); // 显示状态框
updateStatusLabelStyle(true);
return;
}
// 清除状态提示
statusLabel.setText("");
updateStatusLabelStyle(false); // 隐藏状态框
updateStatusLabelStyle(false);
// 记录用户答案的索引
List<RadioButton> radioButtons = List.of(option1, option2, option3, option4);
userAnswers.add(radioButtons.indexOf(selectedRadioButton));
// 移动到下一题或结束答题
currentQuestionIndex++;
if (currentQuestionIndex < questions.size()) {
displayCurrentQuestion();
} else {
// 答题结束,计算分数并跳转到分数界面
calculateScoreAndShowResults();
}
}
/**
*
* @param hasContent
* CSS
*
* @param hasContent true
*/
private void updateStatusLabelStyle(boolean hasContent) {
if (hasContent) {
// 移除空样式,添加有内容样式
statusLabel.getStyleClass().removeAll("quiz-status-label-empty");
if (!statusLabel.getStyleClass().contains("quiz-status-label-with-text")) {
statusLabel.getStyleClass().add("quiz-status-label-with-text");
}
} else {
// 移除有内容样式,添加空样式
statusLabel.getStyleClass().removeAll("quiz-status-label-with-text");
if (!statusLabel.getStyleClass().contains("quiz-status-label-empty")) {
statusLabel.getStyleClass().add("quiz-status-label-empty");
@ -147,7 +138,7 @@ public class QuizController {
}
/**
*
*
*/
private void calculateScoreAndShowResults() {
int correctCount = 0;
@ -158,23 +149,19 @@ public class QuizController {
}
double score = (double) correctCount / questions.size() * 100;
// 禁用当前页面的按钮
submitButton.setDisable(true);
statusLabel.setText("答题已完成,正在为您计算分数...");
updateStatusLabelStyle(true); // 显示状态框
updateStatusLabelStyle(true);
// 加载分数界面并传递数据
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mathgenerator/view/ScoreView.fxml"));
Parent root = loader.load();
ScoreController controller = loader.getController();
controller.initData(currentUser, score); // 将用户和分数传递过去
controller.initData(currentUser, score);
Stage stage = (Stage) submitButton.getScene().getWindow();
stage.setScene(new Scene(root));
stage.setTitle("答题结果");
} catch (IOException e) {
e.printStackTrace();
}

@ -1,6 +1,7 @@
package com.mathgenerator.controller;
import com.mathgenerator.service.UserService;
import com.mathgenerator.util.ValidationUtils;
import javafx.animation.KeyFrame;
import javafx.animation.Timeline;
import javafx.event.ActionEvent;
@ -16,15 +17,17 @@ import javafx.stage.Stage;
import javafx.util.Duration;
import java.io.IOException;
// 导入校验工具类
import com.mathgenerator.util.ValidationUtils;
/**
* (RegisterView.fxml) FXML
*
*/
public class RegisterController {
private final UserService userService = new UserService();
private String sentCode; // 用于存储已发送的验证码
private Timeline countdownTimeline; // 新增用于倒计时的Timeline
private int countdownSeconds = 60; // 新增:倒计时总秒数
private String sentCode;
private Timeline countdownTimeline;
private int countdownSeconds = 60;
@FXML private TextField usernameField;
@FXML private TextField emailField;
@ -36,30 +39,33 @@ public class RegisterController {
@FXML private Button backToLoginButton;
@FXML private Label statusLabel;
/**
*
* 60
*
* @param event
*/
@FXML
private void handleSendCodeAction(ActionEvent event) {
String email = emailField.getText();
// --- 核心修改在这里 ---
// 使用 ValidationUtils.isEmailValid 进行严格校验
if (!ValidationUtils.isEmailValid(email)) {
showStatusMessage("请输入一个有效的邮箱地址!", true);
return;
}
// 调用后端服务发送验证码
this.sentCode = userService.sendVerificationCode(email);
// 处理发送结果
if (this.sentCode != null) {
showStatusMessage("验证码已成功发送,请查收您的邮箱。", true);
startCountdown(); // **核心修改:启动倒计时**
startCountdown();
} else {
showStatusMessage("验证码发送失败!请检查配置或联系管理员。", true);
}
}
/**
* 60
* 60
*
*/
private void startCountdown() {
sendCodeButton.setDisable(true);
@ -70,16 +76,21 @@ public class RegisterController {
countdownTimeline.stop();
sendCodeButton.setDisable(false);
sendCodeButton.setText("发送验证码");
countdownSeconds = 60; // 重置倒计时
countdownSeconds = 60;
}
}));
countdownTimeline.setCycleCount(60);
countdownTimeline.play();
}
/**
*
*
*
* @param event
*/
@FXML
private void handleRegisterAction(ActionEvent event) {
// 1. 字段校验 (已简化,不再校验密码)
String username = usernameField.getText();
String email = emailField.getText();
@ -94,13 +105,10 @@ public class RegisterController {
return;
}
// 2. 调用后端服务进行无密码注册
boolean success = userService.register(username, email);
// 3. 根据结果更新UI或跳转
if (success) {
showStatusMessage("注册成功!请设置您的密码。", true);
// 成功后,加载设置密码界面,并传递用户名
loadSetPasswordScene(username);
} else {
showStatusMessage("注册失败:用户名或邮箱已被占用。", true);
@ -108,7 +116,10 @@ public class RegisterController {
}
/**
*
*
*
* @param message
* @param hasContent true
*/
private void showStatusMessage(String message, boolean hasContent) {
statusLabel.setText(message);
@ -116,18 +127,17 @@ public class RegisterController {
}
/**
*
* @param hasContent
* CSS
*
* @param hasContent true
*/
private void updateStatusLabelStyle(boolean hasContent) {
if (hasContent) {
// 移除空样式,添加有内容样式
statusLabel.getStyleClass().removeAll("register-status-label");
if (!statusLabel.getStyleClass().contains("register-status-label-with-text")) {
statusLabel.getStyleClass().add("register-status-label-with-text");
}
} else {
// 移除有内容样式,添加空样式
statusLabel.getStyleClass().removeAll("register-status-label-with-text");
if (!statusLabel.getStyleClass().contains("register-status-label")) {
statusLabel.getStyleClass().add("register-status-label");
@ -136,15 +146,16 @@ public class RegisterController {
}
/**
* ()
*
*
* @param username
*/
private void loadSetPasswordScene(String username) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mathgenerator/view/SetPasswordView.fxml"));
Parent root = loader.load();
SetPasswordController controller = loader.getController();
controller.initData(username); // 将用户名传递给新界面的控制器
controller.initData(username);
Stage stage = (Stage) registerButton.getScene().getWindow();
stage.setScene(new Scene(root));
@ -154,11 +165,21 @@ public class RegisterController {
}
}
/**
*
*
* @param event
*/
@FXML
private void handleBackToLoginAction(ActionEvent event) {
loadScene("/com/mathgenerator/view/LoginView.fxml");
}
/**
* FXML
*
* @param fxmlPath FXML
*/
private void loadScene(String fxmlPath) {
try {
Parent root = FXMLLoader.load(getClass().getResource(fxmlPath));
@ -170,7 +191,7 @@ public class RegisterController {
}
/**
*
*
*/
public void cleanup() {
if (countdownTimeline != null) {

@ -11,6 +11,10 @@ import javafx.scene.control.Label;
import javafx.stage.Stage;
import java.io.IOException;
/**
* (ScoreView.fxml) FXML
*
*/
public class ScoreController {
private User currentUser;
@ -21,15 +25,15 @@ public class ScoreController {
@FXML private Button logoutButton;
/**
*
* @param user
* @param score
*
*
* @param user
* @param score
*/
public void initData(User user, double score) {
this.currentUser = user;
scoreLabel.setText(String.format("%.2f", score));
// 根据分数显示不同的鼓励语
if (score == 100.0) {
resultMessageLabel.setText("太棒了!你答对了所有题目!");
} else if (score >= 80) {
@ -42,7 +46,10 @@ public class ScoreController {
}
/**
*
*
* 便
*
* @param event ActionEvent
*/
@FXML
private void handleTryAgainAction(ActionEvent event) {
@ -50,7 +57,7 @@ public class ScoreController {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mathgenerator/view/MainMenuView.fxml"));
Parent root = loader.load();
MainMenuController controller = loader.getController();
controller.initData(currentUser); // 将用户信息传回主菜单
controller.initData(currentUser);
Stage stage = (Stage) tryAgainButton.getScene().getWindow();
stage.setScene(new Scene(root));
@ -61,7 +68,10 @@ public class ScoreController {
}
/**
* 退
* 退
*
*
* @param event ActionEvent
*/
@FXML
private void handleLogoutAction(ActionEvent event) {

@ -15,6 +15,10 @@ import javafx.stage.Stage;
import java.io.IOException;
/**
* (SetPasswordView.fxml) FXML
*
*/
public class SetPasswordController {
private final UserService userService = new UserService();
@ -27,13 +31,22 @@ public class SetPasswordController {
@FXML private Label statusLabel;
/**
*
*
*
* @param username
*/
public void initData(String username) {
this.username = username;
promptLabel.setText("为您的账户 " + username + " 设置密码");
}
/**
*
*
*
*
* @param event
*/
@FXML
private void handleConfirmAction(ActionEvent event) {
String newPassword = newPasswordField.getText();
@ -49,12 +62,10 @@ public class SetPasswordController {
return;
}
// 调用后端服务设置密码
boolean success = userService.setPassword(this.username, newPassword);
if (success) {
showStatusMessage("密码设置成功!正在进入主菜单...", true);
// 密码设置成功后,获取完整的用户信息并直接跳转到主菜单
userService.findUserByUsername(this.username).ifPresent(this::loadMainMenu);
} else {
showStatusMessage("密码设置失败,请稍后重试或重新注册。", true);
@ -62,7 +73,10 @@ public class SetPasswordController {
}
/**
*
*
*
* @param message
* @param hasContent true
*/
private void showStatusMessage(String message, boolean hasContent) {
statusLabel.setText(message);
@ -70,18 +84,17 @@ public class SetPasswordController {
}
/**
*
* @param hasContent
* CSS
*
* @param hasContent true
*/
private void updateStatusLabelStyle(boolean hasContent) {
if (hasContent) {
// 移除空样式,添加有内容样式
statusLabel.getStyleClass().removeAll("setpassword-status-label");
if (!statusLabel.getStyleClass().contains("setpassword-status-label-with-text")) {
statusLabel.getStyleClass().add("setpassword-status-label-with-text");
}
} else {
// 移除有内容样式,添加空样式
statusLabel.getStyleClass().removeAll("setpassword-status-label-with-text");
if (!statusLabel.getStyleClass().contains("setpassword-status-label")) {
statusLabel.getStyleClass().add("setpassword-status-label");
@ -90,14 +103,16 @@ public class SetPasswordController {
}
/**
* ()
*
*
* @param user User
*/
private void loadMainMenu(User user) {
try {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/com/mathgenerator/view/MainMenuView.fxml"));
Parent root = loader.load();
MainMenuController controller = loader.getController();
controller.initData(user); // 将完整的User对象传递给主菜单
controller.initData(user);
Stage stage = (Stage) confirmButton.getScene().getWindow();
stage.setScene(new Scene(root));

@ -6,58 +6,56 @@ import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
/**
* ( - )
*
*
* <p>
* {@link PrimarySchoolGenerator}
*
*/
public class JuniorHighSchoolGenerator extends PrimarySchoolGenerator {
private static final int[] PERFECT_SQUARES = {1, 4, 9, 16, 25, 36, 49, 64, 81, 100};
/**
*
* <p>
*
*
* 退
*
* @return {@link ChoiceQuestion}
*/
@Override
public ChoiceQuestion generateSingleQuestion() {
ThreadLocalRandom random = ThreadLocalRandom.current();
int operandCount = random.nextInt(2, 5); // 2到4个操作数
int operandCount = random.nextInt(2, 5);
// 1. 生成基础的表达式组件列表
List<String> parts = new ArrayList<>();
// 使用 getOperand() 和 getRandomOperator() 这些继承自父类的方法
parts.add(String.valueOf(getOperand()));
for (int i = 1; i < operandCount; i++) {
parts.add(getRandomOperator());
parts.add(String.valueOf(getOperand()));
}
// 2. 结构化地插入初中特色运算
int modificationIndex = random.nextInt(operandCount) * 2; // 随机选择一个操作数的位置
int modificationIndex = random.nextInt(operandCount) * 2;
boolean useSquare = random.nextBoolean();
if (useSquare) {
// 平方策略:直接在数字后附加平方符号
parts.set(modificationIndex, parts.get(modificationIndex) + "²");
} else {
// 开根号策略:用一个完美的开根号表达式替换整个数字
int perfectSquare = PERFECT_SQUARES[random.nextInt(PERFECT_SQUARES.length)];
parts.set(modificationIndex, "√" + perfectSquare);
}
// 3. (可选)为增强后的表达式添加括号
if (operandCount > 2 && random.nextBoolean()) {
super.addParentheses(parts); // 调用父类的protected方法
super.addParentheses(parts);
}
String finalQuestionText = String.join(" ", parts);
// 4. 计算答案
double finalCorrectAnswer;
try {
Object result = evaluateExpression(finalQuestionText);
finalCorrectAnswer = ((Number) result).doubleValue();
} catch (Exception e) {
// 发生意外,安全返回一个小学题
return super.generateSingleQuestion();
}
// 5. 生成选项
List<String> options = generateDecimalOptions(finalCorrectAnswer);
int correctIndex = options.indexOf(formatNumber(finalCorrectAnswer));

@ -1,6 +1,7 @@
package com.mathgenerator.generator;
import com.mathgenerator.model.ChoiceQuestion; // 导入新模型
import com.mathgenerator.model.ChoiceQuestion;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
@ -10,11 +11,14 @@ import java.util.concurrent.ThreadLocalRandom;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
import java.text.DecimalFormat;
/**
*
* + - * / ()
*
* <p>
*
*
*
* @see QuestionGenerator
*/
public class PrimarySchoolGenerator implements QuestionGenerator {
@ -22,7 +26,11 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
/**
*
* @return ChoiceQuestion
* <p>
* 24
* {@link ChoiceQuestion}
*
* @return {@code ChoiceQuestion}
*/
@Override
public ChoiceQuestion generateSingleQuestion() {
@ -65,9 +73,13 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
}
/**
* (13)
* @param correctAnswer
* @return
*
* <p>
* 110
*
*
* @param correctAnswer
* @return
*/
protected List<String> generateOptions(int correctAnswer) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -88,28 +100,28 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
}
/**
* 使JVM ()
* @param expression
* @return (IntegerDouble)
* @throws ScriptException
* 使JVM
* <p>
* Rhino
*
* @param expression " (3 + 5) * 2 "
* @return {@code Integer} {@code Double}
* @throws ScriptException
* @throws IllegalStateException Rhino JavaScript
*/
protected Object evaluateExpression(String expression) throws ScriptException {
ScriptEngineManager manager = new ScriptEngineManager();
// --- 核心修改在这里 ---
// 使用 "rhino" 作为引擎名称这是Rhino引擎的官方名称
ScriptEngine engine = manager.getEngineByName("rhino");
if (engine == null) {
// 增加一个健壮性检查,如果引擎还是没找到,就给出清晰的错误提示
throw new IllegalStateException("错误找不到Rhino JavaScript引擎。请检查pom.xml中是否已添加rhino-engine的依赖。");
}
// Rhino不需要预定义函数可以直接计算
// 预处理表达式以兼容Rhino引擎的数学函数
String script = expression.replaceAll("(\\d+(\\.\\d+)?)²", "Math.pow($1, 2)")
.replaceAll("√(\\d+(\\.\\d+)?)", "Math.sqrt($1)")
.replaceAll("(\\d+)°", " * (Math.PI / 180)"); // Rhino对角度计算的语法要求更严格
.replaceAll("(\\d+)°", " * (Math.PI / 180)");
// 为了让sin/cos/tan能正确计算需要特殊处理
script = script.replaceAll("sin\\(", "Math.sin(")
.replaceAll("cos\\(", "Math.cos(")
.replaceAll("tan\\(", "Math.tan(");
@ -118,24 +130,27 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
}
/**
*
* @param number
* @return
* double
* <p>
*
*
* @param number
* @return
*/
protected String formatNumber(double number) {
if (number == (long) number) {
return String.format("%d", (long) number); // 如果是整数,不显示小数位
return String.format("%d", (long) number);
} else {
// 使用DecimalFormat来去除末尾多余的0
DecimalFormat df = new DecimalFormat("#.##");
return df.format(number);
}
}
/**
*
* @param correctAnswer
* @return
*
*
* @param correctAnswer
* @return
*/
protected List<String> generateDecimalOptions(double correctAnswer) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -143,8 +158,7 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
options.add(formatNumber(correctAnswer));
while (options.size() < 4) {
double delta = random.nextDouble(1, 11); // 答案加减1-10之间的随机小数
// 随机决定是加还是减
double delta = random.nextDouble(1, 11);
double distractor = random.nextBoolean() ? correctAnswer + delta : correctAnswer - delta;
options.add(formatNumber(distractor));
}
@ -154,14 +168,29 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
return sortedOptions;
}
/**
* 1100
*
* @return
*/
protected int getOperand() {
return ThreadLocalRandom.current().nextInt(1, 101);
}
/**
* {@code OPERATORS}
*
* @return "+""-""*" "/"
*/
protected String getRandomOperator() {
return OPERATORS[ThreadLocalRandom.current().nextInt(OPERATORS.length)];
}
/**
*
*
* @param parts
*/
protected void addParentheses(List<String> parts) {
ThreadLocalRandom random = ThreadLocalRandom.current();
int startOperandIndex = random.nextInt(parts.size() / 2);
@ -171,7 +200,4 @@ public class PrimarySchoolGenerator implements QuestionGenerator {
parts.add(endIndex + 1, ")");
parts.add(startIndex, "(");
}
}

@ -1,14 +1,22 @@
package com.mathgenerator.generator;
import com.mathgenerator.model.ChoiceQuestion; // 导入新模型
import com.mathgenerator.model.ChoiceQuestion;
/**
*
*
* <p>
*
*
*/
public interface QuestionGenerator {
/**
*
* @return ChoiceQuestion
* <p>
*
* {@link ChoiceQuestion}
*
* @return {@code ChoiceQuestion}
*/
ChoiceQuestion generateSingleQuestion();
}

@ -7,18 +7,24 @@ import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.ThreadLocalRandom;
import javax.script.ScriptEngine;
import javax.script.ScriptEngineManager;
import javax.script.ScriptException;
/**
*
*
* <p>
*
*
*
* @see QuestionGenerator
*/
public class SafePrimarySchoolGenerator implements QuestionGenerator {
/**
*
* @return ChoiceQuestion
*
* <p>
* {@code generateSafeExpression}
* {@link ChoiceQuestion}
*
* @return {@code ChoiceQuestion}
*/
@Override
public ChoiceQuestion generateSingleQuestion() {
@ -34,12 +40,21 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
}
/**
*
* (Record)
*
* @param parts
* @param value
* @param operandsUsed 使
*/
private record Term(List<String> parts, int value, int operandsUsed) {}
/**
*
*
* <p>
*
*
* @param operandBudget
* @return {@code Term}
*/
private Term generateSafeExpression(int operandBudget) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -72,7 +87,12 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
}
/**
* (Term)
* (Term)
* <p>
*
*
* @param operandsRemaining
* @return {@code Term}
*/
private Term generateTerm(int operandsRemaining) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -91,7 +111,12 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
}
/**
*
*
* <p>
*
*
* @param operandsRemaining
* @return {@code Term}
*/
private Term generateSimpleTerm(int operandsRemaining) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -118,6 +143,12 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
return new Term(parts, termValue, operandsUsed);
}
/**
*
*
* @param number
* @return
*/
private List<Integer> getDivisors(int number) {
List<Integer> divisors = new ArrayList<>();
for (int i = 1; i <= number; i++) {
@ -127,7 +158,12 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
}
/**
* (13)
*
* <p>
*
*
* @param correctAnswer
* @return
*/
private List<String> generateOptions(int correctAnswer) {
ThreadLocalRandom random = ThreadLocalRandom.current();
@ -137,8 +173,7 @@ public class SafePrimarySchoolGenerator implements QuestionGenerator {
while (options.size() < 4) {
int delta = random.nextInt(1, 11);
int distractor = random.nextBoolean() ? correctAnswer + delta : correctAnswer - delta;
// 确保干扰项非负
if (distractor >= 0) {
if (distractor >= 0) { // 确保干扰项非负
options.add(String.valueOf(distractor));
}
}

@ -6,8 +6,10 @@ import java.util.Map;
import java.util.concurrent.ThreadLocalRandom;
/**
* ( - )
*
*
* <p>
* {@link JuniorHighSchoolGenerator}
*
*/
public class SeniorHighSchoolGenerator extends JuniorHighSchoolGenerator {
@ -24,6 +26,14 @@ public class SeniorHighSchoolGenerator extends JuniorHighSchoolGenerator {
// 将Map的键转换为数组方便随机选取
private static final String[] TRIG_KEYS = TRIG_TERMS.keySet().toArray(new String[0]);
/**
*
* <p>
*
*
*
* @return {@link ChoiceQuestion}
*/
@Override
public ChoiceQuestion generateSingleQuestion() {
// 1. 先生成一个保证可计算的、高性能的初中选择题,作为基础

@ -3,10 +3,14 @@ package com.mathgenerator.model;
import java.util.List;
/**
*
* @param questionText
* @param options
* @param correctOptionIndex (0-3)
* (Record)
* <p>
* (Record)
*
*
* @param questionText
* @param options (List)
* @param correctOptionIndex {@code options} 0 3
*/
public record ChoiceQuestion(String questionText, List<String> options, int correctOptionIndex) {
}

@ -1,14 +1,29 @@
package com.mathgenerator.model;
/**
*
* (Enum)
* <p>
*
*
*/
public enum Level {
/**
*
*/
PRIMARY("小学"),
/**
*
*/
JUNIOR_HIGH("初中"),
/**
*
*/
SENIOR_HIGH("高中");
private final String chineseName;
/**
*
*
@ -17,10 +32,11 @@ public enum Level {
Level(String chineseName) {
this.chineseName = chineseName;
}
/**
*
*
*
* @return
* @return (, "小学")
*/
public String getChineseName() {
return chineseName;

@ -1,10 +1,14 @@
package com.mathgenerator.model;
/**
* (Record)
* @param username
* @param email ()
* @param password
* (Record)
* <p>
* (Record)
*
*
* @param username
* @param email
* @param password {@code null}
*/
public record User(String username, String email, String password) {
}

@ -5,6 +5,13 @@ import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
/**
*
* <p>
* {@code config.properties}
* SMTP
*
*/
public class EmailConfig {
private static final Properties properties = new Properties();
@ -17,18 +24,38 @@ public class EmailConfig {
}
}
/**
* SMTP
*
* @return SMTP
*/
public static String getHost() {
return properties.getProperty("smtp.host");
}
/**
* SMTP
*
* @return SMTP
*/
public static int getPort() {
return Integer.parseInt(properties.getProperty("smtp.port"));
}
/**
* SMTP
*
* @return SMTP
*/
public static String getUsername() {
return properties.getProperty("smtp.username");
}
/**
* SMTP
*
* @return SMTP
*/
public static String getPassword() {
return properties.getProperty("smtp.password");
}

@ -2,7 +2,7 @@ package com.mathgenerator.service;
import com.mathgenerator.model.User;
import com.mathgenerator.model.Level;
import com.mathgenerator.model.ChoiceQuestion; // 导入新模型
import com.mathgenerator.model.ChoiceQuestion;
import com.mathgenerator.service.strategy.PaperStrategy;
import com.mathgenerator.storage.FileManager;
import java.io.IOException;
@ -12,37 +12,48 @@ import java.util.List;
import java.util.Set;
/**
* ChoiceQuestion
*
* <p>
*
*
*/
public class PaperService {
private final FileManager fileManager;
private final PaperStrategy paperStrategy;
/**
* PaperService
*
* @param fileManager {@link FileManager}
* @param paperStrategy {@link PaperStrategy}
*/
public PaperService(FileManager fileManager, PaperStrategy paperStrategy) {
this.fileManager = fileManager;
this.paperStrategy = paperStrategy;
}
/**
*
* @param user
* @param count
* @param currentLevel
* @return
*
* <p>
*
*
*
*
* @param user
* @param count
* @param currentLevel
* @return {@link ChoiceQuestion}
*/
public List<ChoiceQuestion> createPaper(User user, int count, Level currentLevel) {
// 查重集合现在存储题干字符串
Set<String> existingQuestionTexts = fileManager.loadExistingQuestions(user.username());
List<ChoiceQuestion> newPaper = new ArrayList<>();
Set<String> generatedInSession = new HashSet<>();
System.out.println("正在根据策略生成选择题,请稍候...");
while (newPaper.size() < count) {
// 1. 生成的是ChoiceQuestion对象
ChoiceQuestion question = paperStrategy.selectGenerator(currentLevel).generateSingleQuestion();
String questionText = question.questionText(); // 提取题干用于查重
String questionText = question.questionText();
// 2. 使用题干进行查重
if (!existingQuestionTexts.contains(questionText) && !generatedInSession.contains(questionText)) {
newPaper.add(question);
generatedInSession.add(questionText);
@ -52,9 +63,10 @@ public class PaperService {
}
/**
*
* @param username
* @param paper
*
*
* @param username
* @param paper {@link ChoiceQuestion}
*/
public void savePaper(String username, List<ChoiceQuestion> paper) {
try {

@ -1,10 +1,13 @@
package com.mathgenerator.service;
import com.google.gson.Gson;
import java.util.Objects;
import com.google.gson.GsonBuilder;
import com.google.gson.reflect.TypeToken;
import com.mathgenerator.model.User;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
@ -17,25 +20,35 @@ import java.util.Optional;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ThreadLocalRandom;
import java.util.regex.Pattern;
import org.apache.commons.mail.Email;
import org.apache.commons.mail.EmailException;
import org.apache.commons.mail.SimpleEmail;
/**
*
* <p>
*
* JSON
*/
public class UserService {
private static final Path USER_FILE_PATH = Paths.get("users.json");
// 密码策略: 6-10位, 必须包含大小写字母和数字
private static final Pattern PASSWORD_PATTERN =
Pattern.compile("^(?=.*[a-z])(?=.*[A-Z])(?=.*\\d).{6,10}$");
private Map<String, User> userDatabase;
private final Gson gson = new GsonBuilder().setPrettyPrinting().create();
/**
* UserService
* {@code users.json}
*/
public UserService() {
this.userDatabase = loadUsersFromFile();
}
/**
* {@code users.json} Map
* Map
*
* @return {@code ConcurrentHashMap}
*/
private Map<String, User> loadUsersFromFile() {
// 如果文件不存在直接返回一个空的Map不再创建默认用户
if (!Files.exists(USER_FILE_PATH)) {
return new ConcurrentHashMap<>();
}
@ -43,7 +56,6 @@ public class UserService {
try (FileReader reader = new FileReader(USER_FILE_PATH.toFile())) {
Type type = new TypeToken<Map<String, User>>() {}.getType();
Map<String, User> loadedUsers = gson.fromJson(reader, type);
// 如果文件为空或格式错误也返回一个空的Map
return loadedUsers != null ? new ConcurrentHashMap<>(loadedUsers) : new ConcurrentHashMap<>();
} catch (IOException e) {
System.err.println("错误:加载用户文件失败 - " + e.getMessage());
@ -51,6 +63,9 @@ public class UserService {
}
}
/**
* {@code users.json}
*/
private void saveUsers() {
try (FileWriter writer = new FileWriter(USER_FILE_PATH.toFile())) {
gson.toJson(this.userDatabase, writer);
@ -59,70 +74,72 @@ public class UserService {
}
}
/**
*
*
* @param username
* @return {@link User} {@code Optional}
*/
public Optional<User> findUserByUsername(String username) {
return Optional.ofNullable(this.userDatabase.get(username));
}
/**
*
*
* @param username
* @param password
* @return {@link User} {@code Optional} {@code Optional}
*/
public Optional<User> login(String username, String password) {
return findUserByUsername(username)
.filter(user -> user.password().equals(password));
}
/**
* ()
* @param email
* @return 6, null
* 6
*
* @param email
* @return 6 {@code null}
*/
public String sendVerificationCode(String email) {
String code = String.format("%06d", ThreadLocalRandom.current().nextInt(100000, 1000000));
try {
Email mail = new SimpleEmail();
// 1. 设置SMTP服务器信息
mail.setHostName(EmailConfig.getHost());
mail.setSmtpPort(EmailConfig.getPort());
mail.setAuthentication(EmailConfig.getUsername(), EmailConfig.getPassword());
mail.setSSLOnConnect(true); // 开启SSL加密
// 2. 设置邮件内容
mail.setFrom(EmailConfig.getUsername()); // 发件人
mail.setSubject("【数学学习软件】您的注册验证码"); // 邮件主题
mail.setMsg("您好!\n\n感谢您注册数学学习软件。您的验证码是" + code + "\n\n请在5分钟内使用。"); // 邮件正文
mail.addTo(email); // 收件人
// 3. 发送邮件
mail.setSSLOnConnect(true);
mail.setFrom(EmailConfig.getUsername());
mail.setSubject("【数学学习软件】您的注册验证码");
mail.setMsg("您好!\n\n感谢您注册数学学习软件。您的验证码是" + code + "\n\n请在5分钟内使用。");
mail.addTo(email);
mail.send();
System.out.println("验证码邮件已成功发送至: " + email);
return code;
} catch (EmailException e) {
System.err.println("错误:发送验证码邮件失败!请检查您的 config.properties 配置或网络连接。");
e.printStackTrace();
return null; // 发送失败
return null;
}
}
/**
* ()
* @param username
* @param email
* @return true, false
*
*
* @param username
* @param email
* @return {@code true} {@code false}
*/
public boolean register(String username, String email) {
if (userDatabase.containsKey(username)) {
return false; // 用户名已存在
}
// 检查数据库中已存在的用户的email是否与新email相同
// 使用 email.equals(u.email()) 可以安全地处理 u.email() 为 null 的情况
if (userDatabase.values().stream()
.anyMatch(u -> email.equals(u.email()))) {
if (userDatabase.values().stream().anyMatch(u -> email.equals(u.email()))) {
return false; // 邮箱已存在
}
// --- 核心修正在这里 ---
// 创建用户时,密码字段设为 null表示该用户处于“待设置密码”状态
User newUser = new User(username, email, null);
userDatabase.put(username, newUser);
saveUsers();
@ -130,36 +147,43 @@ public class UserService {
}
/**
* ()
* @param username
* @param password
* @return true, false
*
* {@code null}
*
* @param username
* @param password
* @return {@code true} {@code false}
*/
public boolean setPassword(String username, String password) {
return findUserByUsername(username)
.map(user -> {
// 只有当用户当前密码为 null 时才允许设置
if (user.password() == null) {
User updatedUser = new User(user.username(), user.email(), password);
userDatabase.put(username, updatedUser);
saveUsers();
return true;
}
return false; // 用户已经有密码,不能通过此方法设置
return false;
}).orElse(false);
}
/**
*
* @param password
* @return true
*
*
* @param password
* @return {@code true} {@code false}
*/
public static boolean isPasswordValid(String password) {
return password != null && PASSWORD_PATTERN.matcher(password).matches();
}
/**
*
* @return true
*
*
* @param username
* @param oldPassword
* @param newPassword
* @return {@code true} {@code false}
*/
public boolean changePassword(String username, String oldPassword, String newPassword) {
return findUserByUsername(username)

@ -6,29 +6,39 @@ import java.util.concurrent.ThreadLocalRandom;
/**
*
* ()
* <p>
* 使
*
*
*/
public class MixedDifficultyStrategy implements PaperStrategy {
// 持有所有可能的生成器
// 持有所有可能的生成器实例
private final QuestionGenerator primaryGenerator = new PrimarySchoolGenerator();
private final QuestionGenerator safePrimaryGenerator = new SafePrimarySchoolGenerator(); // 新增
private final QuestionGenerator juniorHighGenerator = new JuniorHighSchoolGenerator();
private final QuestionGenerator seniorHighGenerator = new SeniorHighSchoolGenerator();
/**
*
* <p>
* - ****: 100% 使 {@link SafePrimarySchoolGenerator}
* - ****: 70% 使 {@link JuniorHighSchoolGenerator}30% 使 {@link PrimarySchoolGenerator}
* - ****: 60% 使 {@link SeniorHighSchoolGenerator}30% 使 {@link JuniorHighSchoolGenerator}10% 使 {@link PrimarySchoolGenerator}
*
* @param mainLevel
* @return {@link QuestionGenerator}
*/
@Override
public QuestionGenerator selectGenerator(Level mainLevel) {
double randomValue = ThreadLocalRandom.current().nextDouble();
return switch (mainLevel) {
// 当主难度是小学时100%使用“安全”的生成器
case PRIMARY -> safePrimaryGenerator;
case JUNIOR_HIGH -> {
// 初中试卷70%初中难度30%使用“不安全”的小学难度(允许负数)
if (randomValue < 0.7) yield juniorHighGenerator;
else yield primaryGenerator;
}
case SENIOR_HIGH -> {
// 高中试卷60%高中30%初中10%使用“不安全”的小学难度
if (randomValue < 0.6) yield seniorHighGenerator;
else if (randomValue < 0.9) yield juniorHighGenerator;
else yield primaryGenerator;

@ -5,14 +5,17 @@ import com.mathgenerator.model.Level;
/**
*
*
* <p>
*
*
*/
public interface PaperStrategy {
/**
*
*
*
* @param mainLevel
* @return QuestionGenerator
* @param mainLevel ({@link Level})
* @return {@link QuestionGenerator}
*/
QuestionGenerator selectGenerator(Level mainLevel);
}

@ -18,12 +18,30 @@ import java.util.stream.Collectors;
import java.util.stream.Stream;
/**
* Stream
*
* <p>
*
* <ul>
* <li></li>
* <li></li>
* </ul>
* Stream
*/
public class FileManager {
private static final Path BASE_PATH = Paths.get("generated_papers");
private static final DateTimeFormatter FORMATTER = DateTimeFormatter.ofPattern("yyyy-MM-dd-HH-mm-ss");
/**
*
* <p>
* {@code .txt}
*
*
* @param username
* @param paperContent {@link ChoiceQuestion}
* @return
* @throws IOException I/O
*/
public String savePaper(String username, List<ChoiceQuestion> paperContent) throws IOException {
Path userDir = BASE_PATH.resolve(username);
Files.createDirectories(userDir);
@ -55,6 +73,15 @@ public class FileManager {
return filePath.toString();
}
/**
*
* <p>
* {@code .txt}
* Set
*
* @param username
* @return {@code Set<String>}
*/
public Set<String> loadExistingQuestions(String username) {
Path userDir = BASE_PATH.resolve(username);
if (!Files.exists(userDir)) {
@ -64,8 +91,6 @@ public class FileManager {
try (Stream<Path> stream = Files.walk(userDir)) {
return stream
.filter(file -> !Files.isDirectory(file) && file.toString().endsWith(".txt"))
// --- 核心修改在这里 (Part 1) ---
// flatMap现在操作的是一个由List生成的、全新的、开放的流
.flatMap(file -> readQuestionTextsFromTxtFile(file).stream())
.collect(Collectors.toSet());
} catch (IOException e) {
@ -75,13 +100,14 @@ public class FileManager {
}
/**
* () .txt
* @param file (Path)
* @return (List)
*
* <p>
* 使 "数字."
*
* @param file {@link Path}
* @return (List)
*/
private List<String> readQuestionTextsFromTxtFile(Path file) {
// --- 核心修改在这里 (Part 2) ---
// try-with-resources现在可以安全地关闭流因为它在方法返回前已经被 .collect() 完全消耗了
try (Stream<String> lines = Files.lines(file)) {
Pattern questionPattern = Pattern.compile("^\\d+\\.\\s+(.*)");
return lines
@ -89,10 +115,10 @@ public class FileManager {
.map(questionPattern::matcher)
.filter(Matcher::matches)
.map(matcher -> matcher.group(1).trim())
.collect(Collectors.toList()); // 将流的结果收集到一个List中
.collect(Collectors.toList());
} catch (IOException e) {
System.err.println("错误:读取文件 " + file + " 失败 - " + e.getMessage());
return Collections.emptyList(); // 发生错误时返回一个空列表
return Collections.emptyList();
}
}
}

@ -4,7 +4,10 @@ import java.util.regex.Pattern;
/**
*
*
* <p>
*
*
*
*/
public final class ValidationUtils {
@ -16,19 +19,27 @@ public final class ValidationUtils {
private static final Pattern USERNAME_NO_WHITESPACE_PATTERN =
Pattern.compile("^\\S+$");
// (***修改***) 邮箱策略:使用标准的正则表达式进行格式校验
// 邮箱策略:使用标准的正则表达式进行格式校验
private static final Pattern EMAIL_PATTERN =
Pattern.compile("^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,6}$");
// 私有构造函数,防止这个工具类被实例化
/**
*
*/
private ValidationUtils() {}
/**
*
*
* @param username
* @return true, false
* <p>
*
* <ul>
* <li></li>
* <li></li>
* </ul>
*
* @param username
* @return {@code true} {@code false}
*/
public static boolean isUsernameValid(String username) {
if (username == null || username.isEmpty()) {
@ -38,18 +49,28 @@ public final class ValidationUtils {
}
/**
*
* @param password
* @return true
*
* <p>
*
* <ul>
* <li> 6 10 </li>
* <li></li>
* </ul>
*
* @param password
* @return {@code true} {@code false}
*/
public static boolean isPasswordValid(String password) {
return password != null && PASSWORD_PATTERN.matcher(password).matches();
}
/**
* (******) (使)
* @param email
* @return true
*
* <p>
* 使 (, "user@example.com")
*
* @param email
* @return {@code true} {@code false}
*/
public static boolean isEmailValid(String email) {
if (email == null || email.isEmpty()) {

Loading…
Cancel
Save