切換語言為:簡體

巧用@Convert實現表字段自動轉entity

  • 爱糖宝
  • 2024-07-25
  • 2063
  • 0
  • 0

1.背景

本人自入職以來,接了一堆歷史包(shi)袱(shan),其中有個服務是基於MongoDB實現的,而公司要搞信創化,去掉MongoDB是遲早的事,於是便開始分析底層數據結構,計劃用pg替換MongoDB。

2.難點

2.1 數據結構不同

MongoDB是文件型資料庫,而pg是關係型資料庫,原專案MongoDB的collection中某些欄位型別為List或者entity,存在一對多的情況,如果採用新建關聯表的方式,會增加數據結構複雜性,且底層資料幾乎不會變,因此,覺得直接用VARCHAR型別儲存List型別的json串。

2.2 資料型別轉換

服務的資料庫持久化使用的是jpa,原來MongoDB型別會自動轉成List,如下列的options屬性

@Data
@Document(collection = "input_item")
public class InputItem implements Comparable<InputItem> {

   @Id
   private String itemCode;
   
   private String title;
   private String description;
   private int itemType;
   private List<InputItemOption> options;
   private String defaultOptionNum;
   private String unit;
   private boolean whetherActive;
}


轉成pg後,options欄位在資料庫中是String型別,需要轉成List。經過調研,可以採用自定義Converter+註解@Convert來實現。

2.2.1 List型別

1)自定義Converter

import com.alibaba.fastjson.JSON;
import javax.persistence.AttributeConverter;
/**
 * @ClassName JpaConverterListJson
 * @Description jpa list轉換為String 相互轉換工具類
 * @Author ygt
 * @Date 2021/3/3 14:49
 * @Version V1.0
 */
public class JpaConverterListJson  implements AttributeConverter<Object, String> {
    @Override
    public String convertToDatabaseColumn(Object o) {
        return JSON.toJSONString(o);
    }

    @Override
    public Object convertToEntityAttribute(String s) {
        return JSON.parseArray(s);
    }
}

2)@Convert註解

import java.util.List;
import com.fasterxml.jackson.annotation.JsonInclude;
import io.swagger.annotations.ApiModel;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.NoArgsConstructor;

import lombok.Data;

import javax.persistence.*;

/**
 * 
 * @Description 輸入項實體類
 *
 */
@ApiModel("")
@JsonInclude(value = JsonInclude.Include.NON_NULL)
@Table(name = "input_item")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class InputItem implements Comparable<InputItem> {

   @GeneratedValue
   @Column(name = "id")
   @Id
   private String itemCode;

   @Column(name = "title")
   private String title;
   @Column(name = "description")
   private String description;
   @Column(name = "itemtype")
   private int itemType;

   @Convert(converter = JpaConverterListJson.class)
   private List<InputItemOption> options;
   @Column(name = "defaultoptionnum")
   private String defaultOptionNum;
   @Column(name = "unit")
   private String unit;
   @Column(name = "whetheractive")
   private Boolean whetherActive;

   @Override
   public int compareTo(InputItem o) {
      int index1 = Integer.parseInt(this.itemCode.substring(this.itemCode.lastIndexOf('_') + 1));
      int index2 = Integer.parseInt(o.itemCode.substring(o.itemCode.lastIndexOf('_') + 1));
      if (index1 < index2) {
         return -1;
      }
      else {
         return 1;
      }
   }
}

2.2.2 entity型別

1)自定義Converter

import com.alibaba.fastjson.JSON;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.test.src.domain.index.interest.InterestCreditScoreSection;

import javax.persistence.AttributeConverter;
import java.lang.reflect.ParameterizedType;

/**
 * @ClassName JpaConverterListJson
 * @Description jpa 泛型T轉換為String 相互轉換工具類
 * @Author ygt
 * @Date 2021/3/3 14:49
 * @Version V1.0
 */
public class JpaConverterObjectJson<T> implements AttributeConverter<T, String> {

    private static final ObjectMapper objectMapper = new ObjectMapper();

    @Override
    public String convertToDatabaseColumn(T o) {
        try {
            return objectMapper.writeValueAsString(o);
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert object to string", e);
        }
    }

    @Override
    public T convertToEntityAttribute(String s) {
        try {
            return objectMapper.readValue(s, (Class<T>) ((ParameterizedType) getClass().getGenericSuperclass()).getActualTypeArguments()[0]);
        } catch (Exception e) {
            throw new RuntimeException("Failed to convert string to object", e);
        }
    }
}
import com.fasterxml.jackson.annotation.JsonInclude;
import com.test.src.utils.InterestCreditScoreSectionConverter;
import io.swagger.annotations.ApiModel;
import lombok.NoArgsConstructor;

import lombok.*;

import javax.persistence.*;

/**
 * 
 * @Description 利率授信實體類
 */
@ApiModel("")
@JsonInclude(value = JsonInclude.Include.NON_NULL)
@Table(name = "interest_credit")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class InterestCredit {

   @Id
   @GeneratedValue
   @Column(name = "id")
   private String itemNo;

   @Column(name = "recommendinterestformula")
   private String recommendInterestFormula; //推薦執行利率計算公式;

   @Convert(converter = InterestCreditScoreSectionConverter.class)
   @Column(name = "interestcreditscoresection")
   private InterestCreditScoreSection interestCreditScoreSection;
}

2)@Convert註解

import com.fasterxml.jackson.annotation.JsonInclude;
import com.test.src.utils.InterestCreditScoreSectionConverter;
import io.swagger.annotations.ApiModel;
import lombok.NoArgsConstructor;

import lombok.*;

import javax.persistence.*;

/**
 * 
 * @Description 利率授信實體類
 */
@ApiModel("")
@JsonInclude(value = JsonInclude.Include.NON_NULL)
@Table(name = "interest_credit")
@Builder
@AllArgsConstructor
@NoArgsConstructor
@Data
@Entity
public class InterestCredit {

   @Id
   @GeneratedValue
   @Column(name = "id")
   private String itemNo;

   @Column(name = "recommendinterestformula")
   private String recommendInterestFormula; //推薦執行利率計算公式;

   @Convert(converter = InterestCreditScoreSectionConverter.class)
   @Column(name = "interestcreditscoresection")
   private InterestCreditScoreSection interestCreditScoreSection;
}

3.總結

針對不好處理的json string型別,可透過自定義converter+@Convert的方式實現自動轉換,另外,可在自定義converter類上加@Convert(autoApply = true)實現全域性自動轉換。

0則評論

您的電子郵件等資訊不會被公開,以下所有項目均必填

OK! You can skip this field.