Как скачивать файл в Spring WebFlux?

В Spring WebFlux для скачивания файла можно использовать класс ServerResponse, который позволяет создавать HTTP-ответы. Для начала необходимо создать метод, который будет обрабатывать запрос на скачивание файла. Для этого мы используем аннотацию @GetMapping или @PostMapping.

В коде ниже приведен пример метода, который скачивает файл:

@GetMapping("/download")
public Mono<ServerResponse> downloadFile(ServerRequest request) {
    String filename = "example.txt"; // имя файла для скачивания
    Resource resource = new ClassPathResource(filename); // получаем ресурс файла

    return ServerResponse.ok()
            .contentType(MediaType.APPLICATION_OCTET_STREAM) // указываем тип содержимого
            .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename="" + filename + """) // указываем заголовок Content-Disposition для скачивания
            .body(BodyInserters.fromResource(resource)); // возвращаем тело ответа с ресурсом файла
}

В этом коде мы сначала получаем ресурс файла, используя Resource resource = new ClassPathResource(filename);. Затем создаем HTTP-ответ с помощью ServerResponse.ok(). Мы указываем тип содержимого как MediaType.APPLICATION_OCTET_STREAM, чтобы указать, что мы будем отправлять неформатированные двоичные данные. Заголовок Content-Disposition с атрибутом attachment указывает браузеру, что файл должен быть скачан, а не отображен в браузере.

Наконец, мы используем body(BodyInserters.fromResource(resource)) для создания тела ответа с ресурсом файла.

После создания метода downloadFile, вы должны использовать его в соответствующем роутере или контроллере. Например:

@Configuration
public class RouterConfig {

    @Bean
    public RouterFunction<ServerResponse> routes(FileHandler fileHandler) {
        return RouterFunctions
                .route(GET("/download").and(accept(MediaType.ALL)), fileHandler::downloadFile);
    }
}

В этом примере fileHandler - это экземпляр класса, содержащего метод downloadFile, который мы определили ранее. Мы настраиваем роутер так, чтобы обрабатывать GET-запросы на "/download" и принимать любой тип содержимого (accept(MediaType.ALL)).

Теперь, когда мы отправляем GET-запрос на "/download", сервер будет отправлять файл с указанным именем в ответе, и браузер пользователя предложит скачать этот файл.