本来是不打算写这个课程作业的博客的,但是后续结队编程又需要和队友相互交流代码,而我当时写代码的时候也没有过多的注释,为了我的结队队友“、、”能够更轻松的(至少不会想捶我)完成课程任务,我还是准备写篇博客简单介绍一下课程项目。
PS:也附上“、、”的博客网站,也是关于这次的项目的

程序要求

点击下载需求文件

程序架构

使用java实现程序,总有5个类,并使用数据库来查重

1.Main

程序运行的地方,主要处理逻辑,程序状态和用户交互之类的

2.User抽象类

代表出题者的一个抽象类,拥有登录(连接数据库),出题,检查题目是否重复的功能

3.Primary,JuniorHigh,High三个实例用户类

继承User,并实现出题的具体方法

4.mysql数据库

实现题目的查重功能和用户信息存储功能


下面将从Main类开始介绍整个程序

Main类

变量

private int state = LOGIN;//代表程序状态,初始状态为登录状态
private static final int LOGIN = 0;//定义宏LOGIN
private static final int LOGGED_IN = 1;//定义宏LOGGED_IN
private User user;//当前程序的使用用户
private static Scanner scanner = new Scanner(System.in);//实例化输入对象

main方法,程序入口

public static void main(String[] args) throws SQLException, ClassNotFoundException {System.out.println("中小学数学卷子自动生成程序");Main main = new Main();while (true) {//根据程序状态实现不同功能switch (main.state) {case LOGIN://实现登录功能main.processLogin();break;case LOGGED_IN://实现登录后功能main.processLoggedIn();break;}}
}

processLogin()

private void processLogin() throws SQLException, ClassNotFoundException {System.out.println("请输入用户名、密码");String account = scanner.next();String password = scanner.next();//根据输入的账号密码获取用户实例对象user = User.login(account, password);if (user == null) {System.out.println("请输入正确的用户名、密码");} else {System.out.println("当前选择为" + user.getDifficultyType() + "出题");//将状态更新为已登录state = LOGGED_IN;}
}

processLoggedIn()

private void processLoggedIn() {System.out.println("准备生成" + user.getDifficultyType() + "数学题目,请输入生成题目数量(输入-1将退出当前用户,重新登录):");//接收用户输入String scannerContent = scanner.next();//监测用户输入是否为int型数据try {int questionsNumber = Integer.parseInt(scannerContent);//-1为退出登录,将状态重置为登录状态,并将用户对象置为nullif (questionsNumber == -1) {state = LOGIN;user = null;} else if (questionsNumber >= 10 && questionsNumber <= 30) {System.out.println("指令正确");//开始生产题目,传入的参数为:用户的难度类型,题目数量user.generateQuestionsByType(user.getDifficultyType(), questionsNumber);} else {System.out.println("请输入正确的指令");}}//用户输入为非int型,监测是否为“切换为”指令catch (Exception NumberFormatException) {if (scannerContent.startsWith("切换为")) {String type = scannerContent.substring(3);//重置用户的难度类型if (type.equals("小学") || type.equals("初中") || type.equals("高中")) {user.setDifficultyType(type);} else {System.out.println("请输入正确的指令");}} else {System.out.println("请输入正确的指令");}}
}

User类

变量

    private String type;//用户类型private String account;//用户账号private String password;//用户密码private String difficultyType;//难度类型//下面的变量需要设置为自己的数据库数据private static final String URL = "jdbc:mysql://localhost:3306/testgeneration?useSSL=false&allowPublicKeyRetrieval=true&serverTimezone=UTC";//数据库连接地址private static final String USER = "root";//数据库用户名private static final String PASSWORD = "1234";//数据库密码

构造器,getter,setter不再赘述

但是需要注意保护用户隐私,不比设置密码的getter和setter

login

public static User login(String account, String password) throws SQLException, ClassNotFoundException {//1.加载驱动程序Class.forName("com.mysql.cj.jdbc.Driver");String searchedType;//从数据库获取到的类型String sql = "SELECT identity from user where account=? and password=?";//数据库的运行很耗费资源,所以需要及时关闭try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {//下面使用的是PreparedStatement,用法会贴在下面try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {preparedStatement.setObject(1, account);preparedStatement.setObject(2, password);try (ResultSet resultSet = preparedStatement.executeQuery()) {if (resultSet.next()) {//从数据库获取类型searchedType = resultSet.getString("identity");//返回实例对象switch (searchedType) {case "小学":return new Primary(account, password, searchedType);case "初中":return new JuniorHigh(account, password, searchedType);case "高中":return new High(account, password, searchedType);}}//查询失败,返回nullelse {return null;}}}}return null;
}

statement 、prepareStatement的用法和解释,转自CSDN

getQuestionsArray

//由子类实现的抽象方法
public abstract String[] getQuestionsArray(int number);

generateQuestions

//根据输入的题目数量生成题目,并将其添加到数据库
public void generateQuestions(int number) {Timestamp timestamp = new Timestamp(System.currentTimeMillis());try {//测试重复问题,addQuestionsToDatabase会返回添加失败的个数,getQuestionsArray是根据不同类型的对象生成的,也就是不同难度的题目生成方法int failNum = addQuestionsToDatabase(getQuestionsArray(number), timestamp);while (failNum != 0) {failNum = addQuestionsToDatabase(getQuestionsArray(failNum), timestamp);}} catch (ClassNotFoundException | SQLException e) {e.printStackTrace();}
}

addQuestionsToDatabase

//返回添加失败的问题的个数
protected int addQuestionsToDatabase(String[] questions, Timestamp time) throws ClassNotFoundException, SQLException {int count = 0;//1.加载驱动程序Class.forName("com.mysql.cj.jdbc.Driver");String sql = "INSERT INTO testgeneration.questions (question, account, created_time) VALUES (?, ?, ?);";try (Connection connection = DriverManager.getConnection(URL, USER, PASSWORD)) {try (PreparedStatement preparedStatement = connection.prepareStatement(sql)) {//创建文件对象File file = new File("questionsData/" + account);//如果没有用户的文件就创建文件夹if (!file.exists()) {file.mkdir();}
//                System.out.println(file.getPath());//创建文件写入对象try (FileWriter fileWriter = new FileWriter(file.getPath() + "/" + new SimpleDateFormat("yyyy年-MM月-dd日-HH时-mm分-ss秒").format(time) + ".txt", true)) {//在多次写入时preparedStatement就能大大降低运行成本for (int i = 0; i < questions.length; i++) {preparedStatement.setObject(1, questions[i]);preparedStatement.setObject(2, account);preparedStatement.setObject(3, time);try {preparedStatement.executeUpdate();fileWriter.write(questions[i] + "\r\n");}//如果重复则会报错,并将重复的题目数量+1catch (SQLException e) {System.out.println("'" + questions[i] + "'" + "与之前的题目重复,准备重新出题");count++;}}} catch (IOException e) {e.printStackTrace();}}}return count;
}

User子类

User的子类主要介绍生成题目的方法

Primary

//符号集
private static final String[] symbols = {"+", "-", "*", "/"};
@Override
public String[] getQuestionsArray(int number) {String[] questions = new String[number];//StringBuilder在操作变换的字符串的时候效率更高StringBuilder question = new StringBuilder();//以当前时间作为随机种子Random random = new Random(System.currentTimeMillis());for (int index = 0; index < number; index++) {//随机生成操作数数量,最少为两个int operandsNumber = random.nextInt(4) + 2;//随机生成左括号的位置int bracketStart = random.nextInt(operandsNumber);//随机生成右括号的位置int bracketEnd = random.nextInt(operandsNumber);//判断括号位置是否合法boolean isBracketIllegal = bracketStart < bracketEnd;int[] operands = new int[operandsNumber];for (int i = 0; i < operandsNumber; i++) {//操作数为1~100operands[i] = random.nextInt(100) + 1;//括号位置合法,并且当前为左括号位置if (isBracketIllegal && i == bracketStart) {question.append("(");}question.append(operands[i]);//操作数合法并且当前为右括号位置if (isBracketIllegal && i == bracketEnd) {question.append(")");}if (i < operandsNumber - 1) {//随机从符号集里抽取一个符号int symbolIndex = random.nextInt(symbols.length);question.append(symbols[symbolIndex]);}//最后一个操作数后面为=号else {question.append("=");}}questions[index] = question.toString();System.out.println(question);//重新设置问题question.delete(0, question.length());}return questions;
}

JuniorHigh

//符号集
private static final String[] symbols = {"+", "-", "*", "/"};
@Override
public String[] getQuestionsArray(int number) {String[] questions = new String[number];StringBuilder question = new StringBuilder();Random random = new Random(System.currentTimeMillis());for (int index = 0; index < number; index++) {//操作数数量,1到5个int operandsNumber = random.nextInt(5) + 1;//括号起始点int bracketStart = random.nextInt(operandsNumber);//括号终止点int bracketEnd = random.nextInt(operandsNumber);//初中符号个数int juniorSymbolNum = operandsNumber == 1 ? 1 : random.nextInt(operandsNumber) + 1;//根号个数int RadicalNum = random.nextInt(juniorSymbolNum + 1);//平方个数int squareNum = juniorSymbolNum - RadicalNum;//是否有括号boolean isBracketIllegal = bracketStart < bracketEnd;int[] operands = new int[operandsNumber];for (int i = 0; i < operandsNumber; i++) {//是否加根号boolean addRadical = operandsNumber == 1 ? RadicalNum == 1 : random.nextBoolean();//是否加平方boolean addSquare = operandsNumber == 1 ? !addRadical : !addRadical && random.nextBoolean();operands[i] = random.nextInt(100) + 1;if (isBracketIllegal && i == bracketStart) {//在括号外加根号boolean outsideRadical = random.nextBoolean();if (outsideRadical && RadicalNum > 0) {question.append("√");RadicalNum--;}question.append("(");}//普通根号if (addRadical && RadicalNum > 0) {question.append("√");RadicalNum--;}question.append(operands[i]);//普通平方if (addSquare && squareNum > 0) {question.append("²");squareNum--;}if (isBracketIllegal && i == bracketEnd) {boolean outsideSquare = random.nextBoolean();question.append(")");//括号外平方if (outsideSquare && squareNum > 0) {question.append("²");squareNum--;}}if (i < operandsNumber - 1) {int symbolIndex = random.nextInt(symbols.length);question.append(symbols[symbolIndex]);}//最后一个操作数后面为=号else {question.append("=");}}questions[index] = question.toString();System.out.println(question);question.delete(0, question.length());}return questions;
}

High

//符号集
private static final String[] symbols = {"+", "-", "*", "/"};
private static final String[] highSymbols = {"sin", "cos", "tan"};
@Override
public String[] getQuestionsArray(int number) {String[] questions = new String[number];StringBuilder question = new StringBuilder();Random random = new Random(System.currentTimeMillis());for (int index = 0; index < number; index++) {//操作数数量,1到5个int operandsNumber = random.nextInt(5) + 1;//括号起始点int bracketStart = random.nextInt(operandsNumber);//括号终止点int bracketEnd = random.nextInt(operandsNumber);//初中符号个数int juniorSymbolNum = random.nextInt(operandsNumber) + 1;//根号个数int RadicalNum = random.nextInt(juniorSymbolNum + 1);//平方个数int squareNum = juniorSymbolNum - RadicalNum;//高中符号个数int highSymbolNum = operandsNumber == 1 ? 1 : random.nextInt(operandsNumber) + 1;//是否有括号boolean isBracketIllegal = bracketStart < bracketEnd;int[] operands = new int[operandsNumber];for (int i = 0; i < operandsNumber; i++) {//是否加高中符号boolean addHighSymbol = operandsNumber == 1 || random.nextBoolean();//是否加根号boolean addRadical = !addHighSymbol && random.nextBoolean();//是否加平方boolean addSquare = !addRadical && random.nextBoolean();operands[i] = random.nextInt(100) + 1;if (isBracketIllegal && i == bracketStart) {//在括号外加根号boolean outsideRadical = random.nextBoolean();//在括号外加高中符号boolean outsideHighSymbol = !outsideRadical && random.nextBoolean();if (outsideRadical && RadicalNum > 0) {question.append("√");RadicalNum--;}if (outsideHighSymbol && highSymbolNum > 0) {question.append(highSymbols[random.nextInt(highSymbols.length)]);highSymbolNum--;}question.append("(");}//普通根号if (addRadical && RadicalNum > 0) {question.append("√");RadicalNum--;}if (addHighSymbol && highSymbolNum > 0) {question.append(highSymbols[random.nextInt(highSymbols.length)]);highSymbolNum--;}question.append(operands[i]);//普通平方if (addSquare && squareNum > 0) {question.append("²");squareNum--;}if (isBracketIllegal && i == bracketEnd) {boolean outsideSquare = random.nextBoolean();question.append(")");//括号外平方if (outsideSquare && squareNum > 0) {question.append("²");squareNum--;}}if (i < operandsNumber - 1) {int symbolIndex = random.nextInt(symbols.length);question.append(symbols[symbolIndex]);}//最后一个操作数后面为=号else {question.append("=");}}questions[index] = question.toString();System.out.println(question);question.delete(0, question.length());}return questions;
}

数据库

user用户信息

create table user
(account  varchar(12) not nullprimary key,password varchar(15) null,identity varchar(5)  null
);

questions题目信息

将question和account设置为键,使添加时,同一个用户不能重发添加一个题,实现题目查重

create table questions
(q_id         int auto_incrementprimary key,question     varchar(30) null,account      varchar(8)  null,created_time timestamp   null,constraint questions_pkunique (question, account),constraint questions_fkforeign key (account) references user (account)
);

完整程序代码

项目完整文件已经上传到github,仅供参考

更多

欢迎来访我的个人网站

中小学数学卷子自动生成程序相关推荐

  1. 软件工程导论个人项目 -- 中小学数学卷子自动生成程序

    中小学数学卷子自动生成程序 1. 项目需求 1.1 项目名称 1.2 用户 1.3 功能 2. 程序分析 2.1 Teacher类 2.2 User类 2.2.1 头文件 2.2.2 主函数 2.2. ...

  2. 【java】个人项目:中小学数学卷子自动生成程序

    用户: 小学.初中和高中数学老师. 功能: 1.命令行输入用户名和密码,两者之间用空格隔开(程序预设小学.初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示"当前 ...

  3. 结对编程分析——中小学数学卷子自动生成程序

    中小学数学卷子自动生成程序分析 本次课程任务要求我们在规定时间内完成一个可以自动生成中小学数学题目卷子的程序,用户为老师.主要是实现账户名密码的验证,账户的切换,根据账户类型生成不同难度的试题并查重. ...

  4. 中小学数学卷子自动生成程序--对结对编程队友的分析

    中小学数学卷子自动生成程序大致需求: 用户登录账号后系统根据类型生成小学.初中或者高中的卷子,在登陆状态下,可以切换为不同类型的卷子,也可注销登录. 该同学用java完成了中小学数学卷子自动生成程序, ...

  5. 中小学数学卷子自动生成程序——结队编程队友互相评价

    中小学数学卷子自动生成程序--结队编程队友互相评价 评价方面 中小学数学卷子自动生成程序--结队编程队友互相评价 基本功能实现 一.功能要求: 二.登录要求的实现 三,优缺点分析: 代码分析 一.代码 ...

  6. 个人项目:中小学数学卷子自动生成程序——队友代码点评

    个人项目:中小学数学卷子自动生成程序--队友代码点评 今天开始了结对编程项目,在开展结对编程项目之前我们需要对队友编写的个人项目进行点评.在仔细阅读队友的整个工程的代码后,我有了以下观点. 题目需求 ...

  7. 个人项目——中小学数学卷子自动生成程序

    个人项目 第一次接触这种项目,感觉很难却又有点好玩:第二次写博客,感觉这是一个好习惯,希望后面能够继续坚持,加油! 题目要求 用户:小学.初中和高中数学老师. 功能: 1.命令行输入用户名和密码,两者 ...

  8. 【湖南大学个人项目】中小学数学卷子自动生成程序

    一.项目需求 命令行输入用户名和密码,两者之间用空格隔开(程序预设小学.初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示"当前选择为XX出题",XX为 ...

  9. 个人项目:中小学数学卷子自动生成程序

    需求 用户: 小学.初中和高中数学老师. 功能: 1.命令行输入用户名和密码,两者之间用空格隔开(程序预设小学.初中和高中各三个账号,具体见附表),如果用户名和密码都正确,将根据账户类型显示" ...

最新文章

  1. udacity 同学 pca 客户细分实例操作
  2. 比尔盖茨宣布离开微软董事会:昔日全球首富致力于改变世界
  3. Python基本语法_输入/输出语句详解
  4. WinForm实现Rabbitmq官网6个案例-Topics
  5. pca 主成分分析_超越普通PCA:非线性主成分分析
  6. 修改目录标题层级_关键词所在页面的层级越高权重越大
  7. 洛谷4577 LOJ2521:[FJOI2018]领导集团问题——题解
  8. 洛谷OJ测评常见的错误
  9. 虚拟机安装LEDE之后如何配置连接互联网
  10. Java线程执行native方法时程序计数器为空,如何确保native执行完后的程序执行的位置
  11. 立帖为据,每日学习一课编程技术
  12. mellanox 网卡驱动,Mellanox网卡OFED驱动安装
  13. Android存储管理
  14. 为知笔记离线同步 — 没网也可以随时查看笔记
  15. Rect Transform
  16. 机器人与视觉,基于坐标系的运动偏移
  17. 【读书笔记】Python编程:从入门到实践-埃里克·马瑟斯,python基础体系巩固和常见场景练习
  18. NXP bootloader
  19. to_csv ()出现中文乱码
  20. 记一次·ulimit: open files: cannot modify limit:不允许操作

热门文章

  1. 22考研全程时间计划安排表!
  2. OFFICE 您正试图运行的函数包含有宏或需要宏语言的解决方法
  3. 电商数据分析--用户行为分析
  4. 真正“透明”的PNG图片
  5. Viterbi-Algorithm(维特比)算法
  6. Linux 静态库和动态库的生成及使用
  7. C语言: 编写程序,输出所有的水仙花数
  8. 数据结构入门6-2(图 - 图的应用)
  9. 婚房布置清单 婚房布置图片大全 婚房布置效果图
  10. 微软office服务器连接很慢,解决 RPC 请求处理速度慢的问题