如何为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
相关产品推荐
相关产品推荐

