在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. Docker 搭建 SonarQube

    Docker 搭建 SonarQube Docker 搭建 SonarQube 步骤 创建项目目录 mkdir -p /usr/local/sonarqube && cd /usr/l ...

  2. 树莓派4B的CPU系统里查到为BCM2835而非BCM2711

    树莓派4B采用四核64位的ARM Cortex-A72架构CPU,型号为博通BCM2711 SoC.2711是个64位的四核,而2835是多年前的32位单核CPU. 查看当前芯片版本,显示为4核心,但 ...

  3. db2 创建function报错

     create function fun_fw_sfyczy(pi_operunitid varchar(2)) returns varchar(2)LANGUAGE SQL BEGIN ATOMIC ...

  4. 利用maven的MyBatis Generator 插件自动创建代码

    1.首先创建Maven工程 2.修改pom.xml文件代码如下: <project xmlns="http://maven.apache.org/POM/4.0.0" xml ...

  5. C#LeetCode刷题之#141-环形链表(Linked List Cycle)

    问题 该文章的最新版本已迁移至个人博客[比特飞],单击链接 https://www.byteflying.com/archives/3901 访问. 给定一个链表,判断链表中是否有环. 进阶: 你能否 ...

  6. 三、HelloWorld

    1.创建Hello.java 文件, 2.输入内容 public class Hello{ //公共类 Hello public static void main(String[] args){ // ...

  7. 喵的Unity游戏开发之路 - 推球:游戏中的物理

    很多童鞋没有系统的Unity3D游戏开发基础,也不知道从何开始学.为此我们精选了一套国外优秀的Unity3D游戏开发教程,翻译整理后放送给大家,教您从零开始一步一步掌握Unity3D游戏开发. 本文不 ...

  8. ARM伪指令与伪操作

    一.伪指令 ARM伪指令有四个,分别是LDR.ADR.ADRL和NOP,下边对其分别介绍. 1.1 LDR LDR 伪指令用于加载 32 位的立即数或一个地址值到指定寄存器 .形式如  LDR{con ...

  9. 目录扫描、Nmap

    一.基本定义 1.目录扫描: 扫描站点的目录,寻找敏感文件(目录名.探针文件.后台.robots.txt.备份文件等). 2.目录:站点结构,权限控制不严格. 3.探针文件:服务器配置信息,例:php ...

  10. 开发APP遇到的问题

    1.代码尽量复用 2.调用高德地图,直辖市等,省字段一定有值,市可能为空(pro:'北京市',city:[]) 3.支付密码不用组件 <template> <view> < ...