Finally I was able to sort this out which is now helping me stream huge data from backend to Frontend using Spring 4.3.x as mentioned in my post. Below are the points to guide you to execute the program successfully.
Below procedure is so effective that you can even paginate huge data at the back end (can be hibernate, Mongo-java-driver, cassandra java driver, etc)and keep on streaming the data unless your db operation is complete. In some domains like Manufacturing, Insurance, Logistics etc, you need such utility where end user expects quiet huge data from server in the form of CSV, JSON etc to analyse the raw data.
Add one more annotation @EnableWebMvc
above your controller class.
When you add above annotation, the code will break at runtime, you can see in catalina.log
, this error : java.lang.NoClassDefFoundError: com/fasterxml/jackson/core/util/DefaultIndenter
To fix this you will need to add below jar dependency in your pom.xml
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.9.8</version>
</dependency>
Now, add <async-supported>true</async-supported>
in web.xml
under <servlet>
tag as below example,
<servlet>
<servlet-name>spring</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
<async-supported>true</async-supported>
</servlet>
Below is the code for both FILE Streaming Download and Data Stream support.
DATA STREAM CODE:
package com.emg.server.controller.rest;
import java.io.IOException;
import java.io.OutputStream;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Controller
@EnableWebMvc
public class StreamRecordsController {
@RequestMapping(value = "/streamrecords")
@ResponseBody
public StreamingResponseBody export() {
return new StreamingResponseBody() {
@Override
public void writeTo (OutputStream out) throws IOException {
for (int i = 0; i < 1000; i++) {
out.write((Integer.toString(i) + " - ")
.getBytes());
out.flush();
try {
Thread.sleep(5);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
};
}
}
FILE STREAM CODE:
package com.emg.server.controller.rest;
import java.io.File;
import java.nio.file.Files;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@Controller
@EnableWebMvc
public class StreamRecordsController {
@RequestMapping(value = "/streamrecords", method = RequestMethod.GET, produces = "application/json; charset=UTF-8")
@ResponseBody
public ResponseEntity<StreamingResponseBody> export() {
File file = new File("C:\\Users\\Ankur\\sample.pdf");
StreamingResponseBody responseBody = outputStream -> {
Files.copy(file.toPath(), outputStream);
};
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=generic_file_name.pdf")
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(responseBody);
}
}
OUTPUT for both the streaming style

NOTE: I execute both programs individually, deployed and tested it separately.