Welcome to Yumao′s Blog.
T-ELTS Project Day03
====================
1. 三層架構, 整體架構
2. 開始考試功能實現
3. 上/下一題功能實現 和 交卷
4 查看考分功能實現
5 關閉窗口 問題 與窗口事件監聽
1. 三層架構, 整體架構
1) 表現層(數據呈現/用戶交互)
在ui包中 的 "用戶界面"和"控制器(ClientContext)"
如: 接受登錄請求
2) 業務層(業務模型), 是軟件的核心功能
在service包中, 核心接口ExamService
如: 登錄系統
3) 數據管理層(數據持久化層), 是提供數據的CRUD管理,增刪改查
C: 創建, R: 尋回, 查找, U:更新, D:刪除.
數據管理層: 只關心數據操作, 不涉及業務功能
如: 查找用戶
在entity包中, 核心類: EntityContext, 管理User 和
Question
2. 開始考試功能實現
1) 視圖 MenuFrame 中增加事件監聽
private ClientContext clientContext;
public void setClientContext(ClientContext clientContext) {
this.clientContext = clientContext;
}
//...增加事件監聽
start.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
clientContext.start();
}
});
更新ExamFrame, 增加: updateView()
private JLabel info;//引用到界面控件實例
private JLabel questionCount;//引用到界面控件實例
private JTextArea question;//引用到界面控件實例
public void updateView(
ExamInfo examInfo, QuestionInfo questionInfo){
info.setText(examInfo.toString());
//"題目:20 的 1題"
questionCount.setText("題目:"+
examInfo.getQuestionCount()+" 的 "+
(questionInfo.getQuestionIndex()+1)+"題");
question.setText(questionInfo.toString());
}
2) 控制器, 增加事件響應方法start()
/** 開始考試 */
public void start(){
try {
//考試信息
ExamInfo examInfo = examService.startExam();
//第一道考題
QuestionInfo questionInfo =
examService.getQuestion(0);
examFrame.updateView(examInfo, questionInfo);
menuFrame.setVisible(false);
examFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
menuFrame, e.getMessage());
}
}
3) 業務層: 增加: startExam() getQuestion()
開始考試業務描述: 開始考試時候, 抽取考卷試題, 每個level抽取2題
返回考試描述信息:ExamInfo
考卷是: 有抽取的題目組成的線性表集合
獲取試題: 根據題目序號獲取指定試題
private List paper =
new ArrayList();
public QuestionInfo getQuestion(int index) {
return paper.get(index);
}
private User loginUser;
private void createPaper(){
Random r = new Random();
int idx = 0;
for(int i=Question.LEVEL1; i<=Question.LEVEL10; i++){
List list =
entityContext.findQuestions(i);
//抽出2道題
Question q1 = list.remove(r.nextInt(list.size()));
Question q2 = list.remove(r.nextInt(list.size()));
paper.add(new QuestionInfo(idx++, q1));
paper.add(new QuestionInfo(idx++, q2));
}
}
public ExamInfo startExam() {
createPaper();
ExamInfo info = new ExamInfo();
//初始化info ...
info.setQuestionCount(paper.size());
info.setTimeLimit(entityContext.getTimeLimit());
info.setTitle(entityContext.getTitle());
info.setUser(loginUser);
return info;
}
4) 持久層
public int getTimeLimit() {
return config.getInt("TimeLimit");
}
public String getTitle() {
return config.getString("PaperTitle");
}
5) 更新Main.class
menuFrame.setClientContext(clientContext);
3. 上/下一題功能實現 和 交卷
1) 視圖 (增加界面事件監聽)
A 增加對控制器的引用
private ClientContext clientContext;
public void setClientContext(ClientContext clientContext) {
this.clientContext = clientContext;
}
B 增加界面事件監聽
prev.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
clientContext.prev();
}
});
next.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
clientContext.next();
}
});
send.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
clientContext.send();
}
});
C 更新視圖為下/上一題(更新 用戶的答案)
private JLabel info;
private JLabel questionCount;
private JTextArea question;
public void updateView(
ExamInfo examInfo, QuestionInfo questionInfo){
info.setText(examInfo.toString());
//"題目:20 的 1題"
questionCount.setText("題目:"+
examInfo.getQuestionCount()+" 的 "+
(questionInfo.getQuestionIndex()+1)+"題");
question.setText(questionInfo.toString());
updateOptions(questionInfo.getUserAnswers());
}
private void updateOptions(List userAnswers) {
for (Option o : options) {
o.setSelected(false);
if(userAnswers.contains(o.val)){
o.setSelected(true);
}
}
}
public List getUserAnswers() {
List ans = new ArrayList();
for (Option o : options) {
if(o.isSelected()){
ans.add(o.val);
}
}
return ans;
}
2) 控制器(增加界面功能實現方法 next() prev(), send())
/** 當前正在答對題目, 開始考試時候, 初始化為第一題
* 每次翻頁, 更新為新的當前題目 */
private QuestionInfo currentQuestion;
/** 當前考試的狀態信息, 在開始考試時候初始化為 考試信息
* 重構開始開始start()代碼!
*/
private ExamInfo examInfo;
public void next() {
try {
int idx = currentQuestion.getQuestionIndex();
List userAnswers =
examFrame.getUserAnswers();
examService.saveUserAnswers(idx, userAnswers);
currentQuestion = examService.getQuestion(idx+1);
examFrame.updateView(examInfo, currentQuestion);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
examFrame, e.getMessage());
}
}
public void prev() {
try {
int idx = currentQuestion.getQuestionIndex();
List userAnswers =
examFrame.getUserAnswers();
examService.saveUserAnswers(idx, userAnswers);
currentQuestion = examService.getQuestion(idx-1);
examFrame.updateView(examInfo, currentQuestion);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
examFrame, e.getMessage());
}
}
public void send() {
try {
int val = JOptionPane
.showConfirmDialog(examFrame, "交嗎?");
if(val != JOptionPane.YES_OPTION){
return;
}
int idx = currentQuestion.getQuestionIndex();
List userAnswers =
examFrame.getUserAnswers();
examService.saveUserAnswers(idx, userAnswers);
int score = examService.examOver();
JOptionPane.showMessageDialog(
examFrame, "你的分數:"+score);
examFrame.setVisible(false);
menuFrame.setVisible(true);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
examFrame, e.getMessage());
}
}
3) 業務層(保存用戶答案 saveUserAnswers())
public void saveUserAnswers(int idx, List userAnswers) {
//保存用戶答案到考卷中的考題上
paper.get(idx).setUserAnswers(userAnswers);
}
private int score = 0;
public int examOver() {
//判分
for (QuestionInfo qInfo : paper) {
Question q = qInfo.getQuestion();
if(qInfo.getUserAnswers().equals(q.getAnswer())){
score+=q.getScore();
}
}
return score;
}
4 查看考分功能實現
1) 界面
result.addActionListener(new ActionListener(){
public void actionPerformed(ActionEvent e) {
clientContext.result();
}
});
2) 控制器
public void result() {
try {
int score = examService.getScore();
JOptionPane.showMessageDialog(
menuFrame, "考試分數:"+score);
} catch (Exception e) {
e.printStackTrace();
JOptionPane.showMessageDialog(
menuFrame, e.getMessage());
}
}
3) 業務層
public int getScore() {
if(!finish)
throw new RuntimeException("還沒有考試呀!");
return score;
}
5 關閉窗口 問題 與窗口事件監聽
1) 設置默認的窗口關閉操作
setDefaultCloseOperation(JFrame.DO_NOTHING_ON_CLOSE);
2) 綁定窗口關閉事件
addWindowListener(new WindowAdapter(){
public void windowClosing(WindowEvent e) {
clientContext.send();
}
});
Download==>OnlineExamSystem