2015-07-20 39 views
1

爲了實現長輪詢,我嘗試了不同的解決方案,並沒有獲得任何好的結果。在使用deferredResult提交響應後無法轉發

所以我決定看看異步方法和DeferredResult。 在這裏我實施了REST消費者。

@Controller("sessionStateRest") 
@RequestMapping("ui") 
public class SessionStateRest extends BaseRestResource { 

    private final Queue<DeferredResult<ModelAndView>> mavQueue = new ConcurrentLinkedQueue<>(); 

    /** 
    * Rest to check session state. 
    * 
    * @return string with session state 
    */ 
    @RequestMapping(value = "/session") 
    public @ResponseBody DeferredResult<ModelAndView> sessionState() { 
     final DeferredResult<ModelAndView> stateResult = new DeferredResult<>(); 
     this.mavQueue.add(stateResult); 
     return stateResult; 
    } 

    @Scheduled(fixedDelay = 5000) 
    public void processQueue() { 
     for(DeferredResult<ModelAndView> result: mavQueue) { 
      if (null == SecurityHelper.getUserLogin()) { 
       result.setResult(createSuccessResponse("Invalidated session")); 
       mavQueue.remove(result); 
      } 
     } 
    } 
} 

通過知道它應該處理的請求隊列中,如果每5秒和setResult條件爲真。

同步版本會是這樣的

@RequestMapping(value = "/sync") 
public ModelAndView checkState() { 
    if (null == SecurityHelper.getUserLogin()) { 
     createSuccessResponse("Invalidated session"); 
    } 
    return null; // return something instead 
} 

但過一段時間後,我得到了一個異常

java.lang.IllegalStateException: Cannot forward after response has been committed 
     at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:349) ~[tomcat-embed-core-7.0. 
39.jar:7.0.39] 
     at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:339) ~[tomcat-embed-core-7.0.39 
.jar:7.0.39] 
     at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:467) [tomcat-embed-core-7.0.39.jar:7.0.3 
9] 
     at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:338) [tomcat-embed-core-7.0.39.jar:7.0.3 
9] 
     at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:428) [tomcat-embed-core-7.0.39.jar:7. 
0.39] 
     at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:417) [tomcat-embed-core-7.0.39.jar: 
7.0.39] 
     at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:294) [tomcat-embed-core-7.0.39.jar:7 
.0.39] 
     at org.apache.coyote.http11.AbstractHttp11Processor.asyncDispatch(AbstractHttp11Processor.java:1567) [tomcat-embed-c 
ore-7.0.39.jar:7.0.39] 
     at org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:583) [tomcat-embed-cor 
e-7.0.39.jar:7.0.39] 
     at org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312) [tomcat-embed-core-7.0.39.jar:7. 
0.39] 
     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145) [na:1.7.0_67] 
     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615) [na:1.7.0_67] 
     at java.lang.Thread.run(Thread.java:745) [na:1.7.0_67] 

什麼問題?我應該設置DeferredResult的超時時間嗎?

+0

你應該首先讓它工作**沒有** DeferredResult',然後嘗試添加它。我不明白這段代碼可以做什麼......我不確定春天可以理解哪一個更糟糕;-) –

+0

@SergeBallesta我無法爲異步調用找到解決方案 – lapots

+0

我的意思是*首先讓它同步工作* –

回答

2

我認爲問題來自@ResponseBody註釋。它告訴Spring,控制器方法將直接返回響應的主體。但它沒有,因爲它返回ModelAndView。所以Spring試圖將方法的返回直接發送給客戶端(並且應該發送並提交一個空的響應),然後ModelAndView處理程序嘗試轉發到已經提交響應導致錯誤的視圖。

您至少應該刪除@ResponseBody註釋,因爲它不是同步等價物。

但是這還不是全部:

  • 你寫final DeferredResult<... - 恕我直言,最終不應該存在,因爲你以後會修改DeferredResult
  • 您嘗試在預定的異步線程測試登錄的用戶。這應該不起作用,因爲常見的SecurityHelper使用本地線程存儲來存儲這些信息,而實際的處理將在另一個線程中發生。 Javadoc DeferredResult甚至表示:例如,可能需要通過擴展類併爲用戶添加附加屬性來關聯用於創建DeferredResult的用戶。通過這種方式,用戶可以在以後輕鬆訪問,而無需使用數據結構來進行映射。
  • 你不說你如何配置異步支持。 Spring參考手冊說:MVC Java配置和MVC命名空間都提供了配置異步請求處理的選項。 WebMvcConfigurer具有方法configureAsyncSupport<mvc:annotation-driven>具有<async-support>子元素。
+0

什麼也沒變。我還發現,它似乎不'processQueue'。至少在調試時,它不會輸入該方法。 – lapots

+0

確實。 'xml'配置有問題 – lapots

相關問題