如何使用 Springboot 和 Hibernate 在 DTO 和 Aggentity 类中映射 Postgres JSON 数据类型

Posted

技术标签:

【中文标题】如何使用 Springboot 和 Hibernate 在 DTO 和 Aggentity 类中映射 Postgres JSON 数据类型【英文标题】:How to map Postgres JSON data type in DTO and Aggentity class using Springboot and Hibernate 【发布时间】:2020-09-14 07:19:09 【问题描述】:

我有一个 ResponseDto 类,如下所示:

public static class HealthGoalsHighlight 

    @ApiModelProperty(value = "Total number of eligible users")
    private Long totalEligibleUsers;
    @ApiModelProperty(value = "Total number of registered users")
    private Long totalRegisteredUsers;
    @ApiModelProperty(value = "Total number of users with atleast one goal count")
    private Long totalUsersWithGoal;
    @ApiModelProperty(value = "Top goal name selected by user")
    private String topGoal;
    @ApiModelProperty(value = "Bottom goal name selected by user")
    private String bottomGoal;
  

此 DTO 是根据下表结构制作的:

health_goals
(
  uid BIGSERIAL NOT NULL CONSTRAINT health_goals_pkey primary key,
  employer_key bigint not null,
  total_eligible_users bigint not null,
  total_registered_users bigint not null,
  total_users_with_goal bigint not null,
  top_goal_name varchar(255),
  bottom_goal_name varchar(255),
  created_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  created_by varchar(255),
  updated_by varchar(255)
);

现在表结构已更改为:

health_goals
(
  uid BIGSERIAL NOT NULL CONSTRAINT health_goals_pkey primary key,
  employer_key bigint not null,
  health_goals_metric_value json null,
  created_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  updated_ts TIMESTAMP NOT NULL DEFAULT NOW(),
  created_by varchar(255),
  updated_by varchar(255)
);

现在基本上所有这些列,如total_eligible_userstotal_registered_userstotal_users_with_goaltop_goal_namebottom_goal_name 将被合并为单个列health_goals_metric_value 作为 JSON 数据类型。

如何为 JSON 数据类型列编写响应 DTO。另外,我的 AggMapper 类中需要进行哪些更改。

【问题讨论】:

请分享您现有的 AggMapper 类的代码。 【参考方案1】:

一种方法是使用转换器功能。您可以使用转换器函数来获取相同格式的值。

在您的列定义中更改您的orm.xml 如下所示

<basic name="healthGoalsMetricValue">
                <column name="health_goals_metric_value" nullable="true"/>
                <convert converter="path.to.your.HealthGoalsMetricValueConverter"/>
            </basic>

或者如果你有java文件

代理将有以下条目

  @Convert(converter = HealthGoalsMetricValueConverter.class)
    private HealthGoalsHighlight healthGoalsHighlight ;

你的班级 HealthGoalsMetricValue 看起来像

////////////////在cmets之后编辑转换器类

       import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;

import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
import java.io.IOException;

@Converter
public class HealthGoalsMetricValueConverter implements AttributeConverter<HealthGoalsMetricValue, String> 

private final ObjectMapper mapper = new ObjectMapper();

//And then override like that
@Override
        public String convertToDatabaseColumn(HealthGoalsHighlight healthGoalsMetricValue) 

            try                 
                json = mapper.writeValueAsString(healthGoalsMetricValue);
             catch (JsonProcessingException exception) 
                throw new JsonProcessingException("Error occurred while object serialization", exception);
            
            return json;
    

 //And then override again
@Override
public HealthGoalsMetricValue  convertToEntityAttribute(String healthGoalsMetricValuestr ) 
    HealthGoalsMetricValue  healthGoalsMetricValue  = null;
    try 
        if (healthGoalsMetricValue != null) 
            healthGoalsMetricValue = mapper.readValue(healthGoalsMetricValuestr, HealthGoalsMetricValue.class);
        
     catch (Exception exception) 
        throw new Exception("Error occurred while object Deserialization", exception);
    
    return healthGoalsMetricValue;

这一切都将为您完成工作。

【讨论】:

convertToDatabaseColumn(HealthGoalsMetricValue healthGoalsMetricValue) -- 在这个方法“HealthGoalsMetricValue”中,我应该在哪里定义这个类以及它的内容。否则它给我错误,无法解析符号 HealthGoalsMetricValue。 这将是实体类中 JSON cloumn 的类型。HealthGoalsHighlight@sandeep @Sandeep 如果仍有疑问,请告诉我。 我想我把一切都搞砸了。得到很多错误。让我试着一步一步写到这里。这就是 mu DTO 的样子。公共类 HealthGoalsHighlightResponseDto 实现 Serializable private MetadataDto 元数据;私人健康目标突出健康目标突出; @EqualsAndHashCode 公共静态类 HealthGoalsHighlight @ApiModelProperty(value = "Total metrics") private Map healthGoalsMetricValue; 这是我的 AggEntity 类 public class HealthGoalsHighlightAggEntity extends AggBaseEntity @Convert(converter = HealthGoalsMetricValueConverter.class) private HealthGoalsHighlight healthGoalsHighlight ; 【参考方案2】:

如果您可以添加其他库,请查看 https://github.com/vladmihalcea/hibernate-types 项目,这非常容易。

有了这个库,你最终会得到像这样简单的代码

@Entity
@Table(name = "health_goals")
@TypeDefs(
    @TypeDef(name = "json", typeClass = JsonStringType.class),
    @TypeDef(name = "jsonb", typeClass = JsonBinaryType.class)
)
public class HealthGoal 
    // all other columns
    @Type(type = "json")
    private HealthGoalsHighlight healthGoalsHighlight;

    // getters setters


如果使用maven添加依赖

<dependency>
  <groupId>com.vladmihalcea</groupId>
  <artifactId>hibernate-types-52</artifactId>
  <version>2.9.10</version> // or newer version
</dependency>

【讨论】:

我没有使用 Maven。我该如何使用这个库。我需要下载并安装在我的项目中吗?如果是,该怎么做。 @sandeep 只需将 部分添加到您的 pom.xml 中。并将@TypeDefs 放在您的实体上,将@Type 放在字段上,您就可以开始了。看到这个很酷的文档vladmihalcea.com/…

以上是关于如何使用 Springboot 和 Hibernate 在 DTO 和 Aggentity 类中映射 Postgres JSON 数据类型的主要内容,如果未能解决你的问题,请参考以下文章

Hibernate入门-----Hiberna核心文件详解

手把手教你 Spring Boot 整合 Spring Data Jpa

如何在 Hibernate 中为某些实体禁用模式验证?

如何使用 SpringBoot 和 Angular2 设置结构?

如何使用 SpringBoot 2、InfluxDB 和 Grafana 理解微米指标?

JPA