Ответ
В Spring MVC для возврата файла используется ResponseEntity в комбинации с Resource. Это даёт полный контроль над HTTP-заголовками ответа.
Стандартный подход с ResponseEntity
import org.springframework.core.io.InputStreamResource;
import org.springframework.core.io.Resource;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.*;
@RestController
public class FileController {
@GetMapping("/download")
public ResponseEntity<Resource> downloadFile() throws IOException {
// 1. Загружаем файл в Resource
File file = new File("/path/to/report.pdf");
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
// 2. Формируем ответ с нужными заголовками
return ResponseEntity.ok()
.header(HttpHeaders.CONTENT_DISPOSITION,
"attachment; filename="" + file.getName() + """) // Указывает браузеру на скачивание
.contentType(MediaType.APPLICATION_PDF) // Конкретный MIME-тип
.contentLength(file.length()) // Размер файла для прогресс-бара
.body(resource);
}
}
Ключевые моменты:
Content-Disposition: attachment— главный заголовок, заставляющий браузер скачать файл, а не открыть его.Content-Type— следует указывать точный MIME-тип (например,application/pdf,image/png). Для бинарных данных можно использоватьMediaType.APPLICATION_OCTET_STREAM.Content-Length— необязателен, но помогает браузеру отображать прогресс загрузки.- Типы Resource: Вместо
InputStreamResourceможно использоватьFileSystemResource,ClassPathResourceилиByteArrayResourceв зависимости от источника файла.
Альтернатива с @ResponseBody (менее гибкая):
@GetMapping(value = "/download", produces = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public @ResponseBody Resource downloadFile() {
return new FileSystemResource("file.txt");
}