2017-10-18 152 views
0

我想在一個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。 –

回答

0

目前看來不能做得很清楚。我正在工作,如果我可以將這種支持導入到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。

您能否在您的應用中測試?並請隨時讓我知道任何想法。