How to Download Files in Spring Boot
In this example, we will show you how to download files via a REST API in Spring Boot.
In the following example controller, we are using StreamingResponseBody interface that is capable of writing data to the response OutputStream directly for downloads:
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import javax.servlet.http.HttpServletResponse;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
@RestController
@RequestMapping(path = "/api")
public class DownloadFileExampleController {
@GetMapping(path = "/downloads/{fileId}")
public StreamingResponseBody downloadFile(HttpServletResponse response,
@PathVariable(name = "fileId") String fileId) {
//file path is usually store in a database and is retrieved by id
String path = "C:/Documents/Videos/video_id_123.mp4";
File file = new File(path);
response.setContentLength((int) file.length());
response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
int BUFFER_SIZE = 1024;
return outputStream -> {
int bytesRead;
byte[] buffer = new byte[BUFFER_SIZE];
//convert the file to InputStream
InputStream inputStream = new FileInputStream(file);
while ((bytesRead = inputStream.read(buffer)) != -1) {
outputStream.write(buffer, 0, bytesRead);
}
if (inputStream != null) {
inputStream.close();
}
};
}
}
It is recommended that you explicitly configure the TaskExecutor if the file to be downloaded is large and will take more than a minute to download.
Lets create AsyncConfiguration class and configure the TaskExecutor. Here is the complete code for configuring the TaskExecutor with a request timeout of 3600000 milliseconds (60 minutes). In addition, the code registers an interceptor that is called when a request timeout occurs for handling special cases.
import java.util.concurrent.Callable;
import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
import org.springframework.aop.interceptor.SimpleAsyncUncaughtExceptionHandler;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.task.AsyncTaskExecutor;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.web.context.request.NativeWebRequest;
import org.springframework.web.context.request.async.CallableProcessingInterceptor;
import org.springframework.web.context.request.async.TimeoutCallableProcessingInterceptor;
import org.springframework.web.servlet.config.annotation.AsyncSupportConfigurer;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
@EnableAsync
@EnableScheduling
public class AsyncConfiguration implements AsyncConfigurer {
@Override
@Bean(name = "taskExecutor")
public AsyncTaskExecutor getAsyncExecutor() {
ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
executor.setCorePoolSize(10);
executor.setMaxPoolSize(15);
executor.setQueueCapacity(50);
return executor;
}
@Override
public AsyncUncaughtExceptionHandler getAsyncUncaughtExceptionHandler() {
return new SimpleAsyncUncaughtExceptionHandler();
}
@Bean
public WebMvcConfigurer webMvcConfigurerConfigurer(AsyncTaskExecutor taskExecutor,
CallableProcessingInterceptor callableProcessingInterceptor) {
return new WebMvcConfigurer() {
@Override
public void configureAsyncSupport(AsyncSupportConfigurer configurer) {
configurer.setDefaultTimeout(3600000).setTaskExecutor(taskExecutor);
configurer.registerCallableInterceptors(callableProcessingInterceptor);
WebMvcConfigurer.super.configureAsyncSupport(configurer);
}
};
}
@Bean
public CallableProcessingInterceptor callableProcessingInterceptor() {
return new TimeoutCallableProcessingInterceptor() {
@Override
public <T> Object handleTimeout(NativeWebRequest request, Callable<T> task) throws Exception {
return super.handleTimeout(request, task);
}
};
}
}