如何基于配置的Locale/设置格式化jOOQ查询Trino返回的数字?
问题
我用jOOQ查询Trino数据库,希望在获取org.jooq.Result<org.jooq.Record>后调用formatJSON()时,org.jooq.Field<out Number>类型的字段能按照jOOQ配置的java.util.Locale自动格式化(比如Locale.US显示2,000,Locale.GERMANY显示2.000),不需要额外编写临时格式化代码。
目前已尝试通过Settings设置各类Locale参数,但未达到预期效果。示例代码如下:
val usSettings = Settings().apply { locale = Locale.US renderLocale = Locale.US parseLocale = Locale.US interpreterLocale = Locale.US } val dsl = org.jooq.impl.DSL.using(trinoDataSource, SQLDialect.TRINO, usSettings) val result = dsl .select(<Integer类型的Field>) .from(<表>) .fetch() .formatJSON()
当前返回的JSON结果中数字为原生数值:
{ "fields": [ { "schema": "the schema", "table": "the table", "name": "field name", "type": "INTEGER" } ], "records": [ { "field name": 2000 } // 期望得到"2,000" ] }
解决方案
核心原因
formatJSON()默认输出JSON原生数据类型,而JSON规范中的数字是无格式的数值,不会自动添加千分位分隔符。要实现本地化格式化,需要将数字转换为字符串类型输出。
方案1:查询阶段直接格式化字段
在查询时用jOOQ工具类或Trino原生函数将数字转成本地化字符串,formatJSON()会直接输出格式化后的结果:
val locale = Locale.US val formatter = NumberFormat.getNumberInstance(locale) val result = dsl .select( // 将数字字段格式化为字符串 DSL.val(formatter.format(<Integer类型的Field>)).as(<字段名>) ) .from(<表>) .fetch() .formatJSON()
如果Trino支持SQL原生格式化函数(如format_number),也可以直接调用:
val result = dsl .select( DSL.field("format_number({0}, 'N')", String::class.java, <Integer类型的Field>).as(<字段名>) ) .from(<表>) .fetch() .formatJSON()
方案2:自定义FormattingProvider实现全局配置
通过实现FormattingProvider接口,覆盖JSON格式化时的数字处理逻辑,实现全局自动格式化:
class LocaleAwareFormattingProvider(private val locale: Locale) : DefaultFormattingProvider() { private val numberFormatter = NumberFormat.getNumberInstance(locale) override fun formatValue(ctx: FormatContext, value: Any?) { if (value is Number) { // 将数字格式化为字符串后输出 ctx.format(numberFormatter.format(value)) } else { // 其他类型沿用默认处理逻辑 super.formatValue(ctx, value) } } }
构建DSLContext时注入该自定义Provider:
val locale = Locale.US val configuration = DefaultConfiguration() .set(trinoDataSource) .set(SQLDialect.TRINO) .set(Settings().apply { this.locale = locale }) .set(LocaleAwareFormattingProvider(locale)) val dsl = DSL.using(configuration) val result = dsl .select(<Integer类型的Field>) .from(<表>) .fetch() .formatJSON()
此方案会让所有数字类型字段自动按指定Locale格式化为字符串输出。
注意事项
- 格式化后的数字会变为JSON字符串(带引号),若下游系统需要数值类型,此方案不适用。
- 若要保留JSON数值类型同时显示格式化效果,只能在前端展示阶段做本地化处理,因为JSON本身不支持带格式的数值。
内容的提问来源于stack exchange,提问作者Pablo Cavalieri
相关产品推荐
相关产品推荐

