Exam:

1.包结构
entity: 实体类 domain pojo
service: 服务
test: 测试
ui: 界面 - Swing
util: 工具
2.MVC思想
M: Model 对象, 业务逻辑[服务器端]
V: View 视图, UI
C: Controller 控制器
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210709194825172.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3h1amlhcWlxaXFp,size_16,color_FFFFFF,t_70
数据存储在数据库[模拟数据库->读取文件]

3.读取文件来充当数据库 EntityContext
1.定义集合存储用户
2.定义集合存储试题
3.定义方法来读取用户文件
4.定义方法来读取试题文件
注意: 在3.4中发现读取文件,需要传递文件名,文件名是可能发生改变的
所以将文件名写入到配置文件中, 需要通过Config类来读取配置文件
注意: Config是工具类, 在EntityContext中需要使用config对象
Config是IO流, 所以不能无限创建, 应该是程序启动时创建
EntityContext因为是模拟数据库, 所以也应该是程序启动时初始化好

    主方法: new Config()
           new EntityContext(): 读取文件

在这里插入图片描述

  • 登陆界面
    在这里插入图片描述

  • 菜单界面
    在这里插入图片描述

  • 考试界面
    在这里插入图片描述

  • 交卷
    在这里插入图片描述

  • 退出

在这里插入图片描述

列举几个重要的类:

  • 控制器类
package com.zzxx.exam.ui;

import com.zzxx.exam.entity.ExamInfo;
import com.zzxx.exam.entity.QuestionInfo;
import com.zzxx.exam.entity.User;
import com.zzxx.exam.service.ExamServiceImpl;
import com.zzxx.exam.service.IdOrPwdException;

import javax.swing.*;
import java.awt.*;
import java.sql.Time;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

import static javax.swing.WindowConstants.EXIT_ON_CLOSE;

/**
 * 前端控制器
 */
public class ClientContext {
    private WelcomeWindow welcomeWindow;
    private LoginFrame loginFrame;
    private ExamFrame examFrame;
    private MenuFrame menuFrame;
    private ExamServiceImpl examService;
    private MsgFrame msgFrame;
    private ExamInfo examInfo;


