【问题标题】:How to send response before actions in spring mvc如何在spring mvc中的操作之前发送响应
【发布时间】:2015-11-11 09:08:28
【问题描述】:

说我的spring控制器函数接收到大量数据。 鉴于数据结构正确,我想返回 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??
}

【问题讨论】:

  • 使用@Async 方法可以包装你想运行的所有东西,它将被不同的线程处理

标签: java spring spring-mvc model-view-controller


【解决方案1】:

你可以使用@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 中

【讨论】:

    【解决方案2】:

    您应该使用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.
            }
        };
    }
    

    【讨论】:

      【解决方案3】:

      您当然可以在发送响应后进行处理。更通用的方法是使用HandlerInterceptorafterCompletion 方法。通过构造,它将在响应发送到客户端后执行,但它会强制您将逻辑​​拆分为 2 个组件,即控制器中的 before 部分和 after参与拦截器。

      另一种方法是忘记 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 使用的任何其他线程局部变量...

      【讨论】:

      • 如果请求来自两个不同的用户,那么它会共享相同的变量还是为不同的用户共享不同的变量??
      • 你用过变量 res,那个变量指的是什么?
      • 我不知道。它在原始问题中,所以我将其保留在我的答案中。我只是假设这是一条用于提供响应的消息。
      • 嗨@SergeBallesta,我尝试了您的解决方案,但没有奏效。在 wr.close() 之后,我将 sleep 方法放置了 10 秒。当我点击请求时,它会等待 10 秒发送回响应。 PFB 代码。输出流.close(); System.out.println("流关闭。"); System.out.println("睡觉");尝试{ Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("唤醒");
      • @SergeBallesta,如果我遗漏了什么,请帮忙。
      【解决方案4】:

      我猜你mau使用spring的异步机制 servlet 3.0 中引入了异步方法,Spring 为它们提供了一些支持 基本上……你提出请求;请求由服务器处理,然后在后台,一个新线程管理请求数据 这是一个有用的链接(至少我希望:))http://spring.io/blog/2012/05/10/spring-mvc-3-2-preview-making-a-controller-method-asynchronous/

      【讨论】:

        猜你喜欢
        • 2022-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-12-15
        • 1970-01-01
        • 2020-05-28
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多