通用查詢的抽象

孫工的程式設計生涯發表於2022-07-09

有一批查詢介面,只有引數,返回值,介面地址不通,如何抽象出通用的呼叫方式呢?

分析一下,每個介面返回型別不一樣,我想到了泛型,引數,介面地址不一樣,可以通過引數區分。於是先定義一個帶泛型的介面

public interface CommonQueryService<T> {
    /**
     * 通用查詢
     * @param requestDto 請求dto
     * @param apiUrl  請求地址
     * @param msg 日誌訊息表示
     * @return 查詢返回物件
     * @throws InvalidCipherTextException
     */
    GenericReturnObject<List<T>> commonQuery(Object requestDto,String apiUrl, String msg)  throws InvalidCipherTextException;
}

誰來實現它呢?我定義一個實現類吧

@Slf4j
public abstract class CommonQueryServiceImpl<T> implements CommonQueryService<T> {
    @Autowired
    private BusinessCenterTokenHelper businessCenterTokenHelper;
    @Autowired
    private EpServiceConfig epServiceConfig;
    protected String returnJson;
    public GenericReturnObject<List<T>> commonQuery(Object requestDto,String apiUrl,String msg) throws InvalidCipherTextException {
        String jsonBody = com.alibaba.fastjson.JSON.toJSONString(requestDto);
        long date = System.currentTimeMillis();
        log.info("esServiceConfig:{}", com.alibaba.fastjson.JSON.toJSONString(epServiceConfig));
        String appPubKey = epServiceConfig.getApp().getPubkey() ;
        log.info("appPubKey:{}",appPubKey);
        String  token = businessCenterTokenHelper.getToken();
        log.info("token:{}",token);
        String signature = EncryptUtil.sign("POST" + '\n' + date + '\n'+ token + '\n' + appPubKey +'\n'+ jsonBody);
        log.info("signature:{}",signature);
        String dateX = String.valueOf(date);
        log.info("dataX:{}",dateX);
        EPRequestCaller caller = null;
        try {
            caller = EPRequestCaller.newBuilder(apiUrl)
                    .token(token)
                    .apiVersion(epServiceConfig.getApp().getVersion())
                    .clientId(epServiceConfig.getClient().getId())
                    .putHeadParamsMap("x-date", dateX)
                    .putHeadParamsMap("x-token",token)
                    .putHeadParamsMap("x-signature",signature)
                    .appPubKey(appPubKey);
            caller.setContentBody(jsonBody);
            this.returnJson = caller.doPost();
            GenericReturnObject<List<T>> returnObject = convertJson(returnJson);
            log.info(">>>>>>>>>>>>>>>>>>>>>>>>>{},返回:{}>>>>>>>>>>>>>>>>>>>>>",msg, com.alibaba.fastjson.JSON.toJSONString(returnObject));
            return returnObject;
        } catch (HttpCallerException e) {
            log.error("msg:{} 失敗:{}",msg,e);
            GenericReturnObject genericReturnObject = new GenericReturnObject();
            genericReturnObject.setErrors(e.getMessage());
            return genericReturnObject;
        } catch (Exception e) {
            log.error("msg:{}.e:{}",msg,e);
            GenericReturnObject genericReturnObject = new GenericReturnObject();
            genericReturnObject.setErrors(e.getMessage());
            return genericReturnObject;
        }
    }

    /**
     * 中臺返回的json轉換為json物件,由子類實現
     * @param json
     * @return 返回物件
     */
    public abstract GenericReturnObject<List<T>> convertJson(String json);

大家看到這是一個抽象類,本來不打算用抽象類的,奈何JSON轉物件的時候,不支援泛型的轉換,於是定義為抽象類,再定義一個抽象方法 convertJson,把轉換的工作交給子類來實現,這樣就不涉及JSON轉泛型物件的問題了。

對於不同的查詢,再定義不用的實現類繼承上述抽象類,並實現通用查詢介面。下面舉2個例子。

@Service("commonQueryServiceFire")
public class CommonQueryServiceFireImpl<FireInfoDto> extends CommonQueryServiceImpl<FireInfoDto> implements CommonQueryService<FireInfoDto> {
    @Override
    public GenericReturnObject<List<FireInfoDto>> commonQuery(Object requestDto, String apiUrl,String msg) throws InvalidCipherTextException {
        GenericReturnObject<List<FireInfoDto>> listGenericReturnObject = super.commonQuery(requestDto, apiUrl,msg);
        return listGenericReturnObject;
    }

    @Override
    public GenericReturnObject<List<FireInfoDto>> convertJson(String json) {
            GenericReturnObject<List<FireInfoDto>> returnObject = com.alibaba.fastjson.JSON.parseObject(returnJson,
                new TypeReference<GenericReturnObject<List<FireInfoDto>>>(){});
        return returnObject;
    }
}
@Service("commonQueryServiceFireReport")
public class CommonQueryServiceFireReport<ForecastReportDto> extends CommonQueryServiceImpl<ForecastReportDto> implements CommonQueryService<ForecastReportDto> {
    @Override
    public GenericReturnObject<List<ForecastReportDto>> commonQuery(Object requestDto, String apiUrl,String msg) throws InvalidCipherTextException {
        GenericReturnObject<List<ForecastReportDto>> listGenericReturnObject = super.commonQuery(requestDto, apiUrl,msg);
        return listGenericReturnObject;
    }

    @Override
    public GenericReturnObject<List<ForecastReportDto>> convertJson(String json) {
            GenericReturnObject<List<ForecastReportDto>> returnObject = com.alibaba.fastjson.JSON.parseObject(returnJson,
                new TypeReference<GenericReturnObject<List<ForecastReportDto>>>(){});
        return returnObject;
    }
}

controller呼叫端

@Resource(name = "commonQueryServiceFire")
private CommonQueryService commonQueryServiceFire;
@Resource(name = "commonQueryServiceFireReport")
private CommonQueryService commonQueryServiceFireReport;
 
@PostMapping("/environCenter/fire/fireRealData")
public GenericReturnObject fireRealData(String date,
String fireCode ) throws Exception {
FireRealDataReqDto fireRealDataReqDto = new FireRealDataReqDto();
fireRealDataReqDto.setFireCode(fireCode);
fireRealDataReqDto.setDate(date);
GenericReturnObject<List<FireInfoDto>> listGenericReturnObject = commonQueryServiceFire.commonQuery(fireRealDataReqDto,
"/environCenter/fire/fireRealData",
"查詢xxx資訊");
return listGenericReturnObject;
}

@PostMapping("/environCenter/fire/fireReport")
public GenericReturnObject fireReport(String date ) throws Exception {
date );
FireReportReqDto fireReportReqDto = new FireReportReqDto();
fireReportReqDto.setDate(date);
GenericReturnObject<List<ForecastReportDto>> listGenericReturnObject = commonQueryServiceFireReport.commonQuery(fireReportReqDto,
"/environCenter/fire/fireReport",
"yyy查詢");
return listGenericReturnObject;
}

 新增不用的查詢,需要增加新的實現類,引數dto,返回dto,呼叫方注入實現類,呼叫commonQuery方法即可。隱藏了呼叫細節,不必拷貝重複的程式碼。(程式碼刪除了註釋部分,避免不必要的隱私洩露)。

相關文章