个人项目互评
一、前言
HNU个人项目互评:我与软1黄展同学结对,均使用java语言来完成中小学数学卷子自动生成程序项目,现在我将对其完成的代码进行分析和功能测试,希望在互评中能够学习到新的编程思路,认识到自己的不足,以此来提升自己的思维。
二、项目要求
HNU个人项目:中小学数学卷子自动生成程序
用户:
小学、初中和高中数学老师。
功能:
1、命令行输入用户名和密码,两者之间用空格隔开(程序预设小学、初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示“当前选择为XX出题”,XX为小学、初中和高中三个选项中的一个。否则提示“请输入正确的用户名、密码”,重新输入用户名、密码;
2、登录后,系统提示“准备生成XX数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):”,XX为小学、初中和高中三个选项中的一个,用户输入所需出的卷子的题目数量,系统默认将根据账号类型进行出题。每道题目的操作数在1-5个之间,操作数取值范围为1-100;
3、题目数量的有效输入范围是“10-30”(含10,30,或-1退出登录),程序根据输入的题目数量生成符合小学、初中和高中难度的题目的卷子(具体要求见附表)。同一个老师的卷子中的题目不能与以前的已生成的卷子中的题目重复(以指定文件夹下存在的文件为准,见5);
4、在登录状态下,如果用户需要切换类型选项,命令行输入“切换为XX”,XX为小学、初中和高中三个选项中的一个,输入项不符合要求时,程序控制台提示“请输入小学、初中和高中三个选项中的一个”;输入正确后,显示“”系统提示“准备生成XX数学题目,请输入生成题目数量”,用户输入所需出的卷子的题目数量,系统新设置的类型进行出题;
5、生成的题目将以“年-月-日-时-分-秒.txt”的形式保存,每个账号一个文件夹。每道题目有题号,每题之间空一行;
6、个人项目9月17日晚上10点以前提交至创新课程管理系统。提交方式:工程文件打包,压缩包名为“几班+姓名.rar”。迟交2天及以内者扣分,每天扣20%。迟交2天及以上者0分。
附表-1:账户、密码
|
账户类型 |
账户 |
密码 |
备注 |
|
小学 |
张三1 |
123 |
|
|
张三2 |
123 |
|
|
|
张三3 |
123 |
|
|
|
初中 |
李四1 |
123 |
|
|
李四2 |
123 |
|
|
|
李四3 |
123 |
|
|
|
高中 |
王五1 |
123 |
|
|
王五2 |
123 |
|
|
|
王五3 |
123 |
|
附表-2:小学、初中、高中题目难度要求
|
|
小学 |
初中 |
高中 |
|
|
难度要求 |
+,-,*./ |
平方,开根号 |
sin,cos,tan |
|
|
备注 |
只能有+,-,*./和() |
题目中至少有一个平方或开根号的运算符 |
题目中至少有一个sin,cos或tan的运算符 |
|
三、文件结构
在Generation文件下:
1、src文件夹中:有四个包,connection、generate、main、users
(1)connection包:连接和访问数据库
(2)generate包:题目生成
(3)main包:主函数
(4)users包:用户类
2、Referenced Libraries:注册数据库驱动所需要的jar包

3、对应用户名文件夹:存放该用户生成的题目文件,以txt文件形式保存

四、功能测试
1、登录功能测试:


直接输入用户名和密码,中间空格分隔开,可以正常登录;
当输入错误的用户名或者密码,会提示请输入正确的用户名、密码;
缺点:没有提示输入用户名和密码(中间空格分隔开);
登录功能正常,还有待完善;
2、退出当前用户测试:


在输入生成题目数量时,输入-1,退出当前用户登录;
但是同时也让程序终止了,无法重新登录新的用户,有待完善;
3、出题测试:

当登录成功时,提示该用户准备生成该用户对应的学生类型(小学、初中、高中)的题目,输入需要生成的题目数量,小于10或者大于30都会提示输入题目数量不在10-30范围内,当输入数量在范围内的时候,则会成功生成题目存储在txt文件当中,并提示生成功,请继续输入数量;
如下分别为生成的小学、初中、高中的题目(txt文件中),存在于以对应用户名为名字的文件夹中,保存名称形式为“年-月-日-时-分-秒.txt”,如下:





2
出题功能正常,非常好!
4、切换出题难度测试:

输入如果不是“切换为...”,也不是数量,而是随意的一行,则会提示“请输入正确的指令:”如果输入为“切换为XX”,但XX不是小学、初中、高中的其中一个,则会提示“请输入小学、初中和高中三个选项中的一个”,如果满足要求,则会提示“准备生成XX数学题目,请输入生成题目数量:”,满足要求,并且输入数量都能成功生成txt文件在对应的文件夹中;
切换出题难度功能正常;
五、代码分析
src文件夹中:有四个包,connection、generate、main、users
(1)connection包:连接和访问数据库
a、Connect类:
package connection; import java.sql.Connection; import java.sql.DriverManager; public class Connect{ Connection con; public Connection loding(){ try{ Class.forName("com.mysql.jdbc.Driver"); System.out.println("成功加载数据库驱动!"); } catch(Exception e){ System.out.println("加载数据库驱动出错!"); e.printStackTrace(); } try{ con = DriverManager.getConnection("jdbc:mysql://localhost:3306/generation?serverTimezone=UTC","root","499474"); System.out.println("成功连接数据库服务器"); } catch(Exception e1){
System.out.println("连接数据库服务器出现错误"); } return con; } public void closeCon(java.sql.Connection con)throws Exception{//关闭数据库 if(con!=null){ con.close(); } } }
用于加载数据库驱动和连接数据库服务器,通过数据库generation创建了一个名为user的表去存储所给的9个用户名和密码,如下:



b、Visit类:
用于访问数据库generation中的user表,在登陆功能部分,通过在user表中一行一行判断是否存在用户名和密码和输入的用户名、密码都相等,如果相等,将表中这一行以User对象返回,否则返回一个空User对象;
package connection; import java.sql.Connection; import java.sql.PreparedStatement; import java.sql.ResultSet; import users.User; public class Visit { public static User login(Connection con,User usr) throws Exception{ User resultUser = null; String sql="select * from user where counter=? and password=?"; PreparedStatement pstmt = (PreparedStatement)con.prepareStatement(sql); pstmt.setString(1,usr.getCounter()); pstmt.setString(2,usr.getPassword()); ResultSet rs = pstmt.executeQuery(); if(rs.next()) { resultUser = new User(); resultUser.setCounter(rs.getString("counter")); resultUser.setPassword(rs.getString("password")); resultUser.setType(rs.getString("type")); resultUser.setNote(rs.getString("note")); } return resultUser; } }
(2)generate包:题目生成
a、Generator类:
这个类是一个抽象类,其中:
<1>定义了一个静态的Random对象,用于出题生成随机的操作数;
<2>普通方法createQuestion(User usr, int questionnum),可被子类直接继承,主要是生床架相应的文件夹并生成对应的txt文件和内容;
<3>抽象方法createElem(),对应继承的子类(小学、初中、高中题目生成)具体实现对应的方法;
package generate; import java.io.BufferedWriter; import java.io.FileWriter; import java.io.File; import java.io.IOException; import java.util.Date; import java.util.HashSet; import java.util.Random; import java.util.Set; import java.text.SimpleDateFormat; import users.User; public abstract class Generator { protected static final Random RANDOM = new Random(); protected char getRandomOperator() { char[] operators = {'+', '-', '×', '÷'}; return operators[RANDOM.nextInt(operators.length)]; } public void createQuestion(User usr, int questionnum) { String counter = usr.getCounter(); File userfile = new File(counter); if (!userfile.exists()) { userfile.mkdirs(); } String timestamp = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss").format(new Date()); String fileName = userfile + "/" + timestamp + ".txt"; try(BufferedWriter writer = new BufferedWriter(new FileWriter(fileName))){ Set<String> existingQuestions = new HashSet<>(); writer.write(usr.getType()+"题目"); writer.newLine(); writer.newLine(); for (int i = 0; i < questionnum; i++) { String question = createElem(); while (existingQuestions.contains(question)) { question = createElem(); } existingQuestions.add(question); writer.write((i + 1) + "、 " + question+" ="); writer.newLine(); writer.newLine(); } }catch(IOException e) { e.printStackTrace(); } } protected abstract String createElem(); }
b、PrimaryGenerator类:
该类继承Generator类,就重写一个方法createElem(),生成小学数学题目,只有+、-、×、÷并且可能会有(),但是()似乎只有一对;
package generate; public class PrimaryGenerator extends Generator{ protected String createElem() { int operand = RANDOM.nextInt(4) + 2; // 随机生成2-5个操作数 StringBuilder question = new StringBuilder(); int numbracketpairs = operand==2?0:RANDOM.nextInt(2); if (numbracketpairs > 0) { question.append("("); } for (int i = 0; i < operand; i++) { int digit = RANDOM.nextInt(100) + 1; // 随机生成1-100的数字 question.append(digit); if(i!=0&&(i!=operand-1)&&numbracketpairs > 0) { if(i==operand-2&&numbracketpairs==1) { question.append(")"); numbracketpairs=0; } else if(RANDOM.nextBoolean()) { question.append(")"); numbracketpairs=0; } } if (i < operand - 1) { char operator = getRandomOperator(); question.append(" ").append(operator).append(" "); } } return question.toString(); } }
c、MiddleGenerator类:
该类继承Generator类,重写方法createElem(),生成初中数学题目,在+、-、×、÷的基础上,通过调用自己的函数function()去随机添加平方、根号,并且至少有一个平方或者根号,并且可能会有(),但是()似乎只有一对;
package generate; public class MiddleGenerator extends Generator{ protected String function(int digit) { if(RANDOM.nextBoolean()) { return digit+"²"; } else { return "√"+digit; } } protected String createElem() { int operand = RANDOM.nextInt(4) + 2; // 随机生成2-5个操作数 StringBuilder question = new StringBuilder(); int numbracketpairs = operand==2?0:RANDOM.nextInt(2); if (numbracketpairs > 0) { question.append("("); } for (int i = 0,flag =0; i < operand; i++) { int digit = RANDOM.nextInt(100) + 1; // 随机生成1-100的数字 if(flag==0&&i==operand-1) { question.append(function(digit)); } else if (RANDOM.nextBoolean()) { if(RANDOM.nextBoolean()) { question.append(digit+"²"); } else { question.append("√"+digit); } flag=1; } else { question.append(digit); } if(i!=0&&(i!=operand-1)&&numbracketpairs > 0) { if(i==operand-2&&numbracketpairs==1) { question.append(")"); numbracketpairs=0; } else if(RANDOM.nextBoolean()) { question.append(")"); numbracketpairs=0; } } if (i < operand - 1) { char operator = getRandomOperator(); question.append(" ").append(operator).append(" "); } } return question.toString(); } }
d、HighGenerator类:
该类继承Generator类,重写方法createElem(),生成高中数学题目,在+、-、×、÷的基础上,通过调用自己的函数getOperator()去随机添加sin、cos、tan,并且至少有一个sin、cos或者tan,并且可能会有(),但是()似乎只有一对;
package generate; public class HighGenerator extends Generator{ protected String createElem() { int operand = RANDOM.nextInt(4) + 2; // 随机生成2-5个操作数 StringBuilder question = new StringBuilder(); int numbracketpairs = operand==2?0:RANDOM.nextInt(2); if (numbracketpairs > 0) { question.append("("); } for (int i = 0,flag =0; i < operand; i++) { int digit = RANDOM.nextInt(100) + 1; // 随机生成1-100的数字 if(flag==0&&i==operand-1) { question.append(getOperator()+" "+digit); } else if (RANDOM.nextBoolean()) { question.append(getOperator()+" "+digit); flag=1; } else { question.append(digit); } if(i!=0&&(i!=operand-1)&&numbracketpairs > 0) { if(i==operand-2&&numbracketpairs==1) { question.append(")"); numbracketpairs=0; } else if(RANDOM.nextBoolean()) { question.append(")"); numbracketpairs=0; } } if (i < operand - 1) { char operator = getRandomOperator(); question.append(" ").append(operator).append(" "); } } return question.toString(); } private static String getOperator() { String[] operators = {"sin","cos","tan"}; return operators[RANDOM.nextInt(operators.length)]; } }
(3)users包:用户类
包含一个User类,定义了四个属性:
<1>counter:用户名,String
<2>password:密码,String
<3>type:类型(小学、初中、高中),String
<4>note:备注,String
方法:
<1>空构造函数:啥也没有
<2>带参数构造函数:设置用户名和密码
<3>获取用户名:getCounter()
<4>设置用户名:setCounter(String counter)
<5>获取密码:getPassword()
<6>设置密码:setPassword(String password)
<7>获取类型:getType()
<8>设置类型:setType(String type)
<9>获取备注:getNote()
<10>设置备注:setNote(String note)
package users; public class User { private String counter; private String password; private String type; private String note; public User() {} public User(String counter,String password) { this.counter=counter; this.password=password; } public String getCounter() { return counter; } public String getPassword() { return password; } public String getType() { return type; } public String getNote() { return note; } public void setCounter(String counter) { this.counter=counter; } public void setPassword(String password) { this.password=password; } public void setType(String type) { this.type=type; } public void setNote(String note) { this.note=note; } }
(4)main包:主函数
<1>public static User logon(User usr),用户登录时用于访问数据库user表中看是否有对应的信息,有的话就会返回对应信息的User对象,否则返回的就是空User对象;
<2>public static boolean isConvertToInt(String sentence),判断输入的字符串能否转换成整形,用了一个try{}catch{}结构,如果能转换就返回true,如果不能转换,NumberFormatException e就会捕捉到返回false;
<3>public static User changeStage(User usr,String sentence),切换难度的函数,输入如果不是“切换为...”,也不是数量,而是随意的一行,则会提示“请输入正确的指令:”如果输入为“切换为XX”,但XX不是小学、初中、高中的其中一个,则会提示“请输入小学、初中和高中三个选项中的一个”,如果满足要求,则会提示“准备生成XX数学题目,请输入生成题目数量:”,并返回User对象;
<4>public static void create(User usr,int questionnum),生成题目的函数,具体对应看是生成小学、初中、还是高中的题目;
<5>public static void main(String[] args),main函数,整个程序运行的主代码;
package main; import connection.Connect; import connection.Visit; import generate.HighGenerator; import generate.MiddleGenerator; import generate.PrimaryGenerator; import users.User; import java.sql.Connection; import java.util.Scanner; public class Generate { public static User logon(User usr) { Connect conutil = new Connect(); Connection con = null; try{ con = conutil.loding(); User currentUser= Visit.login(con, usr); if(currentUser!=null){ return currentUser; } else { return null; } } catch(Exception e1){ e1.printStackTrace(); } finally{ try{ conutil.closeCon(con); } catch (Exception e2) { e2.printStackTrace(); } } return null; } public static boolean isConvertToInt(String sentence) { try { Integer.parseInt(sentence); return true; }catch(NumberFormatException e){ return false; } } public static User changeStage(User usr,String sentence) { if(sentence.length()<4) { System.out.println("请输入正确的指令:"); return usr; } String foresentence = sentence.substring(0,3); String endsentence = sentence.substring(3); if(foresentence.equals("切换为")) { if(!(endsentence.equals("小学")||endsentence.equals("初中")||endsentence.equals("高中"))) { System.out.println("请输入小学、初中和高中三个选项中的一个"); } else { System.out.println("准备生成"+endsentence+"数学题目,请输入生成题目数量:"); usr.setType(endsentence); return usr; } } else { System.out.println("请输入正确的指令:"); } return usr; } public static void create(User usr,int questionnum) { switch(usr.getType()) { case "小学": PrimaryGenerator primarygenerator = new PrimaryGenerator(); primarygenerator.createQuestion(usr,questionnum); break; case "初中": MiddleGenerator middlegenerator = new MiddleGenerator(); middlegenerator.createQuestion(usr,questionnum); break; case "高中": HighGenerator highgenerator = new HighGenerator(); highgenerator.createQuestion(usr,questionnum); break; default: System.out.println("不是小学、初中、高中的其中一个"); break; } } public static void main(String[] args) { Scanner in = new Scanner(System.in); outer: while(true) { String counter = in.next(); String password = in.next(); User usr = new User(counter,password); usr= logon(usr); if(usr!=null) { System.out.println("当前选择为"+usr.getType()+"出题"); System.out.println("准备生成"+usr.getType()+"数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):"); while(true) { String sentence = in.next(); boolean whether = isConvertToInt(sentence); int questionnum = 0; if(whether==true) { questionnum = Integer.parseInt(sentence); if(questionnum==-1) { System.out.println("退出当前用户,重新登录"); break outer; } else if(questionnum>=10&&questionnum<=30) { create(usr,questionnum); System.out.println("生成成功,请继续输入数量:"); } else { System.out.println("输入题目数量不在10-30范围内"); } } else { usr = changeStage(usr,sentence); } } } else { System.out.println("请输入正确的用户名、密码:"); } } in.close(); } }
六、总结
总体而言,此项目完成了所有功能,并进行了一定的优化,但是有些细节有待优化。
通过此项目,我们最重要的是要意识到规范编程的重要性。规范编程可以提高代码质量、增加可维护性和可读性、利于团队协作并且提高我们编程的效率。此次个人项目编程是我们规范编程的试手,希望在未来的编程中,我们能一直坚持规范编程。
浙公网安备 33010602011771号