Spring WebFlux:从控制器提供文件

Posted

技术标签:

【中文标题】Spring WebFlux:从控制器提供文件【英文标题】:Spring WebFlux: Serve files from controller 【发布时间】:2018-08-21 21:15:03 【问题描述】:

来自 .NET 和 Node 我真的很难弄清楚如何将这个阻塞的 MVC 控制器转移到一个非阻塞的 WebFlux 注释控制器?我已经理解了这些概念,但找不到合适的异步 Java IO 方法(我希望它返回 Flux 或 Mono)。

@RestController
@RequestMapping("/files")
public class FileController 

    @GetMapping("/fileName")
    public void getFile(@PathVariable String fileName, HttpServletResponse response) 
        try 
            File file = new File(fileName);
            InputStream in = new java.io.FileInputStream(file);
            FileCopyUtils.copy(in, response.getOutputStream());
            response.flushBuffer();
         catch (FileNotFoundException e) 
            e.printStackTrace();
         catch (IOException e) 
            e.printStackTrace();
        
    

【问题讨论】:

【参考方案1】:

首先,使用 Spring MVC 实现这一点的方式应该更像这样:

@RestController
@RequestMapping("/files")
public class FileController 

    @GetMapping("/fileName")
    public Resource getFile(@PathVariable String fileName) 
        Resource resource = new FileSystemResource(fileName);        
        return resource;
    

另外,如果您只是在没有额外逻辑的情况下为这些资源提供服务,您可以使用 Spring MVC 的 static resource support。使用 Spring Boot,spring.resources.static-locations 可以帮助您自定义位置。

现在,使用 Spring WebFlux,您还可以配置相同的 spring.resources.static-locations 配置属性来提供静态资源。

WebFlux 版本看起来完全一样。如果您需要执行一些涉及某些 I/O 的逻辑,您可以直接返回 Mono<Resource> 而不是 Resource,如下所示:

@RestController
@RequestMapping("/files")
public class FileController 

    @GetMapping("/fileName")
    public Mono<Resource> getFile(@PathVariable String fileName) 
        return fileRepository.findByName(fileName)
                 .map(name -> new FileSystemResource(name));
    

请注意,对于 WebFlux,如果返回的 Resource 实际上是磁盘上的一个文件,我们将利用 zero-copy mechanism 来提高效率。

【讨论】:

那么,我已经从第一个版本的 WebFlux(零拷贝)中受益了吗?此外,我不知道从哪里获取 fileRepository?您能否提供示例或文档的链接? (我只知道 JPA 存储库......)。干杯! 只要资源是磁盘上的文件(即不是内存中的文件或 JAR 中包含的文件),您将获得对两者的零拷贝支持。 fileRepository 是您需要实际逻辑的用例的示例。如果你只需要服务资源,第一个控制器会工作,或者更好,使用 Spring 中的静态资源支持会更容易。 是否可以让静态位置每次都从磁盘读取文件而不进行缓存?我已经更改了 org.springframework.boot.autoconfigure.web.WebProperties 中的一些属性,但没有成功。 实际上,更具体地说 - 它缓存了不存在的文件夹。如果它映射到的文件夹出现在它之后,则应用程序需要重新启动才能再次开始读取。

以上是关于Spring WebFlux:从控制器提供文件的主要内容,如果未能解决你的问题,请参考以下文章

使用 Spring WebFlux 路由器功能时如何获取模型属性?

Spring Boot WebFlux 不工作请求控制器

spring 5 webflux 功能端点请求中不存在访问控制源头

Spring webflux 不会使用 @ModelAttribute 从路径变量填充自定义对象

Spring WebFlux 休息控制器仅服务于前两个订阅

无法使用 Spring Webflux 和 Thymeleaf 对静态资源进行版本控制