居于Web的进度条实现思路(下载百分比)
http://www.cnblogs.com/wfyfngu/p/4866434.html
在传统桌面项目中,进度条随处可见,但作为一个很好的用户体验,却没有在如今主流的B/S程序中得到传承,不能不说是个遗憾。这个遗憾并非WEB程序不支持进度条,很大的原因应该是我们由于种种麻烦懒的去实现。前段时间由于新项目等待客户验收,有点闲暇时间,于是突发奇想决定给新系统的所有导出功能添加进度提示,替换现正使用的只简单显示一个Loading图片作为提示的方法,于是有了本文。
实现的思路很简单:服务器端收到客户端一个需要较长时间执行的任务 -> 服务器端开始执行这个任务并创建一个 Progress 状态,保存在 Cache 中,在任务执行过程中,不断更新进度 -> 同时,客户端新取一个线程(异步),每隔0.5秒(经过测试,0.5秒是一个比较好的时间,既不容易造成客户端网络拥堵,也能带来相当好的用户体验)访问一次服务器以获得该任务的进度并呈现给终端用户。
下面是本人的实现方法,它能支持所有需要精确计算进度的任务,觉得有一定的参考性,前后台代码分别采用 Javascript 和 C# 实现,分享给大家。
服务器端我们需要做 2 件事情:进度管理类和一个供客户端查询状态的页面(采用 Handler实现)。
首先是进度管理类,主要用于记录任务总数和当前已经完成的数目,同时自行管理缓存状态,以方便客户端随时访问。代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
using Cache; using System; namespace RapidWebTemplate.WebForm { /// <summary> /// 服务器事件进度服务 /// </summary> public sealed class ProgressService { // 缓存保存的时间,可根据自己的项目设置 private const int CACHE_SECONDS = 600; // 任务唯一ID private string _key = null ; private ProgressService() { } /// <summary> /// 获取或设置总进度 /// </summary> public int Total { get ; set ; } /// <summary> /// 获取或设置已经完成的进度 /// </summary> public int Elapsed { get ; set ; } /// <summary> /// 获取已经完成的进度百分比 /// </summary> public byte ElapsedPercent { get { if (Finished) { return 100; } double d = ( double )Elapsed / ( double )Total * 100d; var tmp = Convert.ToInt32(Math.Ceiling(d)); if (tmp > 100) { tmp = 100; } if (tmp < 0) { tmp = 0; } return Convert.ToByte(tmp); } } /// <summary> /// 获取一个值,该值指示当前进度是否已经完成 /// </summary> public bool Finished { get { return Elapsed >= Total; } } public void Remove() { try { CacheFactory.Remove(_key); } catch { } } /// <summary> /// 获取一个缓存中的进度对象或创建一个全新的进度对象并添加到缓存中 /// </summary> /// <param name="key"></param> /// <returns></returns> public static ProgressService GetInstance( string key) { var obj = CacheFactory.GetCache(key) as ProgressService; if (obj == null ) { obj = new ProgressService(); obj._key = key; CacheFactory.Add(key, obj, DateTime.Now.AddSeconds(CACHE_SECONDS)); } return obj; } } } |
接下来是查询页面,命名为 Progress.ashx,后台代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
|
using RapidWebTemplate.WebForm; using System; using System.Collections.Generic; using System.Linq; using System.Web; using Utility; using Utility.Http; namespace Web.Handlers { /// <summary> /// 获取服务端指定任务执行的进度 /// </summary> public class Progress : IHttpHandler { public void ProcessRequest(HttpContext context) { context.Response.ContentType = "text/json" ; var key = FormHelper.GetString(context.Request.QueryString[ "progress_key" ]); var obj = ProgressService.GetInstance(key); context.Response.Write(obj.ToJSON()); if (obj.Finished) { obj.Remove(); } } public bool IsReusable { get { return false ; } } } } |
到此,我们已经完成了后台代码的编写,下面将是前台代码的编写,这里以导出 Excel 为例,代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
|
var js={ doExport: function (icon){ var key= '' +( new Date().getTime())+(Math.floor(Math.random()*10)); var btns=$( '#btnExport' ); var showProgress= false ; if (btns.size()>0){ //var form=btns.first().parent('form'); //form.attr('target','_blank'); var input=$( '#download_key' ); if (input.size()>0){ input.val(key); } else { btns.first().parents( 'form' ).append( '<input type="hidden" id="download_key" name="download_key" value="' +key+ '"/>' ); } btns.first().trigger( 'click' ); showProgress= true ; } else { js.info( 'Not supported.' ); } var me= this ; setTimeout( function (){ $(document.body).hideLoading(); if (showProgress){ me._showProgress(key); } },500); }, _showProgress: function (key){ var id= 'progress_bar' ; var me= this ; if ($( '#' +id).size()>0){ } else { $(document.body).append( '<div id="' +id+ '_dialog"><div id="' +id+ '"></div></div>' ); } $( '#' +id+ '_dialog' ).dialog({ //title:'\u8bf7\u7a0d\u540e...', // please wait width:400, //height:60, modal: true , closable: false , border: false , noheader: true , onOpen: function (){ $( this ).children().first().progressbar({value:0}); setTimeout( function (){ me._updateProgessState(key,id,me); },1000); } }); }, _progressStateTimer: null , _updateProgessState: function (key,id,ns){ var url= '/Handlers/Progress.ashx?progress_key=' +key; url+= '&ran=' +( new Date().getTime()); $.get(url, function (res){ //res={"Total":0,"Elapsed":0,"ElapsedPercent":100,"Finished":true} if (res.Finished){ $( '#' +id).progressbar( 'setValue' ,100); setTimeout( function (){ $( '#' +id+ '_dialog' ).dialog( 'destroy' );},500); // Wait for 0.5 seconds to close the progress dialog clearTimeout(ns._progressStateTimer); } else { //alert(res.Elapsed); $( '#' +id).progressbar( 'setValue' ,res.ElapsedPercent); ns._progressStateTimer=setTimeout( function (){ns._updateProgessState(key,id,ns);},500); } }); }, }; |
所有必要的代码已经编写完成,下面是服务器端对进度服务的使用,还是以导出 Excel 为例,需要在原有的代码基础上,加入进度的管理(注释部分的A、B、C 3 段),代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
/// <summary> /// 导出当前列表数据到Excel /// </summary> protected void ExportToExcel() { using ( var outputStm = new MemoryStream()) { using ( var document = new SLDocument()) { var fields = this .ExportedFields; //先输出表头 for ( var i = 0; i < fields.Count; i++) { document.SetCellValue(1, i + 1, fields[i].Label); } //输出内容 if (GridControl != null ) { var ps = ProgressService.GetInstance(FormHelper.GetString(Request.Form[ "download_key" ])); // A:创建进度 var f = GetFilter(); var itemCount = 0; var source = GetGridSource(f, GridControl.GetSortExpression().ToOrder(CurrentDAL), int .MaxValue, 1, out itemCount); ps.Total = itemCount; // B: 设置总进度 var row = 2; object value = null ; foreach ( var item in source) { for ( var col = 0; col < fields.Count; col++) { #if DEBUG System.Threading.Thread.Sleep(50); #endif value = item.GetType().GetProperty(fields[col].Field).GetValue(item, null ); document.SetCellValue(row, col + 1, value); } ps.Elapsed += 1; // C: 更新已经完成的进度 row++; } } document.SaveAs(outputStm); } outputStm.Position = 0; WebUtility.WriteFile(outputStm, outputStm.Length, this .Response, ExportedFileName + ".xlsx" ); } } |
最后附上效果图
居于Web的进度条实现思路(下载百分比)的更多相关文章
- HTML5效果:Canvas 实现圆形进度条并显示数字百分比
实现效果 1.首先创建html代码 <canvas id="canvas" width="500" height="500" styl ...
- Java web实时进度条整个系统共用(如java上传、下载进度条、导入、导出excel进度条等)
先上图: 文件上传的: 2017-05-04再次改进.在上传过程中用户可以按 Esc 来取消上传(取消当前上传,或者是全部上传)... 2019-03-26更新进度条显示体验 从服务器上压缩下载: 从 ...
- ASP.NET技巧:教你制做Web实时进度条
网上已经有很多Web进度条的例子,但是很多都是估算时间,不能正真反应任务的真实进度.我自己结合多线程和ShowModalDialog制做了 一个实时进度条,原理很简单:使用线程开始长时间的任务,定义一 ...
- C# winform带进度条的图片下载
代码如下: public partial class FrmMain : Form { public FrmMain() { InitializeComponent(); } private void ...
- Java web实时进度条整个系统共用(如java上传进度条、导入excel进度条等)
先上图: 这上文件上传的: 这是数据实时处理的: 1:先说说什么是进度条:进度条即计算机在处理任务时,实时的,以图片形式显示处理任务的速度,完成度,剩余未完成任务量的大小,和可能需要处理时间,显示方式 ...
- js进度条源码下载—js进度条代码
现在很多网站会用到进入网站特效,到网页没有加载完成的时候,会有一个loding特效,加载完了之后才能看到页面,今天就带着做一个js进度条效果,今天要做的效果是纯js进度条加载,没有用到框架,方便大家进 ...
- .net网站的文件上传读取进度条和断点下载
文件上传到服务器时的进度读取 //调整上传配置 AdapterInfo(info); UpfileResult result = new UpfileResult(); try { //直接使用req ...
- Android有进度条异步任务下载图片
首先在AndroidMainifest中添加上网权限 ? 1 <uses-permission android:name="android.permission.INTERNET&qu ...
- Web报表进度条显示
创建插件 <script src="../CreateControl.js" type="text/javascript"></script& ...
随机推荐
- 关于API认证的问题
问题:如何保证api安全?-->做api的认证 如下图 整个过程大概就是这样. 好像没什么可以讲的....
- Jquery-下拉列表设置默认选择
$('#select option:eq(2)').attr('selected','selected');
- C# for循环及循环嵌套
格式(for循环四要素:初始条件.循环条件.循环体.状态改变) for (int i=1<初始条件>;i<=n<循环条件>;i++<状态改变>) { < ...
- iOS推送通知
推送通知 此通知非彼通知. NSNotification是抽象的,看不见的,但是可以监听,属于观察者模式的一种设计模式. 推送通知是可见的,能用肉眼看见的,是真正的和用户打交道的通知. 推送通知分为两 ...
- iOS7模拟器安装
安装路径:/Library/Developer/CoreSimulator/Profiles/Runtimes 其中,后两个文件夹没有,需要手动创建. 把iOS7模拟器拖拽到Runtimes文件夹下即 ...
- 【BZOJ-3721】Final Bazarek 贪心
3721: PA2014 Final Bazarek Time Limit: 20 Sec Memory Limit: 128 MBSubmit: 610 Solved: 243[Submit][ ...
- 洛谷P1808 单词分类
题目描述 Oliver为了学好英语决定苦背单词,但很快他发现要直接记住杂乱无章的单词非常困难,他决定对单词进行分类. 两个单词可以分为一类当且仅当组成这两个单词的各个字母的数量均相等. 例如“AABA ...
- struts2 CVE-2012-0838 S2-007 Remote Code Execution && Hotfix
catalog . Description . Effected Scope . Exploit Analysis . Principle Of Vulnerability . Patch Fix 1 ...
- sersync2 安装,配置
介绍 rsync rsync,remote synchronize顾名思意就知道它是一款实现远程同步功能的软件,它在同步文件的同时,可以保持原来文件的权限.时间.软硬链接等附加信息.rsync是用 “ ...
- iOS WebView调用JS的一个小坑
假如调用一个函数,传入的参数为String,要以这样的格式传入: let resultStr="1234" self.webView.stringByEvaluatingJavaS ...