具有不同内容类型的WebFlux功能路由器定义中的@RequestPart行为镜像 [英] Mirror @RequestPart behavior in WebFlux functional router definitions with different content types

查看:177
本文介绍了具有不同内容类型的WebFlux功能路由器定义中的@RequestPart行为镜像的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我们正在开发Spring Boot服务,以将数据上传到不同的后端数据库.想法是,在一个multipart/form-data请求中,用户将发送一个模型"消息给用户. (基本上是文件)和"modelMetadata" (这是JSON,它在我们的代码中定义了一个同名对象).

We're developing a Spring Boot service to upload data to different back end databases. The idea is that, in one multipart/form-data request a user will send a "model" (basically a file) and "modelMetadata" (which is JSON that defines an object of the same name in our code).

当用户将"modelMetadata"发送给用户时,我们可以使用WebFlux注释的控制器语法进行以下操作.内容形式为"application/json"的多部分形式:

We got the below to work in the WebFlux annotated controller syntax, when the user sends the "modelMetadata" in the multipart form with the content-type of "application/json":

    @PostMapping(consumes = [MediaType.MULTIPART_FORM_DATA_VALUE], produces = [MediaType.APPLICATION_JSON_VALUE])
    fun saveModel(@RequestPart("modelMetadata") monoModelMetadata: Mono<ModelMetadata>,
                  @RequestPart("model") monoModel: Mono<FilePart>,
                  @RequestHeader headers: HttpHeaders) : Mono<ResponseEntity<ModelMetadata>> {
        return modelService.saveModel(monoModelMetadata, monoModel, headers)
    }

但是我们似乎无法在Webflux的功能路由器定义中弄清楚如何做同样的事情.以下是我们拥有的相关代码段:

But we can't seem to figure out how to do the same thing in Webflux's functional router definition. Below are the relevant code snippets we have:

    @Bean
    fun modelRouter() = router {
        accept(MediaType.MULTIPART_FORM_DATA).nest {
            POST(ROOT, handler::saveModel)
        }
    }


    fun saveModel(r: ServerRequest): Mono<ServerResponse> {
        val headers = r.headers().asHttpHeaders()
        val monoModelPart = r.multipartData().map { multiValueMap ->
            it["model"] // What do we do with this List<Part!> to get a Mono<FilePart>
            it["modelMetadata"] // What do we do with this List<Part!> to get a Mono<ModelMetadata>
        }

从我们已阅读的所有内容中,我们应该能够使用路由器功能语法复制在注释控制器语法中发现的相同功能,但是似乎没有充分记录此特定方面.我们的目标是继续使用新的功能路由器语法,因为这是我们正在开发的新应用程序,并且有一些很好的前瞻性功能/优点,如

From everything we've read, we should be able to replicate the same functionality found in the annotation controller syntax with the router functional syntax, but this particular aspect doesn't seem to be well documented. Our goal was to move over to use the new functional router syntax since this is a new application we're developing and there are some nice forward thinking features/benefits as described here.

  • 在地球尽头搜寻相关示例
    • 是一个类似的问题,但没有获得任何关注,并且与我们从一个多部分的请求数据中创建对象的需求无关.
    • 可能与我们上传我们的多部分请求数据的文件组件,但无法处理通过JSON创建的对象
    • Googling to the ends of the Earth for a relevant example
      • this is a similar question, but hasn't gained any traction and doesn't relate to our need to create an object from one piece of the multipart request data
      • this may be close to what we need for uploading the file component of our multipart request data, but doesn't handle the object creation from JSON
      the content of the part is passed through an {@link HttpMessageConverter} taking into consideration the 'Content-Type' header of the request part.
      

      任何人和所有帮助将不胜感激!即使只是一些链接,我们也可以更好地了解Part/FilePart类型,并且在多部分请求中发挥作用也将有所帮助!

      Any and all help would be appreciated! Even just some links for us to better understand Part/FilePart types and there role in multipart requests would be helpful!

      推荐答案

      我能够使用自动连接的ObjectMapper提出解决此问题的方法.从下面的解决方案中,我可以将modelMetadatamodelPart转换为Mono来镜像@RequestPart返回类型,但这似乎很荒谬.

      I was able to come up with a solution to this issue using an autowired ObjectMapper. From the below solution I could turn the modelMetadata and modelPart into Monos to mirror the @RequestPart return types, but that seems ridiculous.

      我也可以通过创建MappingJackson2HttpMessageConverter并将metadataDataBuffer转换为MappingJacksonInputMessage来解决此问题,但是这种解决方案似乎更符合我们的需求.

      I was also able to solve this by creating a MappingJackson2HttpMessageConverter and turning the metadataDataBuffer into a MappingJacksonInputMessage, but this solution seemed better for our needs.

          fun saveModel(r: ServerRequest): Mono<ServerResponse> {
              val headers = r.headers().asHttpHeaders()
              return r.multipartData().flatMap {
                  // We're only expecting one Part of each to come through...assuming we understand what these Parts are
                  if (it.getOrDefault("modelMetadata", listOf()).size == 1 && it.getOrDefault("model", listOf()).size == 1) {
                      val modelMetadataPart = it["modelMetadata"]!![0]
                      val modelPart = it["model"]!![0] as FilePart
                      modelMetadataPart
                              .content()
                              .map { metadataDataBuffer ->
                                  // TODO: Only do this if the content is JSON?
                                  objectMapper.readValue(metadataDataBuffer.asInputStream(), ModelMetadata::class.java)
                              }
                              .next() // We're only expecting one object to be serialized from the buffer
                              .flatMap { modelMetadata ->
                                  // Function was updated to work without needing the Mono's of each type 
                                  // since we're mapping here
                                  modelService.saveModel(modelMetadata, modelPart, headers)
                              }
                  }
                  else {
                          // Send bad request response message
                  }
              }
      

      尽管此解决方案有效,但我感觉它不如@RequestPart批注注释中提到的那样优雅.因此,我现在将其作为解决方案,但是如果有人有更好的解决方案,请告诉我们,我会接受!

      Although this solution works, I feel like it's not as elegant as the one alluded to in the @RequestPart annotation comments. Thus I will accept this as the solution for now, but if someone has a better solution please let us know and I will accept it!

      这篇关于具有不同内容类型的WebFlux功能路由器定义中的@RequestPart行为镜像的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