You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Scala Akka HTTP中使用Spray JSON对嵌套Seq集合编解码的最佳方案

Akka HTTP结合Spray JSON实现Bid请求响应序列化/反序列化最佳方案

错误根因

你当前运行报错的核心原因是Spray JSON提供的jsonFormatN系列方法,后缀数字N必须和对应样例类的构造参数数量完全一致,你现在所有格式定义都写了jsonFormat1,和你定义的样例类参数数量完全不匹配,所以会触发类型不匹配错误。

正确的隐式JSON格式定义

注意隐式值的定义顺序:必须先定义被依赖的样例类的JSON格式,再定义上层依赖的格式,你用到的Option、Seq、List这些集合类型,DefaultJsonProtocol已经提供了默认序列化实现,不需要额外处理。

import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport
import spray.json.DefaultJsonProtocol

// 统一在一个Trait里管理所有JSON格式,方便后续复用
trait JsonProtocol extends SprayJsonSupport with DefaultJsonProtocol {
  // 先定义最底层依赖的样例类格式
  implicit val geoFormat = jsonFormat1(Geo) // Geo只有1个参数,对应jsonFormat1
  implicit val userFormat = jsonFormat2(User) // User有2个参数:id、geo
  implicit val deviceFormat = jsonFormat2(Device) // Device有2个参数:id、geo
  implicit val impressionFormat = jsonFormat8(Impression) // Impression共8个构造参数
  implicit val siteFormat = jsonFormat2(Site) // Site有2个参数:id、domain
  implicit val bannerFormat = jsonFormat4(Banner) // Banner有4个参数:id、src、width、height
  implicit val targetingFormat = jsonFormat1(Targeting) // Targeting仅1个参数
  implicit val campaignFormat = jsonFormat5(Campaign) // Campaign共5个参数
  implicit val bidRequestFormat = jsonFormat5(BidRequest) // BidRequest共5个参数
  implicit val bidResponseFormat = jsonFormat5(BidResponse) // BidResponse共5个参数
}

完整业务流程实现

1. 嵌套Seq转BidRequest逻辑

你需要把activeUsers嵌套Seq里的Campaign数据,按照业务规则映射为BidRequest字段,参考实现如下:

// 继承JsonProtocol拿到所有隐式格式
object BidService extends JsonProtocol {
  // 从Campaign生成BidRequest,可根据实际业务规则调整字段赋值
  def campaignToBidRequest(campaign: Campaign): BidRequest = {
    BidRequest(
      id = campaign.id.toString,
      imp = Some(List(Impression(
        id = "imp_"+campaign.id,
        wmin = Some(campaign.banners.head.width),
        wmax = Some(campaign.banners.head.width),
        w = Some(campaign.banners.head.width),
        hmin = Some(campaign.banners.head.height),
        hmax = Some(campaign.banners.head.height),
        h = Some(campaign.banners.head.height),
        bidFloor = Some(campaign.bid)
      ))),
      site = Site(id = campaign.id, domain = campaign.targeting.targetedSiteIds.head),
      user = Some(User(id = "user_"+campaign.id, geo = Some(Geo(Some(campaign.country))))),
      device = None
    )
  }

  // 业务计算后生成BidResponse
  def calculateBidResponse(bidRequest: BidRequest, campaign: Campaign): BidResponse = {
    BidResponse(
      id = "resp_"+bidRequest.id,
      bidRequestId = bidRequest.id,
      price = campaign.bid,
      adid = Some(campaign.id.toString),
      banner = Some(campaign.banners.head)
    )
  }
}

2. Akka HTTP路由中使用序列化/反序列化

import akka.actor.typed.ActorSystem
import akka.actor.typed.scaladsl.Behaviors
import akka.http.scaladsl.Http
import akka.http.scaladsl.server.Directives._
import scala.io.StdIn

object BidServer extends App with JsonProtocol {
  implicit val system = ActorSystem(Behaviors.empty, "bid-system")
  implicit val executionContext = system.executionContext

  val route =
    path("bid") {
      post {
        // 自动将请求体反序列化为BidRequest
        entity(as[BidRequest]) { bidRequest =>
          // 业务计算逻辑,此处替换为实际的流量匹配规则
          val matchedCampaign = activeUsers.head
          val bidResponse = BidService.calculateBidResponse(bidRequest, matchedCampaign)
          // 自动将BidResponse序列化为JSON返回
          complete(bidResponse)
        }
      }
    }

  val bindingFuture = Http().newServerAt("localhost", 8080).bind(route)
  println(s"Server online at http://localhost:8080/\nPress RETURN to stop...")
  StdIn.readLine()
  bindingFuture.flatMap(_.unbind()).onComplete(_ => system.terminate())
}

注意事项

  • 所有样例类如果后续新增/减少构造参数,必须同步修改对应的jsonFormatN的后缀数字,否则会报编译或运行错误
  • 如果有自定义字段映射需求(比如Scala字段名是驼峰,JSON要下划线格式),可以用jsonFormat的命名版本,比如implicit val geoFormat = jsonFormat(Geo, "country_code")来自定义JSON字段名
  • 对于可选字段如果序列化时不想输出null,可以自定义格式或者用NullOptions特质扩展你的Protocol

内容的提问来源于stack exchange,提问作者Vakindu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 15:45:03