Hua
Hua

Reputation: 93

Spring @RestController - after request being served

Background

here is the method defined in @RestController, it reads file from disk then stream back.

@RequestMapping(value = "/bill", method = RequestMethod.GET)
public ResponseEntity<Object> getbill(){
  ...
  InputStream in = new FileInputStream(file);
  InputStreamResource inputStreamResource = new InputStreamResource(in);
  httpHeaders.setContentLength(file.Length());
  return new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK);
}

Issue

I would like to delete the file after request is served, but unable to find a good place.

I would assume it should be after inputStream gets closed (https://github.com/spring-projects/spring-framework/blob/v4.3.9.RELEASE/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java#L117) . it can not be done in above method since file is opened by Inputstream.

Answer Summary Thank you all for helping with this.

The accepted answer requires least change and working well.

Upvotes: 0

Views: 1084

Answers (4)

wonsuc
wonsuc

Reputation: 3625

Based on @phlogratos's answer, you can try like this.

@GetMapping("/download")
public ResponseEntity<InputStreamResource> download() throws Exception {

    ... codes ...

    InputStreamResource isr = new InputStreamResource(new FileInputStream(file) {
        @Override
        public void close() throws IOException {
            super.close();
            boolean isDeleted = file.delete();
            logger.info("export:'{}':" + (isDeleted ? "deleted" : "preserved"), filename);
        }
    });
    return new ResponseEntity<>(isr, respHeaders, HttpStatus.OK);
}

Upvotes: 1

Abhinav Agarwal
Abhinav Agarwal

Reputation: 224

Assuming that you are creating the file in the same controller. You can use:

 try (BufferedWriter out = Files
        .newBufferedWriter(newFilePath, Charset.defaultCharset(),
            StandardOpenOption.DELETE_ON_CLOSE)) {

        InputStream in = new FileInputStream(newFilePath.toFile());
        InputStreamResource inputStreamResource = new InputStreamResource(in);
        httpHeaders.setContentLength(file.Length());
        return new ResponseEntity(inputStreamResource, httpHeaders, HttpStatus.OK);

    } catch (Exception e) {
    }

As the BufferedWriter will close on return, the file will get deleted.

Upvotes: 1

phlogratos
phlogratos

Reputation: 13924

Extend FileInputStream with your own implementation and then overwrite close. When the input stream is closed, your file gets deleted as well.

public class MyFileInputStream extends FileInputStream {
    private final File myFile;

    public MyFileInputStream(File file) throws FileNotFoundException {
        super(file);
        myFile = file;
    }
    @Override
    public void close() throws IOException {
        super.close();
        myFile.delete();
    }
}

Upvotes: 0

Gerben Jongerius
Gerben Jongerius

Reputation: 729

Aside from the fact that it is bad practice in a RESTfull service to perform destructive operations on GET requests this can not be done by the default Java libraries. The more widely accepted implementation would be a GET that streams the file followed by a DELETE call to remove the file.

But you can do it by implementing your own InputStream, see an earlier thread in Stackoverflow on deleting files on closing a InputStream.

Upvotes: 1

Related Questions