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

如何在Spring Boot控制器中通过JSON请求体传递Google Calendar Event对象?

如何在Spring Boot控制器中通过JSON请求体传递Google Calendar Event对象?

我来帮你解决这个问题!你遇到的400错误,本质原因是Google官方的com.google.api.services.calendar.model.Event类并不是为Jackson的序列化/反序列化设计的——它没有无参构造器,也没有Jackson相关的注解支持,所以Spring没法自动把你的JSON请求体转换成这个对象。下面给你两种可行的解决方案,都能满足你少依赖的需求:

方案一:自定义DTO(推荐)

这种方法最直接,也最容易维护,不需要额外依赖,完全由你控制数据转换过程。

步骤1:创建和请求JSON匹配的DTO类

先定义一个和你传入的JSON结构一致的Scala case class(因为你用的是Scala的Spring Boot):

// 嵌套的日期时间DTO,对应JSON里的start/end对象
case class EventDateTimeRequest(dateTime: String, timeZone: String)

// 顶层的事件请求DTO
case class CalendarEventRequest(
  summary: String,
  location: String,
  description: String,
  start: EventDateTimeRequest,
  end: EventDateTimeRequest
)

步骤2:在控制器中接收DTO并转换为Google Event

修改你的控制器方法,先接收自定义的DTO,再手动把它转换成Google的Event对象:

@PostMapping(path = Array("/calendar/event"))
def addEvent(@RequestBody request: CalendarEventRequest): Unit = {
  // 构建Google Event对象
  val googleEvent = new com.google.api.services.calendar.model.Event()
    .setSummary(request.summary)
    .setLocation(request.location)
    .setDescription(request.description)
  
  // 处理start字段
  val startDateTime = new com.google.api.services.calendar.model.EventDateTime()
    .setDateTime(new DateTime(request.start.dateTime))
    .setTimeZone(request.start.timeZone)
  googleEvent.setStart(startDateTime)
  
  // 处理end字段
  val endDateTime = new com.google.api.services.calendar.model.EventDateTime()
    .setDateTime(new DateTime(request.end.dateTime))
    .setTimeZone(request.end.timeZone)
  googleEvent.setEnd(endDateTime)
  
  // 这里写你添加日历事件的业务逻辑,比如调用Google Calendar API
  // ...
}

这种方法的好处是:完全避免了Google类的序列化限制,你可以灵活控制数据校验和转换逻辑,后续如果请求结构变化,只需要修改DTO即可。

方案二:用@JsonComponent自定义序列化/反序列化器

如果你一定要在控制器中直接接收com.google.api.services.calendar.model.Event对象,可以通过Jackson的自定义处理器来实现,用@JsonComponent让Spring自动识别这个处理器。

步骤1:创建自定义的JSON处理器

编写一个包含序列化器和反序列化器的类,用@JsonComponent注解标记:

import com.fasterxml.jackson.core.{JsonGenerator, JsonParser}
import com.fasterxml.jackson.databind.{DeserializationContext, JsonDeserializer, JsonSerializer, SerializerProvider}
import com.google.api.services.calendar.model.{Event, EventDateTime}
import org.springframework.boot.jackson.JsonComponent

@JsonComponent
class GoogleCalendarEventJsonHandler {

  // 反序列化器:将JSON转换为Google Event对象
  class EventDeserializer extends JsonDeserializer[Event] {
    override def deserialize(p: JsonParser, ctxt: DeserializationContext): Event = {
      val node = p.getCodec.readTree(p)
      val event = new Event()
        .setSummary(node.get("summary").asText())
        .setLocation(node.get("location").asText())
        .setDescription(node.get("description").asText())
      
      // 解析start字段
      val startNode = node.get("start")
      val startDateTime = new EventDateTime()
        .setDateTime(new DateTime(startNode.get("dateTime").asText()))
        .setTimeZone(startNode.get("timeZone").asText())
      event.setStart(startDateTime)
      
      // 解析end字段
      val endNode = node.get("end")
      val endDateTime = new EventDateTime()
        .setDateTime(new DateTime(endNode.get("dateTime").asText()))
        .setTimeZone(endNode.get("timeZone").asText())
      event.setEnd(endDateTime)
      
      event
    }
  }

  // 序列化器:将Google Event对象转换为JSON(如果需要返回Event给前端的话)
  class EventSerializer extends JsonSerializer[Event] {
    override def serialize(value: Event, gen: JsonGenerator, serializers: SerializerProvider): Unit = {
      gen.writeStartObject()
      gen.writeStringField("summary", value.getSummary)
      gen.writeStringField("location", value.getLocation)
      gen.writeStringField("description", value.getDescription)
      
      // 序列化start字段
      gen.writeObjectFieldStart("start")
      gen.writeStringField("dateTime", value.getStart.getDateTime.toString)
      gen.writeStringField("timeZone", value.getStart.getTimeZone)
      gen.writeEndObject()
      
      // 序列化end字段
      gen.writeObjectFieldStart("end")
      gen.writeStringField("dateTime", value.getEnd.getDateTime.toString)
      gen.writeStringField("timeZone", value.getEnd.getTimeZone)
      gen.writeEndObject()
      
      gen.writeEndObject()
    }
  }
}

步骤2:修改控制器直接接收Event对象

现在你的控制器就可以直接用com.google.api.services.calendar.model.Event作为请求体参数了:

@PostMapping(path = Array("/calendar/event"))
def addEvent(@RequestBody event: com.google.api.services.calendar.model.Event): Unit = {
  // 直接使用event对象执行业务逻辑
  // ...
}

这种方法的注意点是:你需要手动处理Event类的所有字段解析,如果Google后续更新了Event类的结构,你可能需要同步修改这个处理器,维护成本比DTO方案高一些。

总结

如果追求简单易维护,方案一的自定义DTO是首选,它不需要处理第三方类的内部细节,依赖最少;如果控制器代码需要更简洁,可以选择方案二,但要注意后续的维护成本。

备注:内容来源于stack exchange,提问作者Jackie

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.04.22 16:03:03