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

有'execAndWait'拦截器 - http://struts.apache.org/core-developers/execute-and-wait-interceptor.html。 –

目前看来不能做得很清楚。我正在工作,如果我可以将这种支持导入到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。

您能否在您的应用中测试?并请随时让我知道任何想法。