Spring @RestController - после обслуживания запроса

Фон

вот метод, определенный в @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.

Резюме ответа Спасибо всем за помощь в этом.

Принятый ответ требует минимум изменений и работает хорошо.

Использовать ScheduledExecutorService? Может быть, обернуть InputStreamResource и удалить файл методом close()?

chrylis -cautiouslyoptimistic- 04.10.2018 14:25

Взгляните на stackoverflow.com/questions/52387380/…

user10367961 04.10.2018 16:27

FWIW: Было бы лучше перенести работу с контроллера на @Service. Это сделало бы удаление файла в процессе генерации возврата тривиальным. Однако я согласен с ответом Гербена Джонгериуса ниже - GET должен быть идемпотентным; DELETE - подходящий вызов для уничтожения файла.

Bill Horvath 05.10.2018 03:55
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
4
329
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Помимо того факта, что выполнение деструктивных операций с запросами 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 закроется при возврате, файл будет удален.

Разве это не создает новый временный файл в физической файловой системе?

wonsuc 19.02.2019 03:04

Основываясь на ответе @ 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);
}

Другие вопросы по теме