Struts从AsyncContext发送响应
问题描述:
我想在一个struts web应用程序中进行长时间轮询。我在一个ActionSupport动作方法里面启动一个AsyncContext,做一些耗时的异步工作,然后想发送SUCCESS
响应给struts。Struts从AsyncContext发送响应
我知道我可以做PrintWriter pw = asyncContext.getResponse().getWriter();
并编写一个原始响应,但我想以某种方式发出信号指示struts在struts.xml中继续执行预定义的结果。这可能吗?
<action name="myAction" method="action1" class="myActionClass">
<result name="success" type="redirectAction">
/pages/myPage.jsp <!-- I want to run this from async --->
</result>
</action>
在非异步动作我可以简单地返回SUCCESS
和支柱照顾一切,但我有实现与异步操作类似的效果麻烦。这是我到目前为止:
public void action1() {
HttpServletRequest req = ServletActionContext.getRequest();
HttpServletResponse res = ServletActionContext.getResponse();
final AsyncContext asyncContext = req.startAsync(req, res);
asyncContext.start(new Runnable() {
public void run() {
// Some time-consuming polling task is done here
asyncContext.complete();
// Can I somehow proceed to predefined struts result from here?
}
});
}
答
目前看来不能做得很清楚。我正在工作,如果我可以将这种支持导入到Struts中,但现在我有一个破解工作。我下面延伸StrutsExecuteFilter
:
package me.zamani.yasser.ww_convention.utils;
import org.apache.struts2.dispatcher.PrepareOperations;
import org.apache.struts2.dispatcher.filter.StrutsExecuteFilter;
import org.apache.struts2.dispatcher.filter.StrutsPrepareFilter;
import org.apache.struts2.dispatcher.mapper.ActionMapping;
import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
/**
* Created by user on 8/31/2017.
*/
public class MYStrutsAsyncExecuteFilter extends StrutsExecuteFilter {
public final int REQUEST_TIMEOUT = 240000;//set your desired timeout here
private ExecutorService exe;
@Override
public void init(FilterConfig filterConfig) throws ServletException {
int size = 41;//set your desired pool size here
exe = Executors.newFixedThreadPool(
size,
new ThreadFactory() {
public Thread newThread(Runnable r) {
return new Thread(r, "My Struts Async Processor");
}
}
);
super.init(filterConfig);
}
@Override
public void doFilter(final ServletRequest req, final ServletResponse res, final FilterChain chain) throws IOException, ServletException {
final HttpServletRequest request = (HttpServletRequest) req;
final HttpServletResponse response = (HttpServletResponse) res;
if (excludeUrl(request)) {
chain.doFilter(request, response);
return;
}
// This is necessary since we need the dispatcher instance, which was created by the prepare filter
if (execute == null) {
lazyInit();
}
final ActionMapping mapping = prepare.findActionMapping(request, response);
//if recursion counter is > 1, it means we are in a "forward", in that case a mapping will still be
//in the request, if we handle it, it will lead to an infinite loop, see WW-3077
final Integer recursionCounter = (Integer) request.getAttribute(PrepareOperations.CLEANUP_RECURSION_COUNTER);
if (mapping == null || recursionCounter > 1) {
boolean handled = execute.executeStaticResourceRequest(request, response);
if (!handled) {
chain.doFilter(request, response);
}
} else {
/* I ADDED THESE */
final AsyncContext context = req.startAsync();
context.setTimeout(REQUEST_TIMEOUT);
context.addListener(new AsyncListener() {
public void onComplete(AsyncEvent asyncEvent) throws IOException {
}
public void onTimeout(AsyncEvent asyncEvent) throws IOException {
context
.getResponse()
.getWriter().write("Request Timeout");
}
public void onError(AsyncEvent asyncEvent) throws IOException {
context
.getResponse()
.getWriter().write("Processing Error");
}
public void onStartAsync(AsyncEvent asyncEvent) throws IOException {
}
});
exe.execute(new ContextExecution(context, mapping));
}
}
private boolean excludeUrl(HttpServletRequest request) {
return request.getAttribute(StrutsPrepareFilter.class.getName() + ".REQUEST_EXCLUDED_FROM_ACTION_MAPPING") != null;
}
@Override
public void destroy() {
exe.shutdown();
super.destroy();
}
class ContextExecution implements Runnable {
final AsyncContext context;
ActionMapping mapping;
public ContextExecution(AsyncContext context, ActionMapping mapping) {
this.context = context;
this.mapping=mapping;
}
public void run() {
try {
execute.executeAction((HttpServletRequest) context.getRequest(),
(HttpServletResponse) context.getResponse(), mapping);
context.complete();
} catch (Exception e) {
e.printStackTrace();
}
}
}
}
然后
<filter>
<filter-name>struts2asyncexecute</filter-name>
<filter-class>me.zamani.yasser.ww_convention.utils.MYStrutsAsyncExecuteFilter</filter-class>
<async-supported>true</async-supported>
</filter>
然后放在一个特定的软件包所需异步操作,并从支柱的原始过滤排除他们,但他们在您的web.xml
映射到上述过滤。
我正在努力改善这个问题,使其更易于配置和清晰,然后导入到Struts。
您能否在您的应用中测试?并请随时让我知道任何想法。
有'execAndWait'拦截器 - http://struts.apache.org/core-developers/execute-and-wait-interceptor.html。 –