大致把源码中类前面的一段注释给翻译一下:
1 ExecuteAndWaitInterceptor很适合在后台长时间运行的action时,他可以可为用户一个友好的等待界面,例如进度条。
2 不在默认的拦截stack 里面,使用的时候需要配置,但必须是在拦截堆栈的最后一个。
大致配置如下:
<action name="test" method="test" class="com.joe.web.action.ActionTest">
<interceptor-ref name="completeStack"/>
<interceptor-ref name="execAndWait">
<param name="delay">1000</param>
<param name="delaySleepInterval">50</param>
</interceptor-ref>
<result name="wait">wait.jsp</result>
<result name="success">success.jsp</result>
</action> 3 使用的时候需要配置一个名为wait的result,并指向自己的等待页面,如果没有struts
将使用FreeMarker代替,通过使用FreemarkerResult动态注入一个等待页面:struts提供的面板页面可见于:
org/apache/struts2/interceptor/wait.ftl
内容大致如下:
<html>
<head>
<meta http-equiv="refresh" content="5;url=<@s.url includeParams="none"/>"/>
</head>
<body>
Please wait while we process your request...
<p/>
This page will reload automatically and display your request when it is completed.
</body>
</html>
其中的includeParams参数取值为
none,不把参数参加到url参数中
all,是把get和post中的参数参加到url参数中
get,是只把get中的参数参加到url参数中
execAndWait拦截器有2个参数:
delay :意思是初始等待多少秒才出现等待页面。当在这个等待时间内action执行完毕,就不用出现wai界面,如果不配,一开始就会出现。
delaySleepInterval:每个对少时间检查action是否执行完毕。
-------------
大致的原理是:strus遇到这种配置了execAndWait的action会另外起一个线程来执行,这个线程名叫BackgroundProcess,并通过一个done属性的变化来标准执行情况,struts将此线程放到session中,页面每隔一段时间去检查是done==true? 如果不是,就据需返回wai页面,否则返回主action的返回界面。
BackgroundProcess大致源码:
public BackgroundProcess(String threadName, final ActionInvocation invocation, int threadPriority) {
this.invocation = invocation;
this.action = invocation.getAction();
try {
final Thread t = new Thread(new Runnable() {
public void run() {
try {
beforeInvocation();
result = invocation.invokeActionOnly();
afterInvocation();
} catch (Exception e) {
exception = e;
}
done = true;
}
});
t.setName(threadName);
t.setPriority(threadPriority);
t.start();
} catch (Exception e) {
exception = e;
}
}
当这个action结束后会将done属性设置为true表示执行结束,正是每次去检查这个属性来判别。
拦截器主要源码:
if ((!executeAfterValidationPass || secondTime) && bp == null) {
bp = getNewBackgroundProcess(name, actionInvocation, threadPriority);
session.put(KEY + name, bp);//放入session
performInitialDelay(bp); // first time let some time pass before showing wait page
secondTime = false;
}
if ((!executeAfterValidationPass || !secondTime) && bp != null && !bp.isDone()) {//是否完毕
actionInvocation.getStack().push(bp.getAction());//将后台action的相关信息push到statck,时候的页面可是使用
if (TokenHelper.getToken() != null) {
session.put(TokenHelper.getTokenName(), TokenHelper.getToken());
}
Map results = proxy.getConfig().getResults();
if (!results.containsKey(WAIT)) {//如果没有配置wait,struts将为你inject一个
LOG.warn("ExecuteAndWait interceptor has detected that no result named 'wait' is available. " +
"Defaulting to a plain built-in wait page. It is highly recommend you " +
"provide an action-specific or global result named '" + WAIT +
"'.");
// no wait result? hmm -- let's try to do dynamically put it in for you!
//we used to add a fake "wait" result here, since the configuration is unmodifiable, that is no longer
//an option, see WW-3068
FreemarkerResult waitResult = new FreemarkerResult();
container.inject(waitResult);
waitResult.setLocation("/org/apache/struts2/interceptor/wait.ftl");
waitResult.execute(actionInvocation);
return Action.NONE;
}
return WAIT;
} else if ((!executeAfterValidationPass || !secondTime) && bp != null && bp.isDone()) {//如果执行完毕return bp.getResult();
session.remove(KEY + name);
actionInvocation.getStack().push(bp.getAction());
// if an exception occured during action execution, throw it here
if (bp.getException() != null) {
throw bp.getException();
}
return bp.getResult();
} else {
// this is the first instance of the interceptor and there is no existing action
// already run in the background, so let's just let this pass through. We assume
// the action invocation will be run in the background on the subsequent pass through
// this interceptor
return actionInvocation.invoke();
}
。
一个简单的例子(不包含lib):
/Files/freeman1984/execAndWait.rar