6

How can I stream text output to the page on the browser to show the progress of an operation that may take about 15 - 20 seconds? I've tried writing to the output stream of HttpServletResponse directly, but the user still sees the full output after the whole process is finished.

This is what I've tried so far

 @RequestMapping(value = "/test")
 public void test(HttpServletResponse response)
            throws IOException, InterruptedException {
    response.getOutputStream().println("Hello");
    response.getOutputStream().flush();
    Thread.sleep(2000);
    response.getOutputStream().println("How");
    response.getOutputStream().flush();
    Thread.sleep(2000);
    response.getOutputStream().println("are");
    response.getOutputStream().flush();
    Thread.sleep(2000);
    response.getOutputStream().println("you");
    response.getOutputStream().flush();
}
Danish
  • 3,708
  • 5
  • 29
  • 48
  • Have you tried flushing the outputstream after each chuck of data is sent? – Luciano Jul 05 '12 at 14:49
  • @Luciano I've added what I've tried till now to the question. This doesn't work when I view the page from Chrome – Danish Jul 05 '12 at 14:59
  • I think your best bet would be a different approach: use a timer in javascript that fetchs data from /test every 1 second (or half a second), using ajax, and /test would return whatever hasn't been send before up to the point it was called. – Luciano Jul 05 '12 at 15:04
  • @Luciano What you suggest is my fallback plan, which I may end up using anyway. However if my question has a valid answer, I can see this being done without an async job executor and state management, which I feel would be more elegant. – Danish Jul 05 '12 at 18:17
  • you can also try with Web sockets, but that would require more changes to your application. – Luciano Jul 05 '12 at 19:02
  • I believe it's a app-server configuration. Please, see [my post](http://stackoverflow.com/questions/43453508/end-to-end-reactive-streaming-restful-service). – Igor Veloso Apr 18 '17 at 15:24

4 Answers4

2

I am no Spring MVC expert, but I would think you would do something like send a 202 response code of "accepted", which indicates the server has received the request and is going to do some asynchronous processing. Usually, the server provides a URL to allow the client to issue requests about the status of the operation. What you are trying to do violates the usual way server/client relationships work. The client calls the server, and the server responds and then the connection is closed. In what context are you trying to do this and for what reason? Perhaps I could offer some more insight or think of another way to do it?

thatidiotguy
  • 8,701
  • 13
  • 60
  • 105
  • 2
    Thanks for your interest! Basically, I want to provide the user with an ability to request a job execution, be able to monitor the progress and have his view updated once the job finishes. I can see how this can be done by making the job executor async and maintaing some state in the `session` and poll from the UI. *However* if my question has a valid answer, I can see this being done without an async executor and state management. – Danish Jul 05 '12 at 18:15
  • I feel like what you are asking for is for the server to contact the client, and while not impossible, it would be highly irregular. Obviously there are routes to send information back to the client (like FTP) in chunked amounts, but unfortunately, I do know if that is applicable for what you want to do, nor do I know if it is possible with Spring MVC. Good luck! – thatidiotguy Jul 05 '12 at 19:23
  • Thanks! I'll probably go with the polling method that you and other have mentioned for now and keep this question open for the time being. I just love exploring all possibilities. Cheers! – Danish Jul 05 '12 at 19:42
1

try to use:

response.flushBuffer();

as JavaDoc says:

Forces any content in the buffer to be written to the client. A call to this method automatically commits the response, meaning the status code and headers will be written.

Brian Roach
  • 76,169
  • 12
  • 136
  • 161
user1335851
  • 61
  • 1
  • 5
0

This worked for me when testing with Chrome

response.setBufferSize(0);
response.setContentType("text/event-stream");

... write content ...
chenson42
  • 1,108
  • 6
  • 13
-5
@Controller
public class MyController{

    @RequestMapping(value = "/test", method = RequestMethod.GET)
    public @ResponseBody String getTest() {
      return "hello how are you";
    }
}

If you are using spring controller you could do the above with the response body annotation.

NimChimpsky
  • 46,453
  • 60
  • 198
  • 311