【问题标题】:Json is stored as = instead of : colon in postgres DBJson 在 postgres DB 中存储为 = 而不是 : 冒号
【发布时间】:2021-06-20 12:51:34
【问题描述】:

我有一个 Gradle spring-boot 项目。我想在 postgres DB 列(规则)中存储一个 json,因此将列的类型定义为 TEXT。 当我通过邮递员点击保存端点时,我正在发送此数据

{
  "rules": {"key": "97773e0b-3639-4af5-9585-93bc176715c0", "fieldName": "esn", "operator": "eq", "operands": ["599320"]},
  "name": "user",
  "sso": "502622018",
  "ruleMatching": "ALL"
}

但是当我点击 GET 端点时,我得到的响应不是 json,而是一种字符串,其中 : 转换为 = 并且不存储引号。

{
    "id": 9,
    "name": "user",
    "ruleMatching": "ALL",
    "sso": "502622018",
    "rules": "{key=97773e0b-3639-4af5-9585-93bc176715c0, fieldName=esn, operator=eq, operands=[599320]}"
}

如何将rules 保存为 DB 中的正确 json 作为 TEXT 类型?有什么建议吗?

这里是Entity定义和dto定义

@SuppressWarnings("serial")
@Entity
@Getter @Setter @AllArgsConstructor @NoArgsConstructor
@Builder(toBuilder=true)
@Table(name="saved_filters")
@TypeDef(
        name = "jsonb",
        typeClass = JsonBinaryType.class
    )
public class SavedFilter implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="name")
    private String name;

  
    @Column(name="rule_matching")
    private String ruleMatching;
    
    
    @Column(name="rules", columnDefinition= "TEXT")
    private String rules;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_sso")
    private User user;

----DTO--

@SuppressWarnings("serial")
@Data
@Getter @Setter @AllArgsConstructor @NoArgsConstructor
@Builder(toBuilder=true)
public class SavedFilterDto implements Serializable {

    private int id;

    private String name;
    
    @JsonProperty("rules")
    private Object rules;
    
    private String ruleMatching;

    private String sso;      
    
}

将列更改为jsonb后,出现以下错误

RemoteUserContext --> ef227333-4629-4571-bf2f-210c64902eea
2021-03-23 23:42:23 [http-nio-9090-exec-1] DEBUG c.g.d.o.m.c.FilterController.createSavedFilter - Start...SavedFilterDto(id=0, name=user, rules={key=97773e0b-3639-4af5-9585-93bc176715c0, fieldName=esn, operator=eq, operands=[599320]}, ruleMatching=ALL, sso=502622018)
Hibernate: select user0_.sso as sso1_35_0_, user0_.email as email2_35_0_, user0_.first_name as first_na3_35_0_, user0_.hidden as hidden4_35_0_, user0_.last_name as last_nam5_35_0_, user0_.updated_at as updated_6_35_0_, user0_.user_id as user_id7_35_0_ from user_info user0_ where user0_.sso=?
Hibernate: insert into saved_filters (name, rule_matching, rules, user_sso) values (?, ?, ?, ?)
2021-03-23 23:42:24 [http-nio-9090-exec-1] ERROR c.g.d.o.m.e.GenericExceptionHandler.handleException - Application error
org.springframework.orm.jpa.JpaSystemException: java.lang.IllegalArgumentException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('k' (code 107)): was expecting double-quote to start field name
 at [Source: (String)"{key=97773e0b-3639-4af5-9585-93bc176715c0, fieldName=esn, operator=eq, operands=[599320]}"; line: 1, column: 3]; nested exception is org.hibernate.HibernateException: java.lang.IllegalArgumentException: com.fasterxml.jackson.core.JsonParseException: Unexpected character ('k' (code 107)): was expecting double-quote to start field name
 at [Source: (String)"{key=97773e0b-3639-4af5-9585-93bc176715c0, fieldName=esn, operator=eq, operands=[599320]}"; line: 1, column: 3]
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.convertHibernateAccessException(HibernateJpaDialect.java:351) ~[spring-orm-5.1.6.RELEASE.jar:5.1.6.RELEASE]
        at org.springframework.orm.jpa.vendor.HibernateJpaDialect.translateExceptionIfPossible(HibernateJpaDialect.java:253) ~[spring-orm-5.1.6.RELEASE.jar:5.1.6.RELEASE]

如果我更改私有对象规则;在 DTO 到私有字符串规则;..我收到以下错误:

