programing

JPA를 사용하여 JSON 열을 Java 객체에 매핑하는 방법

easyjava 2023. 2. 28. 23:49
반응형

JPA를 사용하여 JSON 열을 Java 객체에 매핑하는 방법

기둥들이 많이 있는 큰 테이블이 있습니다.MySQL 클러스터로 이동한 후 다음 이유로 테이블을 만들 수 없습니다.

ERROR 1118(42000):행 크기가 너무 큽니다.BLOB를 카운트하지 않고 사용되는 테이블타입의 최대 행 사이즈는 14000 입니다.여기에는 스토리지 오버헤드가 포함됩니다. 매뉴얼을 참조하십시오.일부 열을 TEXT 또는 BLOB로 변경해야 합니다.

예를 들어 다음과 같습니다.

@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
    @Id @Column (name = "id", nullable = false)
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int id;

    @OneToOne @JoinColumn (name = "app_id")
    private App app;

    @Column(name = "param_a")
    private ParamA parama;

    @Column(name = "param_b")
    private ParamB paramb;
}

설정 파라미터를 저장하기 위한 테이블입니다.몇 개의 열을 하나로 결합하여 JSON 오브젝트로 저장하고 Java 오브젝트로 변환할 수 있을 것 같습니다.

예를 들어 다음과 같습니다.

@Entity @Table (name = "appconfigs", schema = "myproject")
public class AppConfig implements Serializable
{
    @Id @Column (name = "id", nullable = false)
    @GeneratedValue (strategy = GenerationType.IDENTITY)
    private int id;

    @OneToOne @JoinColumn (name = "app_id")
    private App app;

    @Column(name = "params")
    //How to specify that this should be mapped to JSON object?
    private Params params;
}

여기서 정의:

public class Params implements Serializable
{
    private ParamA parama;
    private ParamB paramb;
}

이를 통해 모든 열을 하나로 결합하여 테이블을 만들 수 있습니다.아니면 전체 테이블을 여러 개의 테이블로 나눌 수도 있습니다.개인적으로 나는 첫 번째 해결책을 선호한다.

아무튼 자바 객체의 JSON 문자열을 포함하는 텍스트인 Params 열을 어떻게 매핑할 것인가?

JPA 변환기를 사용하여 엔티티를 데이터베이스에 매핑할 수 있습니다.다음과 같은 주석을 매개 변수 필드에 추가하십시오.

@Convert(converter = JpaConverterJson.class)

그런 다음 비슷한 방법으로 클래스를 만듭니다(이것에 의해 범용 오브젝트가 변환됩니다.특화시킬 수도 있습니다).

@Converter(autoApply = true)
public class JpaConverterJson implements AttributeConverter<Object, String> {

  private final static ObjectMapper objectMapper = new ObjectMapper();

  @Override
  public String convertToDatabaseColumn(Object meta) {
    try {
      return objectMapper.writeValueAsString(meta);
    } catch (JsonProcessingException ex) {
      return null;
      // or throw an error
    }
  }

  @Override
  public Object convertToEntityAttribute(String dbData) {
    try {
      return objectMapper.readValue(dbData, Object.class);
    } catch (IOException ex) {
      // logger.error("Unexpected IOEx decoding json from database: " + dbData);
      return null;
    }
  }

}

이상입니다. 이 클래스를 사용하여 테이블 내의 모든 개체를 json으로 직렬화할 수 있습니다.

JPAAttributeConverterJSON 오브젝트유형을 매핑하기에는 너무 한정되어 있습니다.특히 JSON 바이너리로 저장하는 경우에는 더욱 그렇습니다.

JSON 지원을 받기 위해 커스텀 휴지 타입을 작성할 필요는 없습니다.필요한 것은 휴지 타입 OSS 프로젝트를 사용하는 것뿐입니다.

를 들어5.2 버전을 5.2에서 .pom.xml★★★★★★★★★

<dependency>
    <groupId>com.vladmihalcea</groupId>
    <artifactId>hibernate-types-52</artifactId>
    <version>${hibernate-types.version}</version> 
</dependency> 

또는 좋은은 기본 클래스 클래스 중 .@MappedSuperclass:

@TypeDef(name = "json", typeClass = JsonType.class)

엔티티 매핑은 다음과 같습니다.

@Type(type = "json")
@Column(columnDefinition = "json")
private Location location;

.2 하고 있는 경우는, 「」5.2 「」를 해 주세요.JSON은 자동으로 됩니다.MySQL57Dialect.

그렇지 않으면 직접 등록해야 합니다.

public class MySQLJsonDialect extends MySQL55Dialect {

    public MySQLJsonDialect() {
        super();
        this.registerColumnType(Types.JAVA_OBJECT, "json");
    }
}

ㅇㅇㅇㅇ을 .hibernate.dialect MySQLJsonDialect작성하신 클래스입니다.

할 때 으로 매핑해야 할 를 들어 응답 json을 합니다(rest API).@JsonRawValue다음과 같습니다.

@Column(name = "params", columnDefinition = "json")
@JsonRawValue
private String params;

이렇게 하면 서버 측에서 DTO 매핑이 수행되지 않을 수 있지만 클라이언트는 json으로 올바른 형식의 속성을 얻을 수 있습니다.

그것은 간단하다.

@Column(name = "json_input", columnDefinition = "json")
private String field;

mysql 데이터베이스에서 열 'json_input' json 유형

여기에 이미지 설명 입력

코드를 너무 많이 쓰는 것을 원하지 않는 사람들을 위한 회피책이 있습니다.

프런트 엔드 -> POST 메서드에서 JSON 개체를 string base64로 인코딩하고 GET 메서드에서 json으로 디코딩합니다.

In POST Method
data.components = btoa(JSON.stringify(data.components));

In GET
data.components = JSON.parse(atob(data.components))

백엔드 -> JPA 코드에서 열을 String 또는 BLOB로 변경합니다.변환 불필요.

@Column(name = "components", columnDefinition = "json")
private String components;

이 새로운 버전의 스프링 부트 및 MySQL 아래 코드에서는 충분합니다.

@Column( columnDefinition = "json" )
private String string;

견적의 문제에 직면하고 있었기 때문에, 프로젝트의 아래 행에 코멘트를 했습니다.

#spring.jpa.properties.hibernate.globally_quoted_identifiers=true

비슷한 문제가 있어 @Externalizer 주석과 잭슨을 사용하여 데이터를 시리얼화/비직렬화함으로써 해결했습니다(@Externalizer는 OpenJPA 고유의 주석이므로 JPA 구현에 동일한 가능성을 확인해야 합니다).

@Persistent
@Column(name = "params")
@Externalizer("toJSON")
private Params params;

Params 클래스의 실장:

public class Params {
    private static final ObjectMapper mapper = new ObjectMapper();

    private Map<String, Object> map;

    public Params () {
        this.map = new HashMap<String, Object>();
    }

    public Params (Params another) {
        this.map = new HashMap<String, Object>();
        this.map.putAll(anotherHolder.map);
    }

    public Params(String string) {
        try {
            TypeReference<Map<String, Object>> typeRef = new TypeReference<Map<String, Object>>() {
            };
            if (string == null) {
                this.map = new HashMap<String, Object>();
            } else {
                this.map = mapper.readValue(string, typeRef);
            }
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    public String toJSON() throws PersistenceException {
        try {
            return mapper.writeValueAsString(this.map);
        } catch (IOException e) {
            throw new PersistenceException(e);
        }
    }

    public boolean containsKey(String key) {
        return this.map.containsKey(key);
    }

    // Hash map methods
    public Object get(String key) {
        return this.map.get(key);
    }

    public Object put(String key, Object value) {
        return this.map.put(key, value);
    }

    public void remove(String key) {
        this.map.remove(key);
    }

    public Object size() {
        return map.size();
    }
}

HTH

JPA 버전 2.1 이후를 사용하고 있는 경우는, 이 케이스를 사용할 수 있습니다.링크 지속성 Json 개체

퍼블릭 클래스 HashMapConverter는 AttributeConverter <맵, 오브젝트>, String> {를 구현합니다.

@Override
public String convertToDatabaseColumn(Map<String, Object> customerInfo) {

    String customerInfoJson = null;
    try {
        customerInfoJson = objectMapper.writeValueAsString(customerInfo);
    } catch (final JsonProcessingException e) {
        logger.error("JSON writing error", e);
    }

    return customerInfoJson;
}

@Override
public Map<String, Object> convertToEntityAttribute(String customerInfoJSON) {

    Map<String, Object> customerInfo = null;
    try {
        customerInfo = objectMapper.readValue(customerInfoJSON, 
            new TypeReference<HashMap<String, Object>>() {});
    } catch (final IOException e) {
        logger.error("JSON reading error", e);
    }

    return customerInfo;
}

}

표준 JSON 개체는 다음 속성을 HashMap으로 나타냅니다.

@Convert(변환기 = HashMapConverter.class) 프라이빗 맵 <String, Object> entityAttributes;

언급URL : https://stackoverflow.com/questions/25738569/how-to-map-a-map-json-column-to-java-object-with-jpa

반응형