Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/340.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 为什么映射Mono时会收到空字符串<;无效>;到Mono<;字符串>;?_Java_Spring_Spring Webflux - Fatal编程技术网

Java 为什么映射Mono时会收到空字符串<;无效>;到Mono<;字符串>;?

Java 为什么映射Mono时会收到空字符串<;无效>;到Mono<;字符串>;?,java,spring,spring-webflux,Java,Spring,Spring Webflux,我正在使用SpringWebFlux开发一个API REST,但在上传文件时遇到了问题。它们被存储,但我没有得到预期的返回值 我就是这么做的: 接收流量 将部分转换为文件部分 使用transferTo()保存部件(这将返回一个Mono) 使用文件名将Mono映射到Mono 将流量返回给客户端 我希望返回文件名,但客户端得到一个空字符串 控制器代码 @PostMapping(value = "/muscles/{id}/image") public Flux<String> updat

我正在使用SpringWebFlux开发一个API REST,但在上传文件时遇到了问题。它们被存储,但我没有得到预期的返回值

我就是这么做的:

  • 接收流量
  • 将部分转换为文件部分
  • 使用transferTo()保存部件(这将返回一个Mono)
  • 使用文件名将Mono映射到Mono
  • 将流量返回给客户端
  • 我希望返回文件名,但客户端得到一个空字符串

    控制器代码

    @PostMapping(value = "/muscles/{id}/image")
    public Flux<String> updateImage(@PathVariable("id") String id, @RequestBody Flux<Part> file) {
        log.info("REST request to update image to Muscle");
        return storageService.saveFiles(file);
    }
    
    public Flux<String> saveFiles(Flux<Part> parts) {
        log.info("StorageService.saveFiles({})", parts);
        return
                parts
                .filter(p -> p instanceof FilePart)
                .cast(FilePart.class)
                .flatMap(file -> saveFile(file));
    }
    
    private Mono<String> saveFile(FilePart filePart) {
        log.info("StorageService.saveFile({})", filePart);
        String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
        Path target = rootLocation.resolve(filename);
        try {
            Files.deleteIfExists(target);
            File file = Files.createFile(target).toFile();
    
            return filePart.transferTo(file)
                    .map(r -> filename);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    @PostMapping(value=“/muscles/{id}/image”)
    公共流量更新图像(@PathVariable(“id”)字符串id,@RequestBody流量文件){
    log.info(“将图像更新到肌肉的REST请求”);
    返回storageService.saveFiles(文件);
    }
    
    存储服务

    @PostMapping(value = "/muscles/{id}/image")
    public Flux<String> updateImage(@PathVariable("id") String id, @RequestBody Flux<Part> file) {
        log.info("REST request to update image to Muscle");
        return storageService.saveFiles(file);
    }
    
    public Flux<String> saveFiles(Flux<Part> parts) {
        log.info("StorageService.saveFiles({})", parts);
        return
                parts
                .filter(p -> p instanceof FilePart)
                .cast(FilePart.class)
                .flatMap(file -> saveFile(file));
    }
    
    private Mono<String> saveFile(FilePart filePart) {
        log.info("StorageService.saveFile({})", filePart);
        String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
        Path target = rootLocation.resolve(filename);
        try {
            Files.deleteIfExists(target);
            File file = Files.createFile(target).toFile();
    
            return filePart.transferTo(file)
                    .map(r -> filename);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    公共通量保存文件(通量部分){
    log.info(“StorageService.saveFiles({})”,parts;
    返回
    部分
    .filter(文件部分的p->p实例)
    .cast(FilePart.class)
    .flatMap(文件->保存文件(文件));
    }
    专用Mono保存文件(FilePart FilePart){
    log.info(“StorageService.saveFile({})”,filePart;
    字符串filename=DigestUtils.sha256Hex(filePart.filename()+新日期());
    路径目标=rootLocation.resolve(文件名);
    试一试{
    文件。deleteIfExists(目标);
    File File=Files.createFile(target.toFile();
    返回filePart.transferTo(文件)
    .map(r->filename);
    }捕获(IOE异常){
    抛出新的运行时异常(e);
    }
    }
    
    FilePart.transferTo()返回常量为空的Mono。然后,映射之后就再也没有执行过。我通过这样做解决了这个问题:

    private Mono<String> saveFile(FilePart filePart) {
        log.info("StorageService.saveFile({})", filePart);
        String filename = DigestUtils.sha256Hex(filePart.filename() + new Date());
        Path target = rootLocation.resolve(filename);
        try {
            Files.deleteIfExists(target);
            File file = Files.createFile(target).toFile();
            return filePart
                    .transferTo(file)
                    .doOnSuccess(data -> log.info("do something..."))
                    .thenReturn(filename);
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
    }
    
    private Mono保存文件(FilePart FilePart){
    log.info(“StorageService.saveFile({})”,filePart;
    字符串filename=DigestUtils.sha256Hex(filePart.filename()+新日期());
    路径目标=rootLocation.resolve(文件名);
    试一试{
    文件。deleteIfExists(目标);
    File File=Files.createFile(target.toFile();
    返回文件部分
    .transferTo(文件)
    .doOnSuccess(数据->日志.info(“做点什么…”)
    .thenReturn(文件名);
    }捕获(IOE异常){
    抛出新的运行时异常(e);
    }
    }
    
    FilePart.transferTo()
    返回
    Mono
    ,当操作完成时发出信号-这意味着反应式
    发布者将只发布
    onComplete
    /
    onError
    信号,并且在此之前不会发布值

    这意味着,
    map
    操作从未执行过,因为它只是源代码发布的给定元素

    您可以返回文件名并仍然链接反应运算符,如下所示:

    return part.transferTo(file).thenReturn(part.filename());
    
    禁止在反应性管道内使用
    操作符,并且禁止使用该操作符


    使用
    subscribe
    作为替代方案也不好,因为
    subscribe
    将使传输过程与请求处理分离,从而使它们在不同的执行序列中发生。这意味着您的服务器可以完成处理请求并关闭HTTP连接,而另一部分仍在尝试读取文件部分以将其复制到磁盘上。这可能会在运行时以微妙的方式失败。

    作为旁注:除了
    .filter(p->p FilePart的instanceof)
    之外,您还可以使用
    .filter(FilePart.class::isInstance)
    在管道中添加几个
    log
    操作符,并在此处共享日志?可能是在
    cast
    操作员之后进行一次,以了解您获得了多少零件,然后在
    flatMap
    之后进行另一次,以了解传输了多少文件。谢谢您的建议。我解决了它:)小心,在这个上下文中使用
    block
    是被禁止的,并且很可能在运行时对最新的reactor版本抛出异常。我只是来纠正这个问题。添加更多的东西,我得到了例外。现在我有了这一行:filePart.transferTo(file.doOnSuccess(data->log.info(“做点什么…”)).subscribe()<代码>订阅
    也不是正确的选择-我已经编辑了我的答案