Xen*_*ono 8 java postgresql jsonb spring-webflux r2dbc
所以我有这个想法,这真的超出了我的想象,因为我只编程了很短一段时间,但我想构建一个反应式 Spring webflux 应用程序,将 json 端点暴露给反应前端。
当我决定在 Postgres 中使用 jsonb 格式时,问题就开始了,因为我认为我可能会从数据库一直到前端层一直使用 json。
当我尝试使用反应式 R2dbc 驱动程序使用 jsonb SELECT 表时,出现以下错误:
Caused by: java.lang.IllegalArgumentException: 3802 is not a valid object id
Run Code Online (Sandbox Code Playgroud)
我在 postgres 中有一个表,如下所示:
Column | Type | Collation | Nullable | Default
---------+---------+-----------+----------+------------------------------
id | integer | | not null | generated always as identity
details | jsonb | | |
Indexes:
"snacks_new_pkey" PRIMARY KEY, btree (id)
Run Code Online (Sandbox Code Playgroud)
因此,如果我将其作为文本提取到 Spring webflux,它就可以正常工作,因为它不再是 json。
"SELECT id, details->>'name' as NAME, details->>'price' AS PRICE, details->>'quantity' AS QUANTITY FROM snacks_new"
Run Code Online (Sandbox Code Playgroud)
我已经看到了一些关于如何使用旧的阻塞驱动程序将 jsonb 转换为 json 对象的示例,但我无法将其与较新的非阻塞驱动程序一起使用,我无法以任何方式访问它们。
所以我真的有两个问题,我如何使用反应式驱动程序选择一个包含 jsonb 的表,我是否在浪费时间尝试这样做,将 json 提取为文本并从中创建一个普通的 POJO 就足够了吗?
谢谢你的时间!
更新:请升级到 R2DBC Postgres 0.8.0.RC1。
该驱动程序最近添加了对 JSON 和 JSONB 类型的支持。您可以将 JSON 用作String,byte[]或io.r2dbc.postgresql.codec.Json键入:
// Read as Json
connection.createStatement("SELECT my_json FROM my_table")
.execute()
.flatMap(it -> it.map((row, rowMetadata) -> row.get("my_json", Json.class)))
.map(Json::asString)
// Read as String
connection.createStatement("SELECT my_json FROM my_table")
.execute()
.flatMap(it -> it.map((row, rowMetadata) -> row.get("my_json", String.class)))
// Write JSON
connection.createStatement("INSERT INTO my_table (my_json) VALUES($1)")
.bind("$1", Json.of("{\"hello\": \"world\"}"))
.execute()
// Write JSON as String using ::JSON casting
connection.createStatement("INSERT INTO my_table (my_json) VALUES($1::JSON)")
.bind("$1", "{\"hello\": \"world\"}")
.execute()
Run Code Online (Sandbox Code Playgroud)
请注意,当您想要绑定SELECT、INSERT或 的JSON 值时UPDATE,您必须使用驱动程序Json类型或将绑定值强制转换$1::JSON为 JSON。
如果您想使用 GSON 或 Jackson 在驱动程序级别映射序列化/反序列化值,您还可以利用JsonCodec驱动程序提供自己的实现。CodecRegistrar
参考:
正如@mp911de所解释的,R2DBC 现在包含Json的编解码器。但是将实体属性定义为String,byte[]并不是很舒服,并且类型io.r2dbc.postgresql.codec.Json不太可移植。此外,如果您想在 REST API 中使用自定义序列化器/反序列化器,则需要定义一个自定义序列化器/反序列化器(如参考文献中所述)。
一个更好的选择是定义一个自定义转换器io.r2dbc.postgresql.codec.Jsonfrom/toJsonNode并将此后一种类型用于您的属性:
@Configuration
public class ReactivePostgresConfig {
private final ObjectMapper objectMapper;
public ReactivePostgresConfig(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Bean
public R2dbcCustomConversions customConversions() {
List<Converter<?, ?>> converters = new ArrayList<>();
converters.add(new JsonToJsonNodeConverter(objectMapper));
converters.add(new JsonNodeToJsonConverter(objectMapper));
return R2dbcCustomConversions.of(PostgresDialect.INSTANCE, converters);
}
@ReadingConverter
static class JsonToJsonNodeConverter implements Converter<Json, JsonNode> {
private final ObjectMapper objectMapper;
public JsonToJsonNodeConverter(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public JsonNode convert(Json json) {
try {
return objectMapper.readTree(json.asString());
} catch (IOException e) {
LOG.error("Problem while parsing JSON: {}", json, e);
}
return objectMapper.createObjectNode();
}
}
@WritingConverter
static class JsonNodeToJsonConverter implements Converter<JsonNode, Json> {
private final ObjectMapper objectMapper;
public JsonNodeToJsonConverter(ObjectMapper objectMapper) {
this.objectMapper = objectMapper;
}
@Override
public Json convert(JsonNode source) {
try {
return Json.of(objectMapper.writeValueAsString(source));
} catch (JsonProcessingException e) {
LOG.error("Error occurred while serializing map to JSON: {}", source, e);
}
return Json.of("");
}
}
}
Run Code Online (Sandbox Code Playgroud)
参考:
| 归档时间: |
|
| 查看次数: |
9733 次 |
| 最近记录: |