異構API數據處理實踐

數據來源:陳同學 | 異構API數據處理實踐

首先用下圖闡述業務場景。

基礎服務爲各個業務服務(服務A/B/C) 提供API,同時基礎服務數據又來源於第三方服務商。

各個服務商之間API的數據結構不同,本文不涉及不同服務商之間的安全通訊方式。

爲什麼需要多個服務商?

例舉我所遇到的兩個因素

系統穩定性考慮

以發送短信爲例,若只有一個服務商,若服務商因某些因素中斷服務,將導致依賴於短信的業務受到嚴重影響。

若對接了多個服務商,當其中一個無法使用,自動切換到可用的服務商即可。

切換服務商

因各種因素導致商務合作終止,從而切換服務商

異構數據的場景舉例

先舉兩個例子加以說明:

  • 簡單數據異構場景

    假設通過企查查、天眼查的API獲取工商信息,對於企業名稱字段,企業可能分別名稱是ENTNAMEorg_name,有的甚至是中文字段名企業名稱

  • 複雜數據異構場景

    假設對接企業ERP中財務數據,A企業可能是金蝶系統、B企業是用友系統、其他企業可能是Oracle EBS或SAP系統。

    這種場景不僅需要將異構數據處理成統一結構,而且處理過程中需要進行復雜的數據轉換過程。

異構數據處理簡單Demo

數據處理的目的是可以通過配置,將不同服務商的異構數據統一解析,簡化代碼,增強拓展性。

這裏以企業工商數據做演示。下面假設三種工商信息的數據結構,均使用JSON格式展示:

數據結構示例

  • 自身標準數據結構

業務系統中以自身的數據結構爲準,假設字段名稱是正常翻譯:

{
    "organizationName":"企業名稱",
    "taxpayerNumber":"納稅人識別號"
}
  • A服務商API返回的數據結構

假設字段名稱是不規則簡寫:

{
    "ENTNAME":"企業名稱",
    "TAXNUMBER":"納稅人識別號"
}
  • B服務商API返回的數據結構

假設字段名稱是中文首字母簡寫:

{
    "QYMC":"企業名稱",
    "NSRSBH":"納稅人識別號"
}

簡單處理示例

先採用簡單的方式處理,首先新建一個Domain表示企業工商信息:

public class Organization {
    private String organizationName; //企業名稱
    private String taxpayerNumber; //納稅人識別號
}

將A服務商的數據轉換爲標準數據

假設JSONObject是阿里的fastjson

// JSONObject data = {"ENTNAME":"企業名稱", "TAXNUMBER":"納稅人識別號"}
Organization org = new Organization();
org.setOrganizationName(data.getString("ENTNAME"));
org.setTaxpayerNumber(data.getString("TAXNUMBER"));

將B服務商的數據轉換爲標準數據

// JSONObject data = {"QYMC":"企業名稱", "NSRSBH":"納稅人識別號"}
Organization org = new Organization();
org.setOrganizationName(data.getString("QYMC"));
org.setTaxpayerNumber(data.getString("NSRSBH"));

上面看上去非常簡單,但實際上API字段非常繁多,首先會導致大量的累贅代碼,其次是有N個服務商就會有N種冗餘代碼。

統一解析處理示例

使用註解在Domain上標記各個服務商的對應字段

定義用於數據自動轉換的註解

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface FiledMapper {
    String serviceA() default ""; // A服務商字段
    String serviceB() default ""; // B服務商字段
}

使用註解標記Domain的屬性

使用註解將異構數據的字段名與標準字段建立Mapping關係

public class Organization {
    @FiledMapper(serviceA="ENTNAME", serviceB="QYMC")
    private String organizationName; //企業名稱

    @FiledMapper(serviceA="TAXNUMBER", serviceB="NSRSBH")
    private String taxpayerNumber; //納稅人識別號
}

使用反射統一解析數據

/**
 * 統一解析數據
 *
 * @param source      數據源
 * @param targetClass 目標類
 * @param serviceProvider 服務提供商
 * @return 目標類instance
 * @throws Exception
 */
public static Object parse(JSONObject source, Class targetClass, String serviceProvider) throws Exception {
    Object instance = targetClass.newInstance();
    Field[] fields = targetClass.getDeclaredFields();
    if (fields != null) {
        for (Field field : fields) {
            if (field.isAnnotationPresent(FiledMapper.class)) {
                FiledMapper filedMapper = field.getAnnotation(FiledMapper.class);
                field.setAccessible(true);
                field.set(instance, source.get("A".equals(serviceProvider) ? filedMapper.serviceA() : filedMapper.serviceB())); // 此處hardcode做演示
            }
        }
    }
    return instance;
}

數據處理測試

JSONObject dataA = JSON.parseObject("{\"ENTNAME\":\"企業A\", \"TAXNUMBER\":\"1001\"}");
JSONObject dataB = JSON.parseObject("{\"QYMC\":\"企業A\", \"NSRSBH\":\"1001\"}");
Organization orgA = (Organization) parse(dataA, Organization.class, "A");
Organization orgB = (Organization) parse(dataB, Organization.class, "B");

總結

本文僅提取了異構數據處理中的一個“點”做分析,爲數據解析提供一種解決的思路。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章