【问题标题】:Struts send response from AsyncContextStruts 从 AsyncContext 发送响应
【发布时间】:2017-10-18 10:52:54
【问题描述】:

我正在尝试在 struts Web 应用程序中进行长轮询。我在 ActionSupport 操作方法中启动 AsyncContext,异步执行一些耗时的工作,然后想将 SUCCESS 响应发送到 struts。

我知道我可以执行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 并且 struts 会处理所有事情,但是我无法通过异步操作实现类似的效果。这是我目前所拥有的:

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?
        }
    });
}

【问题讨论】:

标签: asynchronous struts2 long-polling servlet-3.0


【解决方案1】:

目前似乎无法明确。如果我可以将这种支持导入到 Struts,我正在工作,但现在,我有一个可行的 hack。我扩展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>

然后将您所需的异步操作放入特定包中,并将它们从 Strut 的原始过滤器中排除,但将它们映射到您的 web.xml 中的上述过滤器。

我正在努力改进它,使其更易于配置和清晰,然后导入到 Struts。

您能在您的应用中进行测试吗?如有任何想法,请随时告诉我。

【讨论】:

    猜你喜欢
    • 2017-04-26
    • 2013-10-23
    • 1970-01-01
    • 2020-03-06
    • 2017-12-21
    • 1970-01-01
    • 1970-01-01
    • 2022-09-27
    • 2013-12-23
    相关资源
    最近更新 更多