对于一些须要较长时间才能完成的任务,在Web开发中,会由HTTP协议会由于超时而断开而面临许多风险,这是在桌面开发未曾遇到的。Struts 2提供的execAndWait拦截器就是为了处理和应付这种状况而设计的。注意,该拦截器不在"defaultStack"中,因此必须在使用它的动做里声明它,而且必须放在拦截器栈的最后一个。
使用了该拦截器后,动做依然正常执行,只是该拦截器会分配一个后台线程处理动做的运行,并在动做完成以前把用户带到一个"等待"页面。,该页面每隔一段时间刷新一次,直到那个后台线程执行完毕为止。若是用户随后又触发了同一个动做,但顶一个动做还没有执行完毕,这个拦截器将继续向用户发送"等待"结果;若是他已经执行完毕,用户会看到该动做的最终结果。
"等待"结果的行为与"dispatcher"结果的行为很类似,可是要注意的是,"等待"结果对应的视图带有以下的meta标签:
<meta http-equiv="refresh" content="5;url=/Struts2/default_progressbar.action"/>
该标签的做用就每隔多少秒就从新加载一次一样的URL。这里"5"表示5秒,"url=/Struts2/default_progressbar.action"表示要加载的URL。
Struts 2是一个灵活强大的框架,若是你不喜欢Struts 2提供的默认"等待页面",你也能够本身设计本身的等待页面,若在动做声明中,没有找到"等待"结果,将使用默认值。 javascript
execAndWait拦截器
execAndWait拦截器 能够接收如下参数:
- threadPriority:分配给相关线程的优先级,默认值为Thread.NORM_PRIORITY。
- delay:向用户发送"等待"结果前的毫秒数,默认值为0。若是你不想马上发送"等待"结果,能够将该参数设置为一个值。例如,你想让动做超过2秒还未完成时才发送"等待"结果,须要将其值设置为2000.
- delaySleepInterval:每隔多少毫秒唤醒主线程(处理动做的后台线程)去检查后台线程是否已经处理完成,默认值是100。这个值设为0时无效。
模拟长时间运行的Action
为了示例,首先来模拟一个运行时间长的Action:在这个Action中首先定义了一个int类型的progress属性及其getter/setter,用来向外界返回当前任务的完成进度。在execute方法中,让Action所在的线程在每次循环的时候sleep一秒钟,每次循环把进度加十。 css
这样,随着外界不断访问progress属性,就能够知道当前任务运行的进度了。示例代码以下: html
java代码:
- public class WaitAction extends ActionSupport{
- /**
- * 准备向等待页面返回工做的进度
- */
- private int progress;
- public int getProgress() {
- return progress;
- }
- public void setProgress(int progress) {
- this.progress = progress;
- }
-
- public String execute() throws Exception {
- //循环十次,每次线程睡1秒,且进度加10
- for (int i=0;i<10;i++){
- Thread.sleep(1000L);
- progress += 10;
- }
- return SUCCESS;
- }
- }
19.2.2配置Action
首先,在配置Action的时候,要让这个Action引用execAndWait拦截器,并且,这个拦截器会停止声明在它之后的拦截器的执行,所以这个拦截器的引用要出如今defaultStack拦截器栈以后。 java
其次,还要为这个Action声明一个名称为wait的Result,由它来指定具体的等待页面。示例代码以下: 浏览器
java代码:
- <package name="helloworld" extends="struts-default">
- <action name="waitAction" class="cn.javass.wait.WaitAction">
- <interceptor-ref name="defaultStack"/>
- <interceptor-ref name="execAndWait"/>
- <result>/wait/success.jsp</result>
- <result name="wait">/wait/wait.jsp</result>
- </action>
- </package>
19.2.3实现“进度条”页面
因为HTTP页面在显示以后,不会再与服务器交互,因此,要不断的刷新这个“进度条”页面才行。 服务器
能够简单的使用<html>标签中的<meta>标签来设置这个页面不断进行自我刷新。示例代码以下: 框架
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
- "http://www.w3.org/TR/html4/loose.dtd">
- <html>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">
- <title>Insert title here</title>
- </head>
- <body>
- 您好,任务还未完成,已经运行到了任务的<s:property value="progress"/>%
- </body>
- </html>
<meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">这句话表明了当前页面会在显示2秒以后访问” /helloworld/waitAction.action”这个URL。因为wait.jsp就是从这个Action中跳转出来的,因此就至关于每隔2秒就刷新一次wait.jsp页面。一样能够经过<s:property/>标签访问值栈。 jsp
19.2.4实现完成页面
实现一个完成页面,在完成页面中,简单的告知用户已经成功执行。示例代码以下: 测试
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <head>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- </head>
- 恭喜您,任务结束!
19.2.5运行测试
在浏览器的地址栏输入“http://localhost:9080/helloworld/waitAction.action”,来直接访问waitAction。 ui
在访问这个WaitAction的时候,第一次访问会使execute方法开始运行。可是,因为引用了execAndWait拦截器,并非一直等到execute方法运行完以后再跳转到下一个页面,而是立刻跳转到struts.xml中注册的名为wait的Result,也就是wait.jsp。
在wait.jsp中仍然能够访问值栈里面的值,所以,经过访问了progress属性来显示当前任务运行的进度。以下图所示:
图19.1 显示任务进度一
在wait.jsp,又指定了每隔2秒访问一次WaitAction,这时候,只要execute方法还没运行完,就立刻再次转发到名为wait的Result,依次类推,直到execute方法运行完以后。所以页面显示的进度数据会一直增长,如图所示:
图19.2 显示任务进度二
所以,若是不引用execAndWait拦截器,在访问WaitAction的时候,本应该等到10秒后浏览器才有反应。可是,如今引用了execAndWait拦截器,在访问WaitAction的时候,立刻跳转到了wait.jsp,并且每隔2秒刷新一次,直到10秒以后,直到execute方法运行完成,浏览器正确的跳转到success.jsp。以下图所示:
图19.3 任务结束
19.2.6图形化的进度条
看到这里,确定有朋友会说,这哪里像是进度条啊,明明只是显示了一个运行进度而已。确实,从表现上看,不像咱们熟悉的进度条,尤为是不像图形化的进度条。
1:JavaScript的图形化进度条
其实,要实现图形化的进度条也很简单,使用Javascript就能够很方便的实现。先看个最简单的Javascript的进度条的实现,示例代码以下:
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <style type="text/css">
- #out{width:300px;height:20px;background:#EEE000;}
- #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}
- </style>
- </HEAD>
- <BODY onload="start();" >
- <div id='out'>
- <div id="in" style="width:10%">10%</div>
- <div>
- <script type="text/javascript">
- var i=0;
- function start(){
- ba=setInterval("begin()",100);
- }
- function begin(){
- i+=1;
- if(i<=100){
- document.getElementById("in").style.width=i+"%";
- document.getElementById("in").innerHTML=i+"%";
- }else{
- clearInterval(ba);
- document.getElementById("out").style.display="none";
- document.write("进度条运行成功");
- }
- }
- </script>
- </BODY>
具体的Javascript的知识,这里就不去深刻了,要注意下面几点:
- 进度条的效果是经过两个Div来实现的,id为out的div做为底框,id为in的div做为动态显示进度的进度框
- 启动方法是<body>元素的onload属性所指定的方法
- Start方法里面的setInterval(表达式,间隔时间),意思是:启动后,每隔指定的间隔时间,就执行前面的表达式一次,这个方法至关于一个定时器
- 在begin方法里面,经过动态的改变id为in的div框所包含的文字,从而实现动态显示进度的效果
- 运行到最后,必定要记得清除掉setInterval所设置的定时器,用的是clearInterval方法
固然,使用Javascript来实现进度条有不少种方式,这里只是其中的一种而已。
2:把Struts2的进度条图形化
接下来把前面的wait.jsp页面显示的进度,改为图形化的进度条的形式。
一样须要使用Javascript来图形化的显示进度条,只不过具体的进度数据应该从Struts2的waitAction中去获取,也就是直接把从Action中获取的进度数据,直接赋值给Javascript,而后经过Javascript来显示进度条。示例代码以下:
java代码:
- <%@ page language="java" contentType="text/html; charset=gb2312"
- pageEncoding="gb2312"%>
- <%@taglib prefix="s" uri="/struts-tags" %>
- <html>
- <head>
- <style type="text/css">
- #out{width:300px;height:20px;background:#EEE000;}
- #in{width:10px; height:20px;background:#0000ff;color:white;text-align:center;}
- </style>
- <meta http-equiv="Content-Type" content="text/html; charset=gb2312">
- <meta http-equiv="refresh" content="2;url=/helloworld/waitAction.action">
- <title>Insert title here</title>
- </head>
- <body>
- <BODY onload="start();" >
- <div id='out'>
- 您好,任务还未完成,已经运行到了任务的<div id="in" style="width:10%">10%</div>
- <div>
- <script type="text/javascript">
- function start(){
- ba=setInterval("begin()",100);
- }
- function begin(){
- var i = <s:property value="progress"/>;
- if(i<=100){
- document.getElementById("in").style.width=i+"%";
- document.getElementById("in").innerHTML=i+"%";
- }else{
- clearInterval(ba);
- document.getElementById("out").style.display="none";
- document.write("进度条运行成功");
- }
- }
- </script>
- </BODY>
- </html>
最重要的变化就在加粗的那句话,把从Action获取的数据直接设置给了Javascript,要注意这个过程是在服务端完成的,到了客户端,值已经设置好了,所以Javascript一样能正常地运行。
运行URL:http://localhost:9080/helloworld/waitAction.action,测试一下看看效果,以下图所示:
图19.4 Struts2的进度条图形化
进度条会不断滚动,直到运行结束,转向success.jsp为止。
本文参考自:http://www.cnblogs.com/suxiaolei/archive/2011/11/06/2232009.html
http://sishuok.com/forum/blogPost/list/4174.html