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

如何在Akka Scala应用中用Json4s提取并转换含日期的Case Class?

嘿,我来帮你搞定这个Akka Scala里的JSON解析问题!你要把REST接口的JSON响应映射到带Date类型的Case Class,用Circe配合Akka HTTP是个非常顺畅的方案,下面是完整的可运行实现步骤:

1. 先添加必要的依赖

首先在你的build.sbt里引入Akka HTTP、Circe以及两者的整合库,这些是实现功能的基础:

libraryDependencies ++= Seq(
  "com.typesafe.akka" %% "akka-http" % "10.5.0",
  "com.typesafe.akka" %% "akka-stream" % "2.8.5",
  "io.circe" %% "circe-core" % "0.14.6",
  "io.circe" %% "circe-generic" % "0.14.6",
  "io.circe" %% "circe-parser" % "0.14.6",
  "de.heikoseeberger" %% "akka-http-circe" % "1.39.2"
)

注意:版本号可以根据你使用的Scala版本调整,确保Akka和Circe的版本兼容。

2. 定义Case Class和自定义日期解析器

Circe默认不支持java.util.Date的解析,所以我们需要自定义解码器来处理JSON里的日期字符串,同时自动生成Case Class的解析器:

import java.text.SimpleDateFormat
import java.util.Date
import io.circe._
import io.circe.generic.semiauto._
import de.heikoseeberger.akkahttpcirce.FailFastCirceSupport._
import akka.actor.ActorSystem
import akka.http.scaladsl.Http
import akka.http.scaladsl.model._
import akka.stream.ActorMaterializer
import scala.concurrent.Future
import scala.concurrent.duration._

// 定义匹配JSON的日期格式:"2018-02-13T16:59:59.570+0000"
// 用ThreadLocal包装SimpleDateFormat,避免线程安全问题
private val dateFormat = new ThreadLocal[SimpleDateFormat] {
  override def initialValue(): SimpleDateFormat = 
    new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSSZ")
}

// 自定义Date类型的Circe解码器
implicit val dateDecoder: Decoder[Date] = Decoder.decodeString.emap { str =>
  try {
    Right(dateFormat.get.parse(str))
  } catch {
    case e: Exception => Left(s"Invalid date format: $str, expected format is yyyy-MM-dd'T'HH:mm:ss.SSSZ")
  }
}

// 自动生成FinishedRun的解码器(会自动复用上面的Date解码器)
implicit val finishedRunDecoder: Decoder[FinishedRun] = deriveDecoder[FinishedRun]

// 你的目标Case Class
case class FinishedRun(id: String, createdAt: Date, finishedAt: Date)
3. 编写Akka HTTP客户端调用并解析响应

接下来是调用REST接口、获取响应并解析成FinishedRun的完整代码:

object RestClient extends App {
  // 初始化Akka系统和流材料器
  implicit val system: ActorSystem = ActorSystem("FinishedRunClient")
  implicit val materializer: ActorMaterializer = ActorMaterializer()
  implicit val executionContext = system.dispatcher

  // 替换成你要调用的REST接口URL
  val apiUrl = "http://your-target-api/finished-run"

  // 发送GET请求并处理响应
  val requestFuture: Future[FinishedRun] = Http().singleRequest(HttpRequest(uri = apiUrl))
    .flatMap { response =>
      response.status match {
        case StatusCodes.Success(_) =>
          // 将响应实体转为严格字符串,超时时间设为5秒
          response.entity.toStrict(5.seconds).map(_.data.decodeString("UTF-8"))
            .flatMap { jsonStr =>
              io.circe.parser.decode[FinishedRun](jsonStr) match {
                case Right(run) => Future.successful(run)
                case Left(parseError) => Future.failed(new RuntimeException(s"JSON解析失败: ${parseError.getMessage}"))
              }
            }
        case otherStatus =>
          Future.failed(new RuntimeException(s"请求失败,状态码: $otherStatus"))
      }
    }

  // 处理最终结果
  requestFuture.onComplete {
    case scala.util.Success(run) =>
      println("成功解析FinishedRun:")
      println(s"ID: ${run.id}")
      println(s"创建时间: ${dateFormat.get.format(run.createdAt)}")
      println(s"完成时间: ${dateFormat.get.format(run.finishedAt)}")
      system.terminate()
    case scala.util.Failure(error) =>
      println(s"出错了: ${error.getMessage}")
      system.terminate()
  }
}
4. 优化建议

如果你用的是Java 8+,非常推荐把java.util.Date换成java.time.Instant或LocalDateTime,因为Java 8的日期API是不可变且线程安全的,代码会更健壮:

import java.time.Instant
import java.time.format.DateTimeFormatter

// 线程安全的DateTimeFormatter
private val instantFormatter = DateTimeFormatter.ofPattern("yyyy-MM-dd'T'HH:mm:ss.SSSZ")

implicit val instantDecoder: Decoder[Instant] = Decoder.decodeString.emap { str =>
  try {
    Right(Instant.from(instantFormatter.parse(str)))
  } catch {
    case e: Exception => Left(s"Invalid instant format: $str")
  }
}

// 更新后的Case Class
case class FinishedRun(id: String, createdAt: Instant, finishedAt: Instant)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.25 06:26:43