简体   繁体   English

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

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

Say that my spring controller function receives a large amount of data. 假设我的弹簧控制器功能接收到大量数据。 I want to return 200 OK, given that the data is structured right, and after that I want to perform the processing, which might take a while. 我想返回200 OK,因为数据结构正确, 之后我想执行处理,这可能需要一段时间。

To my understanding the only way to send response is by return command. 据我所知,发送响应的唯一方法是使用return命令。 But I don't want to end the function on response send. 但我不想结束响应发送功能。

Are there other ways to send response to client at the middle of the function? 是否有其他方法可以在功能中间向客户端发送响应?

Creating a new thread run is obvious but other languages (JS) let you handle it more elegantly. 创建一个新的线程运行是显而易见的,但其他语言(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??
}

You can of course do processing after sending the response. 您当然可以在发送响应后进行处理。 The more general way would be to use the afterCompletion method of a HandlerInterceptor . 更通用的方法是使用HandlerInterceptorafterCompletion方法。 By construction, it will be executed after the response have been sent to client, but it forces you to split you logic in 2 components the before part in controller, and the after part in the interceptor. 通过建设,响应已发送到客户端后,它会被执行,但是它迫使你拆你的逻辑在2个组件在控制器部分之前 ,以及在拦截部分之后

The alternative way is to forget Spring MVC machinery and manually commit the response in the controller: 另一种方法是忘记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
    ...
}

Note the void return code to notify Spring that the response have been committed in the controller. 请注意void返回代码,以通知Spring响应已在控制器中提交。

As a side advantage, the processing still occurs in the same thread, so you have full access to session scoped attributes or any other thread local variables used by Spring MVC or Spring Security... 作为一个优势,处理仍然发生在同一个线程中,因此您可以完全访问会话范围属性或Spring MVC或Spring Security使用的任何其他线程局部变量...

I guess you mau use the async mechanism of spring Async methods have been introduced in servlet 3.0 and Spring offers some support to them Basically... you make a request; 我想你们使用了Spring的异步机制。在servlet 3.0中引入了异步方法,Spring为它们提供了一些支持基本上......你提出了一个请求; the request is handled by the server and then, in background, a new thread manages the requesta data Here a useful link (at least i hope :) ) http://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/ 请求由服务器处理,然后,在后台,新线程管理请求数据这里一个有用的链接(至少我希望:)) http://spring.io/blog/2012/05/10/spring- MVC-3-2-预览决策-A-控制器方法的异步/

You should use the HandlerInterceptor . 您应该使用HandlerInterceptor But the code get a little bit more complex than expected. 但是代码比预期的要复杂得多。 So, here's a code suggestion to make it simpler by putting the whole solution in a single class: 所以,这里有一个代码建议,通过将整个解决方案放在一个类中来简化它:

@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.
        }
    };
}

You can use @Async 您可以使用@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
}

this work in java 8 这项工作在java 8中

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

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