Scala Lagom中的多部分表单数据

Scala Lagom中的多部分表单数据,scala,playframework,akka,multipartform-data,lagom,Scala,Playframework,Akka,Multipartform Data,Lagom,我想有一个服务,它接收一个item对象,该对象包含;名称、描述、价格和图片 其他属性是字符串,可以很容易地作为Json对象发送,但是对于包含图片,最好的解决方案是什么 如果多部分formdata是最佳解决方案,那么在Lagom中如何处理它 您可能希望在GitHub上的lagom recipes存储库中检查 基本上,这个想法是创建一个额外的播放路由器。之后,我们必须告诉Lagom按照中的说明使用它(此功能从1.5.0开始提供)。以下是路由器的外观: class FileUploadRouter(a

我想有一个服务,它接收一个item对象,该对象包含;名称、描述、价格和图片

  • 其他属性是字符串,可以很容易地作为Json对象发送,但是对于包含图片,最好的解决方案是什么
  • 如果多部分formdata是最佳解决方案,那么在Lagom中如何处理它

  • 您可能希望在GitHub上的lagom recipes存储库中检查

    基本上,这个想法是创建一个额外的播放路由器。之后,我们必须告诉Lagom按照中的说明使用它(此功能从1.5.0开始提供)。以下是路由器的外观:

    class FileUploadRouter(action: DefaultActionBuilder,
                           parser: PlayBodyParsers,
                           implicit val exCtx: ExecutionContext) {
      private def fileHandler: FilePartHandler[File] = {
        case FileInfo(partName, filename, contentType, _) =>
          val tempFile = {
            val f = new java.io.File("./target/file-upload-data/uploads", UUID.randomUUID().toString).getAbsoluteFile
            f.getParentFile.mkdirs()
            f
          }
          val sink: Sink[ByteString, Future[IOResult]] = FileIO.toPath(tempFile.toPath)
          val acc: Accumulator[ByteString, IOResult] = Accumulator(sink)
          acc.map {
            case akka.stream.IOResult(_, _) =>
              FilePart(partName, filename, contentType, tempFile)
          }
    
      }
      val router = Router.from {
        case POST(p"/api/files") =>
          action(parser.multipartFormData(fileHandler)) { request =>
            val files = request.body.files.map(_.ref.getAbsolutePath)
            Results.Ok(files.mkString("Uploaded[", ", ", "]"))
          }
      }
    }
    
    然后,我们简单地告诉Lagom使用它

      override lazy val lagomServer =
        serverFor[FileUploadService](wire[FileUploadServiceImpl])
          .additionalRouter(wire[FileUploadRouter].router)
    
    或者,我们可以使用
    PlayServiceCall
    类。以下是Lightbend团队的James Roper提供的关于如何实现这一点的简单草图:

    // The type of the service call is NotUsed because we are handling it out of band
    def myServiceCall: ServiceCall[NotUsed, Result] = PlayServiceCall { wrapCall =>
      // Create a Play action to handle the request
      EssentialAction { requestHeader =>
    
        // Now we create the sink for where we want to stream the request to - eg it could
        // go to a file, a database, some other service. The way Play gives you a request
        // body is that you need to return a sink from EssentialAction, and when it gets
        // that sink, it stream the request body into that sink.
        val sink: Sink[ByteString, Future[Done]] = ...
    
        // Play wraps sinks in an abstraction called accumulator, which makes it easy to
        // work with the result of handling the sink. An accumulator is like a future, but
        // but rather than just being a value that will be available in future, it is a
        // value that will be available once you have passed a stream of data into it.
        // We wrap the sink in an accumulator here.
        val accumulator: Accumulator[ByteString, Done] = Accumulator.forSink(sink)
    
        // Now we have an accumulator, but we need the accumulator to, when it's done,
        // produce an HTTP response.  Right now, it's just producing akka.Done (or whatever
        // your sink materialized to).  So we flatMap it, to handle the result.
        accumulator.flatMap { done =>
    
          // At this point we create the ServiceCall, the reason we do that here is it means
          // we can access the result of the accumulator (in this example, it's just Done so
          // not very interesting, but it could be something else).
          val wrappedAction = wrapCall(ServiceCall { notUsed =>
    
            // Here is where we can do any of the actual business logic, and generate the
            // result that can be returned to Lagom to be serialized like normal
    
            ...
          })
    
          // Now we invoke the wrapped action, and run it with no body (since we've already
          // handled the request body with our sink/accumulator.
          wrappedAction(request).run()
        }
      }
    }
    
    一般来说,使用Lagom来达到这个目的可能不是一个好主意。正如GitHub发行的
    PlayServiceCall
    文档中所述:

    我们回退到PlayServiceCall的许多用例都与表示或HTTP特定使用(I18N,文件上载,…)有关,这表明:lagom服务与表示层的耦合或lagom服务与传输的耦合

    再次引用詹姆斯·罗珀(几年前)的话:

    因此,目前Lagom中不支持多部分/表单数据,至少不支持开箱即用。您可以下拉到较低级别的Play API来处理它,但可能最好在web网关中处理它,在web网关中处理的任何文件都直接上载到存储服务(如S3),然后Lagom服务可能会存储与之相关的元数据


    您还可以查看此处,它提供了更多的见解。

    虽然此链接可以回答问题,但最好在此处包含答案的基本部分,并提供链接以供参考。如果链接页面发生更改,仅链接的答案可能无效。-@KrzysztofAtłasik,对不起,我不知道。试着用更多的解释来给他指出正确的方向。请用你提供的资料加上一个例子,你肯定会得到公认的答案+从meDone,我只是希望帮助更多和我有同样问题的人,不管是否被接受都无关紧要。干杯。当然,我只是想解释一下为什么有些人投了反对票。不管怎样,干得好!