Spring WebFlux:从控制器提供文件

Kna*_*ack 6 java spring spring-boot spring-webflux

来自.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();
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

Bri*_*zel 5

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

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

    @GetMapping("/{fileName}")
    public Resource getFile(@PathVariable String fileName) {
        Resource resource = new FileSystemResource(fileName);        
        return resource;
    }
}
Run Code Online (Sandbox Code Playgroud)

此外,并不是说如果您只是 在没有附加逻辑的情况下为这些资源提供服务,则可以使用 Spring MVC 的静态资源支持。使用 Spring Boot,spring.resources.static-locations可以帮助您自定义位置。

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

它的 WebFlux 版本看起来完全一样。如果您需要执行一些涉及某些 I/O 的逻辑,您可以直接返回 aMono<Resource>而不是 a 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));
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,对于 WebFlux,如果返回Resource的实际上是磁盘上的文件,我们将利用零复制机制来提高效率。

  • 只要 Resource 是磁盘上的文件(即不是内存中已有的文件或 JAR 中包含的文件),您将获得对两者的零复制支持。`fileRepository` 是你需要实际逻辑的用例的一个例子。如果你只需要服务资源,第一个控制器就可以工作,或者更好,使用 Spring 中的静态资源支持会更容易。 (2认同)