在cli程序中,输入命令得到连续的输出已经是一种进度而美观的页面交互形式,好比下图:

而web程序里也有类似的场景,比如执行一个耗时任务,除了显示出等待图标外,用户还希望把执行的状态及时显示出来.如下图:

这样的界面如何设计呢?我的思路如下:

1.点击按钮后,产生一个新ID,后台运行的线程拿到id后开始运行并及时往数据库中插入记录,同时id被送回到前台;

2.前台拿到id后,开始以此id轮询后台数据表,并将取得的数据显示出来,而取得的数据是后台运行的线程不断写入的;

3.后台线程写入状态1后,即认为任务完成,前台取得此数据后不再轮询并恢复成初始状态.

下面请看具体实现:

前台点击按钮触发Ajax:

    $("#startPhonexCrawl").click(function(){
var taskId=$("#taskIdTxt").val(); if(taskId!="0"){
// 有任务启动则取状态
alert("有任务在执行,请稍等...");
}else{
// 没有任务则启动任务
$.get("/startCrawl/phonex",{},function(data,textStatus){
var taskId=data;
$("#taskIdTxt").val(taskId);
$("#crawlsDiv").html("");
$("#loadingImg").show();
showTask();
});
}
});

后台接到请求后一边启动线程,一边将产生的taskid回传:

    /**
* Start crawl and return crawltask id
* @param crawlName
* @return
*/
@RequestMapping("/startCrawl/{crawlName}")
String startCrawl(@PathVariable("crawlName") String crawlName) {
logger.info("准备启动爬虫:"+crawlName);
long taskId=crawlMapper.getNextTaskId(); BaseCTH cth=null; if("phonex".equalsIgnoreCase(crawlName)) {
cth=new PhonexCTH();
logger.info("Phonex crawl thread is ready.");
}else if("163".equalsIgnoreCase(crawlName) || "Netease".equalsIgnoreCase(crawlName)) {
cth=new NeteaseCTH();
logger.info("Netease crawl thread is ready.");
}else if("snowball".equalsIgnoreCase(crawlName)) {
cth=new SnowballCTH();
logger.info("Snowball crawl thread is ready.");
}else {
logger.warn("Error crawlName:"+crawlName+",so no crawl thread started.");
taskId=0;
} if(cth!=null) {
cth.setTaskId(taskId);
cth.setStockMapper(stockMapper);
cth.setCrawlMapper(crawlMapper);
cth.start();
logger.info("Crawl thread started.");
} return String.valueOf(taskId);
}

从上面的程序也可看出,前台按钮和后台具体爬虫联系的纽带是crawlName,这样处理后,如果要增加新爬虫,只要前台做个链接,然后在分支中与具体爬虫联系上即可.

前台的ajax会在得到返回id后调用showTasks函数:

function showTask(){
var taskId=$("#taskIdTxt").val(); if(taskId!="0"){
$.get("/getCrawlTasks/"+taskId,{},function(data,textStatus){
var message="";
var state="";
var percent=""; for(var i=0,l=data.length;i<l;i++){
message+=data[i].ctime+" "+data[i].msg+"<br/>";
state=data[i].state;
percent=data[i].percent;
} $("#crawlsDiv").html(message);
$("#percentSpan").html(percent+"%"); if(state=="1"){
//alert("爬虫任务"+taskId+"结束");
// 如果任务结束则可启动下一任务
clearTimeout(timerHandler);
$("#taskIdTxt").val("0");
$("#loadingImg").hide();
$("#percentSpan").html("");
}else{
timerHandler=setTimeout("showTask()",3000);
}
});
}
}

showTasks函数会在结束前查看数据状态,如果状态不是1则会以三秒为间隔不断调用自己,从而达到轮询的目的,而轮询取状态的后台函数是

    @RequestMapping("/getCrawlTasks/{taskId}")
List<CrawlTask> getCrawlTasks(@PathVariable("taskId") String taskId) {
logger.info("取得taskId="+taskId+"的爬虫状态:"); return crawlMapper.getCrawlTasks(taskId);
}
    @Select("select id,taskid,state,msg,DATE_FORMAT(ctime,'%Y-%m-%d %T') as ctime,percent from crawltask where taskid=#{taskId} order by id ")
List<CrawlTask> getCrawlTasks(@Param("taskId") String taskId);

这样,每过三秒就会从crawltask表里取得信息显示在页面上.

整套设计里,taskid是前台从db取值和后台线程往数据库写值的联系纽带,有了它的出现,前后台可以在互不知情的情况下良好配合.

当从后台取得状态为1时,下面语句便会发挥作用:

clearTimeout(timerHandler);

timerHandler是启动时的句柄,而一旦clear掉,timeout便不会再起作用,从而结束轮询.

这就是全部设计过程.

--2020年5月6日--

