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 java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.lang.reflect.Type; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Map; 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; 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 userDatabase; private final Gson gson = new GsonBuilder().setPrettyPrinting().create(); public UserService() { this.userDatabase = loadUsersFromFile(); } private Map loadUsersFromFile() { try { if (Files.exists(USER_FILE_PATH) && Files.size(USER_FILE_PATH) > 0) { try (FileReader reader = new FileReader(USER_FILE_PATH.toFile())) { Type type = new TypeToken>() {}.getType(); Map loadedUsers = gson.fromJson(reader, type); return loadedUsers != null ? new ConcurrentHashMap<>(loadedUsers) : new ConcurrentHashMap<>(); } } } catch (IOException e) { System.err.println("错误:加载用户文件失败 - " + e.getMessage()); } return new ConcurrentHashMap<>(); } private void saveUsers() { try (FileWriter writer = new FileWriter(USER_FILE_PATH.toFile())) { gson.toJson(this.userDatabase, writer); } catch (IOException e) { System.err.println("错误:保存用户文件失败 - " + e.getMessage()); } } public Optional findUserByUsername(String username) { return Optional.ofNullable(this.userDatabase.get(username)); } public Optional login(String username, String password) { return findUserByUsername(username) .filter(user -> user.password().equals(password)); } /** * (已更新) 发送真实的邮件验证码。 * @param email 用户的邮箱 * @return 成功发送则返回生成的6位验证码, 失败则返回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.send(); System.out.println("验证码邮件已成功发送至: " + email); return code; } catch (EmailException e) { System.err.println("错误:发送验证码邮件失败!请检查您的 config.properties 配置或网络连接。"); e.printStackTrace(); return null; // 发送失败 } } /** * 注册新用户。 * @return 成功返回true, 否则返回false */ public boolean register(String username, String email, String password) { // 1. 基础校验:防止 null 或空白输入 if (username == null || email == null || password == null || username.trim().isEmpty() || email.trim().isEmpty() || password.trim().isEmpty()) { return false; } // 2. 检查用户名或邮箱是否已存在(使用 Objects.equals 安全比较) boolean usernameExists = userDatabase.containsKey(username); boolean emailExists = userDatabase.values().stream() .anyMatch(u -> Objects.equals(u.email(), email)); if (usernameExists || emailExists) { return false; // 用户名或邮箱已存在 } // 3. 创建新用户并保存 User newUser = new User(username, email, password); userDatabase.put(username, newUser); saveUsers(); return true; } /** * 验证密码是否符合复杂度要求。 * @param password 待验证的密码 * @return true如果符合要求 */ public static boolean isPasswordValid(String password) { return password != null && PASSWORD_PATTERN.matcher(password).matches(); } /** * 修改密码。 * @return 成功返回true */ public boolean changePassword(String username, String oldPassword, String newPassword) { return findUserByUsername(username) .filter(user -> user.password().equals(oldPassword)) .map(user -> { User updatedUser = new User(user.username(), user.email(), newPassword); userDatabase.put(username, updatedUser); saveUsers(); return true; }).orElse(false); } }