diff --git a/lib/activation-1.1.1.jar b/lib/activation-1.1.1.jar new file mode 100644 index 0000000..1b703ab Binary files /dev/null and b/lib/activation-1.1.1.jar differ diff --git a/lib/javax.mail-1.6.2.jar b/lib/javax.mail-1.6.2.jar new file mode 100644 index 0000000..0cd0528 Binary files /dev/null and b/lib/javax.mail-1.6.2.jar differ diff --git a/src/Base/Email_settings.java b/src/Base/Email_settings.java new file mode 100644 index 0000000..43e8fb1 --- /dev/null +++ b/src/Base/Email_settings.java @@ -0,0 +1,13 @@ +package Base; + +public class Email_settings { + public static final String SMTP_HOST = "smtp.qq.com"; + // 邮箱服务器端口 + public static final String SMTP_PORT = "587"; + // 发件人邮箱 + public static final String FROM_EMAIL = "835981889@qq.com"; + // 发件人邮箱授权码 + public static final String EMAIL_PASSWORD = "fpqfprqznbvdbcdf"; + // 是否启用SSL + public static final boolean SSL_ENABLE = true; +} diff --git a/src/Base/Question.java b/src/Base/Question.java new file mode 100644 index 0000000..71a0fe9 --- /dev/null +++ b/src/Base/Question.java @@ -0,0 +1,267 @@ +package Base; + +import java.util.HashMap; +import java.util.Random; +import java.util.Stack; + +public class Question { + private int number; + private String content; + private String type; + private String answer; + private String[] options; + private final Random ra= new Random(); + public static final HashMap trigValues = new HashMap<>(); + + static { + // 15° + trigValues.put("sin(15°)", "√2*(√3-1)/4"); + trigValues.put("cos(15°)", "√2*(√3+1)/4"); + trigValues.put("tan(15°)", "(2-√3)"); + trigValues.put("sin²(15°)", "(2-√3)/4"); + trigValues.put("cos²(15°)", "(2+√3)/4"); + trigValues.put("tan²(15°)", "(7-4*√3)"); + + // 22.5° + trigValues.put("sin(22.5°)", "√0.59/2"); //√(2-√2)/2 + trigValues.put("cos(22.5°)", "√3.41/2"); //√(2+√2)/2 + trigValues.put("tan(22.5°)", "(√2-1)"); + trigValues.put("sin²(22.5°)", "(2-√2)/4"); + trigValues.put("cos²(22.5°)", "(2+√2)/4"); + trigValues.put("tan²(22.5°)", "(3-2*√2)"); + + // 75° + trigValues.put("sin(75°)", "√2*(√3+1)/4"); + trigValues.put("cos(75°)", "√2*(√3-1)/4"); + trigValues.put("tan(75°)", "(2+√3)"); + trigValues.put("sin²(75°)", "(2+√3)/4"); + trigValues.put("cos²(75°)", "(2-√3)/4"); + trigValues.put("tan²(75°)", "(7+4*√3)"); + + // 105° + trigValues.put("sin(105°)", "√2*(√3+1)/4"); + trigValues.put("cos(105°)", "√2*(1-√3)/4"); + trigValues.put("tan(105°)", "(0-(2+√3))"); + trigValues.put("sin²(105°)", "(2+√3)/4"); + trigValues.put("cos²(105°)", "(2-√3)/4"); + trigValues.put("tan²(105°)", "(7+4*√3)"); + + // 120° + trigValues.put("sin(120°)", "√3/2"); + trigValues.put("cos(120°)", "(0-1/2)"); + trigValues.put("tan(120°)", "(0-√3)"); + trigValues.put("sin²(120°)", "3/4"); + trigValues.put("cos²(120°)", "1/4"); + trigValues.put("tan²(120°)", "3"); + + // 135° + trigValues.put("sin(135°)", "√2/2"); + trigValues.put("cos(135°)", "(0-√2/2)"); + trigValues.put("tan(135°)", "(0-1)"); + trigValues.put("sin²(135°)", "1/2"); + trigValues.put("cos²(135°)", "1/2"); + trigValues.put("tan²(135°)", "1"); + + // 150° + trigValues.put("sin(150°)", "1/2"); + trigValues.put("cos(150°)", "(0-√3/2)"); + trigValues.put("tan(150°)", "(0-√3/3)"); + trigValues.put("sin²(150°)", "1/4"); + trigValues.put("cos²(150°)", "3/4"); + trigValues.put("tan²(150°)", "1/3"); + + // 210° + trigValues.put("sin(210°)", "(0-1/2)"); + trigValues.put("cos(210°)", "(0-√3/2)"); + trigValues.put("tan(210°)", "√3/3"); + trigValues.put("sin²(210°)", "1/4"); + trigValues.put("cos²(210°)", "3/4"); + trigValues.put("tan²(210°)", "1/3"); + + // 300° + trigValues.put("sin(300°)", "(0-√3/2)"); + trigValues.put("cos(300°)", "1/2"); + trigValues.put("tan(300°)", "(0-√3)"); + trigValues.put("sin²(300°)", "3/4"); + trigValues.put("cos²(300°)", "1/4"); + trigValues.put("tan²(300°)", "3"); + } + + public Question(int number, String content, String type) { + this.number = number; + this.content = content; + this.type = type; + options=new String[4]; + } + + public int getNumber() { return number; } + public String getContent() { return content; } + public String getType() { return type; } + public String getAnswer() {return answer;} + public String getOptions(int i) {return options[i];} + + @Override + public String toString(){ + return this.number+". "+this.content+" = ?"; + } + + public void set_options(){ + answer=calculate(this.content); + int which=ra.nextInt(4); + options[which]=answer; + for (int i=0;i<4;i++) { + if (i != which) { + if (this.type.equals("高中")) { + options[i] = answer.equals("不可解") ? String.format("%.2f", Math.sqrt(3) * ra.nextInt(10) + ra.nextDouble(1)) : + String.format("%.2f", Double.parseDouble(answer) + Math.sqrt(2) * ra.nextInt(5)); + } else { + if (Double.parseDouble(answer) ==Math.floor(Double.parseDouble(answer)) ) { + options[i] = answer.equals("不可解") ? String.valueOf((int) ra.nextInt(1000) + ra.nextInt(10)) : + String.valueOf((int) Double.parseDouble(answer) + ra.nextInt(10)); + } else { + options[i] = answer.equals("不可解") ? String.format("%.2f", ra.nextInt(1000) + ra.nextDouble(10)) : + String.format("%.2f", Double.parseDouble(answer) + ra.nextDouble(10)); + } + } + for (int j = 0; j < i; j++) { + if (options[j].equals(options[i])) { + i--; + break; + } + } + if (options[i].equals(answer)) { + i--; + } + } + } + } + + public String calculate(String question){ + try { + String expr = question.replaceAll(" ", ""); + double result; + if (!type.equals("高中")) { + result = deal_calculate(expr); + if (Double.isNaN(result) || Double.isInfinite(result)) { + return "不可解"; + } + if (result == Math.floor(result)) { + return String.valueOf((int) result); + } else { + return String.format("%.2f", result); + } + } + else{ + return deal_sen_calculate(expr); + } + } catch (Exception e) { + return "不可解"; + } + } + + private double deal_calculate(String expr){ + Stack numbers = new Stack<>(); + Stack operators = new Stack<>(); + expr=expr.replace("²", "^2"); + for (int i = 0; i < expr.length(); i++) { + char c = expr.charAt(i); + if (Character.isDigit(c)) { + StringBuilder temp = new StringBuilder(); + while (i < expr.length() && (Character.isDigit(expr.charAt(i)) || expr.charAt(i) == '.')) { + temp.append(expr.charAt(i++)); + } + i--; + numbers.push(Double.parseDouble(temp.toString())); + } else if (c == '(') { + operators.push(c); + } else if (c == ')') { + while (operators.peek() != '(') { + numbers.push(Deal_Operator(operators.pop(), numbers.pop(), numbers.pop())); + } + operators.pop(); + } else if (isOperator(c)) { + while (!operators.isEmpty() && hasPrecedence(c, operators.peek())) { + numbers.push(Deal_Operator(operators.pop(), numbers.pop(), numbers.pop())); + } + operators.push(c); + } + else if (c == '√'){ + i++; + StringBuilder temp = new StringBuilder(); + while (i < expr.length() && (Character.isDigit(expr.charAt(i)) || expr.charAt(i) == '.')) { + temp.append(expr.charAt(i++)); + } + i--; + numbers.push(Math.sqrt(Double.parseDouble(temp.toString()))); + } + } + while (!operators.isEmpty()) { + numbers.push(Deal_Operator(operators.pop(), numbers.pop(), numbers.pop())); + } + return numbers.pop(); + } + + private String deal_sen_calculate(String m_expr){ + try { + String expr = m_expr.replaceAll(" ", ""); + StringBuilder result = new StringBuilder(); + + int i = 0; + while (i < expr.length()) { + char c = expr.charAt(i); + if (c == 's' || c == 'c' || c == 't') { + StringBuilder trigFunc = new StringBuilder(); + while (i < expr.length() && expr.charAt(i) != ')') { + trigFunc.append(expr.charAt(i++)); + } + trigFunc.append(')'); // 添加右括号 + String trigKey = trigFunc.toString(); + String trigValue = trigValues.get(trigKey); + if (trigValue != null) { + result.append(trigValue); + } + } else if (isOperator(c) || c == '(' || c == ')') { + result.append(c); + } + i++; + } + return String.format("%.2f",deal_calculate(Deal_Expression(result.toString()))); + } catch (Exception e) { + return "不可解"; + } + } + + private double Deal_Operator(char operator, double b, double a) { + switch (operator) { + case '+': return a + b; + case '-': return a - b; + case '*': return a * b; + case '/': { + if (b == 0) throw new ArithmeticException("除零错误"); + return a / b; + } + case '^': return Math.pow(a, b); + default: return 0; + } + } + + private boolean isOperator(char c) { + return c == '+' || c == '-' || c == '*' || c == '/' || c == '^'; + } + + //检验运算优先级,来决定先计算再压栈还是直接压栈 + private boolean hasPrecedence(char op1, char op2) { + if ( (op2 == '(' || op2 == ')') + || ((op1 == '*' || op1 == '/') && (op2 == '+' || op2 == '-')) + || (op1 == '^' && (op2 == '*' || op2 == '/' || op2 == '+' || op2 == '-'))) { + return false; + } + return true; + } + + private String Deal_Expression(String expr) { + String simplified = expr.replace("+-","-"); + simplified = simplified.replace("--","+"); + return simplified; + } +} diff --git a/src/Base/User.java b/src/Base/User.java new file mode 100644 index 0000000..8c137f5 --- /dev/null +++ b/src/Base/User.java @@ -0,0 +1,32 @@ +package Base; + +public class User { + private String email; + private String password; + + + public User(String email) { + this.email = email; + } + + public String get_email() { return email; } + public String get_password() { return password; } + public void set_password(String password) { this.password = password; } + + public static boolean check_password(String password) { + if (password == null || password.length() < 6 || password.length() > 20) { + return false; + } + + boolean hasUpper = false; + boolean hasLower = false; + boolean hasDigit = false; + + for (char c : password.toCharArray()) { + if (Character.isUpperCase(c)) hasUpper = true; + if (Character.isLowerCase(c)) hasLower = true; + if (Character.isDigit(c)) hasDigit = true; + } + return hasUpper && hasLower && hasDigit; + } +} diff --git a/src/Generator/G_ques.java b/src/Generator/G_ques.java new file mode 100644 index 0000000..5a18448 --- /dev/null +++ b/src/Generator/G_ques.java @@ -0,0 +1,8 @@ +package Generator; + +public interface G_ques { + String g_question(); + String g_type(); + char g_operator(); + String add_brackets(StringBuilder s,int count); +} diff --git a/src/Generator/Jun_g_ques.java b/src/Generator/Jun_g_ques.java new file mode 100644 index 0000000..4eb84df --- /dev/null +++ b/src/Generator/Jun_g_ques.java @@ -0,0 +1,82 @@ +package Generator; + +import java.util.Random; + +public class Jun_g_ques implements G_ques{ + private Random ra= new Random(); + + @Override + public String g_question() { + int count=ra.nextInt(5)+1; + StringBuilder question = new StringBuilder(); + boolean flag=false; + for (int i=0;i0){ + question.append(" ").append(g_operator()).append(" "); + } + if (ra.nextDouble()<0.25) { + if (ra.nextBoolean()) { + question.append(ra.nextInt(30) + 1).append("²"); + } + else { + question.append("√").append(ra.nextInt(100) + 1); + } + flag=true; + } + else { + question.append(ra.nextInt(100) + 1); + } + } + if (!flag){ + if(count==1){ + if (ra.nextBoolean()){ + question.append("²"); + } + else { + question.insert(0,"√"); + } + } + else { + String[] parts = question.toString().split(" "); + int pos = ra.nextInt(count); + if (ra.nextBoolean()) { + parts[pos * 2] = parts[pos * 2] + "²"; + } else { + parts[pos * 2] = "√" + parts[pos * 2]; + } + question = new StringBuilder(String.join(" ", parts)); + } + } + return add_brackets(question,count); + } + + @Override + public String g_type(){ + return "初中"; + } + + @Override + public char g_operator(){ + char[] op={'+','-','*','/'}; + return op[ra.nextInt(op.length)]; + } + + @Override + public String add_brackets(StringBuilder s,int count){ + String res=s.toString(); + String[] parts=s.toString().split(" "); + if (ra.nextBoolean()&&parts.length!=1) { + int num=ra.nextInt(3)+1; + for (int i=0;i 0) { + question.append(" ").append(g_operator()).append(" "); + } + if (i!=count-1&&ra.nextDouble()<0.4){ + question.append("("); + count_bracket++; + } + question.append(ra.nextInt(100) + 1); + } + if (count_bracket!=0){ + question.append(")".repeat(Math.max(0, count_bracket))); + } + return question.toString(); + } + + @Override + public String g_type(){ + return "小学"; + } + + @Override + public char g_operator(){ + char[] op={'+','-','*','/'}; + return op[ra.nextInt(op.length)]; + } + + @Override + public String add_brackets(StringBuilder s,int count){ + return s.toString(); + } +} diff --git a/src/Generator/Sen_g_ques.java b/src/Generator/Sen_g_ques.java new file mode 100644 index 0000000..f4ca55f --- /dev/null +++ b/src/Generator/Sen_g_ques.java @@ -0,0 +1,64 @@ +package Generator; + +import java.util.Random; + +public class Sen_g_ques implements G_ques{ + private Random ra= new Random(); + + @Override + public String g_question() { + int count=ra.nextInt(5)+1; + StringBuilder question = new StringBuilder(); + for (int i=0;i 0) { + question.append(" ").append(g_operator()).append(" "); + } + if (ra.nextDouble()<0.3){ + question.append(g_trig()).append("²").append("(").append(g_angle()).append("°)"); + } + else { + question.append(g_trig()).append("(").append(g_angle()).append("°)"); + } + } + return add_brackets(question,count); + } + + @Override + public String g_type(){ + return "高中"; + } + + @Override + public char g_operator(){ + char[] op={'+','-','*','/'}; + return op[ra.nextInt(op.length)]; + } + + public String g_trig(){ + String[] trig={"sin","cos","tan"}; + return trig[ra.nextInt(trig.length)]; + } + + public String g_angle(){ + String[] angle={"15","22.5","75","105","120","135","150","210","300"}; + return angle[ra.nextInt(angle.length)]; + } + + public String add_brackets(StringBuilder s,int count){ + String res=s.toString(); + String[] parts=s.toString().split(" "); + if (ra.nextBoolean()&&parts.length!=1) { + int num=ra.nextInt(3)+1; + for (int i=0;i codeMap = new ConcurrentHashMap<>(); + + private static class I_Code { + String code; + long createTime; + private static final long EXPIRATION_TIME = 5 * 60 * 1000; + + I_Code(String code) { + this.code = code; + this.createTime = System.currentTimeMillis(); + } + + boolean isExpired() { + return System.currentTimeMillis() - createTime > EXPIRATION_TIME; + } + } + + public static String generate_code(String email) { + String code = Generate_i_code.generateCode(6); + codeMap.put(email, new I_Code(code)); + return code; + } + + public static boolean judge_code(String email, String inputCode) { + I_Code codeInfo = codeMap.get(email); + if (codeInfo == null) { + return false; + } + if (codeInfo.isExpired()) { + codeMap.remove(email); + return false; + } + boolean isValid = codeInfo.code.equals(inputCode); + if (isValid) { + codeMap.remove(email); + } + return isValid; + } + + public static void clean_codes() { + codeMap.entrySet().removeIf(entry -> entry.getValue().isExpired()); + } + + public static void clean_all_codes(){ + codeMap.clear(); + } +} diff --git a/src/Send_Email/Generate_i_code.java b/src/Send_Email/Generate_i_code.java new file mode 100644 index 0000000..d9404ac --- /dev/null +++ b/src/Send_Email/Generate_i_code.java @@ -0,0 +1,18 @@ +package Send_Email; + +import java.util.Random; + +public class Generate_i_code { + public static String generateCode(int length) { + Random ra = new Random(); + StringBuilder code = new StringBuilder(); + for (int i = 0; i < length; i++) { + if (ra.nextBoolean()){ + code.append((char)('A'+ra.nextInt(26))); + } else { + code.append((char)('0'+ra.nextInt(10))); + } + } + return code.toString(); + } +} diff --git a/src/Send_Email/Send_email.java b/src/Send_Email/Send_email.java new file mode 100644 index 0000000..3df6b77 --- /dev/null +++ b/src/Send_Email/Send_email.java @@ -0,0 +1,107 @@ +package Send_Email; + +import Base.Email_settings; + +import javax.mail.*; +import javax.mail.internet.InternetAddress; +import javax.mail.internet.MimeMessage; +import java.util.Properties; +import java.util.regex.Pattern; + +public class Send_email { + public static boolean judge_email_address(String email) { + if (email == null || email.trim().isEmpty()) { + System.out.println("邮箱不能为空"); + return false; + } + // 去除前后空格 + email = email.trim(); + // 检查长度 + if (email.length() > 254) { // RFC标准规定邮箱最大长度 + System.out.println("邮箱地址过长"); + return false; + } + // 检查是否包含@ + if (!email.contains("@")) { + System.out.println("邮箱格式错误:缺少@符号"); + return false; + } + // 分割本地部分和域名部分 + String[] parts = email.split("@"); + if (parts.length != 2) { + System.out.println("邮箱格式错误:只能有一个@符号"); + return false; + } + String localPart = parts[0]; + String domainPart = parts[1]; + // 验证本地部分 + if (localPart.isEmpty()) { + System.out.println("邮箱格式错误:@前必须有内容"); + return false; + } + if (localPart.length() > 64) { + System.out.println("邮箱格式错误:@前内容过长"); + return false; + } + // 验证域名部分 + if (domainPart.isEmpty()) { + System.out.println("邮箱格式错误:@后必须有内容"); + return false; + } + if (!domainPart.contains(".")) { + System.out.println("邮箱格式错误:域名不完整"); + return false; + } + // 验证顶级域名 + String[] domainParts = domainPart.split("\\."); + String topLevelDomain = domainParts[domainParts.length - 1]; + if (topLevelDomain.length() < 2) { + System.out.println("邮箱格式错误:顶级域名太短"); + return false; + } + String emailRegex = "^(?=.{1,64}@)[A-Za-z0-9_-]+(\\.[A-Za-z0-9_-]+)*@" + + "[^-][A-Za-z0-9-]+(\\.[A-Za-z0-9-]+)*(\\.[A-Za-z]{2,})$"; + boolean matches = Pattern.matches(emailRegex, email); + System.out.println(matches ? "" : "邮箱格式错误"); + return matches; + } + + public static boolean send_email(String toEmail, String Code) { + try { + Properties props = new Properties(); + props.put("mail.smtp.host", Email_settings.SMTP_HOST); + props.put("mail.smtp.port", Email_settings.SMTP_PORT); + props.put("mail.smtp.auth", "true"); + if (Email_settings.SSL_ENABLE) { + props.put("mail.smtp.starttls.enable", "true"); + props.put("mail.smtp.ssl.trust", Email_settings.SMTP_HOST); + } + // 创建会话 + Session session = Session.getInstance(props, new Authenticator() { + @Override + protected PasswordAuthentication getPasswordAuthentication() { + return new PasswordAuthentication(Email_settings.FROM_EMAIL, Email_settings.EMAIL_PASSWORD); + } + }); + // 创建邮件消息 + Message message = new MimeMessage(session); + message.setFrom(new InternetAddress(Email_settings.FROM_EMAIL)); + message.setRecipients(Message.RecipientType.TO, InternetAddress.parse(toEmail)); + message.setSubject("注册验证码"); + // 邮件内容 + String content = String.format( + "尊敬的用户:%s

" + + "您的注册验证码是:%s

" + + "验证码有效期为5分钟,请尽快完成注册。

" + + "如果不是您本人操作,请忽略此邮件。", + toEmail,Code + ); + message.setContent(content, "text/html;charset=UTF-8"); + // 发送邮件 + Transport.send(message); + return true; + } catch (Exception e) { + return false; + } + } +} diff --git a/src/Service/Generate_paper.java b/src/Service/Generate_paper.java new file mode 100644 index 0000000..989a051 --- /dev/null +++ b/src/Service/Generate_paper.java @@ -0,0 +1,39 @@ +package Service; + +import Base.Question; +import Generator.G_ques; +import Generator.Jun_g_ques; +import Generator.Pri_g_ques; +import Generator.Sen_g_ques; + +import java.util.ArrayList; + +public class Generate_paper { + public static ArrayList g_paper(int num,String type) { + ArrayList result = new ArrayList<>(); + G_ques generator; + switch (type){ + case "小学":{ + generator=new Pri_g_ques(); + break; + } + case "初中":{ + generator=new Jun_g_ques(); + break; + } + case "高中":{ + generator=new Sen_g_ques(); + break; + } + default:{ + generator=new Pri_g_ques(); + } + } + for (int i=0;i users; + private final String base_dir="用户/"; + + public User_service() { + if (!load_users()){ + users=new ArrayList<>(); + } + } + + public String change_pwd(String email, String oldPassword, String newPassword){ + User user=find_user(email); + if (user == null) { + return "用户不存在"; + } + if (!user.get_password().equals(oldPassword)) { + return "原密码不正确"; + } + if (oldPassword.equals(newPassword)){ + return "新密码与原密码一致"; + } + if (!User.check_password(newPassword)) { + return "密码长6-20位,至少包含大小写字母和数字"; + } + user.set_password(newPassword); + if (save_users()) { + return "修改成功"; + } + return "修改失败"; + } + + public User find_user(String email){ + for (User user : users) { + if (user.get_email().equals(email)) { + return user; + } + } + return null; + } + + public boolean save_users(){ + File baseDir = new File(base_dir); + if (!baseDir.exists()) { + if (!baseDir.mkdirs()){ + return false; + } + } + String file_path=base_dir+"用户信息.txt"; + try (PrintWriter writer = new PrintWriter(new FileWriter(file_path))) { + for (int i = 0; i < users.size(); i++) { + writer.println(users.get(i).get_email()+" "+users.get(i).get_password()); + if (i < users.size() - 1) { + writer.println(); + } + } + return true; + } catch (IOException e) { + return false; + } + } + + public boolean load_users(){ + users=new ArrayList<>(); + String file_path=base_dir+"用户信息.txt"; + File file=new File(file_path); + if (file.exists()){ + try (BufferedReader reader = new BufferedReader(new FileReader(file))) { + String line; + while ((line = reader.readLine()) != null) { + if (!line.trim().isEmpty()) { + String l=line.trim(); + String[] parts=l.split(" "); + if (parts.length==2){ + User temp=new User(parts[0]); + temp.set_password(parts[1]); + users.add(temp); + } + } + } + return true; + } catch (IOException e) { + return false; + } + } + return false; + } +}