最近在搞一個含有在線考試模塊的系統。既然是考試,必不可少的一部分就是計時了。
總的來說,需要計時的系統大體上分兩種:1.規定時間內的倒計時。2.規定時間段內的計時判斷。
對於第一種倒計時,我覺得下面這篇文章寫的很好,這是鏈接:
https://blog.csdn.net/a13432421434/article/details/71346153
對於第二種倒計時,我並沒有找到合適的,首先介紹一下這個項目的實現,總的是前後端分離,前端試用的是vue,後臺用的是spring-boot。
一開始的想法:就單純前端獲取Internet時間,然後把與後臺返還來的結束時間對比,如果結束就結束。後來一想- -如果考生懂點JS知識,控制檯幾行代碼就可以無限延長考試時間了。
(PS:當然了,也會有很多人說用閉包寫進去就行了)但是這樣是不好的,同樣存在隱患。
後來的想法:前端無時無刻在調用一個接口,將當前的時間傳給後臺(或是間隔一段時間傳),這樣是存在併發隱患,因爲考試的不可能就是一個學生,spring-boot通俗的講只有一個入口,這樣無論間隔多久- -一起傳送的數據仍然是一起的,佔用過大。
再後來的想法:前端不傳數據,由後臺單獨計時,從開始時間計時到規定的結束時間,一旦時間結束了,那就向前端發送考試結束的信息。但是轉念一想,也是不存在的。如果是這樣,前端還是需要不斷的執行一個函數,和上面的想法幾乎沒差別不過就是避免了被懂js的人修改作弊。
最後的想法:利用springboot中的schelling機制,添加計時任務,比如每10分鐘,5分鐘檢查一次考試的數據表數據。通過當前時間和規定開始時間結束時間的比較,來更新當前數據狀態下的考試狀態。未考,考中,已考。
代碼如下
1.現在你的項目啓動項APPLICATION中加入如下的註解
@EnableScheduling //boot定時任務
這是spring-boot的計時任務的必要註解。
2.新建一個類,輸入如下代碼
package com.project.myBeans; import com.project.entity.Exam; import com.project.service.ExamService; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.autoconfigure.EnableAutoConfiguration; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Component; import org.springframework.web.bind.annotation.RestController; import java.sql.Timestamp; import java.util.List; /** * @Author: TateBrown * @date: 2018/7/3 15:51 * @param: * @return: */ @Component @EnableAutoConfiguration @RestController public class SchedulingTask { @Autowired ExamService examService; /** * @Description:定時掃描所有考試任務修改考試state. * @param: [] * @return: void * @author: TateBrown * @Date: 2018/7/3 */ @Scheduled(fixedRate = 60000)//每隔一分鐘查一次 public void CheckExam() { List<Exam> list = examService.GetAllExam(); Timestamp curtime = new Timestamp(System.currentTimeMillis()); for (Exam tmp : list) { Timestamp tmpfinishtime = tmp.getFinishtime(); Timestamp tmpstarttime = tmp.getStarttime(); if (curtime.before(tmpstarttime)) { tmp.setState(1); examService.modify(tmp); } else if ((curtime.equals(tmpstarttime) || curtime.after(tmpstarttime)) && (curtime.equals(tmpfinishtime) || curtime.before(tmpfinishtime))) { tmp.setState(2); examService.modify(tmp); } else { tmp.setState(3); examService.modify(tmp); } } } }
我這裏的數據是由時間戳進行存儲的,所以上述也是時間戳比較前後的方法。其中第一句是獲取全部考試的信息,第二句是獲取當前的系統時間並轉換成時間戳模式,後面的就是根據當前時間判斷是否更新數據。
優化:存在的優化空間就是對於已考過的考試,我們不需要這樣掃描,我們每次之找出全部未考和考中的考試。這樣的做法是必然需要的,但是這裏我就不貼代碼了。
總結:最後的做法就是符合了邏輯,因爲這必然是有幾場考試同時發生的存在的。而且完全由後臺控制,較被修改的可能較小。
邏輯上講,後臺纔是控制進程的地方,前後端分離的特性應該是把前端後端儘可能的分離開來。可能還有更好的方法。