为了实施长轮询,我尝试了不同的解决方案并没有获得任何好结果。
所以我决定研究异步方法和DeferredResult
。
在这里,我实现了REST
constroller。
@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 :(得分:2)
我认为问题来自@ResponseBody
注释。它告诉Spring,控制器方法将直接返回响应的主体。但它没有,因为它返回ModelAndView
。因此Spring尝试将方法的返回直接发送到客户端,(并且应该发送并提交空响应),然后ModelAndView处理程序尝试转发到已经提交的响应导致错误的视图。
您至少应该删除@ResponseBody
注释,因为它不是同步等价物。
但那不是全部:
final DeferredResult<...
- 恕我直言,决赛不应该出现,因为你稍后会修改DeferredResult
DeferredResult
的Javadoc甚至说:例如,人们可能希望通过扩展类并为用户添加附加属性来关联用于创建DeferredResult的用户。通过这种方式,用户可以在以后轻松访问,而无需使用数据结构进行映射。 WebMvcConfigurer
方法configureAsyncSupport
,而<mvc:annotation-driven>
有<async-support>
子元素。