0

I'm using Spring boot 2.2.6.RELEASE with Java 11. I have some images inside the static folder. Example: static/img/category/some_image.jpg.

When I click the download button on the GUI, this method runs in the backend.

@ResponseBody
@GetMapping(value = "/download", produces = MediaType.IMAGE_JPEG_VALUE)
public FileSystemResource downloadImage(@Param(value = "url") String url,
                                        @Param(value = "id") Integer id,
                                        HttpServletResponse response) throws IOException {

    Media media = mediaService.findById(id);
    String fileName = media.getFileName();

    InputStream inputStream = new ClassPathResource(url).getInputStream();
    File file = new File(fileName);
    FileUtils.copyToFile(inputStream, file);
    inputStream.close();

    response.addHeader("Content-Disposition", "attachment; filename=" + fileName + ".jpg");
    return new FileSystemResource(file);
}

I'm using InputStream since I will run this application as a jar file in a docker container. Anyway, this method works fine and the image will be downloaded fine. But the problem is that after the file download is completed, a new file without the extension (jpg) will be created in the root of the project. It's content looks like this:

ffd8 ffe1 0018 4578 6966 0000 4949 2a00
0800 0000 0000 0000 0000 0000 ffec 0011
4475 636b 7900 0100 0400 0000 3c00 00ff
ee00 0e41 646f 6265 0064 c000 0000 01ff
db00 8400 0604 0404 0504 0605 0506 0906
0506 090b 0806 0608 0b0c 0a0a 0b0a 0a0c
100c 0c0c 0c0c 0c10 0c0e 0f10 0f0e 0c13
...

If I rename the file and add file jpg extension then the image will open just fine. For every downloaded file, a new file will be created inside the project root folder and this is not good. Any idea why this is happening?

oxyt
  • 1,816
  • 3
  • 23
  • 33

2 Answers2

2

This is because File file = new File(fileName); is actually creating a permanent file on the classpath.

What needs to be done, is to create a temp file

Replace File file = new File(fileName); with File file = File.createTempFile(fileName, "jpeg");

So, whole method should go like this

@ResponseBody
@GetMapping(value = "/download", produces = MediaType.IMAGE_JPEG_VALUE)
public FileSystemResource downloadImage(@Param(value = "url") String url,
                                        @Param(value = "id") Integer id,
                                        HttpServletResponse response) throws IOException {

    Media media = mediaService.findById(id);
    String fileName = media.getFileName();

    InputStream inputStream = new ClassPathResource(url).getInputStream();
    File file = File.createTempFile(fileName,"");
    FileUtils.copyToFile(inputStream, file);
    inputStream.close();
    file.deleteOnExit(); // delete temp file on exit
    response.addHeader("Content-Disposition", "attachment; filename=" + fileName + ".jpg");
    return new FileSystemResource(file);
}
Suraj
  • 737
  • 6
  • 21
1

This is because you use FileUtils.copyToFile(inputStream, file);

You can write this with using InputStreamResource:

@RestController
@RequestMapping("/test")
public class Controller {

    @ResponseBody
    @GetMapping(value = "/download", produces = MediaType.IMAGE_JPEG_VALUE)
    public ResponseEntity<Resource> downloadImage(HttpServletResponse response) throws IOException {

        String fileName = "test.jpg";
        InputStream inputStream = new ClassPathResource("images/test.jpg").getInputStream();
        InputStreamResource inputStreamResource = new InputStreamResource(inputStream);

        response.addHeader("Content-Disposition", "attachment; filename=" + fileName + ".jpg");
        return new ResponseEntity<>(inputStreamResource, HttpStatus.OK);

    }

}

You also don't need close input steam because

Andrew Sulyz
  • 236
  • 2
  • 10