Entiende el código bien previamente a usarlo a tu proyecto y si tquieres aportar algo puedes compartirlo con nosotros.
Solución:
Opción 1 usando un InputStreamResource
Implementación de recursos para un InputStream determinado.
Solo debe ser usado si no hay otra implementación de Recurso específica > aplicable. En particular, prefiera ByteArrayResource o cualquiera de las implementaciones de recursos basadas en archivos cuando sea posible.
@RequestMapping(path = "/download", method = RequestMethod.GET)
public ResponseEntity download(String param) throws IOException
// ...
InputStreamResource resource = new InputStreamResource(new FileInputStream(file));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
Opcion 2 como sugiere la documentación de InputStreamResource, usando un ByteArrayResource:
@RequestMapping(path = "/download", method = RequestMethod.GET)
public ResponseEntity download(String param) throws IOException
// ...
Path path = Paths.get(file.getAbsolutePath());
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));
return ResponseEntity.ok()
.headers(headers)
.contentLength(file.length())
.contentType(MediaType.APPLICATION_OCTET_STREAM)
.body(resource);
El siguiente código de muestra funcionó para mí y podría ayudar a alguien.
import org.springframework.core.io.ByteArrayResource;
import org.springframework.core.io.Resource;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import java.io.File;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
@RestController
@RequestMapping("/app")
public class ImageResource
private static final String EXTENSION = ".jpg";
private static final String SERVER_LOCATION = "/server/images";
@RequestMapping(path = "/download", method = RequestMethod.GET)
public ResponseEntity download(@RequestParam("image") String image) throws IOException
File file = new File(SERVER_LOCATION + File.separator + image + EXTENSION);
HttpHeaders header = new HttpHeaders();
header.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=img.jpg");
header.add("Cache-Control", "no-cache, no-store, must-revalidate");
header.add("Pragma", "no-cache");
header.add("Expires", "0");
Path path = Paths.get(file.getAbsolutePath());
ByteArrayResource resource = new ByteArrayResource(Files.readAllBytes(path));
return ResponseEntity.ok()
.headers(header)
.contentLength(file.length())
.contentType(MediaType.parseMediaType("application/octet-stream"))
.body(resource);
Sugeriría usar un StreamingResponseBody ya que con él la aplicación puede escribir directamente en la respuesta (OutputStream) sin retrasar el subproceso del contenedor Servlet. Es un buen enfoque si está descargando un archivo muy grande.
@GetMapping("download")
public StreamingResponseBody downloadFile(HttpServletResponse response, @PathVariable Long fileId)
FileInfo fileInfo = fileService.findFileInfo(fileId);
response.setContentType(fileInfo.getContentType());
response.setHeader(
HttpHeaders.CONTENT_DISPOSITION, "attachment;filename="" + fileInfo.getFilename() + """);
return outputStream ->
int bytesRead;
byte[] buffer = new byte[BUFFER_SIZE];
InputStream inputStream = fileInfo.getInputStream();
while ((bytesRead = inputStream.read(buffer)) != -1)
outputStream.write(buffer, 0, bytesRead);
;
Ps.: Al usar StreamingResponseBody, se recomienda encarecidamente configurar TaskExecutor utilizado en Spring MVC para ejecutar solicitudes asincrónicas. TaskExecutor es una interfaz que abstrae la ejecución de un Runnable.
Más información: https://medium.com/swlh/streaming-data-with-spring-boot-restful-web-service-87522511c071