3

所以我真的有这个想法,因为我只编程了一小段时间,但我想构建一个反应式 Spring webflux 应用程序,将 json 端点暴露给反应前端。

当我决定在 Postgres 中使用 jsonb 格式时,问题就开始了,因为我认为我可能会一直使用 json 从数据库一直到前端层。

当我尝试使用反应式 R2dbc 驱动程序使用 jsonb 选择表时,我收到以下错误:

Caused by: java.lang.IllegalArgumentException: 3802 is not a valid object id

我在 postgres 中有一个如下所示的表:

Column  |  Type   | Collation | Nullable |           Default
---------+---------+-----------+----------+------------------------------
 id      | integer |           | not null | generated always as identity
 details | jsonb   |           |          |
Indexes:
    "snacks_new_pkey" PRIMARY KEY, btree (id)

因此,如果我将其作为文本提取到 Spring webflux 它工作正常,因为它不再是 json。

"SELECT id, details->>'name' as NAME, details->>'price' AS PRICE, details->>'quantity' AS QUANTITY FROM snacks_new"

我已经看到了一些关于如何使用较旧的阻塞驱动程序将 jsonb 转换为 json 对象的示例,但是我无法与较新的非阻塞驱动程序一起使用,我无法以任何方式访问它们。

所以我真的有 2 个问题,如何使用响应式驱动程序选择包含 jsonb 的表,我是否在浪费时间尝试这样做,将 json 提取为文本并从中创建一个正常的 POJO 就足够了吗?

谢谢你的时间!

4

3 回答 3

5

更新:请升级到 R2DBC Postgres 0.8.0.RC1。

该驱动程序最近添加了对 JSON 和 JSONB 类型的支持。您可以使用 JSON 作为Stringbyte[]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()

请注意,当您想为 a或绑定 JSON 值时SELECT,您必须使用驱动程序类型或将绑定值转换为 JSON。INSERTUPDATEJson$1::JSON

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

参考:

于 2019-09-28T14:06:00.513 回答
1

更新:

截至撰写本文时(2019 年 9 月 15 日),他们不支持 JSON,但现在他们支持 0.8.0 及更高版本的 JSON

老答案:

我很遗憾地说,我认为你是,正如你所说的,在浪费你的时间

在查看 R2DBC 驱动程序的github时,您可以在他们的表中看到他们支持的内容,该 json 截至目前,不支持

于 2019-09-15T09:55:23.183 回答
1

正如@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("");
    }
}
}

参考:

于 2021-11-19T23:06:04.250 回答