In order to implement long polling I've tried different solution and did not acquire any good result.
So I decide to look into asynchronous methods and DeferredResult
. Here I implemented 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);
}
}
}
}
By idea it should process queue of requests every 5 seconds and setResult
if condition is true.
Synchronous version would be something like this
@RequestMapping(value = "/sync")
public ModelAndView checkState() {
if (null == SecurityHelper.getUserLogin()) {
createSuccessResponse("Invalidated session");
}
return null; // return something instead
}
But after some time I've got an exception
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]
What's the problem? Should I set the timeout for DeferredResult
?
I think the problem comes from the @ResponseBody
annotation. It tells Spring that the controller method will directly returns the body of the response. But it does not, because it returns a ModelAndView
. So Spring tries to send the return of the method directly to client, (and should send and commit an empty response), then the ModelAndView handler tries to forward to a view with an already committed response causing the error.
You should at least remove the @ResponseBody
annotation since it is not it what would be a synchronous equivalent.
But that's not all :
final DeferredResult<...
- IMHO the final should not be there since you will modify later the DeferredResult
DeferredResult
even says : For example, one might want to associate the user used to create the DeferredResult by extending the class and adding an addition property for the user. In this way, the user could easily be accessed later without the need to use a data structure to do the mapping. WebMvcConfigurer
has the method configureAsyncSupport
while <mvc:annotation-driven>
has an <async-support>
sub-element.
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.