1. 程式人生 > >線上考試系統思路總結

線上考試系統思路總結

最近正在完成一個電網的線上考試系統,這個專案的整個業務部分和功能模組部分已經確定。
在這個專案中,主幹部分主要難點是四個部分,分為:設計資料庫、考試隨機出題、提交試卷評分、頁面上題下題提交試卷的JS。

下面就模擬一個小的考試系統,給大家演示:
一、資料庫部分
在設計資料庫時,
1、先設計題型的表,在這部分每個題型都是一張獨立的表,主要是單選表、多選表、判斷表、型別表。在表字段的設計上,都是類似的。主要欄位和一條虛擬資料如下

單選表:
id      |  content      | a   |   b    |    c   |   d    | answer | 所屬專業id 
radio01 |  C
語言重要不? | 重要 | 不重要 | 不瞭解 | 拒絕回答 | a | 1 多選表: id | content | a | b | c | d | e | answer | 所屬專業id 類似 判斷表: id | content | a | b | answer | 所屬專業id 類似 專業型別表 id | content 1 | 配電

2、設計試卷引數表,用於設定不同專業出題的型別和數量,主要欄位如下。

試卷引數表:

id | 所屬專業id | 單選題數量 | 多選題數量 | 判斷題數量 | 答題時間 | 
1  |    1      |     20   |     20   |     10    |   30

二、考試隨機出題部分
在專案中,業務要求每個考生登入考試,即使報考專業相同,得到的題目也是不同的,在這個模組,有兩個思路。

1、在資料庫試題表中儲存一個自增的id作為主鍵,或者每次新增的時候獲取最大的id數目,新增時原有id+1作為主鍵,不管怎麼實現最後在表中要形成不間斷的數字,然後建立一個得到不重複數字的隨機數工具類,獲取的數字作為id進行獲取試題。這種方法較第二種方法,效率較高,但當對某些進行刪除後,處理相對麻煩,因為不可以獲取空的題。
2、第二種思路是在資料庫試題表中儲存的主鍵是具有自己填寫規則的varchar型別的字串,比如201701
,在抽取試題時,將所有的單選、多選、判斷分別存到三個集合中,然後使用隨機數工具類,要求不同題型多少道就獲取多少不重複的隨機數,然後分別在集合中獲取試題。這種方式較笨重,但刪除操作不會造成任何影響,適合題量較少、經常修改的考試系統、效能較低。

/** 
 * 隨機指定範圍內N個不重複的數 
 * 在初始化的無重複待選陣列中隨機產生一個數放入結果中, 
 * 將待選陣列被隨機到的數,用待選陣列(len-1)下標對應的數替換 
 * 然後從len-2裡隨機產生下一個隨機數,如此類推 
 * @param max  指定範圍最大值 
 * @param min  指定範圍最小值 
 * @param n  隨機數個數 
 * @return int[] 隨機數結果集 
 */  
public class randomSet {
    public static int[] randomArray(int min,int max,int n){  
        int len = max-min+1;  

        if(max < min || n > len){  
            return null;  
        }  

        //初始化給定範圍的待選陣列  
        int[] source = new int[len];  
           for (int i = min; i < min+len; i++){  
            source[i-min] = i;  
           }  

           int[] result = new int[n];  
           Random rd = new Random();  
           int index = 0;  
           for (int i = 0; i < result.length; i++) {  
            //待選陣列0到(len-2)隨機一個下標  
               index = Math.abs(rd.nextInt() % len--);  
               //將隨機到的數放入結果集  
               result[i] = source[index];  
               //將待選陣列中被隨機到的數,用待選陣列(len-1)下標對應的數替換  
               source[index] = source[len];  
           }  
           return result;  
    }  

三、提交試卷評分部分
在這個部分,主要分為兩個模組,一個是多選部分的checkBox、一個是單選和判斷部分的radio
1、checkBox部分
當在登入完成後,後臺隨機出題時,將隨機數儲存到session中,將在多選部分是在遍歷時候,checkBox的name設定為當前題的id,保證名稱是唯一,提交後,在後臺取出session中的隨機數,然後如果試題id是自增的話,直接可以獲取試題的所有資訊,按id獲取考生每道題的選擇,在這裡由於是CheckBox,所以有可能是多個值,先將值拼接為字串,然後和試題的答案進行對比,相同的話得分。
2、radio部分
這部分和checkBox部分類似,最後不需要拼接字串,就可以比對。

四、上下題、提交JS部分
在頁面這個部分,分為三個部分進行遍歷,在頁面上有一個大的form表單,用於提交資料,單form表單中有三個foreach用於遍歷,然後在foreach中有一個div,三個型別的題具有三個不同結構的id,同時使用varStatus屬性,實現dan1、dan2、dan3這種效果。然後將所有div隱藏。在最上方的rnum、cnum、tnum分別代表不同型別的試題數目。在form的上方實現顯示所有題目號,並通過下面的方式將連結中的class和遍歷題的id設為一樣的值,用於實現上下題和點選顯示題目的效果。
具體程式碼如下
1、表單和頁面設定

