|
|
|
|
@ -12,17 +12,24 @@ import java.util.regex.Pattern;
|
|
|
|
|
*/
|
|
|
|
|
public class Application {
|
|
|
|
|
|
|
|
|
|
// 依赖注入:在构造函数中初始化所有需要的服务
|
|
|
|
|
// 用于从控制台读取用户输入
|
|
|
|
|
private final Scanner scanner;
|
|
|
|
|
// 负责用户认证服务,处理登录逻辑
|
|
|
|
|
private final AuthService authService;
|
|
|
|
|
// 管理用户会话信息,当前登录用户和题目难度级别
|
|
|
|
|
private final SessionManager sessionManager;
|
|
|
|
|
// 负责文件操作,读写历史题目和新生成的题目
|
|
|
|
|
private final IFileService fileService;
|
|
|
|
|
|
|
|
|
|
// 用于解析“切换为XX”命令的正则表达式
|
|
|
|
|
private static final Pattern SWITCH_COMMAND_PATTERN = Pattern.compile("^切换为(小学|初中|高中)$");
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 构造函数,负责初始化应用程序所需的所有服务和组件。
|
|
|
|
|
* 通过依赖注入的方式,在这里创建并组装各个服务模块的实例,确保各模块职责单一。
|
|
|
|
|
*/
|
|
|
|
|
public Application() {
|
|
|
|
|
this.scanner = new Scanner(System.in, "UTF-8");
|
|
|
|
|
this.scanner = new Scanner(System.in);
|
|
|
|
|
|
|
|
|
|
// 创建数据访问层的实例
|
|
|
|
|
IUserRepository userRepository = new UserRepository();
|
|
|
|
|
@ -35,18 +42,26 @@ public class Application {
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 启动并运行应用程序的主循环。
|
|
|
|
|
* 该方法会持续监听用户输入,并根据用户当前的登录状态(已登录或未登录),
|
|
|
|
|
* 分别调用不同的处理逻辑。
|
|
|
|
|
*/
|
|
|
|
|
public void run() throws IOException {
|
|
|
|
|
public void run() {
|
|
|
|
|
System.out.println("欢迎使用中小学数学卷子自动生成程序!");
|
|
|
|
|
while (true) {
|
|
|
|
|
if (!sessionManager.isUserLoggedIn()) {
|
|
|
|
|
handleLoggedOutState();
|
|
|
|
|
} else {
|
|
|
|
|
handleLoggedInState();
|
|
|
|
|
try {
|
|
|
|
|
if (!sessionManager.isUserLoggedIn()) {
|
|
|
|
|
handleLoggedOutState();
|
|
|
|
|
} else {
|
|
|
|
|
handleLoggedInState();
|
|
|
|
|
}
|
|
|
|
|
} catch (Exception e) {
|
|
|
|
|
System.out.println("error");
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理用户未登录状态下的逻辑。
|
|
|
|
|
*/
|
|
|
|
|
@ -54,28 +69,35 @@ public class Application {
|
|
|
|
|
System.out.print("请输入用户名和密码(以空格隔开,输入 'exit' 退出程序): ");
|
|
|
|
|
String input = scanner.nextLine();
|
|
|
|
|
|
|
|
|
|
// 检查用户是否希望退出
|
|
|
|
|
if ("exit".equalsIgnoreCase(input.trim())) {
|
|
|
|
|
System.out.println("感谢使用,程序已退出。");
|
|
|
|
|
System.exit(0);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 按空格分割输入,获取用户名和密码
|
|
|
|
|
String[] credentials = input.split(" ");
|
|
|
|
|
if (credentials.length != 2) {
|
|
|
|
|
System.out.println("输入格式错误,请输入正确的用户名、密码。");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// 调用认证服务进行登录验证
|
|
|
|
|
Optional<User> userOptional = authService.login(credentials[0], credentials[1]);
|
|
|
|
|
if (userOptional.isPresent()) {
|
|
|
|
|
// 如果登录成功,启动会话
|
|
|
|
|
sessionManager.startSession(userOptional.get());
|
|
|
|
|
System.out.println("登录成功!欢迎您," + credentials[0] + "。");
|
|
|
|
|
} else {
|
|
|
|
|
// 登录失败,提示用户
|
|
|
|
|
System.out.println("用户名或密码错误,请重试。");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理用户已登录状态下的逻辑。
|
|
|
|
|
* 处理用户已登录状态下的交互逻辑。
|
|
|
|
|
* 根据当前选择的题目级别,提示用户输入要生成的题目数量、切换级别或退出登录。
|
|
|
|
|
* @throws IOException 如果在生成题目并保存文件的过程中发生IO错误
|
|
|
|
|
*/
|
|
|
|
|
private void handleLoggedInState() throws IOException {
|
|
|
|
|
String currentLevel = sessionManager.getCurrentLevel();
|
|
|
|
|
@ -84,23 +106,33 @@ public class Application {
|
|
|
|
|
currentLevel);
|
|
|
|
|
String input = scanner.nextLine().trim();
|
|
|
|
|
|
|
|
|
|
// 根据用户输入分发到不同的处理方法
|
|
|
|
|
if ("-1".equals(input)) {
|
|
|
|
|
handleLogout();
|
|
|
|
|
handleLogout(); // 处理退出登录
|
|
|
|
|
} else if (isSwitchCommand(input)) {
|
|
|
|
|
handleSwitchLevel(input);
|
|
|
|
|
handleSwitchLevel(input); // 处理切换级别
|
|
|
|
|
} else if (isNumeric(input)) {
|
|
|
|
|
handleGenerateProblems(input);
|
|
|
|
|
handleGenerateProblems(input); // 处理生成题目
|
|
|
|
|
} else {
|
|
|
|
|
System.out.println("无效的选项,请重新输入");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理用户退出登录的逻辑。
|
|
|
|
|
* 打印退出信息并调用会话管理器结束当前会话。
|
|
|
|
|
*/
|
|
|
|
|
private void handleLogout() {
|
|
|
|
|
System.out.println("用户 " + sessionManager.getCurrentUser().getUsername() + " 已退出登录。");
|
|
|
|
|
sessionManager.endSession();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理切换题目级别的命令。
|
|
|
|
|
* 使用正则表达式解析用户输入的级别(小学、初中、高中),并更新会话中的生成器设置。
|
|
|
|
|
* @param input 用户的完整输入命令,例如 "切换为小学"
|
|
|
|
|
*/
|
|
|
|
|
private void handleSwitchLevel(String input) {
|
|
|
|
|
Matcher matcher = SWITCH_COMMAND_PATTERN.matcher(input);
|
|
|
|
|
if (matcher.matches()) {
|
|
|
|
|
@ -112,21 +144,35 @@ public class Application {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 处理生成题目的请求。
|
|
|
|
|
* 1. 验证输入的题目数量是否在有效范围(10-30)。
|
|
|
|
|
* 2. 加载用户的历史题目以避免重复。
|
|
|
|
|
* 3. 调用相应级别的题目生成器生成新的、不重复的题目。
|
|
|
|
|
* 4. 在控制台打印生成的题目。
|
|
|
|
|
* 5. 将新生成的题目保存到用户专属的文件中。
|
|
|
|
|
* @param input 用户输入的题目数量字符串
|
|
|
|
|
* @throws IOException 如果在加载或保存文件时发生错误
|
|
|
|
|
*/
|
|
|
|
|
private void handleGenerateProblems(String input) throws IOException {
|
|
|
|
|
|
|
|
|
|
int count = Integer.parseInt(input);
|
|
|
|
|
// 验证题目数量是否在指定范围内
|
|
|
|
|
if (count < 10 || count > 30) {
|
|
|
|
|
System.out.println("生成数量必须在10到30之间。");
|
|
|
|
|
return;
|
|
|
|
|
return; // 结束当前操作,返回到主循环
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
User currentUser = sessionManager.getCurrentUser();
|
|
|
|
|
System.out.println("正在加载历史题目,请稍候...");
|
|
|
|
|
// 从文件中加载该用户的所有历史题目,用于去重
|
|
|
|
|
Set<String> history = fileService.loadAllProblemHistory(currentUser);
|
|
|
|
|
System.out.println("历史题目加载完毕。共找到 " + history.size() + " 道历史题目。");
|
|
|
|
|
|
|
|
|
|
System.out.println("正在生成 " + count + " 道不重复的新题目...");
|
|
|
|
|
// 从会话中获取当前难度级别对应的题目生成器
|
|
|
|
|
IProblemGenerator generator = sessionManager.getCurrentGenerator();
|
|
|
|
|
// 生成指定数量且不与历史题目重复的新题目
|
|
|
|
|
List<Equation> newProblems = generator.generate(count, history);
|
|
|
|
|
|
|
|
|
|
// 命令行显示生成题目
|
|
|
|
|
@ -141,15 +187,30 @@ public class Application {
|
|
|
|
|
System.out.println("保存成功!新的题目已存储在用户目录 " + currentUser.getStoragePath() + " 下。");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查输入字符串是否匹配“切换为XX”的命令格式。
|
|
|
|
|
* @param input 待检查的用户输入
|
|
|
|
|
* @return 如果匹配则返回 true,否则返回 false
|
|
|
|
|
*/
|
|
|
|
|
private boolean isSwitchCommand(String input) {
|
|
|
|
|
return SWITCH_COMMAND_PATTERN.matcher(input).matches();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* 检查给定字符串是否只包含数字。
|
|
|
|
|
* @param str 待检查的字符串
|
|
|
|
|
* @return 如果字符串为非空且纯数字则返回 true,否则返回 false
|
|
|
|
|
*/
|
|
|
|
|
private boolean isNumeric(String str) {
|
|
|
|
|
return str != null && str.matches("\\d+");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public static void main(String[] args) throws IOException {
|
|
|
|
|
/**
|
|
|
|
|
* 应用程序的入口点 (main方法)。
|
|
|
|
|
* 负责创建 Application 实例并启动主循环,从而开始整个程序。
|
|
|
|
|
* @param args 命令行参数(本项目中未使用)
|
|
|
|
|
*/
|
|
|
|
|
public static void main(String[] args) {
|
|
|
|
|
Application app = new Application();
|
|
|
|
|
app.run();
|
|
|
|
|
}
|
|
|
|
|
|