在项目中会遇到这样的状况,因为后台须要执行、计算一段时间(如计算积分、自动排课等)。这时前台请求一段时间后,得不到返回结果就会发生请求超时。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); }