How to send response before actions in spring mvc

11,295

Solution 1

You can of course do processing after sending the response. The more general way would be to use the afterCompletion method of a HandlerInterceptor. 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.

The alternative way is to forget Spring MVC machinery and manually commit the response in the controller:

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

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...

Solution 2

You can use @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

Solution 3

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; 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/

Share:
11,295
orshachar
Author by

orshachar

DevOps and CI lover

Updated on June 26, 2022

Comments

  • orshachar
    orshachar almost 2 years

    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.

    To my understanding the only way to send response is by return command. 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.

    @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??
    }
    
  • Satish Kr
    Satish Kr almost 7 years
    If request from two different users then will it share same variable or different for differnt user??
  • Sagar Shetty
    Sagar Shetty about 5 years
    you ave used variable res, what does that variable refer to?
  • Serge Ballesta
    Serge Ballesta about 5 years
    I do not know. It was in the original question, so I kept it in my answer. I just assumed it was a message to feed the response with.
  • Vivek Garg
    Vivek Garg almost 5 years
    Hi @SergeBallesta, I tried your solution but didn't work. After wr.close() i have put sleep method for 10sec. When i am hitting the request then it is waiting for 10 sec to send back response. PFB for code. outputStream.close(); System.out.println("Stream closed."); System.out.println("Sleeping"); try { Thread.sleep(10000); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println("Awake");
  • Vivek Garg
    Vivek Garg almost 5 years
    @SergeBallesta, Please help if I am missing something.