Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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.

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??
}
like image 251
orshachar Avatar asked Aug 18 '15 12:08

orshachar


2 Answers

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

like image 172
Serge Ballesta Avatar answered Sep 21 '22 14:09

Serge Ballesta


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

like image 38
Javier Solis Guzman Avatar answered Sep 21 '22 14:09

Javier Solis Guzman