    /**
     * 1.显示欢迎界面 -2000毫秒
     * 2。计时 -> 到时间,欢迎界面消失
     *          显示登陆界面
     */
    public void show(){
        welcomeWindow.setVisible(true);
        //跳转页面时间延迟
        Timer timer = new Timer();
        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                welcomeWindow.setVisible(false);
                loginFrame.setVisible(true);
            }
            },1000

        );
    }


    public void setExamFrame(ExamFrame examFrame) {
        this.examFrame = examFrame;
    }

    public void setMenuFrame(MenuFrame menuFrame) {
        this.menuFrame = menuFrame;
    }

    public void setExamService(ExamServiceImpl examService) {
        this.examService = examService;
    }

    public void login(){
        //1.收集数据:loginFrame界面获得
        /**
         * 想要获得loginFrame中id和password
         * loginFrame提供一个对外的方法
         */
        int id = loginFrame.getId();
        String pwd = loginFrame.getPwd();
        //2。调用业务模型
        try {
            User u = examService.login(id, pwd);
            loginFrame.setVisible(false);
            menuFrame.showName(u);
            menuFrame.setVisible(true);
        } catch (IdOrPwdException e) {
            loginFrame.showMes(e.getMessage());
        }

    }

    /**
     * 开始考试
     * @param
     */
    private ExamInfo info;
    private QuestionInfo currentQuestion;
    public void start(){

        // 1.调用service 的 start方法
        info = examService.start();
        // 2.调用service 的 getQuestion方法
        QuestionInfo questionInfo = examService.getQuestion(0);
        currentQuestion = questionInfo;
        // 3.更新界面信息
        examFrame.updateInfo(info);
        examFrame.updateQuestion(questionInfo);

        // 4.显示界面/隐藏界面
        menuFrame.setVisible(false);
        examFrame.setVisible(true);
        timer();
    }

    /**
     * 下一题
     * @return
     */
    public void next(){
        List<Integer> userAnswer = examFrame.getUserAnswer();
        // 1.保存当前题目的用户答案
        examService.saveUserAnswers(currentQuestion.getQuestionIndex(),userAnswer);
        // 知道当前是哪一题
        // index ++
        if(currentQuestion.getQuestionIndex()<=18){
            QuestionInfo question = examService.getQuestion(currentQuestion.getQuestionIndex() + 1);
            // 2.获得下一题对应的题目信息QuestionInfo
            currentQuestion=question;
            // 3.更新界面
            examFrame.updateQuestion(question);
            //更新选项的状态
            examFrame.updateOption(currentQuestion.getUserAnswers());
        }else {
            JOptionPane.showMessageDialog(examFrame,"已经是最后一题了");
            System.out.println("已经是最后一题了");
        }

    }
    public WelcomeWindow getWelcomeWindow() {
        return welcomeWindow;
    }

    public void setWelcomeWindow(WelcomeWindow welcomeWindow) {
        this.welcomeWindow = welcomeWindow;
    }

    public LoginFrame getLoginFrame() {
        return loginFrame;
    }

    public void setLoginFrame(LoginFrame loginFrame) {
        this.loginFrame = loginFrame;
    }



    public void showName() {
        menuFrame.getName();
    }

    public void prev() {

        List<Integer> userAnswer = examFrame.getUserAnswer();
        // 1.保存当前题目的用户答案
        examService.saveUserAnswers(currentQuestion.getQuestionIndex(),userAnswer);
        // 知道当前是哪一题
        // index ++
        if (currentQuestion.getQuestionIndex()>0){
            QuestionInfo question = examService.getQuestion(currentQuestion.getQuestionIndex() - 1);
            // 2.获得下一题对应的题目信息QuestionInfo
            currentQuestion=question;
            // 3.更新界面

            examFrame.updateQuestion(question);
            //更新选项的状态
            examFrame.updateOption(currentQuestion.getUserAnswers());

        }else {
            JOptionPane.showMessageDialog(examFrame,"已经是第一题了");
            System.out.println("已经是第一题了");
        }

    }

    public void over() {
        // 1.记录当前这道题的用户答案
        List<Integer> userAnswer = examFrame.getUserAnswer();
        examService.saveUserAnswers(currentQuestion.getQuestionIndex(),userAnswer);
        // 2.计算分数
        int score = examService.examOver();
        // 3.弹窗显示分数
        JOptionPane.showConfirmDialog(this.examFrame,"你确定要交卷吗?","请确认",JOptionPane.YES_NO_OPTION, JOptionPane.WARNING_MESSAGE);
        JOptionPane.showMessageDialog(examFrame,"你的分数是"+score);
        System.out.println(score);
        timer.cancel();
    }

    public void setMsgFrame(MsgFrame msgFrame) {
        this.msgFrame = msgFrame;
    }

    public void msg() {

        msgFrame.showMsg(examService.getMsg());
    }
    private Timer timer = new Timer();
    public void timer(){
        long end = System.currentTimeMillis()+info.getTimeLimit()*60*1000;
        //剩余时间的概念:计时结束的时间-当前时间

        timer.schedule(new TimerTask() {
            @Override
            public void run() {
                long now = System.currentTimeMillis();
                long left = end - now; // 显示格式 01:10:34
                long hour = left / 1000 / 60 / 60;
                long minute = left / 1000 / 60 - hour * 60;
                long second = left / 1000 - hour * 60 * 60 - minute * 60;
                examFrame.updateTime(hour, minute, second);
                if (left <= 0) { // 到时间了
                    over(); // 强制交卷了
                }
            }
        }, 1, 1000);
        //考试时间



    }

    public void exit(JFrame source ) {
        int i = JOptionPane.showConfirmDialog(source, "确定要离开吗?");
        // 判断点击的是 确定还是取消
        if (i == JOptionPane.OK_OPTION) {
            System.exit(0);
        }

    }
}

  • 数据库类(通过集合自己写的数据库)
