繁体   English   中英

如何在spring mvc中的动作之前发送响应

[英]How to send response before actions in spring mvc

假设我的弹簧控制器功能接收到大量数据。 我想返回200 OK,因为数据结构正确, 之后我想执行处理,这可能需要一段时间。

据我所知,发送响应的唯一方法是使用return命令。 但我不想结束响应发送功能。

是否有其他方法可以在功能中间向客户端发送响应?

创建一个新的线程运行是显而易见的,但其他语言(JS)可以让你更优雅地处理它。

@RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(@RequestBody List<Message> messages) {
    HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
            : HttpStatus.NOT_FOUND;
    return new ResponseEntity<String>(res, code);
   // how do I add code here??
}

您当然可以在发送响应后进行处理。 更通用的方法是使用HandlerInterceptorafterCompletion方法。 通过建设,响应已发送到客户端后,它会被执行,但是它迫使你拆你的逻辑在2个组件在控制器部分之前 ,以及在拦截部分之后

另一种方法是忘记Spring MVC机制并在控制器中手动提交响应:

@RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public void doSomething(@RequestBody List<Message> messages, HttpServletResponse response) {
    int code = (messages!=null && !messages.isEmpty()) ? HttpServletResponse.SC_OK
            : HttpServletResponse.SC_NOT_FOUND;
    if (code != HttpServletResponse.SC_OK) {
        response.sendError(code, res);
        return;
    }
    java.io.PrintWriter wr = response.getWriter();
    response.setStatus(code);
    wr.print(res);
    wr.flush();
    wr.close();

    // Now it it time to do the long processing
    ...
}

请注意void返回代码,以通知Spring响应已在控制器中提交。

作为一个优势,处理仍然发生在同一个线程中,因此您可以完全访问会话范围属性或Spring MVC或Spring Security使用的任何其他线程局部变量...

我想你们使用了Spring的异步机制。在servlet 3.0中引入了异步方法,Spring为它们提供了一些支持基本上......你提出了一个请求; 请求由服务器处理,然后,在后台,新线程管理请求数据这里一个有用的链接(至少我希望:)) http://spring.io/blog/2012/05/10/spring- MVC-3-2-预览决策-A-控制器方法的异步/

您应该使用HandlerInterceptor 但是代码比预期的要复杂得多。 所以,这里有一个代码建议,通过将整个解决方案放在一个类中来简化它:

@RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = RequestMethod.POST)
public ResponseEntity<String> doSomething(@RequestBody List<Message> messages) {
    HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
            : HttpStatus.NOT_FOUND;

    result.set(res); // Save the object to be used after response

    return new ResponseEntity<String>(res, code);
}

private static final ThreadLocal<String> result = new ThreadLocal<String>();

@Bean
public HandlerInterceptor interceptor() {
    return new HandlerInterceptor() {
        @Override
        public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
            // Get the saved object and clean for the next request
            String res = result.get();
            result.set(null);

            // TODO Your code to be executed after response.
        }
    };
}

您可以使用@Async

@RequestMapping(value = Connectors.CONNECTOR_HEARTBEAT, method = 
      RequestMethod.POST)
public ResponseEntity<String> doSomething(@RequestBody List<Message> 
      messages) {
    do();
    HttpStatus code = (messages!=null && !messages.isEmpty()) ? HttpStatus.OK
        : HttpStatus.NOT_FOUND;
     return new ResponseEntity<String>(res, code);

}

@Async 
void do(){
   //your code
}

这项工作在java 8中

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM