[英]How to extract jsonb from Postgresql to Spring webflux using R2dbc
所以我有這個想法真的超出了我的頭腦,因為我只編程了很短的時間,但我想構建一個反應式 Spring webflux 應用程序,將 json 端點暴露給一個反應前端。
當我決定在 Postgres 中使用 jsonb 格式時,問題就開始了,因為我認為我可能會從 DB 到前端層一直使用 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 對象的示例,但我無法使用較新的非阻塞驅動程序,我無法以任何方式訪問它們。
所以我真的有兩個問題,如何使用反應驅動程序選擇包含 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()
請注意,當您想為SELECT
、 INSERT
或UPDATE
綁定 JSON 值時,您必須使用驅動程序Json
類型或將綁定值與$1::JSON
為 JSON。
如果您想使用 GSON 或 Jackson 在驅動程序級別映射序列化/反序列化值,您還可以利用驅動程序的CodecRegistrar
提供您自己的JsonCodec
實現。
參考:
更新:
截至撰寫本文時(2019 年 9 月 15 日),他們不支持 JSON,但現在他們確實支持 0.8.0 及更高版本的 JSON
舊答案:
我很抱歉地說,正如你所說,我認為你是在浪費時間。
在查看 R2DBC 驅動程序的github 時,您可以在他們的表中看到它們支持的內容,該 json 是截至目前,不支持。
正如@mp911de所解釋的那樣,R2DBC 現在包含一個用於Json的編解碼器。 但是將您的實體屬性定義為String
, byte[]
不是很舒服,類型io.r2dbc.postgresql.codec.Json
不是很便攜。 此外,如果您想在 REST API 中使用它,您需要定義一個自定義序列化器/反序列化器,如參考資料中所述。
一個更好的選擇是定義一個自定義轉換器io.r2dbc.postgresql.codec.Json
from/to JsonNode
並使用后面的類型作為您的屬性:
@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("");
}
}
}
參考:
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.