Фон
вот метод, определенный в @RestController, он читает файл с диска, а затем выполняет обратную передачу.
@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);
}
Проблема
Я хотел бы удалить файл после того, как запрос будет обработан, но не могу найти подходящее место.
Я бы предположил, что это должно быть после закрытия inputStream (https://github.com/spring-projects/spring-framework/blob/v4.3.9.RELEASE/spring-web/src/main/java/org/springframework/http/converter/ResourceHttpMessageConverter.java#L117). это невозможно сделать описанным выше методом, так как файл открывается Inputstream.
Резюме ответа Спасибо всем за помощь в этом.
Принятый ответ требует минимум изменений и работает хорошо.
Взгляните на stackoverflow.com/questions/52387380/…
FWIW: Было бы лучше перенести работу с контроллера на @Service. Это сделало бы удаление файла в процессе генерации возврата тривиальным. Однако я согласен с ответом Гербена Джонгериуса ниже - GET должен быть идемпотентным; DELETE - подходящий вызов для уничтожения файла.




Помимо того факта, что выполнение деструктивных операций с запросами GET в службе RESTfull является плохой практикой, этого нельзя сделать с помощью библиотек Java по умолчанию. Более широко распространенной реализацией будет GET, который передает файл в потоковом режиме с последующим вызовом DELETE для удаления файла.
Но вы можете сделать это, реализовав свой собственный InputStream, см. Предыдущий поток в Stackoverflow на удаление файлов при закрытии InputStream.
Расширьте FileInputStream своей собственной реализацией, а затем перезапишите close. Когда входной поток закрывается, ваш файл также удаляется.
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();
}
}
Предполагая, что вы создаете файл в том же контроллере. Вы можете использовать:
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) {
}
Поскольку BufferedWriter закроется при возврате, файл будет удален.
Разве это не создает новый временный файл в физической файловой системе?
Основываясь на ответе @ phlogratos, вы можете попробовать вот так.
@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);
}
Использовать
ScheduledExecutorService? Может быть, обернутьInputStreamResourceи удалить файл методомclose()?