如何让JSON响应中实体属性createdAt显示为数据库列名created_at?
问题:如何让JSON响应使用数据库列名(如
created_at)而非实体属性名? 我在从数据库获取实体后序列化JSON响应时,希望输出的字段名使用数据库列名(比如created_at),但当前返回的是实体属性名createdAt。相关代码如下:
GET请求处理代码
get("/v1/posts") { val posts= service.getAll() val mapper: ObjectMapper = JsonMapper.builder() .addModule(JavaTimeModule()) .addModule(KtormModule()) .build() val json = mapper.writeValueAsString(posts) call.respond(HttpStatusCode.OK, json) }
当前JSON输出
{ "id": 1, "title": "Some Title", "description": "some text...", "createdAt": [ 2018, 9, 16, 1, 1, 36, 399357000 ] }
实体与表定义
interface Post: Entity<Post> { companion object : Entity.Factory<Post>() val id: Int var title: String var description: String var createdAt: LocalDateTime } object Posts: Table<Post>("posts") { val id = int("id").primaryKey().bindTo { it.id } val title = varchar("title").bindTo { it.title } val description = varchar("description").bindTo { it.description } val createdAt = datetime("created_at").bindTo { it.createdAt } } val Database.posts get() = this.sequenceOf(Posts)
Application配置
fun Application.module() { install(ContentNegotiation) { json() jackson { configure(SerializationFeature.INDENT_OUTPUT, true) setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) indentObjectsWith(DefaultIndenter(" ", "\n")) }) registerModule(JavaTimeModule()) // support java.time.* types configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) } } configureRouting() }
需要解决的是让JSON中的createdAt显示为created_at。
解决方案
方法1:全局配置Jackson蛇形命名策略
Jackson默认使用实体属性名,要自动将驼峰式转换为蛇形命名(如createdAt→created_at),只需在Application.kt的Jackson配置中添加命名策略:
fun Application.module() { install(ContentNegotiation) { json() jackson { configure(SerializationFeature.INDENT_OUTPUT, true) setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) indentObjectsWith(DefaultIndenter(" ", "\n")) }) registerModule(JavaTimeModule()) configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) // 启用蛇形命名策略 propertyNamingStrategy = PropertyNamingStrategies.SNAKE_CASE } } configureRouting() }
同时删除路由中手动创建的ObjectMapper,直接返回实体即可,Ktor会复用全局配置的Jackson:
get("/v1/posts") { val posts = service.getAll() call.respond(HttpStatusCode.OK, posts) }
此方法同时解决日期序列化为数组的问题,因为全局配置已正确处理Java时间类型。
方法2:为单个字段指定JSON别名
若无需全局修改命名策略,仅针对特定字段设置别名,可在实体属性上添加@JsonProperty注解:
interface Post: Entity<Post> { companion object : Entity.Factory<Post>() val id: Int var title: String var description: String @JsonProperty("created_at") var createdAt: LocalDateTime }
这种方式更灵活,适合仅需修改个别字段的场景。
方法3:利用Ktorm模块的列名序列化特性
Ktorm的KtormModule可根据表定义中的数据库列名序列化实体,只需将其注册到全局Jackson配置:
fun Application.module() { install(ContentNegotiation) { json() jackson { // 保留原有配置 configure(SerializationFeature.INDENT_OUTPUT, true) setDefaultPrettyPrinter(DefaultPrettyPrinter().apply { indentArraysWith(DefaultPrettyPrinter.FixedSpaceIndenter.instance) indentObjectsWith(DefaultIndenter(" ", "\n")) }) registerModule(JavaTimeModule()) configure(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS, false) // 注册Ktorm模块 registerModule(KtormModule()) } } }
路由代码直接返回实体,无需手动序列化:
get("/v1/posts") { val posts = service.getAll() call.respond(HttpStatusCode.OK, posts) }
Ktorm模块会自动匹配表定义中的列名,将createdAt序列化为created_at。
内容的提问来源于stack exchange,提问作者user21225362
相关产品推荐
相关产品推荐

