Coming from .NET and Node I really have a hard time to figure out how to transfer this blocking MVC controller to a non-blocking WebFlux annotated controller? I've understood the concepts, but fail to find the proper async Java IO method (which I would expect to return a Flux or 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();
}
}
}
First, the way to achieve that with Spring MVC should look more like this:
@RestController
@RequestMapping("/files")
public class FileController {
@GetMapping("/{fileName}")
public Resource getFile(@PathVariable String fileName) {
Resource resource = new FileSystemResource(fileName);
return resource;
}
}
Also, not that if you just server those resources without additional logic, you can use Spring MVC's static resource support. With Spring Boot, spring.resources.static-locations
can help you customize the locations.
Now, with Spring WebFlux, you can also configure the same spring.resources.static-locations
configuration property to serve static resources.
The WebFlux version of that looks exactly the same. If you need to perform some logic involving some I/O, you can return a Mono<Resource>
instead of a Resource
directly, like this:
@RestController
@RequestMapping("/files")
public class FileController {
@GetMapping("/{fileName}")
public Mono<Resource> getFile(@PathVariable String fileName) {
return fileRepository.findByName(fileName)
.map(name -> new FileSystemResource(name));
}
}
Note that with WebFlux, if the returned Resource
is actually a file on disk, we will leverage a zero-copy mechanism that will make things more efficient.