如何让Web程序在点击按钮后出现如执行批处理程序般的效果的更多相关文章

  1. 请写出一段JavaScript代码,要求页面有一个按钮,点击按钮弹出确认框。程序可以判断出用

    请写出一段JavaScript代码,要求页面有一个按钮,点击按钮弹出确认框.程序可以判断出用 户点击的是“确认”还是“取消”. 解答: <HTML> <HEAD> <TI ...

  2. response 后刷新页面,点击按钮后,禁用该按钮

    一,正常的点击按钮后,将其灰显,全部执行完毕再正常显示. this.btnSave.Attributes.Add("onclick", "if (typeof(Page_ ...

  3. TProcedure,TMethod,TNotifyEvent,TWndMethod的区别,并模拟点击按钮后发生的动作

    忽然发现TProcedure和TNotifEvent的区别还挺大的: procedure TForm1.Button2Click(Sender: TObject); begin ShowMessage ...

  4. Java基础 awt Button 点击按钮后在控制台输出文字

        JDK :OpenJDK-11      OS :CentOS 7.6.1810      IDE :Eclipse 2019‑03 typesetting :Markdown   code ...

  5. 微信小程序开发——点击按钮获取用户授权没反应或反应很慢的解决方法

    异常描述: 点击按钮获取用户手机号码,有的时候会出现点击无反应或很久之后才弹出用户授权获取手机号码的弹窗,这种情况下,也会出现点击穿透的问题(详见:微信小程序开发——连续快速点击按钮调用小程序api返 ...

  6. 微信小程序开发——点击按钮退出小程序的实现

    微信小程序官方是没有提供退出的API的,但是在navigator这个组件中,是有退出这个功能的:详情参考官方文档:navigator.示例代码:1 navigator open-type=" ...

  7. 点击按钮后到底发生了什么,Touch,LongClick或者Click?

    按钮点击事件详解 最近一个项目需要给应用初始界面上的动态按钮添加在不同状态的变换效果,如点击(俗一点也可称为按压)后实现背景图的更换或者图标的缩放等效果.由于按钮点击的时间有长有短,所以采用OnTou ...

  8. 如何点击按钮后在加载外部的Js文件

    或许有朋友遇到过,想等自己点击按钮之后才执行某一个js文件,那么,你运气好,看到了我的代码了哈哈, <html> <head> <title></title& ...

  9. 移动端开发H5页面点击按钮后出现闪烁或黑色背景的解决办法

    H5页面在IOS端测试的时候发现,点击按钮会闪动,出现一个黑色的背景一闪而过,影响用户体验.最后通过度娘,找到解决方法: 就是给点击的元素添加一个CSS属性或者全局添加一个css. -webkit-t ...

随机推荐

  1. 修改 jar 包 或 war 包内容

    修改 jar 包 或 war 包内容 有一个 java web 项目,是 .jar 或 .war 文件,我想替换其中的部分样式(.css)或功能(.class). 步骤就是解压,替换,重新打包. 以 ...

  2. [leetcode/lintcode 题解] 前序遍历和中序遍历树构造二叉树

    [题目描述] 根据前序遍历和中序遍历树构造二叉树. 在线评测地址: https://www.jiuzhang.com/solution/construct-binary-tree-from-preor ...

  3. tableau用户留存分析

    1.数据源 这是个母婴产品的购买流水数据 2.数据处理 字段拆分.创建购买点会员生命周期 3.分析不同省份的留存率情况 根据第12个月的留存率对省市进行分组 实际业务中也可以通过类似的方法对用户年龄组 ...

  4. 火题小战 C. 情侣?给我烧了!

    火题小战 C. 情侣?给我烧了! 题目描述 有 \(n\) 对情侣来到电影院观看电影.在电影院,恰好留有 \(n\) 排座位,每排包含 \(2\) 个座位,共 \(2×n\) 个座位. 现在,每个人将 ...

  5. CVT1100 错误的修复 2009-10-12 11:38

    我们在用VS2005编译MFC工程时极少会出现如下错误: 一,CVTRES : fatal error CVT1100: 重复的资源.type:MANIFEST, name:1, language:0 ...

  6. Android 找不到所标识的资源 java.lang.NoSuchFieldError: No static field XXX of type I in class Lcom/XX/R$id

    报错: java.lang.NoSuchFieldError: No static field XXX of type I in class Lcom/XXX/R$id; or its supercl ...

  7. PHP、JS一些用法

    PHP去除小数点后面的0,保留非零 floatval($num) PHP转数组var d = eval(数组d); PHP字符串转数组 $row['0'] = explode(";" ...

  8. 计算机网络-网络层(2)NAT协议

    网络地址转换(NAT,Network Address Translation)协议: 本地网络内通信的IP数据报的源与目的IP地址均在子网10.0.0.0/24内:所有离开本地网络去往Internet ...

  9. IA-32/centos7开机流程

    开机后系统首先在实地址模式下工作(只有1MB的寻址空间) 开机过程中,需要先准备在实模式下的中断向量表和中断服务程序.通常,由固化在主板上一块ROM芯片中的BIOS程序完成 加载BIOS的硬件信息,B ...

  10. Combining STDP and Reward-Modulated STDP in Deep Convolutional Spiking Neural Networks for Digit Recognition

    郑重声明:原文参见标题,如有侵权,请联系作者,将会撤销发布! Abstract 灵长类视觉系统激发了深度人工神经网络的发展,使计算机视觉领域发生了革命性的变化.然而,这些网络的能量效率比它们的生物学对 ...