        <input type="hidden" id="zhi1" value="${rnum}">
        <input type="hidden" id="zhi2" value="${cnum}">
        <input type="hidden" id="zhi3" value="${tnum}">
    <table>
    <tr><th>單選題部分</th></tr>
    <tr>
         <c:forEach  begin="${begin}" end="${rend}" var="r">
          <td><a onclick="getdanxuan(this)" class="dan${r}">【${r}】</a>&nbsp;&nbsp;</td>
         </c:forEach>
    </tr>
    <tr><th>多選題部分</th></tr>
    <br>
    <tr>
        <c:forEach  begin="${begin}" end="${cend}" var="c">
        <td><a onclick="getduoxuan(this)" class="duo${c}">【${c}】</a>&nbsp;&nbsp;</td>
        </c:forEach>
    </tr>
    <tr><th>判斷題部分</th></tr>

    <tr>
        <c:forEach  begin="${begin}" end="${tend}" var="t">
        <td><a onclick="getpanduan(this)" class="pan${t}">【${t}】</a>&nbsp;&nbsp;</td>
        </c:forEach>
    </tr>
</table>
    <br>
<c:forEach items="${rflist}" var="rf"  varStatus="state">
<div id="dan${state.count}" class="danxuan" style="display: none">
            <tr>【單選題】${state.count}</tr>
</div>
</forEach>
<br>
<c:forEach items="${cflist}" var="cf"  varStatus="state1">
    <div id="duo${state1.count}" class="duoxuan" style="display: none">
            <tr>【多選題】${state1.count}</tr>
    </div>
</forEach>
<c:forEach items="${tflist}" var="tf"  varStatus="state2">
   <div id="pan${state2.count}" class="panduan" style="display: none;">
            <tr>【判斷題】${state2.count}</tr>
   </div>
</forEach>
<input type="button" value="上一題" onclick="shang()">
<input type="button" value="下一題" onclick="xia()">

2、JS部分
在這部分使用JS實現上一題、下一題、和點選題目號顯示題目的效果。
(1)在頁面顯示初始化部分設定單選第一道顯示,先獲取三個型別的數目,然後獲取div的數目,由於只有題目具有div,所以可以通過這種方式進行設定;
(2)在點選題目顯示部分,有三個函式,分別對應三類題型,道理相同,首先設定所有div是隱藏的,然後獲取目標的class名稱,在通過class名稱獲取指定div,將其設定為block。
(3)點選上下題,顯示指定題目,道理是類似的,都是先獲取所有div元素,然後判斷哪個是顯示的,記錄下來,將其隱藏,然後將上一個或者下一個進行顯示。

<script type="text/javascript">
//頁面顯示初始化部分
var zhi1=document.getElementById("zhi1").value;
var zhi2=document.getElementById("zhi2").value;
var zhi3=document.getElementById("zhi3").value;
var zhi=parseInt(zhi1)+parseInt(zhi2)+parseInt(zhi3);
var divs=document.getElementsByTagName("div");
divs[0].style.display="block";
//點選單選題目顯示
function getdanxuan(obj){
    for(var i=0;i<zhi;i++){
        divs[i].style.display="none";
    }
    var a=obj.className;
    var div1=document.getElementById(a);
     div1.style.display = "block";

}
//點選多選題目顯示
function getduoxuan(obj){
    for(var i=0;i<zhi;i++){
        divs[i].style.display="none";
    }
    var b=obj.className;
    var div2=document.getElementById(b);
    div2.style.display="block";
}
//點選判斷題目顯示
function getpanduan(obj){
    for(var i=0;i<zhi;i++){
        divs[i].style.display="none";
    }
    var c=obj.className;
    var div3=document.getElementById(c);
    div3.style.display="block";
}
//點選上一題
function shang(){
    var divs=document.getElementsByTagName("div");
    for(var i=0;i<divs.length;i++){
        if(divs[i].style.display=='block'){
        if(i==0){
            alert("已經是第一題了");break;
        }else{
                divs[i].style.display="none";
                divs[i-1].style.display="block";
                break;
        }
        }
    }
}
//點選下一題
function xia(){
    var divs=document.getElementsByTagName("div");
    for(var i=0;i<divs.length;i++){
        if(divs[i].style.display=='block'){
            if(i==divs.length-1){
                alert("已經是最後一題了");break;
            }else{
                divs[i].style.display="none";
                divs[i+1].style.display="block";
                break;
            }
            }
        }
}

基本上思路就是這樣了,本人能力有限,歡迎指點迷津。