package com.zzxx.exam.entity;

import com.zzxx.exam.util.Config;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 实体数据管理, 用来读取数据文件放到内存集合当中
 * 模拟数据库
 */
public class EntityContext {
    private Config config; // null, 要通过set方法注入[程序开启后]
    // 存储所有用户的集合 用户的id对应的用户对象
    private Map<Integer, User> users = new HashMap<>();
    // 存储所有试题的集合 一个难度级别下面对应这个难度级别所有的题目
    private Map<Integer, List<Question>> questions = new HashMap<>();
    private List<String> messages = new ArrayList<>();
    public EntityContext(Config config) {
        this.config = config;
        String userFile = config.getString("UserFile");
        String questionFile = config.getString("QuestionFile");
        String msgFile = config.getString("rule.txt");
        loadUsers(userFile);
        loadQuestions(questionFile);
        //loadMsg(msgFile);
    }
    /**
     * 读取user.txt文件
     * 并且解析成user对象, 添加到users集合中
     */
    private void loadUsers(String userFile) {
        System.out.println("loadUsers");
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(userFile)));
            String str;
            while((str = br.readLine()) != null) {
                // 跳过 空格 和 #行
                str = str.trim();
                if (str.startsWith("#") || str.equals("")){
                    continue;
                }
                User one = parseUser(str);
                users.put(one.getId(), one);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //System.out.println(users.size());
    }
