如何使用 R2dbc 将 jsonb 从 Postgresql 提取到 Spring webflux

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 就足够了吗?

谢谢你的时间!

mp9*_*1de 8

更新:请升级到 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)

请注意,当您想要绑定SELECTINSERT或 的JSON 值时UPDATE,您必须使用驱动程序Json类型或将绑定值强制转换$1::JSON为 JSON。

如果您想使用 GSON 或 Jackson 在驱动程序级别映射序列化/反序列化值,您还可以利用JsonCodec驱动程序提供自己的实现。CodecRegistrar

参考:


ant*_*ar9 8

正如@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)

参考: