【问题标题】:Spring WebFlux: Serve files from controllerSpring WebFlux:从控制器提供文件
【发布时间】: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();
        }
    }
}

【问题讨论】:

    标签: java spring spring-boot spring-webflux


    【解决方案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 中的一些属性,但没有成功。
    • 实际上,更具体地说 - 它缓存了不存在的文件夹。如果它映射到的文件夹出现在它之后,则应用程序需要重新启动才能再次开始读取。
    猜你喜欢
    • 1970-01-01
    • 2012-08-09
    • 1970-01-01
    • 2020-02-21
    • 2021-06-12
    • 2021-07-05
    • 2019-01-02
    • 2014-11-07
    • 1970-01-01
    相关资源
    最近更新 更多