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

Spring Boot+Kotlin接口报错:未传createdAt致JSON解析失败

问题

近期学习用Kotlin和Spring Boot构建REST API,创建领域模型与控制器接口时遇到问题,相关代码与表结构如下:

模型代码(/model/Country.kt)

package com.example.example.model

import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.sql.Timestamp


@Entity
@Table(name = "country")
class Country (
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "country_id")
    val id: Int,
    val code: String,
    val displayName: String,

    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    val createdAt: Timestamp,

    @LastModifiedDate
    @Column(name = "updated_at", nullable = false)
    val updatedAt: Timestamp
)

控制器代码(/controller/CountryController.kt)

package com.example.example.controller

import com.example.example.model.Country
import com.example.example.repository.CountryRepository
import jakarta.validation.Valid
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.web.bind.annotation.RequestBody
import org.springframework.web.bind.annotation.RestController

import org.springframework.http.MediaType
import org.springframework.web.bind.annotation.PostMapping

@RestController
class CountryController {

    @Autowired
    lateinit var countryRepository: CountryRepository

    @PostMapping("/countries", consumes = arrayOf(MediaType.APPLICATION_JSON_VALUE))
    fun createCountry(@Valid @RequestBody country: Country): Country {
        return countryRepository.save(country);
    }
}

Country表结构

country_id INT(10) UNSIGNED NOT NULL AUTO_INCREMENT,
  code VARCHAR(3) NOT NULL,
  displayName VARCHAR(40) NOT NULL,
  created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP,
  updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
  PRIMARY KEY (country_id)

错误情况

运行Spring Boot应用后,用Postman调用POST /countries接口时收到400 Bad Request错误,日志提示:

2023-01-12T14:09:15.423Z  WARN 90037 --- [nio-8080-exec-3] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Instantiation of [simple type, class com.example.example.model.Country] value failed for JSON property createdAt due to missing (therefore NULL) value for creator parameter createdAt which is a non-nullable type]

请求体仅包含{"code": "FRA", "displayName": "France"},请求头Content-Type设置正确。曾尝试给createdAt和updatedAt添加@JsonIgnore注解,仍返回相同错误。需求是让这两个字段由Spring Boot调用仓库方法或MySQL自动填充,无需请求体传入。

解决方案

1. 调整实体类的构造器参数配置

Kotlin主构造器参数默认不可空,Jackson反序列化时会要求JSON包含所有参数值,但id、createdAt、updatedAt属于框架/数据库自动生成字段,无需请求传入。需将这些参数改为可空类型并设置默认值,同时通过Jackson注解控制序列化规则:

修改后的Country类:

package com.example.example.model

import com.fasterxml.jackson.annotation.JsonIgnoreProperties
import jakarta.persistence.Column
import jakarta.persistence.Entity
import jakarta.persistence.EntityListeners
import jakarta.persistence.GeneratedValue
import jakarta.persistence.GenerationType
import jakarta.persistence.Id
import jakarta.persistence.Table
import org.springframework.data.annotation.CreatedDate
import org.springframework.data.annotation.LastModifiedDate
import org.springframework.data.jpa.domain.support.AuditingEntityListener
import java.sql.Timestamp

@Entity
@Table(name = "country")
@JsonIgnoreProperties(value = ["createdAt", "updatedAt"], allowGetters = true)
class Country (
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    @Column(name = "country_id")
    val id: Int? = null,
    val code: String,
    val displayName: String,

    @CreatedDate
    @Column(name = "created_at", nullable = false, updatable = false)
    val createdAt: Timestamp? = null,

    @LastModifiedDate
    @Column(name = "updated_at", nullable = false)
    val updatedAt: Timestamp? = null
)
  • @JsonIgnoreProperties(value = ["createdAt", "updatedAt"], allowGetters = true):告知Jackson反序列化时忽略这两个字段(不要求JSON传入),但序列化返回响应时保留它们。
  • 给id、createdAt、updatedAt设置可空类型和默认值null,让Jackson能通过Kotlin自动生成的可选参数构造器实例化对象。

2. 启用Spring Data JPA审计功能

要让@CreatedDate和@LastModifiedDate自动生效,需在Spring Boot启动类上添加@EnableJpaAuditing注解:

package com.example.example

import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.boot.runApplication
import org.springframework.data.jpa.repository.config.EnableJpaAuditing

@SpringBootApplication
@EnableJpaAuditing
class ExampleApplication

fun main(args: Array<String>) {
    runApplication<ExampleApplication>(*args)
}

该注解会激活审计机制,自动填充标注的时间字段。

3. 可选:依赖MySQL默认值填充(替代方案)

如果希望完全由数据库处理时间字段,可以调整实体类配置,让JPA不干预这些字段的生成:

  • 移除@CreatedDate和@LastModifiedDate注解
  • 设置字段的insertable = false和updatable = false,告知JPA插入/更新时不处理这些字段,交由数据库默认值处理

修改后的时间字段部分:

@Column(name = "created_at", nullable = false, updatable = false, insertable = false)
val createdAt: Timestamp? = null,

@Column(name = "updated_at", nullable = false, insertable = false, updatable = false)
val updatedAt: Timestamp? = null

这种方式无需启用@EnableJpaAuditing,完全依赖数据库的默认值和更新触发器。

4. 验证效果

重新启动应用后,用Postman发送POST /countries请求,请求体为{"code": "FRA", "displayName": "France"},接口应返回200 OK,响应体中会包含自动填充的id、createdAt和updatedAt字段。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 20:40:46