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

如何为Akka HTTP添加自定义编组器?Scala与Akka HTTP新手求助

给Java.Util.Currency添加Akka HTTP自定义编组器(基于spray-json)

作为刚接触Scala和Akka HTTP的新手,要给Java自带的Currency类做序列化/反序列化确实得搞点自定义逻辑——毕竟spray-json默认不支持这个类。我来一步步给你讲怎么实现:

1. 确认依赖(你已经加了,但再核对下)

确保你的build.sbt里已经引入了Akka HTTP和spray-json的桥接依赖:

"com.typesafe.akka" %% "akka-http-spray-json" % "10.0.10"

2. 编写Currency的spray-json格式器

spray-json需要我们为每一个非默认支持的类型实现JsonFormat接口,用来定义序列化和反序列化规则。Currency核心标识是它的货币代码(比如USD、EUR),所以我们可以基于这个字符串来做转换:

import java.util.Currency
import spray.json._

// 定义一个协议特质,把格式器封装进去
trait CurrencyJsonProtocol extends DefaultJsonProtocol {
  implicit val currencyFormat: JsonFormat[Currency] = new JsonFormat[Currency] {
    // 序列化:把Currency对象转成JSON字符串(用它的货币代码)
    override def write(currency: Currency): JsValue = 
      JsString(currency.getCurrencyCode)
    
    // 反序列化:从JSON字符串解析出Currency实例
    override def read(json: JsValue): Currency = json match {
      case JsString(code) => Currency.getInstance(code)
      case invalid => deserializationError(s"Expected currency code string, got $invalid")
    }
  }
}

3. 在Akka HTTP路由里集成这个格式器

要让Akka HTTP能识别我们的自定义格式器,需要导入SprayJsonSupport._(这是Akka HTTP和spray-json的桥接工具),同时让路由类继承刚才的协议特质,把格式器引入作用域:

import akka.http.scaladsl.server.Directives._
import akka.http.scaladsl.marshallers.sprayjson.SprayJsonSupport._

// 继承协议特质,让格式器在路由里可用
class CurrencyController extends CurrencyJsonProtocol {
  def getCurrencyExample: Route = {
    path("currencyExample") {
      val currency: Currency = Currency.getInstance("USD")
      // 直接返回Currency对象,Akka HTTP会自动用我们的格式器序列化它
      complete(currency)
    }
  }

  // 额外给你加个列表的例子,spray-json会自动基于单个格式器生成列表格式器
  def getCurrencyListExample: Route = {
    path("currencyList") {
      val currencies = List(Currency.getInstance("USD"), Currency.getInstance("EUR"))
      complete(currencies)
    }
  }
}

4. 处理反序列化(接收包含Currency的请求)

如果需要接收包含Currency的JSON请求(比如POST接口),只需要在协议里给对应的case class添加格式器就行:

// 先定义请求体的case class
case class CurrencyRequest(currency: Currency, amount: Double)

// 在刚才的CurrencyJsonProtocol里添加case class的格式器
trait CurrencyJsonProtocol extends DefaultJsonProtocol {
  implicit val currencyFormat: JsonFormat[Currency] = ... // 之前的代码
  // 用jsonFormat2生成case class的格式器(数字对应参数个数)
  implicit val currencyRequestFormat: RootJsonFormat[CurrencyRequest] = jsonFormat2(CurrencyRequest)
}

// 路由里的POST接口示例
class CurrencyController extends CurrencyJsonProtocol {
  // ... 之前的get接口

  def postCurrencyExample: Route = {
    path("currencyRequest") {
      post {
        // 自动把请求体反序列化成CurrencyRequest对象
        entity(as[CurrencyRequest]) { request =>
          complete(s"收到请求:货币${request.currency.getCurrencyCode},金额${request.amount}")
        }
      }
    }
  }
}

这样客户端发送{"currency": "USD", "amount": 100.0}这样的JSON,就能被正确解析成CurrencyRequest实例了。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 09:39:31