akka 如何在Scala中从Http响应实体中解编集自定义对象?

c9x0cxw0  于 2022-11-23  发布在  Scala
关注(0)|答案(1)|浏览(227)

我试图通过Scala中的akka库从本地服务器检索一些数据。数据以JSON格式从服务器返回,但我无法以自定义类型解组它们。
自定义类是"配置文件",其中包含配置文件列表。

case class Profile(
    Name: String,
    Surname: String,
    Mail: String,
    Age: Int,
    Town: String,

    Role: String,
    PrimaryInstr: String,
    SecondaryInstr: String,
    PrimaryGenre: String,
    SecondaryGenre: String,
    Influences: String,
    RecordLabel: String,
    GigAvailability: String,
    RehearseAvailability: String,
    RecordingExperience: String,
    MusicalAge: Int)

  case class Profiles(profiles: Vector[Profile])

我尝试用下面的代码解组到配置文件,但由于错误而无法编译
找不到参数um的隐式值:解组。解组器[响应实体,配置文件]

import akka.http.scaladsl.Http
import akka.http.scaladsl.unmarshalling.Unmarshal
import akka.http.scaladsl.client.RequestBuilding.Get
import akka.http.scaladsl.model.HttpResponse

... 

def getProfiles = {
        var req = Get("http://localhost:9090/profiles")
        val responseFuture: Future[HttpResponse] = Http().singleRequest(req)
        responseFuture
          .onComplete {
            case Success(response) =>
              println(response.entity)
              //Here I want actually Unmarshall to Profiles, not to String
              var responseAsString = Unmarshal(response.entity).to[String] //Tried here with Profiles
              println(responseAsString)
            case Failure(_)   => sys.error("something wrong")
          }
           ...
      }

使用[String]解组代码将生成以下输出(缩写为..."")。
HttpEntity. Strict(application/json,[{"姓名":"阿玛迪斯","姓氏":"拉皮萨尔达",...,"音乐年龄":9},{"姓名":"费德里科","姓氏":"安布罗西奥",...,"音乐年龄":24}])FulfilledFuture([{"姓名":"阿玛迪斯","姓氏":"拉皮萨尔达",...,"音乐年龄":9},{"姓名":"费德里科","姓氏":"安布罗西奥",...,"音乐年龄":24}])
我如何才能获得一个配置文件对象?提前感谢!

h79rfbju

h79rfbju1#

我终于找到了一个很好的解决办法。
1 -在build.sbt文件中添加这些依赖项

val AkkaVersion = "2.6.9"
val AkkaHttpVersion = "10.2.0"
libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-actor-typed" % AkkaVersion,
  "com.typesafe.akka" %% "akka-stream" % AkkaVersion,
  "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion,
  "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion
)

2 -将这些导入添加到文件中

import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.http.scaladsl.client.RequestBuilding.Get
import akka.http.scaladsl.model.{HttpResponse, StatusCodes}
import akka.http.scaladsl.unmarshalling.Unmarshal

import scala.util.{Failure, Success}
// for JSON serialization/deserialization following dependency is required:
// "com.typesafe.akka" %% "akka-http-spray-json" % "10.1.7"
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._
import spray.json.DefaultJsonProtocol._

import scala.concurrent.Future

3 -定义您的自定义模型(在我的示例中,仅限Profile模型)

final case class Profile(
                      Name: String,
                      Surname: String,
                      Mail: String,
                      Age: Int,
                      Town: String,

                      Role: String,
                      PrimaryInstr: String,
                      SecondaryInstr: String,
                      PrimaryGenre: String,
                      SecondaryGenre: String,
                      Influences: String,
                      RecordLabel: String,
                      GigAvailability: String,
                      RehearseAvailability: String,
                      RecordingExperience: String,
                      MusicalAge: Int)

4 -定义自定义“解组程序”:计算自定义模型的属性个数,比如***n***,使用jsonFormat***n***(yourCustomType),这样我们就有16个属性--〉

implicit val profileFormat = jsonFormat16(Profile)

5 - make http请求。确保你的响应包含一个JSON对象或一个与你的模型匹配的JSON对象数组。使用下面的代码来检索响应并将其转换成你的自定义模型。

def getProfiles = {
    
    //Make request
    var req = Get("http://localhost:9090/profiles")
    
    //Save Response in a Future object
    val responseFuture: Future[HttpResponse] = Http().singleRequest(req)
    
    //When the Future is fulfilled
    responseFuture.onComplete {

        case Success(response) =>
          //Here your code if there is a response
          
          //Convert your response body (response.entity) in a profile array. Note that it is a Future object
          var responseAsProfiles: Future[Array[Profile]]= Unmarshal(response.entity).to[Array[Profile]]
          
          //When the Future is fulfilled
          responseAsProfiles.onComplete{

            _.get match {

              case profiles: Array[Profile] => 
                //If response was a array of Profiles you can work with profiles
                profiles.foreach[Profile] { profile =>
                  println(profile)
                  profile
                }

              case _ => println("error")
            }

          }

        case Failure(_)   => 
          //Here your code if there is not a response
          sys.error("something wrong")
      }
}

希望这能对某人有所帮助!再见!

相关问题