2021-03-24 11:12:05 [http-nio-9090-exec-10] WARN  o.s.w.s.m.m.a.ExceptionHandlerExceptionResolver.logException - Resolved [org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token; nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot deserialize instance of `java.lang.String` out of START_OBJECT token
 at [Source: (PushbackInputStream); line: 2, column: 12] (through reference chain: com.ge.digital.oa.moa.dto.SavedFilterDto["rules"])]

【问题讨论】:

  • 您的rules 属性是String 类型。如果您希望 String 的值将 = 替换为其他字符(例如 :),则必须编写一些内容来获取 JSON 对象 {"key": "97773e0b-3639-4af5-9585-93bc176715c0", "fieldName": "esn", "operator": "eq", "operands": ["599320"]} 并将其转换为满足要求的 String你的要求。框架中没有任何内容可以假设您需要。
  • 我相信您有两个选择 - (1) 将 rules 转换为 jsonb 数据类型 (2) 将 rules 保持为 text 数据类型并使用 ObjectMapper 以编程方式编组/解组
  • 我已将该列转换为 jsonb,但是当我尝试插入时..我收到帖子中提到的上述错误

标签: java json spring postgresql hibernate


【解决方案1】:

我能够在两件事的帮助下保存 jsonb 对象 -

  1. 为休眠类型使用了第三方库implementation group: 'com.vladmihalcea', name: 'hibernate-types-52', version: '2.10.3'
  2. 定义了一个名为 Rules 的 POJO,并在 DTO 和 Entity 类中使​​用它

公共类规则实现可序列化{

    private String key;
    private String fieldName;
    private String operator;
    private String eq;
    List<String> operands;

}

我修改后的实体类:

@Getter @Setter @AllArgsConstructor @NoArgsConstructor
@Builder(toBuilder=true)
@Table(name="saved_filters")
@TypeDef(
        name = "jsonb",
        typeClass = JsonBinaryType.class
    )
public class SavedFilter implements Serializable {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name="id")
    private int id;

    @Column(name="name")
    private String name;

  
    @Column(name="rule_matching")
    private String ruleMatching;
    
    
    @Column(name="rules", columnDefinition= "jsonb")
    @Type(type = "jsonb")
    private Rules rules;

    @JsonIgnore
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "user_sso")
    private User user;

还有我修改后的 DTO 类:

@SuppressWarnings("serial")
@Data
@Getter @Setter @AllArgsConstructor @NoArgsConstructor
@Builder(toBuilder=true)
public class SavedFilterDto implements Serializable {

    private int id;

    private String name;
    
    @JsonProperty("rules")
    private Rules rules;
    
    private String ruleMatching;

    private String sso;      
    
}

【讨论】:

    【解决方案2】:

    更新答案

    如果以 json 格式保存不是您最关心的问题,那么您可以 按照这个答案。

    您只需做一件事即可轻松实现。将带有关联实体的键字符串转换为类并使其嵌入:

    {"key": "97773e0b-3639-4af5-9585-93bc176715c0", "fieldName": "esn", "operator": "eq", "operands": ["599320"]}.
    

    创建可嵌入类:

    @Embeddable
    Public class Rules
    {
     private String key;
    private String fieldName;
    private String operator;
    private String eq;
    List<String> operands;
    //getters and setters
    }
    

    现在在您的 SaveFilter 类中,添加带有嵌入注释的规则实体:

     @Embedded
     @Column(name="rules")
     private Rules rules;
    

    这会将您的完整对象保存为嵌入对象的每个实体的不同列。

    【讨论】:

    • 但我没有任何名为 Rules 的表
    • :[PersistenceUnit:默认] 无法构建 Hibernate SessionFactory;嵌套异常是 org.hibernate.MappingException:无法确定类型:com.ge.digital.oa.moa.domain.Rules,在表:saved_filters,对于列:[org.hibernate.mapping.Column(rules)] 在org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapa
    • 请再次检查我的答案。抱歉上次更新。如果保存在 json 中不是您最关心的问题,那么您可以遵循这种方法,否则,您需要为规则添加新表并将其与父表关联。
    • UI 发送一个 json 并期望 GET 中的一个 json 响应..所以需要将 json 存储在 DB 中
    猜你喜欢
    • 2015-08-21
    • 2022-01-25
    • 1970-01-01
    • 2021-09-01
    • 2021-02-23
    • 1970-01-01
    • 2020-12-04
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多