//    private void loadMsg(String msgFile){
//        System.out.println("msmFile");
//        BufferedReader br = null;
//        try {
//            br = new BufferedReader(new InputStreamReader(new FileInputStream(msgFile)));
//            String str;
//            while ((str=br.readLine())!=null){
//                str = str.trim();
//                if (str.startsWith("#") || str.equals("")){
//                    continue;
//                }
//                messages.add(str);
//            }
//        } catch (IOException e) {
//            e.printStackTrace();
//        }finally {
//            if (br != null) {
//                try {
//                    br.close();
//                } catch (IOException e) {
//                    e.printStackTrace();
//                }
//            }
//        }
//    }
    /**
     * 解析字符串
     * 1001:陈贺贺:1234:13810381038:chenhh@zzxx.com.cn
     * @param str
     * @return
     */
    private User parseUser(String str) {
        String[] data = str.split(":");
        User user = new User();
        user.setId(Integer.valueOf(data[0]));
        user.setName(data[1]);
        user.setPassword(data[2]);
        user.setPhone(data[3]);
        user.setEmail(data[4]);
        return user;
    }

    /**
     * 读取corejava.txt文件
     * 并且解析成Question对象, 添加到questions集合中
     */
    private void loadQuestions(String questionFile) {
        System.out.println("loadQuestions");
        BufferedReader br = null;
        try {
            br = new BufferedReader(new InputStreamReader(new FileInputStream(questionFile)));
            String str;
            while((str = br.readLine()) != null) {
                Question question = parseQuestion(str, br);
                addQuestion(question);
            }
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (br != null) {
                try {
                    br.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        //System.out.println(questions.size());
    }

    /**
     * 将question对象添加到questions集合中
     * 相同的难度级别, 放在同一个List中
     * @param question
     */
    private void addQuestion(Question question) {
        List<Question> list = this.questions.get(question.getLevel());
        // 第一次出现这个难度级别的题目
        if (list == null) {
            list = new ArrayList<>();
            questions.put(question.getLevel(), list);
        }
        list.add(question);
    }

    /**
     * 解析Question对象
     * @param str @answer=2/3,score=5,level=5   @answer=  ,score=    ,level=
     * @param br
     * @return
     */
    private Question parseQuestion(String str, BufferedReader br) {
        Question question = new Question();
        try { // 2/3  5  5
            String[] data = str.split("[@,][a-z]+=");
            // {"", "2/3", "5", "5"}
            question.setAnswers(parseAnswer(data[1]));
            question.setScore(Integer.parseInt(data[2]));
            question.setLevel(Integer.parseInt(data[3]));
            question.setTitle(br.readLine()); // 读一行是题干
            List<String> option = new ArrayList<>();
            // 连续读4行是选项
            option.add(br.readLine());
            option.add(br.readLine());
            option.add(br.readLine());
            option.add(br.readLine());
            question.setOptions(option);
            question.setType(question.getAnswers().size()==1 ? Question.SINGLE_SELECTION:Question.MULTI_SELECTION);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return question;
    }

    /**
     * 解析 2/3 正确答案
     * @param str
     * @return
     */
    private List<Integer> parseAnswer(String str){
        String[] data = str.split("/");
        List<Integer> answers = new ArrayList<>();
        for (String s : data) {
            answers.add(Integer.valueOf(s));
        }
        return answers;
    }
    public void setConfig(Config config) {
        this.config = config;
    }

    /**
     * 根据用户ID查找用户实例
     * @param id
     * @return
     */
    public User getUserById(int id) {
        return users.get(id);
    }

    public Map<Integer, List<Question>> getQuestions() {
        return questions;
    }

    public void setQuestions(Map<Integer, List<Question>> questions) {
        this.questions = questions;
    }

    public int getTime() {
        return config.getInt("TimeLimit");
    }

    public String getTitle() {
        return config.getString("PaperTitle");
    }

//    public ExamInfo getExamInfo() {
//
//        return null;
//    }
}

  • 业务层
package com.zzxx.exam.service;

import com.zzxx.exam.entity.*;

import java.util.*;

public class ExamServiceImpl implements ExamService{
    private EntityContext entityContext;
    private User user;

    public void setEntityContext(EntityContext entityContext) {
        this.entityContext = entityContext;
    }

    @Override
    public User login(int id, String pwd) throws IdOrPwdException {
        user = entityContext.getUserById(id);
        if (user==null){
            throw new IdOrPwdException("用户不存在");
        }
        if (!user.getPassword().equals(pwd)){
            throw new IdOrPwdException("密码错误");
        }
        return user;
    }

    // 定义一个集合 List<QuestionInfo> paper, 用来存储试卷题目
    private List<QuestionInfo>paper = new ArrayList<>();
    @Override
    public ExamInfo start() {
        int num =0;
        Random random = new Random();
        // 1.生成试卷[每一个难度级别随机生成2道题目]
        for (int i = 1; i < 11; i++) {
            List<Question> questions = entityContext.getQuestions().get(i);
            Question q1 = questions.remove(random.nextInt(questions.size()));
            Question q2 = questions.remove(random.nextInt(questions.size()));
            paper.add(new QuestionInfo(num++,q1));
            paper.add(new QuestionInfo(num++,q2));
        }
        //   调用EntityContext来获得题目
        // 2.封装一个考试信息返回 ExamInfo
        ExamInfo examInfo = new ExamInfo();
        examInfo.setQuestionCount(paper.size());
        examInfo.setTimeLimit(entityContext.getTime());
        examInfo.setTitle(entityContext.getTitle());
        examInfo.setUser(user);
        // ExamInfo : title-自定 user->登陆过的(login赋值过了)
        //   timeLimit: 配置文件  questionCount: 生成试卷时记录的
        return examInfo;
    }

    @Override
    public QuestionInfo getQuestion(int index) {
        return paper.get(index);
    }

    @Override
    public void saveUserAnswers(int index, List<Integer> userAnswers) {
        getQuestion(index).setUserAnswers(userAnswers);
    }

    @Override
    public int examOver() {
        int sum=0;
        for (int i = 0; i < 20; i++) {
            List<Integer> userAnswers = getQuestion(i).getUserAnswers();
            List<Integer> answers = getQuestion(i).getQuestion().getAnswers();
            if (userAnswers.equals(answers)){
                sum+=getQuestion(i).getQuestion().getScore();
            }
        }
        // paper 用户答案和正确答案对比
        return sum;
    }

    @Override
    public String getMsg() {
        return null;
    }

}

源码:
https://gitee.com/xjq860955921/exam

Logo

CSDN联合极客时间,共同打造面向开发者的精品内容学习社区,助力成长!

更多推荐