在項目中會遇到這樣的狀況,因爲後臺須要執行、計算一段時間(如計算積分、自動排課等)。這時前臺請求一段時間後,得不到返回結果就會發生請求超時。javascript
拿自動排課來講,若是一個學校上百個班級,執行一次排課可能須要1-2分鐘甚至更長時間,那麼會形成前臺訪問接口超時(固然也能夠延長超時時間實現)。前端
解決方案:java
考慮改造爲輪詢查詢程序執行結果。ajax
將自動排課功能的接口分爲兩個:redis
①建立線程執行自動排課app
②提供接口查詢排課結果post
對原有的方法進行改造:原有的方法,方法執行完成後纔會返回執行結果。時間過長,考慮將原方法改造爲線程執行,這樣一旦線程開始執行,就能夠返回結果。this
改造方法:spa
代碼示例:線程
Controller層
@Controller public class Controller{ @Autowired //自動注入排課功能所在的service private CourseTableService courseTableService; @RequestMapping(value = "/arrange/{id}") @ResponseBody public ResponseMessage arrange(@PathVariable String id) { return courseTableService.arrange(id); //自動排課 } @RequestMapping(value = "/arrangeResult/{id}") @ResponseBody public Map<String,Object> arrangeResult(@PathVariable String id) { //查詢自動排課結果,並返回 } }
Service層
@Service @Transactional(readOnly = true) public class CourseTableService implements Runnable { //實現Runnable接口 @Autowired private ThreadPoolTaskExecutor taskExecutor; //線程池 //自動paike public ResponseMessage arrange(String scheduleId) { this.scheduleId=scheduleId; //設置run方法中須要用的參數 taskExecutor.execute(this); //執行線程 return ResponseMessage.ok(); //返回線程執行結果 } //自動排課,線程 public void run(){ //排課邏輯代碼 String scheId=this.scheduleId; //使用接收的參數 } }
第一次請求接口自動排課(線程或者mQ執行),這樣在啓動自動排課的時候就返回請求結果,告知用戶正在進行排課。
而後輪詢調用第二接口,每隔幾秒鐘就去查詢排課的結果。若是返回的狀態爲0表明排課成功,提示用戶;若是返回的狀態爲1達標排課失敗,提示失敗緣由;若是返回的狀態爲2表明排課正在執行中,繼續輪詢訪問查詢排課結果的接口。
主要代碼示例:
var intervalFlag=true; //是否執行輪詢的標誌 //_post2是封裝的ajax請求, $._post2('/arrange/' + _id, {}, function(res) { var interVal; //調用接口,查詢自動排課結果,加上這個是爲了用戶點擊後立馬訪問,ajax同步訪問, //由於此次的查詢結果決定了,是否執行輪詢。 getProgress(_id, interVal); if(intervalFlag){ //第一次查詢結果代表排課還在進行中,纔會執行輪詢。 //若是第一次已經返回結果表示程序執行完成,就不須要輪詢訪問排課結果了。 interval(_id); } }); // 進度查詢 function getProgress(_id, interVal) { $._post2('/arrangeResult/' + _id, {}, function(res) { if (res.arrangeStatus == 0) { //排課成功 clearInterval(interVal); //清空輪詢 intervalFlag=false; //設置爲不執行輪詢 }else if(res.arrangeStatus==1){ //排課失敗 clearInterval(interVal); intervalFlag=false; }else if(res.arrangeStatus==2){ //排課進行中,什麼都不作 } }); } // 隔兩秒訪問 function interval(_id) { var pro; // 定時器 var interVal; interVal = setInterval(function() { // 獲取返回對象 pro = getProgress(_id, interVal); }, 2000); }