浏览代码

海通期货eta数据同步一期

kobe6258 7 月之前
当前提交
a8e5417c81
共有 100 个文件被更改,包括 4538 次插入0 次删除
  1. 27 0
      .gitignore
  2. 8 0
      .idea/.gitignore
  3. 209 0
      .idea/easyCodeTableSetting.xml
  4. 13 0
      .idea/misc.xml
  5. 8 0
      .idea/modules.xml
  6. 9 0
      .idea/qhtx-parent.iml
  7. 6 0
      .idea/vcs.xml
  8. 93 0
      README.md
  9. 96 0
      qhtx-eta-integrator/pom.xml
  10. 100 0
      qhtx-eta-integrator/qhtx-integrator-common/pom.xml
  11. 19 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/annotation/DataOperator.java
  12. 143 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/aspect/DataOperatorAspect.java
  13. 25 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/DataSourceProperties.java
  14. 9 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/LimitProperties.java
  15. 30 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/OkHttpClientProperties.java
  16. 37 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/constant/ETAConstants.java
  17. 111 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/entity/SignatureParam.java
  18. 8 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/DataSourceType.java
  19. 7 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ETAApiType.java
  20. 27 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ETARetryEnum.java
  21. 45 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ErrorEnum.java
  22. 19 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/HttpMethod.java
  23. 23 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/LimiterType.java
  24. 17 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/OperatorEnum.java
  25. 81 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/exception/ETAException.java
  26. 95 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/interceptor/RetryInterceptor.java
  27. 8 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/Limiter.java
  28. 27 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/LimiterProvider.java
  29. 16 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/impl/GuavaRateLimiter.java
  30. 128 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/AssertUtils.java
  31. 81 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/HttpClient.java
  32. 53 0
      qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/SignatureUtil.java
  33. 39 0
      qhtx-eta-integrator/qhtx-integrator-domain/pom.xml
  34. 75 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/ApiServiceHolder.java
  35. 14 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/ETAHttpClient.java
  36. 133 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/ETAHttpClientImpl.java
  37. 18 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/request/ETADataHttpRequest.java
  38. 17 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAData.java
  39. 18 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAHttpResponse.java
  40. 37 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAQuota.java
  41. 58 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/QuotaDataResponse.java
  42. 75 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/QuotaInfoResponse.java
  43. 41 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/inner/InnerResponse.java
  44. 69 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/proxy/ApiParameterProxy.java
  45. 17 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/proxy/impl/ETADataParameterProxy.java
  46. 18 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/DomainConfig.java
  47. 25 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ETAConfigProperties.java
  48. 35 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ETAThreadFactory.java
  49. 15 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ScheduleConfig.java
  50. 17 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ScheduleTaskConfig.java
  51. 30 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ThreadPoolConfig.java
  52. 30 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/convert/EtaApiQuotaDataConverter.java
  53. 29 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/convert/EtaApiQuotaInfoConverter.java
  54. 28 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaDataDTO.java
  55. 15 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaDataUpdateBO.java
  56. 47 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaInfoDTO.java
  57. 18 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ETADataStatus.java
  58. 68 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ETAInterfaceEnum.java
  59. 15 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ExcludedField.java
  60. 17 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ExcludedQuotaSource.java
  61. 198 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/job/ETADataSyncJob.java
  62. 19 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/service/ETAQuotaService.java
  63. 158 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/service/impl/ETAQuotaServiceImpl.java
  64. 59 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/FixedDelayTaskRegistrar.java
  65. 18 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/ScheduledTask.java
  66. 59 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/SchedulingRunnable.java
  67. 101 0
      qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/TaskConfigChangeListener.java
  68. 71 0
      qhtx-eta-integrator/qhtx-integrator-infra/pom.xml
  69. 12 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/annotation/UseDataSource.java
  70. 38 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/aspect/DataSourceSwitchAspect.java
  71. 69 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/config/InfraConfig.java
  72. 55 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/config/SqlStatementInterceptor.java
  73. 18 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DataSourceContextHolder.java
  74. 46 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DecryptDataSourcePostProcessor.java
  75. 12 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DynamicDataSource.java
  76. 30 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/entity/EtaApiQuotaData.java
  77. 58 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/entity/EtaApiQuotaInfo.java
  78. 31 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/enums/Frequency.java
  79. 8 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/DimIncDao.java
  80. 55 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/EtaApiQuotaDataDao.java
  81. 76 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/EtaApiQuotaInfoDao.java
  82. 27 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/EtaApiQuotaDataService.java
  83. 55 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/EtaApiQuotaInfoService.java
  84. 8 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/OdsDimService.java
  85. 57 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/EtaApiQuotaDataServiceImpl.java
  86. 103 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/EtaApiQuotaInfoServiceImpl.java
  87. 43 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/OdsDimServiceImpl.java
  88. 42 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/utils/DruidEncryptUtil.java
  89. 21 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/DimIncDao.xml
  90. 62 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/EtaApiQuotaDataDao.xml
  91. 73 0
      qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/EtaApiQuotaInfoDao.xml
  92. 18 0
      qhtx-eta-integrator/qhtx-integrator-starter/Dockerfile
  93. 73 0
      qhtx-eta-integrator/qhtx-integrator-starter/pom.xml
  94. 20 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/ETAIntegratorApplication.java
  95. 41 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/config/HttpClientConfig.java
  96. 26 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/config/RateLimiterConfig.java
  97. 42 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/init/ETAEnvironmentInit.java
  98. 1 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/META-INF/services/com.qhtx.eta.common.limiter.Limiter
  99. 27 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/banner.txt
  100. 12 0
      qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/bootstrap-dev.yml

+ 27 - 0
.gitignore

@@ -0,0 +1,27 @@
+# Compiled class file
+*.class
+
+# Log file
+*.log
+
+# BlueJ files
+*.ctxt
+
+# Mobile Tools for Java (J2ME)
+.mtj.tmp/
+
+# Package Files #
+*.jar
+*.war
+*.nar
+*.ear
+*.zip
+*.ta
+r.gz
+*.rar
+
+# virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
+hs_err_pid*
+*target*
+*log*
+*test*

+ 8 - 0
.idea/.gitignore

@@ -0,0 +1,8 @@
+# Default ignored files
+/shelf/
+/workspace.xml
+# Editor-based HTTP Client requests
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml

+ 209 - 0
.idea/easyCodeTableSetting.xml

@@ -0,0 +1,209 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="EasyCodeTableSetting">
+    <option name="tableInfoMap">
+      <map>
+        <entry key="QHTX.ETA_API_QUOTA_DATA">
+          <value>
+            <TableInfoDTO>
+              <option name="fullColumn">
+                <list>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dataId" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="edbInfoId" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="value" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dateTime" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="updateTime" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="isDelete" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="isQuality" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dataCreateTime" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dataUpdateTime" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="htUniqueCode" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                </list>
+              </option>
+              <option name="name" value="EtaApiQuotaData" />
+              <option name="preName" value="" />
+              <option name="saveModelName" value="qhtx-integrator-infra" />
+              <option name="savePackageName" value="com.qhtx.eta" />
+              <option name="savePath" value="./qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta" />
+              <option name="templateGroupName" value="Default" />
+            </TableInfoDTO>
+          </value>
+        </entry>
+        <entry key="QHTX.ETA_API_QUOTA_INFO">
+          <value>
+            <TableInfoDTO>
+              <option name="fullColumn">
+                <list>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="quoteId" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="edbInfoId" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="edbCode" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="edbName" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="unit" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="frequency" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="startDate" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="endDate" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="lastDate" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="classifyId" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="source" />
+                    <option name="type" value="java.util.Date" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="sourceName" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="noUpdate" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="isDelete" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="isQuality" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dataCreateTime" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="dataUpdateTime" />
+                    <option name="type" value="java.lang.Integer" />
+                  </ColumnInfoDTO>
+                  <ColumnInfoDTO>
+                    <option name="custom" value="false" />
+                    <option name="ext" value="{}" />
+                    <option name="name" value="htUniqueCode" />
+                    <option name="type" value="java.lang.String" />
+                  </ColumnInfoDTO>
+                </list>
+              </option>
+              <option name="name" value="EtaApiQuotaInfo" />
+              <option name="preName" value="" />
+              <option name="saveModelName" value="qhtx-integrator-infra" />
+              <option name="savePackageName" value="com.qhtx.eta" />
+              <option name="savePath" value="./qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta" />
+              <option name="templateGroupName" value="Default" />
+            </TableInfoDTO>
+          </value>
+        </entry>
+      </map>
+    </option>
+  </component>
+</project>

+ 13 - 0
.idea/misc.xml

@@ -0,0 +1,13 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="MavenProjectsManager">
+    <option name="originalFiles">
+      <list>
+        <option value="$PROJECT_DIR$/qhtx-eta-task/pom.xml" />
+      </list>
+    </option>
+  </component>
+  <component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
+    <output url="file://$PROJECT_DIR$/out" />
+  </component>
+</project>

+ 8 - 0
.idea/modules.xml

@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="ProjectModuleManager">
+    <modules>
+      <module fileurl="file://$PROJECT_DIR$/.idea/qhtx-parent.iml" filepath="$PROJECT_DIR$/.idea/qhtx-parent.iml" />
+    </modules>
+  </component>
+</project>

+ 9 - 0
.idea/qhtx-parent.iml

@@ -0,0 +1,9 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<module type="JAVA_MODULE" version="4">
+  <component name="NewModuleRootManager" inherit-compiler-output="true">
+    <exclude-output />
+    <content url="file://$MODULE_DIR$" />
+    <orderEntry type="inheritedJdk" />
+    <orderEntry type="sourceFolder" forTests="false" />
+  </component>
+</module>

+ 6 - 0
.idea/vcs.xml

@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project version="4">
+  <component name="VcsDirectoryMappings">
+    <mapping directory="" vcs="Git" />
+  </component>
+</project>

+ 93 - 0
README.md

@@ -0,0 +1,93 @@
+# qhtx-parent
+
+
+
+## Getting started
+
+To make it easy for you to get started with GitLab, here's a list of recommended next steps.
+
+Already a pro? Just edit this README.md and make it your own. Want to make it easy? [Use the template at the bottom](#editing-this-readme)!
+
+## Add your files
+
+- [ ] [Create](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#create-a-file) or [upload](https://docs.gitlab.com/ee/user/project/repository/web_editor.html#upload-a-file) files
+- [ ] [Add files using the command line](https://docs.gitlab.com/ee/gitlab-basics/add-file.html#add-a-file-using-the-command-line) or push an existing Git repository with the following command:
+
+```
+cd existing_repo
+git remote add origin https://gitlab.com/chenhan/qhtx-parent.git
+git branch -M main
+git push -uf origin main
+```
+
+## Integrate with your tools
+
+- [ ] [Set up project integrations](https://gitlab.com/chenhan/qhtx-parent/-/settings/integrations)
+
+## Collaborate with your team
+
+- [ ] [Invite team members and collaborators](https://docs.gitlab.com/ee/user/project/members/)
+- [ ] [Create a new merge request](https://docs.gitlab.com/ee/user/project/merge_requests/creating_merge_requests.html)
+- [ ] [Automatically close issues from merge requests](https://docs.gitlab.com/ee/user/project/issues/managing_issues.html#closing-issues-automatically)
+- [ ] [Enable merge request approvals](https://docs.gitlab.com/ee/user/project/merge_requests/approvals/)
+- [ ] [Set auto-merge](https://docs.gitlab.com/ee/user/project/merge_requests/merge_when_pipeline_succeeds.html)
+
+## Test and Deploy
+
+Use the built-in continuous integration in GitLab.
+
+- [ ] [Get started with GitLab CI/CD](https://docs.gitlab.com/ee/ci/quick_start/index.html)
+- [ ] [Analyze your code for known vulnerabilities with Static Application Security Testing (SAST)](https://docs.gitlab.com/ee/user/application_security/sast/)
+- [ ] [Deploy to Kubernetes, Amazon EC2, or Amazon ECS using Auto Deploy](https://docs.gitlab.com/ee/topics/autodevops/requirements.html)
+- [ ] [Use pull-based deployments for improved Kubernetes management](https://docs.gitlab.com/ee/user/clusters/agent/)
+- [ ] [Set up protected environments](https://docs.gitlab.com/ee/ci/environments/protected_environments.html)
+
+***
+
+# Editing this README
+
+When you're ready to make this README your own, just edit this file and use the handy template below (or feel free to structure it however you want - this is just a starting point!). Thanks to [makeareadme.com](https://www.makeareadme.com/) for this template.
+
+## Suggestions for a good README
+
+Every project is different, so consider which of these sections apply to yours. The sections used in the template are suggestions for most open source projects. Also keep in mind that while a README can be too long and detailed, too long is better than too short. If you think your README is too long, consider utilizing another form of documentation rather than cutting out information.
+
+## Name
+Choose a self-explaining name for your project.
+
+## Description
+Let people know what your project can do specifically. Provide context and add a link to any reference visitors might be unfamiliar with. A list of Features or a Background subsection can also be added here. If there are alternatives to your project, this is a good place to list differentiating factors.
+
+## Badges
+On some READMEs, you may see small images that convey metadata, such as whether or not all the tests are passing for the project. You can use Shields to add some to your README. Many services also have instructions for adding a badge.
+
+## Visuals
+Depending on what you are making, it can be a good idea to include screenshots or even a video (you'll frequently see GIFs rather than actual videos). Tools like ttygif can help, but check out Asciinema for a more sophisticated method.
+
+## Installation
+Within a particular ecosystem, there may be a common way of installing things, such as using Yarn, NuGet, or Homebrew. However, consider the possibility that whoever is reading your README is a novice and would like more guidance. Listing specific steps helps remove ambiguity and gets people to using your project as quickly as possible. If it only runs in a specific context like a particular programming language version or operating system or has dependencies that have to be installed manually, also add a Requirements subsection.
+
+## Usage
+Use examples liberally, and show the expected output if you can. It's helpful to have inline the smallest example of usage that you can demonstrate, while providing links to more sophisticated examples if they are too long to reasonably include in the README.
+
+## Support
+Tell people where they can go to for help. It can be any combination of an issue tracker, a chat room, an email address, etc.
+
+## Roadmap
+If you have ideas for releases in the future, it is a good idea to list them in the README.
+
+## Contributing
+State if you are open to contributions and what your requirements are for accepting them.
+
+For people who want to make changes to your project, it's helpful to have some documentation on how to get started. Perhaps there is a script that they should run or some environment variables that they need to set. Make these steps explicit. These instructions could also be useful to your future self.
+
+You can also document commands to lint the code or run tests. These steps help to ensure high code quality and reduce the likelihood that the changes inadvertently break something. Having instructions for running tests is especially helpful if it requires external setup, such as starting a Selenium server for testing in a browser.
+
+## Authors and acknowledgment
+Show your appreciation to those who have contributed to the project.
+
+## License
+For open source projects, say how it is licensed.
+
+## Project status
+If you have run out of energy or time for your project, put a note at the top of the README saying that development has slowed down or stopped completely. Someone may choose to fork your project or volunteer to step in as a maintainer or owner, allowing your project to keep going. You can also make an explicit request for maintainers.

+ 96 - 0
qhtx-eta-integrator/pom.xml

@@ -0,0 +1,96 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+
+    <groupId>com.qhtx.eta</groupId>
+    <artifactId>qhtx-eta-integrator</artifactId>
+    <version>1.0.0.0-SNAPSHOT</version>
+    <packaging>pom</packaging>
+
+    <properties>
+        <maven.compiler.source>8</maven.compiler.source>
+        <maven.compiler.target>8</maven.compiler.target>
+        <java.version>1.8</java.version>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+        <spring-boot.version>2.4.2</spring-boot.version>
+        <spring-cloud-alibaba.version>2021.1</spring-cloud-alibaba.version>
+        <spring-cloud.version>2020.0.6</spring-cloud.version>
+        <okhttp.version>4.9.3</okhttp.version>
+        <oracle.version>11.2.0.4</oracle.version>
+        <durid.version>1.1.22</durid.version>
+        <kafka.version>2.7.9</kafka.version>
+    </properties>
+
+    <modules>
+        <module>qhtx-integrator-starter</module>
+        <module>qhtx-integrator-domain</module>
+        <module>qhtx-integrator-common</module>
+        <module>qhtx-integrator-infra</module>
+    </modules>
+
+    <dependencyManagement>
+        <dependencies>
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-dependencies</artifactId>
+                <version>${spring-boot.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.cloud</groupId>
+                <artifactId>spring-cloud-dependencies</artifactId>
+                <version>${spring-cloud.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>com.alibaba.cloud</groupId>
+                <artifactId>spring-cloud-alibaba-dependencies</artifactId>
+                <version>${spring-cloud-alibaba.version}</version>
+                <type>pom</type>
+                <scope>import</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>com.squareup.okhttp3</groupId>
+                <artifactId>okhttp</artifactId>
+                <version>${okhttp.version}</version>
+            </dependency>
+
+            <dependency>
+                <groupId>junit</groupId>
+                <artifactId>junit</artifactId>
+                <version>4.13.2</version>
+                <scope>test</scope>
+            </dependency>
+
+            <dependency>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-starter-test</artifactId>
+                <scope>test</scope>
+            </dependency>
+        </dependencies>
+    </dependencyManagement>
+
+
+    <repositories>
+        <repository>
+            <id>central</id>
+            <name>aliyun maven</name>
+            <url>http://maven.aliyun.com/nexus/content/groups/public/</url>
+            <layout>default</layout>
+            <releases>
+                <enabled>true</enabled>
+            </releases>
+            <snapshots>
+                <enabled>true</enabled>
+            </snapshots>
+        </repository>
+    </repositories>
+</project>

+ 100 - 0
qhtx-eta-integrator/qhtx-integrator-common/pom.xml

@@ -0,0 +1,100 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.qhtx.eta</groupId>
+        <artifactId>qhtx-eta-integrator</artifactId>
+        <version>1.0.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>qhtx-integrator-common</artifactId>
+    <packaging>jar</packaging>
+
+
+    <properties>
+        <maven.compiler.source>1.8</maven.compiler.source>
+        <maven.compiler.target>1.8</maven.compiler.target>
+        <maven.compiler.compilerVersion>1.8</maven.compiler.compilerVersion>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <version>1.18.16</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct</artifactId>
+            <version>1.4.2.Final</version>
+        </dependency>
+        <dependency>
+            <groupId>org.mapstruct</groupId>
+            <artifactId>mapstruct-processor</artifactId>
+            <version>1.4.2.Final</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-log4j2</artifactId>
+            <version>2.4.2</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.24</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-lang3</artifactId>
+            <version>3.11</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-collections4</artifactId>
+            <version>4.4</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.google.guava</groupId>
+            <artifactId>guava</artifactId>
+            <version>19.0</version>
+        </dependency>
+        <!--springboot-->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-context</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot</artifactId>
+        </dependency>
+
+        <!--okhttp-->
+        <dependency>
+            <groupId>com.squareup.okhttp3</groupId>
+            <artifactId>okhttp</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.aspectj</groupId>
+            <artifactId>aspectjweaver</artifactId>
+        </dependency>
+
+        <!-- Spring AOP -->
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-aop</artifactId>
+        </dependency>
+        
+        <dependency>
+            <groupId>org.springframework</groupId>
+            <artifactId>spring-core</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 19 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/annotation/DataOperator.java

@@ -0,0 +1,19 @@
+package com.qhtx.eta.common.annotation;
+
+import com.qhtx.eta.common.eunms.ETAApiType;
+import com.qhtx.eta.common.eunms.OperatorEnum;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.METHOD)
+public @interface DataOperator {
+    Class<?> dataType() default Object.class;
+
+    String[] fields() default {};
+
+    OperatorEnum operator() default OperatorEnum.BATCH;
+
+    ETAApiType apiType();
+}

+ 143 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/aspect/DataOperatorAspect.java

@@ -0,0 +1,143 @@
+package com.qhtx.eta.common.aspect;
+
+import com.alibaba.fastjson.JSON;
+import com.google.common.util.concurrent.RateLimiter;
+import com.qhtx.eta.common.annotation.DataOperator;
+import com.qhtx.eta.common.config.DataSourceProperties;
+import com.qhtx.eta.common.eunms.ETAApiType;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.common.eunms.OperatorEnum;
+import com.qhtx.eta.common.exception.ETAException;
+import lombok.extern.slf4j.Slf4j;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.beans.Introspector;
+import java.beans.PropertyDescriptor;
+import java.sql.SQLRecoverableException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+
+@Aspect
+@Component
+@Slf4j
+public class DataOperatorAspect {
+
+    @Resource(name = "dataRateLimiter")
+    private RateLimiter dataRateLimiter;
+
+    @Resource(name = "quotaRateLimiter")
+    private RateLimiter quotaRateLimiter;
+
+    @Resource
+    private DataSourceProperties dataSourceProperties;
+
+    @Around("@annotation(com.qhtx.eta.common.annotation.DataOperator)")
+    public Object handleDataOperator(ProceedingJoinPoint joinPoint) throws Throwable {
+        Object[] parameters = joinPoint.getArgs();
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        DataOperator dataOperator = signature.getMethod().getAnnotation(DataOperator.class);
+        Map<String, Object> operatorParams = new HashMap<>();
+        if (dataOperator.operator() == OperatorEnum.BATCH) {
+            if (parameters.length > 0 && parameters[0] instanceof List) {
+                List<?> dataList = (List<?>) parameters[0];
+                Class<?> clazz = dataOperator.dataType();
+                if (!dataList.isEmpty() && clazz.isAssignableFrom(dataList.get(0).getClass())) {
+                    PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+                    for (String field : dataOperator.fields()) {
+                        for (PropertyDescriptor pd : propertyDescriptors) {
+                            if (field.equals(pd.getName())) {
+                                operatorParams.put(pd.getName(), pd.getReadMethod().invoke(dataList.get(0)));
+                                break;
+                            }
+                        }
+                    }
+                }
+            }
+        } else {
+            Class<?> clazz = dataOperator.dataType();
+            if (parameters.length > 0 && clazz.isAssignableFrom(parameters[0].getClass())) {
+                PropertyDescriptor[] propertyDescriptors = Introspector.getBeanInfo(clazz).getPropertyDescriptors();
+                for (String field : dataOperator.fields()) {
+                    for (PropertyDescriptor pd : propertyDescriptors) {
+                        if (field.equals(pd.getName())) {
+                            operatorParams.put(pd.getName(), pd.getReadMethod().invoke((parameters[0])));
+                            break;
+                        }
+                    }
+                }
+            }
+        }
+        if (!limit(dataOperator.apiType())) {
+            if (dataOperator.apiType() == ETAApiType.QUOTA) {
+                throw new ETAException(ErrorEnum.SYSTEM_ERROR.getCode(), String.format(ErrorEnum.SYSTEM_ERROR.getMsg(), "数据库操作请求被拒绝,当前无可用请求令牌"));
+            }
+            if (dataOperator.apiType() == ETAApiType.DATA) {
+                throw new ETAException(ErrorEnum.SYSTEM_ERROR.getCode(), String.format(ErrorEnum.SYSTEM_ERROR.getMsg(), "数据库操作请求被拒绝,当前无可用请求令牌,请求指标{" + JSON.toJSONString(operatorParams) + "}"));
+            }
+        }
+
+        int retryCount = 0;
+        try {
+            // 执行方法
+            return joinPoint.proceed();
+        } catch (Exception e) {
+            SQLRecoverableException sqlException = findSQLRecoverableCause(e);
+            if (sqlException != null) {
+                log.warn(String.format(ErrorEnum.DATASOURCE_EXECUTE_ERROR.getMsg(), "可恢复的数据库异常"));
+                while (retryCount < dataSourceProperties.getRetryTimes()) {
+                    retryCount++;
+                    try {
+                        TimeUnit.MILLISECONDS.sleep(dataSourceProperties.getRetryInterval());
+                        log.info("尝试重新提交数据库执行操作:{}次", retryCount);
+                        Object obj = joinPoint.proceed();
+                        if (obj != null) {
+                            log.info("重试成功:{},第{}次尝试", JSON.toJSONString(operatorParams), retryCount);
+                        }
+                        return obj;
+                    } catch (InterruptedException interruptEx) {
+                        Thread.currentThread().interrupt(); // 保持中断状态
+                        log.error(ErrorEnum.INTERNAL_SERVER_ERROR.getMsg(), interruptEx);
+                        throw new ETAException(ErrorEnum.INTERNAL_SERVER_ERROR);
+                    } catch (SQLRecoverableException retrySqlEx) {
+                        // 如果重试也失败了,并且还是SQLRecoverableException,则继续循环或在达到重试次数后抛出
+                        sqlException = retrySqlEx;
+                    }
+                }
+                throw new ETAException(ErrorEnum.DATASOURCE_EXECUTE_ERROR.getCode(), String.format(ErrorEnum.DATASOURCE_EXECUTE_ERROR.getMsg(), sqlException.getMessage()));
+            } else {
+                // 对其他类型的异常进行处理
+                throw new ETAException(ErrorEnum.SYSTEM_ERROR.getCode(), e.getMessage());
+            }
+        }
+    }
+
+    // 方法来查找并返回SQLRecoverableException,如果存在的话
+    private SQLRecoverableException findSQLRecoverableCause(Throwable throwable) {
+        if (throwable instanceof SQLRecoverableException) {
+            return (SQLRecoverableException) throwable;
+        } else if (throwable.getCause() != null) {
+            return findSQLRecoverableCause(throwable.getCause());
+        }
+        return null;
+    }
+
+    private boolean limit(ETAApiType etAApiType) {
+        switch (etAApiType) {
+            case DATA:
+                return dataRateLimiter.tryAcquire();
+            case QUOTA:
+                return quotaRateLimiter.tryAcquire();
+            default:
+                return true;
+        }
+    }
+
+
+}

+ 25 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/DataSourceProperties.java

@@ -0,0 +1,25 @@
+package com.qhtx.eta.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@Data
+@ConfigurationProperties(prefix = "eta.datasource")
+public class DataSourceProperties {
+    /**
+     * 读取超时时间
+     */
+    private int retryInterval;
+
+    /**
+     * 重试次数
+     */
+    private int retryTimes;
+
+    private LimitProperties data;
+
+    private LimitProperties quota;
+}

+ 9 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/LimitProperties.java

@@ -0,0 +1,9 @@
+package com.qhtx.eta.common.config;
+
+import lombok.Data;
+
+@Data
+public class LimitProperties {
+    private int chunkSize;
+    private int permitsPerSecond;
+}

+ 30 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/config/OkHttpClientProperties.java

@@ -0,0 +1,30 @@
+package com.qhtx.eta.common.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
+
+
+@Component
+@Data
+@ConfigurationProperties(prefix = "okhttp")
+public class OkHttpClientProperties {
+    /**
+     * 连接超时时间
+     */
+    private int connectTimeout;
+    /**
+     * 读取超时时间
+     */
+    private int readTimeout;
+
+    /**
+     * 重试次数
+     */
+    private int retryTimes;
+    /**
+     * 重试间隔
+     */
+    private int retryInterval;
+
+}

+ 37 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/constant/ETAConstants.java

@@ -0,0 +1,37 @@
+package com.qhtx.eta.common.constant;
+
+public class ETAConstants {
+
+    /**
+     * ETA api contants
+     */
+    public static final String NONCE = "Nonce";
+
+    public static final String APP_ID = "AppId";
+    public static final String SIGNATURE = "Signature";
+    public static final String TIME_STAMP = "Timestamp";
+
+    public static final String UNKNOWN_ERROR = "unknown error";
+
+    public static final String ETA_EMPTY_RESPONSE_COMMENT = "eta response is empty";
+    /**
+     * thread pool
+     */
+    public static final String THREAD_POOL_ETA_INFO = "eta_info";
+    public static final String THREAD_POOL_ETA_DATA = "eta_data";
+
+    /**
+     * date
+     */
+    public static final String DATE_PATTERN = "yyyy-MM-dd";
+    public static final String TIMESTAMP_PATTERN = "yyyy-MM-dd HH:mm:ss";
+    public static final String TIME_ZONE = "Asia/Shanghai";
+
+    /**
+     * other
+     */
+    public static final String LINE_SEPARATOR = "===========================================================";
+    public static final String MAPPER_LOCATION = "classpath*:mapper/*.xml";
+
+    public static final String ODS_DATA_TABLE_NAME = "T_ETA_API_QUOTA_DATA";
+}

+ 111 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/entity/SignatureParam.java

@@ -0,0 +1,111 @@
+package com.qhtx.eta.common.entity;
+
+import lombok.Data;
+import org.apache.commons.lang3.StringUtils;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 验签参数
+ * Created by chenhan on 2024/04/24.
+ */
+@Data
+public class SignatureParam {
+    /**
+     * 随机字符串
+     */
+    private String nonce;
+    /**
+     * 时间戳
+     */
+    private Long timestamp;
+
+    /**
+     * 应用ID
+     */
+    private String appid;
+
+    private String secretKey;
+
+    public SignatureParam(Builder builder) {
+        this.nonce = builder.nonce;
+        this.timestamp = builder.timestamp;
+        this.appid = builder.appid;
+        this.secretKey = builder.secretKey;
+    }
+
+
+    public static class Builder {
+        /**
+         * 随机字符串
+         */
+        private String nonce;
+        /**
+         * 时间戳
+         */
+        private Long timestamp;
+        /**
+         * 应用ID
+         */
+        private String appid;
+        /**
+         * 密钥
+         */
+        private String secretKey;
+
+        /**
+         * 设置随机字符串
+         */
+        public Builder nonce(String nonce) {
+            this.nonce = nonce;
+            return this;
+        }
+
+        /**
+         * 设置时间戳
+         */
+        public Builder timestamp(Long timestamp) {
+            this.timestamp = timestamp;
+            return this;
+        }
+
+        /**
+         * 设置应用ID
+         */
+        public Builder appid(String appid) {
+            this.appid = appid;
+            return this;
+        }
+
+        public Builder secretKey(String secretKey) {
+            this.secretKey = secretKey;
+            return this;
+        }
+
+        /**
+         * 构建SignatureParam实例
+         */
+        public SignatureParam build() {
+            // 可在此处添加必要的参数校验,如不能为空等
+            return new SignatureParam(this);
+        }
+    }
+
+
+    @Override
+    public String toString() {
+        Map<String, Object> resultMap = new HashMap<>(3);
+        if (StringUtils.isNotBlank(this.appid)) {
+            resultMap.put("appid", this.appid);
+        }
+        if (StringUtils.isNotBlank(this.nonce)) {
+            resultMap.put("nonce", this.nonce);
+        }
+        if (this.timestamp != null) {
+            resultMap.put("timestamp", this.timestamp);
+        }
+        return resultMap.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).sorted().collect(Collectors.joining("&"));
+    }
+}

+ 8 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/DataSourceType.java

@@ -0,0 +1,8 @@
+package com.qhtx.eta.common.eunms;
+
+public enum DataSourceType {
+    ODS, DW;
+
+    DataSourceType() {
+    }
+}

+ 7 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ETAApiType.java

@@ -0,0 +1,7 @@
+package com.qhtx.eta.common.eunms;
+
+public enum ETAApiType {
+    QUOTA,
+    DATA,
+    ;
+}

+ 27 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ETARetryEnum.java

@@ -0,0 +1,27 @@
+package com.qhtx.eta.common.eunms;
+
+import lombok.Getter;
+
+@Getter
+public enum ETARetryEnum {
+    SERVICE_UNAVAILABLE(503, "服务不可用"),
+    GATEWAY_TIMEOUT(504, "网关超时"),
+    NOT_FOUND(404, "服务不存在"),
+    ;
+    private int code;
+    private String desc;
+
+    ETARetryEnum(int code, String desc) {
+        this.code = code;
+        this.desc = desc;
+    }
+
+    public static boolean needRetry(int code) {
+        for (ETARetryEnum etaRetryEnum : ETARetryEnum.values()) {
+            if (etaRetryEnum.code == code) {
+                return true;
+            }
+        }
+        return false;
+    }
+}

+ 45 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/ErrorEnum.java

@@ -0,0 +1,45 @@
+package com.qhtx.eta.common.eunms;
+
+import lombok.Getter;
+
+@Getter
+public enum ErrorEnum {
+
+    /**
+     * SYSTEM INNER ERROR CODE
+     */
+    BEAN_COVERT_TO_MAP_ERROR("00001", "bean转换成map失败"),
+    /**
+     * SYSTEM ERROR CODE
+     */
+    SYSTEM_ERROR("10001", "系统错误:[%s]"),
+    API_NOT_FOUND("10002", "API接口不存在"),
+    PROXY_REGISTER_ERROR("10003", "注册接口代理失败"),
+    API_RESPONSE_CONFIG_ERROR("10004", "API接口应答配置错误,应答类不能为NULL"),
+    DATASOURCE_EXECUTE_ERROR("10005", "数据库执行异常[%s]"),
+    INTERNAL_SERVER_ERROR("10006", "系统异常中断"),
+    UNKNOWN_DATASOURCE_ERROR("10007", "未知数据源"),
+    /*HTTP ERROR CODE*/
+    HTTP_METHOD_NOT_ALLOWED("20001", "http请求方法不允许"), /*INTERNAL ERROR CODE*/ //HTTP ERROR CODE
+    ILLEGAL_HEAD_PARAM("20002", "非法的head参数类型{%s}:${%s}"), /*INTERNAL ERROR CODE*/
+    ILLEGAL_IPV4_ADDRESS("20003", "非法的ipv4地址"),
+    ILLEGAL_IPV6_ADDRESS("20004", "非法的ipv6地址"),
+    ILLEGAL_URL_ADDRESS("20005", "非法的URL地址"),
+
+    URL_NOT_NULL("20005", "url不能为空"),
+
+    API_CALL_ERROR("20006", "调用api失败:[%d:%s]"),
+
+    PARSE_RESPONSE_ERROR("20007", "解析返回结果失败%s"),
+    RESPONSE_EMPTY_ERROR("20008", "接口请求应答为空"),
+    PARAM_TYPE_ERROR("20009", "参数类型错误"),
+    ;
+    private String code;
+    private String msg;
+
+    ErrorEnum(String code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+
+}

+ 19 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/HttpMethod.java

@@ -0,0 +1,19 @@
+package com.qhtx.eta.common.eunms;
+
+public enum HttpMethod {
+
+    GET("GET"),
+    POST("POST"),
+    PUT("PUT"),
+    DELETE("DELETE");
+
+    private String value;
+
+    private HttpMethod(String value) {
+        this.value = value;
+    }
+
+    public String getValue() {
+        return value;
+    }
+}

+ 23 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/LimiterType.java

@@ -0,0 +1,23 @@
+package com.qhtx.eta.common.eunms;
+
+import lombok.Getter;
+
+@Getter
+public enum LimiterType {
+    GUAVA_RATE_LIMITER("GuavaRateLimiter"),
+    ;
+    private String name;
+
+    LimiterType(String name) {
+        this.name = name;
+    }
+
+    public static LimiterType getByName(String name) {
+        for (LimiterType type : LimiterType.values()) {
+            if (type.getName().equals(name)) {
+                return type;
+            }
+        }
+        return null;
+    }
+}

+ 17 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/eunms/OperatorEnum.java

@@ -0,0 +1,17 @@
+package com.qhtx.eta.common.eunms;
+
+import lombok.Getter;
+
+@Getter
+public enum OperatorEnum {
+    INSERT("insert"),
+    UPDATE("update"),
+    BATCH("batch"),
+    ;
+    private String value;
+
+    OperatorEnum(String value) {
+        this.value = value;
+    }
+
+}

+ 81 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/exception/ETAException.java

@@ -0,0 +1,81 @@
+package com.qhtx.eta.common.exception;
+
+import com.qhtx.eta.common.eunms.ErrorEnum;
+
+/**
+ * ETA 业务异常类
+ */
+public class ETAException extends RuntimeException {
+
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * 错误代码,用于标识具体的业务错误类型。
+     */
+    private String errorCode;
+
+    /**
+     * 错误消息,描述业务异常的具体情况。
+     */
+    private String errorMessage;
+
+    /**
+     * 可选的附加信息,如受影响的实体ID、操作详情等。
+     */
+    private Object additionalInfo;
+
+    public ETAException(ErrorEnum errorEnum) {
+        super(errorEnum.getMsg());
+        this.errorCode = errorEnum.getCode();
+        this.errorMessage = errorEnum.getMsg();
+    }
+
+    public ETAException(String errorCode, String errorMessage) {
+        super(errorMessage);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+
+    public ETAException(Throwable cause) {
+        super(cause);
+        this.errorCode = ErrorEnum.SYSTEM_ERROR.getCode();
+        this.errorMessage = cause.getMessage();
+    }
+
+    public ETAException(String errorCode, String errorMessage, Throwable cause) {
+        super(errorMessage, cause);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+    }
+
+    public ETAException(String errorCode, String errorMessage, Object additionalInfo) {
+        super(errorMessage);
+        this.errorCode = errorCode;
+        this.errorMessage = errorMessage;
+        this.additionalInfo = additionalInfo;
+    }
+
+    // Add other constructors as needed, depending on your requirements.
+
+    public String getErrorCode() {
+        return errorCode;
+    }
+
+    public String getErrorMessage() {
+        return errorMessage;
+    }
+
+    public Object getAdditionalInfo() {
+        return additionalInfo;
+    }
+
+    @Override
+    public String getMessage() {
+        return String.format("Business Error: [Code=%s] %s", errorCode, errorMessage);
+    }
+
+    @Override
+    public String toString() {
+        return String.format("BusinessException{errorCode='%s', errorMessage='%s', additionalInfo=%s}", errorCode, errorMessage, additionalInfo);
+    }
+}

+ 95 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/interceptor/RetryInterceptor.java

@@ -0,0 +1,95 @@
+package com.qhtx.eta.common.interceptor;
+
+import com.qhtx.eta.common.eunms.ETARetryEnum;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import okhttp3.*;
+import org.jetbrains.annotations.NotNull;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class RetryInterceptor implements Interceptor {
+    private static final Logger log = LoggerFactory.getLogger(RetryInterceptor.class);
+    /**
+     * 重试次数
+     */
+    private int retryTimes;
+    /**
+     * 重试间隔
+     */
+    private int retryInterval;
+
+    private RetryInterceptor(int retryInterval, int retryTimes) {
+        this.retryInterval = retryInterval;
+        this.retryTimes = retryTimes;
+    }
+
+    @NotNull
+    @Override
+    public Response intercept(@NotNull Chain chain) throws IOException {
+        AtomicInteger retryCount = new AtomicInteger(0);
+        Request request = chain.request();
+        Response response = null;
+        while (retryCount.getAndIncrement() < retryTimes) {
+            try {
+                response = chain.proceed(request);
+                if (!isSuccessful(response) && shouldRetry(response.code())) {
+                    TimeUnit.MILLISECONDS.sleep(retryInterval);
+                    log.warn("尝试重新请求第 " + retryCount + " 次,上次应答为:[{}:{}]", response.code(), response.message());
+                    response.close();
+                    continue;
+                }
+                return response;
+            } catch (IOException var1) {
+                log.warn("请求失败,应答结果为:[{}]", var1.getMessage());
+            } catch (InterruptedException var2) {
+                log.warn("请求等待中断异常:[{}]", var2.getMessage());
+            }
+        }
+        if (response != null) {
+            throw new IOException(String.format("请求失败,最后一次应答结果为:[%d:%s]", response.code(), response.message()));
+        }
+        throw new IOException(String.format("请求失败,最后一次应答结果为:[%s]", ErrorEnum.RESPONSE_EMPTY_ERROR.getMsg()));
+    }
+
+
+    public static class Builder {
+        /**
+         * 重试次数
+         */
+        private int retryTimes;
+        /**
+         * 重试间隔
+         */
+        private int retryInterval;
+
+
+        public Builder retryTimes(int retryTimes) {
+            this.retryTimes = retryTimes;
+            return this;
+        }
+
+        public Builder retryInterval(int retryInterval) {
+            this.retryInterval = retryInterval;
+            return this;
+        }
+
+        public RetryInterceptor build() {
+            return new RetryInterceptor(retryInterval, retryTimes);
+        }
+    }
+
+    private boolean isSuccessful(Response response) {
+        return response.isSuccessful();
+    }
+
+
+    private boolean shouldRetry(int code) {
+        return ETARetryEnum.needRetry(code);
+    }
+
+
+}

+ 8 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/Limiter.java

@@ -0,0 +1,8 @@
+package com.qhtx.eta.common.limiter;
+
+public interface Limiter<T> {
+
+    boolean limit();
+
+    T offer(int permitsPerSecond);
+}

+ 27 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/LimiterProvider.java

@@ -0,0 +1,27 @@
+package com.qhtx.eta.common.limiter;
+
+import com.qhtx.eta.common.eunms.LimiterType;
+
+import java.util.Map;
+import java.util.ServiceLoader;
+import java.util.concurrent.ConcurrentHashMap;
+
+public enum LimiterProvider {
+    INSTANCE;
+    private final Map<LimiterType, Limiter<?>> cache = new ConcurrentHashMap<>();
+
+    LimiterProvider() {
+        ServiceLoader<Limiter> loader = ServiceLoader.load(Limiter.class);
+        loader.forEach(provider -> {
+            String limiterName = provider.getClass().getSimpleName();
+            LimiterType type = LimiterType.getByName(limiterName);
+            if (type != null) {
+                cache.putIfAbsent(type, provider);
+            }
+        });
+    }
+
+    public Limiter<?> getLimiter(LimiterType type) {
+        return cache.get(type);
+    }
+}

+ 16 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/limiter/impl/GuavaRateLimiter.java

@@ -0,0 +1,16 @@
+package com.qhtx.eta.common.limiter.impl;
+
+import com.google.common.util.concurrent.RateLimiter;
+import com.qhtx.eta.common.limiter.Limiter;
+
+public class GuavaRateLimiter implements Limiter<RateLimiter> {
+    @Override
+    public boolean limit() {
+        return false;
+    }
+
+    @Override
+    public RateLimiter offer(int permitsPerSecond) {
+        return RateLimiter.create(permitsPerSecond);
+    }
+}

+ 128 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/AssertUtils.java

@@ -0,0 +1,128 @@
+package com.qhtx.eta.common.utils;
+
+import com.qhtx.eta.common.eunms.ErrorEnum;
+
+import java.net.*;
+import java.util.Collection;
+import java.util.Objects;
+
+public class AssertUtils {
+    private AssertUtils() {
+
+    }
+
+    /**
+     * 断言对象非空。
+     *
+     * @param object  待检查的对象
+     * @param message 断言失败时抛出的异常消息
+     * @throws IllegalArgumentException 当对象为空时抛出
+     */
+    public static void assertNotNull(Object object, String message) {
+        if (object == null) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    /**
+     * 断言字符串非空且长度不为0。
+     *
+     * @param str     待检查的字符串
+     * @param message 断言失败时抛出的异常消息
+     * @throws IllegalArgumentException 当字符串为空或长度为0时抛出
+     */
+    public static void assertNonEmptyString(String str, String message) {
+        if (str == null || str.isEmpty()) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    /**
+     * 断言集合非空且至少包含一个元素。
+     *
+     * @param collection 待检查的集合
+     * @param message    断言失败时抛出的异常消息
+     * @throws IllegalArgumentException 当集合为空或无元素时抛出
+     */
+    public static <T extends Collection<?>> void assertNonEmptyCollection(T collection, String message) {
+        if (collection == null || collection.isEmpty()) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+
+    /**
+     * 断言两个对象相等(使用equals方法比较)。
+     *
+     * @param expected 期望的对象
+     * @param actual   实际的对象
+     * @param message  断言失败时抛出的异常消息
+     * @throws IllegalArgumentException 当对象不相等时抛出
+     */
+    public static void assertEquals(Object expected, Object actual, String message) {
+        if (!Objects.equals(expected, actual)) {
+            throw new IllegalArgumentException(message);
+        }
+    }
+
+    private static boolean isValidIPv6(String ip) {
+        if (ip == null || ip.isEmpty()) {
+            return false;
+        }
+
+        String regex = "(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}";
+        return ip.matches(regex);
+    }
+
+    private static boolean isValidIPv4(String ip) {
+        if (ip == null || ip.isEmpty()) {
+            return false;
+        }
+
+        String[] parts = ip.split("\\.");
+        if (parts.length != 4) {
+            return false;
+        }
+
+        for (String part : parts) {
+            try {
+                int num = Integer.parseInt(part);
+                if (num < 0 || num > 255) {
+                    return false;
+                }
+            } catch (NumberFormatException e) {
+                return false;
+            }
+        }
+        return true;
+    }
+
+    private static void isValidURL(String urlStr, boolean isIPv6) {
+        if (urlStr == null || urlStr.isEmpty()) {
+        }
+        try {
+            assertNonEmptyString(urlStr, ErrorEnum.URL_NOT_NULL.getMsg());
+            URL url = new URL(urlStr);
+            url.toURI();
+            String hostname = url.getHost();
+            InetAddress inetAddress = InetAddress.getByName(hostname);
+            String ipAddress = inetAddress.getHostAddress();
+            if (isIPv6) {
+                if (!isValidIPv6(ipAddress)) {
+                    throw new IllegalArgumentException(ErrorEnum.ILLEGAL_IPV6_ADDRESS.getMsg());
+                }
+            } else {
+                if (!isValidIPv4(ipAddress)) {
+                    throw new IllegalArgumentException(ErrorEnum.ILLEGAL_IPV4_ADDRESS.getMsg());
+                }
+            }
+        } catch (MalformedURLException | URISyntaxException | UnknownHostException e) {
+            throw new IllegalArgumentException(ErrorEnum.ILLEGAL_URL_ADDRESS.getMsg());
+        }
+    }
+
+    public static void assertLegalUrl(String url) {
+        isValidURL(url, false);
+    }
+
+}

+ 81 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/HttpClient.java

@@ -0,0 +1,81 @@
+package com.qhtx.eta.common.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.qhtx.eta.common.exception.ETAException;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+
+import java.io.IOException;
+import java.time.Instant;
+import java.util.Date;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * OKHTTP 客户端
+ *
+ * @description: 主要对okHttpClient的基础封装,提供发送接口,url和head参数的初始化
+ */
+@Slf4j
+public class HttpClient {
+    private static volatile OkHttpClient instance;
+
+    public HttpClient(OkHttpClient okHttpClient) {
+        instance = okHttpClient;
+    }
+
+    private HttpClient() {
+        instance = new OkHttpClient.Builder().build();
+    }
+
+    public static OkHttpClient getInstance() {
+        if (instance == null) {
+            synchronized (HttpClient.class) {
+                if (instance == null) {
+                    new HttpClient();
+                }
+            }
+        }
+        return instance;
+    }
+
+    public Response send(Request request) throws IOException {
+        if (log.isInfoEnabled()) {
+            log.info("api请求接口:{},head信息:{}", request.url(), JSONObject.toJSONString(request.headers()));
+        }
+        return getInstance().newCall(request).execute();
+    }
+
+    public String buildGetUrl(String url, Map<String, Object> params) {
+        String path;
+        if (params != null && !params.isEmpty()) {
+            String paramStr = params.entrySet().stream().map(entry -> entry.getKey() + "=" + entry.getValue()).collect(Collectors.joining("&"));
+            path = String.format("%s?%s", url, paramStr);
+        } else {
+            path = url;
+        }
+        AssertUtils.assertLegalUrl(path);
+        return path;
+    }
+
+    public Headers buildHeader(Map<String, ?> params) {
+        Headers.Builder headersBuilder = new Headers.Builder();
+        for (Map.Entry<String, ?> entry : params.entrySet()) {
+            if (entry.getValue() instanceof String) {
+                headersBuilder.add(entry.getKey(), (String) entry.getValue());
+                continue;
+            }
+            if (entry.getValue() instanceof Date) {
+                headersBuilder.add(entry.getKey(), (Date) entry.getValue());
+                continue;
+            }
+            if (entry.getValue() instanceof Instant) {
+                headersBuilder.add(entry.getKey(), (Instant) entry.getValue());
+                continue;
+            }
+            throw new ETAException(ErrorEnum.ILLEGAL_HEAD_PARAM.getCode(), String.format(ErrorEnum.ILLEGAL_HEAD_PARAM.getMsg(), entry.getValue(), entry.getValue().getClass()));
+        }
+        return headersBuilder.build();
+    }
+}

+ 53 - 0
qhtx-eta-integrator/qhtx-integrator-common/src/main/java/com/qhtx/eta/common/utils/SignatureUtil.java

@@ -0,0 +1,53 @@
+package com.qhtx.eta.common.utils;
+
+import com.qhtx.eta.common.entity.SignatureParam;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import java.nio.charset.StandardCharsets;
+import java.security.InvalidKeyException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Base64;
+
+@Slf4j
+public class SignatureUtil {
+
+    private static final String HMAC_SHA256_ALGORITHM = "HmacSHA256";
+
+    /**
+     * 生成HMAC-SHA256签名。
+     *
+     * @return 签名字符串(Base64编码)
+     * @throws Exception 如果签名过程中发生错误
+     */
+    public static String generateSignature(SignatureParam signatureParam) {
+        try {
+            return sign(signatureParam.toString(), signatureParam.getSecretKey());
+        } catch (Exception e) {
+            log.warn("生成签名失败:{}", e.getMessage());
+        }
+        return "";
+    }
+
+    public static String generateNonce() {
+        return RandomStringUtils.randomAlphabetic(32);
+    }
+
+    public static Long generateTimestamp() {
+        return System.currentTimeMillis() / 1000;
+    }
+
+
+    public static String sign(String signStr, String apiKey) throws NoSuchAlgorithmException, InvalidKeyException {
+        // 使用HMAC-SHA256算法计算签名
+        Mac mac = Mac.getInstance(HMAC_SHA256_ALGORITHM);
+        SecretKeySpec secretKey = new SecretKeySpec(apiKey.getBytes(StandardCharsets.UTF_8), HMAC_SHA256_ALGORITHM);
+        mac.init(secretKey);
+        byte[] sign = mac.doFinal(signStr.getBytes(StandardCharsets.UTF_8));
+
+        return StringUtils.replaceEach(Base64.getEncoder().encodeToString(sign), new String[]{"+", "/"}, new String[]{"-", "_"});
+    }
+}

+ 39 - 0
qhtx-eta-integrator/qhtx-integrator-domain/pom.xml

@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.qhtx.eta</groupId>
+        <artifactId>qhtx-eta-integrator</artifactId>
+        <version>1.0.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>qhtx-integrator-domain</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-core</artifactId>
+            <version>2.12.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.fasterxml.jackson.core</groupId>
+            <artifactId>jackson-databind</artifactId>
+            <version>2.12.7</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.commons</groupId>
+            <artifactId>commons-pool2</artifactId>
+            <version>2.9.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.qhtx.eta</groupId>
+            <artifactId>qhtx-integrator-infra</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+    </dependencies>
+</project>

+ 75 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/ApiServiceHolder.java

@@ -0,0 +1,75 @@
+package com.qhtx.eta.domain.api;
+
+import com.qhtx.eta.domain.enums.ETAInterfaceEnum;
+import com.qhtx.eta.domain.api.http.response.inner.InnerResponse;
+import com.qhtx.eta.domain.api.proxy.ApiParameterProxy;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.common.exception.ETAException;
+import com.qhtx.eta.domain.api.http.ETAHttpClient;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+
+import java.lang.reflect.InvocationTargetException;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * API 接口持有者
+ */
+@Component
+@Slf4j
+public class ApiServiceHolder {
+
+    private static final Map<ETAInterfaceEnum, ApiParameterProxy> proxyMap = new ConcurrentHashMap<>();
+    private ETAHttpClient etaHttpClient;
+
+    public void registerClient(ETAHttpClient etaHttpClient) {
+        this.etaHttpClient = etaHttpClient;
+    }
+
+    public void register(ETAInterfaceEnum etaInterfaceEnum) {
+        try {
+            Class<? extends ApiParameterProxy> proxy = etaInterfaceEnum.getProxy();
+            proxyMap.put(etaInterfaceEnum, proxy.getConstructor().newInstance());
+        } catch (NoSuchMethodException | InstantiationException | IllegalAccessException |
+                 InvocationTargetException e) {
+            log.warn("注册ETA代理失败{}", e.getMessage());
+            throw new ETAException(ErrorEnum.PROXY_REGISTER_ERROR);
+        }
+
+    }
+
+    /**
+     * API接口调用
+     *
+     * @return Response
+     */
+    public List<?> runApi(ETAInterfaceEnum etaInterfaceEnum) {
+        return runApi(etaInterfaceEnum, null);
+    }
+
+    public List<?> runApi(ETAInterfaceEnum etaInterfaceEnum, Object param) {
+        if (!etaInterfaceEnum.getEnable()) {
+            throw new ETAException(ErrorEnum.API_NOT_FOUND);
+        }
+        if (etaInterfaceEnum.getResponse() == null) {
+            throw new ETAException(ErrorEnum.API_RESPONSE_CONFIG_ERROR);
+        }
+        ApiParameterProxy<?> apiParameterProxy = proxyMap.get(etaInterfaceEnum);
+        Map<String, Object> params = null;
+        if (apiParameterProxy != null) {
+            params = apiParameterProxy.parameters(param);
+        }
+        InnerResponse response = etaHttpClient.send(etaInterfaceEnum, params);
+        if (isSuccess(response)) {
+            return response.getData();
+        }
+        log.warn("调用接口失败:{}", response.getErrorMsg());
+        return null;
+    }
+
+    private boolean isSuccess(InnerResponse response) {
+        return response != null && response.getSuccess();
+    }
+}

+ 14 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/ETAHttpClient.java

@@ -0,0 +1,14 @@
+package com.qhtx.eta.domain.api.http;
+
+import com.qhtx.eta.domain.api.http.response.inner.InnerResponse;
+import com.qhtx.eta.domain.enums.ETAInterfaceEnum;
+
+import java.util.Map;
+
+/**
+ * ETAHttpClient 是对ETA API请求封装的工具接口
+ */
+public interface ETAHttpClient {
+    InnerResponse send(ETAInterfaceEnum etaInterface, Map<String, Object> params);
+
+}

+ 133 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/ETAHttpClientImpl.java

@@ -0,0 +1,133 @@
+package com.qhtx.eta.domain.api.http;
+
+import com.alibaba.fastjson.JSONObject;
+import com.qhtx.eta.domain.api.http.response.eta.ETAHttpResponse;
+import com.qhtx.eta.domain.config.ETAConfigProperties;
+import com.qhtx.eta.domain.enums.ETAInterfaceEnum;
+import com.qhtx.eta.domain.api.http.response.inner.InnerResponse;
+import com.qhtx.eta.common.constant.ETAConstants;
+import com.qhtx.eta.common.entity.SignatureParam;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.common.eunms.HttpMethod;
+import com.qhtx.eta.common.exception.ETAException;
+import com.qhtx.eta.common.utils.HttpClient;
+import com.qhtx.eta.common.utils.SignatureUtil;
+import lombok.extern.slf4j.Slf4j;
+import okhttp3.*;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.io.IOException;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Objects;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * ETAHttpClient的实现类
+ */
+@Component
+@Slf4j
+public class ETAHttpClientImpl implements ETAHttpClient {
+    @Resource
+    private ETAConfigProperties properties;
+    @Resource
+    private HttpClient httpClient;
+
+    private static final Map<String, ETAInterfaceEnum> apiInterfaceMap = new ConcurrentHashMap<String, ETAInterfaceEnum>();
+
+    @PostConstruct
+    public void init() {
+        for (ETAInterfaceEnum etaInterface : ETAInterfaceEnum.values()) {
+            apiInterfaceMap.put(etaInterface.getApi(), etaInterface);
+        }
+    }
+
+
+    private Request buildETARequest(ETAInterfaceEnum etaInterface, Map<String, Object> params) {
+        String api = etaInterface.getApi();
+        String url = properties.getUrl().endsWith("/") ? properties.getUrl().substring(0, properties.getUrl().length() - 1) : properties.getUrl();
+        String apiUrl = String.format("%s%s", url, api);
+        if (Objects.requireNonNull(etaInterface.getMethod()) == HttpMethod.GET) {
+            apiUrl = httpClient.buildGetUrl(apiUrl, params);
+        } else {
+            throw new ETAException(ErrorEnum.HTTP_METHOD_NOT_ALLOWED);
+        }
+        //生成Header信息
+        Headers headers = buildETAHeader();
+        return new Request.Builder().url(apiUrl).headers(headers).build();
+    }
+
+    private Headers buildETAHeader() {
+        String nonce = SignatureUtil.generateNonce();
+        long timestamp = SignatureUtil.generateTimestamp();
+        String appid = properties.getAppid();
+        String secretKey = properties.getSecretKey();
+        SignatureParam signatureParam = new SignatureParam.Builder().appid(appid).secretKey(secretKey).nonce(nonce).timestamp(timestamp).build();
+        String sign = SignatureUtil.generateSignature(signatureParam);
+        if (log.isDebugEnabled()) {
+            log.info("签名数据:" + signatureParam.toString());
+            log.info("生成签名:" + sign);
+        }
+        Map<String, String> etaHeader = new HashMap<>();
+        etaHeader.put(ETAConstants.NONCE, nonce);
+        etaHeader.put(ETAConstants.TIME_STAMP, String.valueOf(timestamp));
+        etaHeader.put(ETAConstants.APP_ID, appid);
+        etaHeader.put(ETAConstants.SIGNATURE, sign);
+        return httpClient.buildHeader(etaHeader);
+    }
+
+
+    public InnerResponse send(ETAInterfaceEnum etaInterface, Map<String, Object> params) throws ETAException {
+        Request request = buildETARequest(etaInterface, params);
+        try {
+            Response response = httpClient.send(request);
+            if (response == null || !response.isSuccessful()) {
+                if (response != null) {
+                    log.warn("{}", String.format(ErrorEnum.API_CALL_ERROR.getMsg(), response.code(), response.message()));
+                } else {
+                    log.warn("{}", ErrorEnum.RESPONSE_EMPTY_ERROR.getMsg());
+                }
+                return InnerResponse.errorResponse(response);
+            }
+            return buildETAResponse(response, etaInterface);
+        } catch (IOException e) {
+            log.info(e.getMessage());
+            return InnerResponse.errorResponse(e.getMessage());
+        }
+    }
+
+    private InnerResponse buildETAResponse(Response response, ETAInterfaceEnum etaInterfaceEnum) throws IOException {
+        if (isSuccessful(response)) {
+            ResponseBody responseBody = response.body();
+            InnerResponse responseInner = new InnerResponse();
+            if (responseBody == null) {
+                responseInner.setSuccess(false);
+                responseInner.setNeedRetry(false);
+                responseInner.setErrorMsg("获取eta应答结果失败,应答结果为空!");
+            } else {
+                ETAHttpResponse<?, ?> responseData = JSONObject.parseObject(responseBody.string(), etaInterfaceEnum.getResponse());
+                if (200 == responseData.getRet()) {
+                    List<?> quotaInfoDTOs = etaInterfaceEnum.getResponse().cast(responseData).convertDataToDTO();
+                    responseInner.setSuccess(true);
+                    responseInner.setNeedRetry(false);
+                    responseInner.setData(quotaInfoDTOs);
+                } else {
+                    responseInner.setSuccess(false);
+                    responseInner.setNeedRetry(false);
+                    responseInner.setErrorMsg(String.format("API请求应答错误,api url:[%s],应答结果:[%d:%s]", etaInterfaceEnum.getApi(), responseData.getRet(), StringUtils.isNoneEmpty(responseData.getErrMsg()) ? responseData.getErrMsg() : responseData.getMsg()));
+                }
+            }
+            return responseInner;
+        }
+        return InnerResponse.emptyResponse();
+    }
+
+    private boolean isSuccessful(Response response) {
+        return response.isSuccessful();
+    }
+
+}

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/request/ETADataHttpRequest.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.domain.api.http.request;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ETADataHttpRequest implements Serializable {
+    private static final long serialVersionUID = -5039575649543966177L;
+    /**
+     * 唯一码
+     */
+    private String UniqueCode;
+    /**
+     * 开始日期
+     */
+    private String StartDate;
+}

+ 17 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAData.java

@@ -0,0 +1,17 @@
+package com.qhtx.eta.domain.api.http.response.eta;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+
+@Data
+public class ETAData implements Serializable {
+    private static final long serialVersionUID = -1631134790207415156L;
+
+    private String DataTime;
+
+    private String Value;
+
+    private String UpdateTime;
+}

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAHttpResponse.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.domain.api.http.response.eta;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public abstract class ETAHttpResponse<T, R> implements Serializable {
+    private static final long serialVersionUID = -7870786351073443255L;
+    private String Msg;
+    private Integer Ret;
+    private String ErrMsg;
+    private Integer ErrCode;
+    private List<T> Data;
+
+    public abstract List<R> convertDataToDTO();
+}

+ 37 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/ETAQuota.java

@@ -0,0 +1,37 @@
+package com.qhtx.eta.domain.api.http.response.eta;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+@Data
+public class ETAQuota implements Serializable {
+    private static final long serialVersionUID = 7369699713409116062L;
+    private Integer EdbInfoId;
+    private String UniqueCode;
+    private String EdbCode;
+    private Integer EdbInfoType;
+    private Integer EdbType;
+    private String EdbName;
+    private Integer ClassifyId;
+    private Integer Source;
+    private String SourceName;
+    private String Frequency;
+    private String Unit;
+    private String StartDate;
+    private String EndDate;
+    private BigDecimal MinValue;
+    private BigDecimal MaxValue;
+    private String LatestDate;
+    private BigDecimal LatestValue;
+    private String ChartImage;
+    private String Calendar;
+    private String DataDateType;
+    private Integer Sort;
+    private Integer NoUpdate;
+    private String CreateTime;
+    private String ModifyTime;
+    private String SysUserRealName;
+}

+ 58 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/QuotaDataResponse.java

@@ -0,0 +1,58 @@
+package com.qhtx.eta.domain.api.http.response.eta;
+
+import com.qhtx.eta.common.constant.ETAConstants;
+import com.qhtx.eta.domain.entity.QuotaDataDTO;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.math.BigDecimal;
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Data
+@Slf4j
+public class QuotaDataResponse extends ETAHttpResponse<ETAData, QuotaDataDTO> {
+
+    private static final long serialVersionUID = -1579830772947683015L;
+
+    public List<QuotaDataDTO> convertDataToDTO() {
+        return this.getData().stream().map(item -> {
+            QuotaDataDTO result = new QuotaDataDTO();
+            result.setDataTime(StrToDate(item.getDataTime()));
+            result.setDataValue(new BigDecimal(item.getValue()));
+            result.setUpdateTime(StrToTimestamp(item.getUpdateTime()));
+            return result;
+        }).filter(item -> item.getDataTime() != null).collect(Collectors.toList());
+    }
+
+    private Date StrToDate(String dateTime) {
+        try {
+            if (StringUtils.isEmpty(dateTime)) {
+                return null;
+            }
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ETAConstants.DATE_PATTERN);
+            return Date.from(LocalDate.parse(dateTime, formatter).atStartOfDay(ZoneId.of(ETAConstants.TIME_ZONE)).toInstant());
+        } catch (Exception e) {
+            log.warn("字段日期格式错误:{}", dateTime);
+            return null;
+        }
+    }
+
+    private Date StrToTimestamp(String dateTime) {
+        try {
+            if (StringUtils.isEmpty(dateTime)) {
+                return null;
+            }
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ETAConstants.TIMESTAMP_PATTERN);
+            return Date.from(LocalDateTime.parse(dateTime, formatter).atZone(ZoneId.of(ETAConstants.TIME_ZONE)).toInstant());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 75 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/eta/QuotaInfoResponse.java

@@ -0,0 +1,75 @@
+package com.qhtx.eta.domain.api.http.response.eta;
+
+import com.qhtx.eta.domain.entity.QuotaInfoDTO;
+import com.qhtx.eta.common.constant.ETAConstants;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.FileNotFoundException;
+import java.io.PrintStream;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.time.format.DateTimeFormatter;
+import java.util.Date;
+import java.util.List;
+import java.util.stream.Collectors;
+
+@Data
+@Slf4j
+public class QuotaInfoResponse extends ETAHttpResponse<ETAQuota, QuotaInfoDTO> {
+    private static final long serialVersionUID = -5485763626281589776L;
+
+    public List<QuotaInfoDTO> convertDataToDTO() {
+
+        return this.getData().stream().map(item -> {
+            QuotaInfoDTO result = new QuotaInfoDTO();
+            result.setEdbName(item.getEdbName());
+            result.setUniqueCode(item.getUniqueCode());
+            result.setFrequency(item.getFrequency());
+            result.setClassifyId(item.getClassifyId());
+            result.setEdbCode(item.getEdbCode());
+            result.setEdbSource(item.getSource());
+            result.setEdbInfoId(item.getEdbInfoId());
+            result.setEndDate(StrToDate(item.getEndDate()));
+            result.setUnit(item.getUnit());
+            result.setStartDate(StrToDate(item.getStartDate()));
+            result.setLatestDate(StrToDate(item.getLatestDate()));
+            result.setNoUpdate(item.getNoUpdate());
+            result.setEdbSourceName(item.getSourceName());
+            return result;
+        }).filter(item -> item.getLatestDate() != null && item.getEndDate() != null && item.getStartDate() != null).collect(Collectors.toList());
+    }
+
+    private void printf(String str) {
+        try {
+            // 指定日志文件路径
+            String logFilePath = "../log/output.json.log";
+
+            // 创建一个PrintStream实例,指向日志文件
+            PrintStream printStream = new PrintStream(logFilePath);
+
+            // 将System.out替换为新创建的PrintStream实例
+            System.setOut(printStream);
+            // 你的对象
+            // 打印JSON格式的对象到日志文件
+            // 关闭资源是个好习惯,但在这个场景下可能不是必须的,因为程序结束时JVM会自动关闭
+            printStream.close();
+        } catch (FileNotFoundException e) {
+            // 处理文件未找到异常
+            e.printStackTrace();
+        }
+    }
+
+    private Date StrToDate(String dateTime) {
+        try {
+            if (StringUtils.isEmpty(dateTime)) {
+                return null;
+            }
+            DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ETAConstants.DATE_PATTERN);
+            return Date.from(LocalDate.parse(dateTime, formatter).atStartOfDay(ZoneId.of(ETAConstants.TIME_ZONE)).toInstant());
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 41 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/http/response/inner/InnerResponse.java

@@ -0,0 +1,41 @@
+package com.qhtx.eta.domain.api.http.response.inner;
+
+import com.qhtx.eta.common.constant.ETAConstants;
+import lombok.Data;
+import okhttp3.Response;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class InnerResponse implements Serializable {
+    private static final long serialVersionUID = -5959366645709223497L;
+    private Boolean success;
+    private Boolean needRetry;
+    private String errorMsg;
+    private List<?> data;
+
+    public static InnerResponse emptyResponse() {
+        InnerResponse innerResponse = new InnerResponse();
+        innerResponse.setSuccess(false);
+        innerResponse.setNeedRetry(false);
+        innerResponse.setErrorMsg(ETAConstants.ETA_EMPTY_RESPONSE_COMMENT);
+        return innerResponse;
+    }
+
+    public static InnerResponse errorResponse(Response response) {
+        InnerResponse innerResponse = new InnerResponse();
+        innerResponse.setSuccess(false);
+        innerResponse.setNeedRetry(false);
+        innerResponse.setErrorMsg(response == null ? ETAConstants.UNKNOWN_ERROR : response.message());
+        return innerResponse;
+    }
+
+    public static InnerResponse errorResponse(String errorMsg) {
+        InnerResponse innerResponse = new InnerResponse();
+        innerResponse.setSuccess(false);
+        innerResponse.setNeedRetry(false);
+        innerResponse.setErrorMsg(errorMsg);
+        return innerResponse;
+    }
+}

+ 69 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/proxy/ApiParameterProxy.java

@@ -0,0 +1,69 @@
+package com.qhtx.eta.domain.api.proxy;
+
+import com.alibaba.fastjson.JSONObject;
+import com.qhtx.eta.domain.enums.ExcludedField;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+
+import java.lang.reflect.Field;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+@Slf4j
+@Data
+public abstract class ApiParameterProxy<T> {
+
+    protected static final ThreadLocal<Object> THREAD_LOCAL_DATA = new ThreadLocal<>();
+
+    public void setData(Object data) {
+        THREAD_LOCAL_DATA.set(data);
+    }
+
+    /**
+     * 获取线程局部变量data
+     */
+    public Object getData() {
+        return THREAD_LOCAL_DATA.get();
+    }
+
+
+    /**
+     * 代理方法
+     */
+    protected abstract T acceptParam(Object data);
+
+    public Map<String, Object> parameters(Object data) {
+        if (data == null) {
+            return null;
+        }
+        setData(acceptParam(data));
+        return afterExecute(getData());
+    }
+
+    /**
+     * 将参数转成map
+     */
+    private Map<String, Object> afterExecute(Object data) {
+        Class<?> clazz = data.getClass();
+        Field[] fields = clazz.getDeclaredFields();
+        fields = Arrays.stream(fields)
+                .filter(field -> Arrays.stream(ExcludedField.values())
+                        .noneMatch(excludedField -> field.getName().equals(excludedField.getFieldName()))).toArray(Field[]::new);
+        Map<String, Object> params = new HashMap<>(fields.length);
+        for (Field field : fields) {
+            field.setAccessible(true);
+            try {
+                Object obj = field.get(data);
+                if (obj != null) {
+                    params.put(field.getName(), obj);
+                }
+            } catch (IllegalAccessException e) {
+                log.error("{},类:{}-{}", ErrorEnum.BEAN_COVERT_TO_MAP_ERROR.getMsg(), data.getClass().getName(), JSONObject.toJSONString(data));
+            }
+        }
+        THREAD_LOCAL_DATA.remove();
+        return params;
+    }
+}

+ 17 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/api/proxy/impl/ETADataParameterProxy.java

@@ -0,0 +1,17 @@
+package com.qhtx.eta.domain.api.proxy.impl;
+
+import com.qhtx.eta.domain.api.proxy.ApiParameterProxy;
+import com.qhtx.eta.domain.api.http.request.ETADataHttpRequest;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.common.exception.ETAException;
+
+public class ETADataParameterProxy extends ApiParameterProxy<ETADataHttpRequest> {
+
+    @Override
+    public ETADataHttpRequest acceptParam(Object data) {
+        if (data instanceof ETADataHttpRequest) {
+            return (ETADataHttpRequest) data;
+        }
+        throw new ETAException(ErrorEnum.PARAM_TYPE_ERROR);
+    }
+}

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/DomainConfig.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.domain.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskScheduler;
+
+@Configuration
+public class DomainConfig {
+    @Bean
+    public TaskScheduler taskScheduler() {
+        ThreadPoolTaskScheduler taskScheduler = new ThreadPoolTaskScheduler();
+        taskScheduler.setPoolSize(2);
+        taskScheduler.setAwaitTerminationSeconds(10);
+        taskScheduler.setWaitForTasksToCompleteOnShutdown(true);
+        return taskScheduler;
+    }
+}

+ 25 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ETAConfigProperties.java

@@ -0,0 +1,25 @@
+package com.qhtx.eta.domain.config;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+@Component
+@Data
+@ConfigurationProperties(prefix = "eta")
+public class ETAConfigProperties {
+    /**
+     * eta接口地址
+     */
+    private String url;
+
+    /**
+     * appid
+     */
+    private String appid;
+    /**
+     * 密钥
+     */
+    private String secretKey;
+}

+ 35 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ETAThreadFactory.java

@@ -0,0 +1,35 @@
+package com.qhtx.eta.domain.config;
+
+import org.apache.commons.lang3.StringUtils;
+import org.jetbrains.annotations.NotNull;
+
+import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.atomic.AtomicInteger;
+
+public class ETAThreadFactory implements ThreadFactory {
+    private static final AtomicInteger poolNumber = new AtomicInteger(1);
+    private final ThreadGroup group;
+    private final AtomicInteger threadNumber = new AtomicInteger(1);
+    private final String namePrefix;
+
+    ETAThreadFactory(String name) {
+        SecurityManager s = System.getSecurityManager();
+        group = (s != null) ? s.getThreadGroup() : Thread.currentThread().getThreadGroup();
+        if (StringUtils.isBlank(name)) {
+            name = "pool";
+        }
+        namePrefix = "NO." + poolNumber.getAndIncrement() +"-"+ name + "-" + "-thread-";
+    }
+
+    @Override
+    public Thread newThread(@NotNull Runnable r) {
+        Thread t = new Thread(group, r, namePrefix + threadNumber.getAndIncrement(), 0);
+        if (t.isDaemon()) {
+            t.setDaemon(false);
+        }
+        if (t.getPriority() != Thread.NORM_PRIORITY) {
+            t.setPriority(Thread.NORM_PRIORITY);
+        }
+        return t;
+    }
+}

+ 15 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ScheduleConfig.java

@@ -0,0 +1,15 @@
+package com.qhtx.eta.domain.config;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class ScheduleConfig implements Serializable {
+
+
+    private static final long serialVersionUID = 857963555565694343L;
+    private Integer interval;
+    private Integer initialDelay;
+    private Boolean enabled;
+}

+ 17 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ScheduleTaskConfig.java

@@ -0,0 +1,17 @@
+package com.qhtx.eta.domain.config;
+
+import lombok.Data;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.cloud.context.config.annotation.RefreshScope;
+import org.springframework.stereotype.Component;
+
+@Component
+@ConfigurationProperties(prefix = "eta.scheduled")
+@Data
+@RefreshScope
+public class ScheduleTaskConfig {
+
+    private ScheduleConfig info;
+    private ScheduleConfig data;
+}

+ 30 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/config/ThreadPoolConfig.java

@@ -0,0 +1,30 @@
+package com.qhtx.eta.domain.config;
+
+import com.qhtx.eta.common.constant.ETAConstants;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.concurrent.LinkedBlockingDeque;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 线程池的config管理
+ *
+ * @author: ChickenWing
+ * @date: 2023/11/26
+ */
+@Configuration
+public class ThreadPoolConfig {
+
+    @Bean(name = "ETAInfoThreadPool")
+    public ThreadPoolExecutor etaInfoThreadPool() {
+        return new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>(40), new ETAThreadFactory(ETAConstants.THREAD_POOL_ETA_INFO), new ThreadPoolExecutor.CallerRunsPolicy());
+    }
+
+    @Bean(name = "ETADataThreadPool")
+    public ThreadPoolExecutor etaDataThreadPool() {
+        return new ThreadPoolExecutor(10, 20, 5, TimeUnit.SECONDS, new LinkedBlockingDeque<>(40), new ETAThreadFactory(ETAConstants.THREAD_POOL_ETA_DATA), new ThreadPoolExecutor.CallerRunsPolicy());
+    }
+
+}

+ 30 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/convert/EtaApiQuotaDataConverter.java

@@ -0,0 +1,30 @@
+package com.qhtx.eta.domain.convert;
+
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+import com.qhtx.eta.domain.entity.QuotaDataDTO;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface EtaApiQuotaDataConverter {
+    EtaApiQuotaDataConverter INSTANCE = Mappers.getMapper(EtaApiQuotaDataConverter.class);
+
+    List<EtaApiQuotaData> convertEntityToBoList(List<QuotaDataDTO> quotaDataList);
+
+
+    EtaApiQuotaInfo convertEntityToBo(QuotaDataDTO quotaDataDTO);
+
+    @AfterMapping
+    default void setCreateDateTime(@MappingTarget EtaApiQuotaData etaApiQuotaData) {
+        // 设置当前时间戳
+//        etaApiQuotaData.setDataCreateTime(System.currentTimeMillis());
+//        etaApiQuotaData.setDataUpdateTime(System.currentTimeMillis());
+//        etaApiQuotaData.setIsDelete(0);
+//        etaApiQuotaData.setIsQuality(0);
+    }
+}

+ 29 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/convert/EtaApiQuotaInfoConverter.java

@@ -0,0 +1,29 @@
+package com.qhtx.eta.domain.convert;
+
+import com.qhtx.eta.domain.entity.QuotaInfoDTO;
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+import org.mapstruct.AfterMapping;
+import org.mapstruct.Mapper;
+import org.mapstruct.MappingTarget;
+import org.mapstruct.factory.Mappers;
+
+import java.util.List;
+
+@Mapper
+public interface EtaApiQuotaInfoConverter {
+    EtaApiQuotaInfoConverter INSTANCE = Mappers.getMapper(EtaApiQuotaInfoConverter.class);
+
+    List<EtaApiQuotaInfo> convertEntityToBoList(List<QuotaInfoDTO> quotaInfoList);
+
+
+    EtaApiQuotaInfo convertEntityToBo(QuotaInfoDTO quotaInfoDTO);
+
+    @AfterMapping
+    default void setCreateDateTime(@MappingTarget EtaApiQuotaInfo etaApiQuotaInfo) {
+        // 设置当前时间戳
+//        etaApiQuotaInfo.setDataCreateTime(System.currentTimeMillis());
+//        etaApiQuotaInfo.setDataUpdateTime(System.currentTimeMillis());
+//        etaApiQuotaInfo.setIsDelete(0);
+//        etaApiQuotaInfo.setIsQuality(0);
+    }
+}

+ 28 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaDataDTO.java

@@ -0,0 +1,28 @@
+package com.qhtx.eta.domain.entity;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * (EtaApiQuotaInfo)实体类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:36
+ */
+@Data
+public class QuotaDataDTO implements Serializable {
+
+    private static final long serialVersionUID = 2737918141640942407L;
+
+    private Date dataTime;
+    
+    private String uniqueCode;
+
+    private BigDecimal dataValue;
+
+    private Date updateTime;
+}
+

+ 15 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaDataUpdateBO.java

@@ -0,0 +1,15 @@
+package com.qhtx.eta.domain.entity;
+
+import com.qhtx.eta.domain.enums.ETADataStatus;
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class QuotaDataUpdateBO implements Serializable {
+    private static final long serialVersionUID = -178247323034598388L;
+    private String uniqueCode;
+    private String frequency;
+    private ETADataStatus status;
+    private String currentDate;
+}

+ 47 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/entity/QuotaInfoDTO.java

@@ -0,0 +1,47 @@
+package com.qhtx.eta.domain.entity;
+
+import lombok.Data;
+import lombok.Setter;
+
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * (EtaApiQuotaInfo)实体类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:36
+ */
+@Data
+public class QuotaInfoDTO implements Serializable {
+
+    private static final long serialVersionUID = 2737918141640942407L;
+
+    private Integer edbInfoId;
+
+    private String uniqueCode;
+
+    private String edbCode;
+
+    private String edbName;
+
+    private String unit;
+
+    private String frequency;
+
+    private Date startDate;
+
+    private Date endDate;
+
+    private Date latestDate;
+
+    private Integer classifyId;
+
+    private Integer edbSource;
+
+    private String edbSourceName;
+
+    private Integer noUpdate;
+
+}
+

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ETADataStatus.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.domain.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum ETADataStatus {
+    NEW(0),
+    UPDATE(1),
+    LATEST(2);
+
+
+    private int status;
+
+    ETADataStatus(int status) {
+        this.status = status;
+    }
+
+}

+ 68 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ETAInterfaceEnum.java

@@ -0,0 +1,68 @@
+package com.qhtx.eta.domain.enums;
+
+import com.qhtx.eta.domain.api.http.response.eta.ETAHttpResponse;
+import com.qhtx.eta.domain.api.http.response.eta.QuotaDataResponse;
+import com.qhtx.eta.domain.api.http.response.eta.QuotaInfoResponse;
+import com.qhtx.eta.domain.api.proxy.ApiParameterProxy;
+import com.qhtx.eta.domain.api.proxy.impl.ETADataParameterProxy;
+import com.qhtx.eta.common.eunms.HttpMethod;
+import lombok.Getter;
+
+@Getter
+public enum ETAInterfaceEnum {
+
+
+    // 获取用户信息
+    // GET_EDB_SOURCE_LIST("getEdbSourceList", "/v1/edb/source/list", HttpMethod.GET, "指标来源列表", null, false), // 指标来源列表
+    //  GET_EDB_CLASSIFY_TREE("getEdbClassifyTree", "/v1/edb/classify/tree", HttpMethod.GET, "指标分类树", null, false), // 获取用户信息
+    // GET_EDB_CLASSIFY_LIST("getEdbClassifyList", "/v1/edb/classify/list", HttpMethod.GET, "指标分类列表", null, false), // 获取用户信息
+    GET_EDB_LIST("getEdbList", "/v1/edb/list", HttpMethod.GET, "指标列表", null, true, QuotaInfoResponse.class), // 获取用户信息
+    // GET_EDB_DETAIL("getEdbDetail", "/v1/edb/detail", HttpMethod.GET, "指标详情", EdbDetailProxy.class, false),
+    GET_EDB_DATA("getEdbData", "/v1/edb/data", HttpMethod.GET, "指标数据", ETADataParameterProxy.class, true, QuotaDataResponse.class),
+    //GET_DATA_MANAGE_EDB_INFO_TRACE("getDataManageEdbInfoTrace", "/v1/datamanage/edb_info/trace", HttpMethod.GET, "指标详情", null, false),
+    ;
+
+    /**
+     * 接口名称
+     */
+    private String name;
+    /**
+     * 接口地址
+     */
+    private String api;
+    /**
+     *
+     */
+    private HttpMethod method;
+    /**
+     * 接口描述
+     */
+    private String desc;
+
+    /**
+     * 代理类
+     */
+    private Class<? extends ApiParameterProxy> proxy;
+
+    /**
+     * 是否启用
+     */
+    private Boolean enable;
+
+    /**
+     * 应答结果
+     */
+    private Class<? extends ETAHttpResponse> response;
+
+    ETAInterfaceEnum(String name, String api, HttpMethod method, String desc, Class<? extends ApiParameterProxy> proxy, Boolean enable, Class<? extends ETAHttpResponse> response) {
+        this.name = name;
+        this.api = api;
+        this.method = method;
+        this.desc = desc;
+        this.proxy = proxy;
+        this.enable = enable;
+        this.response = response;
+    }
+
+
+}

+ 15 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ExcludedField.java

@@ -0,0 +1,15 @@
+package com.qhtx.eta.domain.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum ExcludedField {
+    SERIAL_VERSION_UID("serialVersionUID"),
+    ;
+    private String fieldName;
+
+    ExcludedField(String fieldName) {
+        this.fieldName = fieldName;
+    }
+
+}

+ 17 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/enums/ExcludedQuotaSource.java

@@ -0,0 +1,17 @@
+package com.qhtx.eta.domain.enums;
+
+import lombok.Getter;
+
+public enum ExcludedQuotaSource {
+    SELF_DATA(84, "自有数据"),
+    ;
+    @Getter
+    private Integer sourceId;
+    private String sourceName;
+
+    ExcludedQuotaSource(Integer sourceId, String sourceName) {
+        this.sourceId = sourceId;
+        this.sourceName = sourceName;
+    }
+
+}

+ 198 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/job/ETADataSyncJob.java

@@ -0,0 +1,198 @@
+package com.qhtx.eta.domain.job;
+
+import com.qhtx.eta.common.utils.AssertUtils;
+import com.qhtx.eta.domain.config.ScheduleConfig;
+import com.qhtx.eta.domain.config.ScheduleTaskConfig;
+import com.qhtx.eta.domain.entity.QuotaDataUpdateBO;
+import com.qhtx.eta.domain.entity.QuotaInfoDTO;
+import com.qhtx.eta.domain.enums.ETADataStatus;
+import com.qhtx.eta.domain.enums.ETAInterfaceEnum;
+import com.qhtx.eta.domain.enums.ExcludedQuotaSource;
+import com.qhtx.eta.domain.service.ETAQuotaService;
+import com.qhtx.eta.domain.api.ApiServiceHolder;
+import com.qhtx.eta.domain.api.http.request.ETADataHttpRequest;
+import com.qhtx.eta.common.constant.ETAConstants;
+import com.qhtx.eta.domain.entity.QuotaDataDTO;
+import com.qhtx.eta.domain.task.FixedDelayTaskRegistrar;
+import com.qhtx.eta.domain.task.SchedulingRunnable;
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+import com.qhtx.eta.infra.enums.Frequency;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+import org.springframework.util.StringUtils;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.format.DateTimeFormatter;
+import java.util.*;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+public class ETADataSyncJob implements CommandLineRunner {
+
+    @Value("${eta.http.interval}")
+    private int interval;
+
+    @Value("${eta.http.numberOfPeriods}")
+    private int numberOfPeriods;
+    @Resource
+    private ApiServiceHolder apiServiceHolder;
+
+    @Resource
+    private ETAQuotaService etaQuotaService;
+
+    @Resource(name = "ETADataThreadPool")
+    private ThreadPoolExecutor etaDataThreadPool;
+
+    @Resource
+    private FixedDelayTaskRegistrar fixedDelayTaskRegistrar;
+
+    @Resource
+    private ScheduleTaskConfig scheduleTaskConfig;
+
+    /**
+     * 同步指标信息
+     */
+    public void syncETAInfo() {
+        List<?> dataList = apiServiceHolder.runApi(ETAInterfaceEnum.GET_EDB_LIST);
+        if (dataList != null) {
+            List<QuotaInfoDTO> etaQuotaList = dataList.stream().filter(item -> item instanceof QuotaInfoDTO && Arrays.stream(ExcludedQuotaSource.values()).noneMatch(excludedSource -> ((QuotaInfoDTO) item).getEdbSource().equals(excludedSource.getSourceId()))).map(item -> (QuotaInfoDTO) item).collect(Collectors.toList());
+            log.info("================================ 开始同步接口指标列表 ================================ ");
+            log.info("================================ 指标接口列表数量:{}条================================ ", etaQuotaList.size());
+            etaQuotaService.syncQuota(etaQuotaList);
+            log.info("================================ 同步接口指标列表完成 ================================ ");
+        } else {
+            log.warn("调用接口失败,无数据同步");
+        }
+    }
+
+    /**
+     * 同步指标数据
+     */
+    public void syncETAData() {
+        log.info("{} 开始同步指标数据任务 {}", ETAConstants.LINE_SEPARATOR, ETAConstants.LINE_SEPARATOR);
+        Date minDate = null;
+        boolean dataUpdated = false;
+        QuotaInfoDTO quotaInfoDTO = new QuotaInfoDTO();
+        //查询条件暂时不设置
+//        quotaInfoDTO.setNoUpdate(0);
+        List<QuotaDataUpdateBO> updateList = etaQuotaService.getQuotaInfoListForUpdate(quotaInfoDTO).stream().filter(item -> item.getStatus() != ETADataStatus.LATEST).collect(Collectors.toList());
+        if (CollectionUtils.isEmpty(updateList)) {
+            log.info("{} 当前无同步指标 {}", ETAConstants.LINE_SEPARATOR, ETAConstants.LINE_SEPARATOR);
+            return;
+        }
+        int count = 0;
+        for (QuotaDataUpdateBO quotaDataUpdateBO : updateList) {
+            ETADataHttpRequest etaDataRequest = new ETADataHttpRequest();
+            etaDataRequest.setUniqueCode(quotaDataUpdateBO.getUniqueCode());
+            if (quotaDataUpdateBO.getStatus() == ETADataStatus.UPDATE) {
+                String startDate = calculatePreviousDate(quotaDataUpdateBO.getCurrentDate(), Frequency.getFrequencyByDesc(quotaDataUpdateBO.getFrequency()), numberOfPeriods);
+                etaDataRequest.setStartDate(startDate);
+            }
+            log.info("================================ 开始同步接口指标明细数据 ================================ ");
+            List<?> dataList = apiServiceHolder.runApi(ETAInterfaceEnum.GET_EDB_DATA, etaDataRequest);
+            if (CollectionUtils.isEmpty(dataList)) {
+                log.info("{} 没有获取到新的指标数据 {}", ETAConstants.LINE_SEPARATOR, ETAConstants.LINE_SEPARATOR);
+                continue;
+            }
+            List<QuotaDataDTO> quotaDataList = dataList.stream().filter(item -> item instanceof QuotaDataDTO).map(item -> {
+                QuotaDataDTO data = (QuotaDataDTO) item;
+                data.setUniqueCode(etaDataRequest.getUniqueCode());
+                return data;
+            }).collect(Collectors.toList());
+//                log.info("================================ 开始同步接口指标明细数据 ================================ ");
+//                if (CollectionUtils.isEmpty(quotaDataList)) {
+//                    log.info("{} 没有获取到新的指标数据 {}", ETAConstants.LINE_SEPARATOR, ETAConstants.LINE_SEPARATOR);
+//                    continue;
+//                }
+            log.info("================================ 指标接口数据[{}]数量:{}条================================ ", quotaDataList.get(0).getUniqueCode(), quotaDataList.size());
+            //对指标数据做一个时间排序
+            quotaDataList.sort(Comparator.comparing(QuotaDataDTO::getDataTime));
+            //取最小的日期
+            Date startDate = quotaDataList.get(0).getDataTime();
+            minDate = getMinDate(minDate, startDate);
+            count += quotaDataList.size();
+            Runnable task = () -> etaQuotaService.syncData(quotaDataList);
+            etaDataThreadPool.submit(task);
+            pause();
+        }
+        log.info("{} 同步指标数据任务完成 {}", ETAConstants.LINE_SEPARATOR, ETAConstants.LINE_SEPARATOR);
+        if (count > 0) {
+            long minUpdateTime = 0;
+            // 设置为前一天
+            if (minDate != null) {
+//            Calendar calendar = Calendar.getInstance();
+//            calendar.setTime(minDate);
+//            calendar.add(Calendar.DAY_OF_MONTH, -1);
+                minUpdateTime = minDate.getTime();
+            }
+            etaQuotaService.LinkedCodeMessage(minUpdateTime);
+        }
+    }
+
+    private Date getMinDate(Date date1, Date date2) {
+        if (date2 == null) {
+            return date1;
+        }
+        if (date1 == null) {
+            return date2;
+        }
+        return date1.before(date2) ? date1 : date2;
+    }
+
+    private String calculatePreviousDate(String startDate, Frequency frequency, int numberOfPeriods) {
+        if (frequency == null) {
+            frequency = Frequency.DAILY;
+        }
+        LocalDate localDate = LocalDate.parse(startDate);
+        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(ETAConstants.DATE_PATTERN);
+        switch (frequency) {
+            case DAILY:
+                return localDate.minusDays(numberOfPeriods).format(formatter);
+            case WEEKLY:
+                return localDate.minusWeeks(numberOfPeriods).format(formatter);
+            case MONTHLY:
+                return localDate.minusMonths(numberOfPeriods).format(formatter);
+            case YEARLY:
+                return localDate.minusYears(numberOfPeriods).format(formatter);
+            case SEMI_ANNUAL:
+                return localDate.minusMonths(6L * numberOfPeriods).format(formatter);
+            case QUARTERLY:
+                return localDate.minusMonths(3L * numberOfPeriods).format(formatter);
+            case DECADELY:
+                return localDate.minusDays(10L * numberOfPeriods).format(formatter);
+            default:
+                throw new IllegalArgumentException("Unsupported frequency: " + frequency);
+        }
+    }
+
+    private void pause() {
+        try {
+            Thread.sleep(interval);
+        } catch (InterruptedException e) {
+            Thread.currentThread().interrupt();
+            log.info("网络请求延时异常中断:[{}]", e.getLocalizedMessage());
+        }
+    }
+
+    //加载系统中的定时任务,目前只有2个就冗余写一下,后续有新任务再抽代码改造
+    @Override
+    public void run(String... args) {
+        ScheduleConfig dataConfig = scheduleTaskConfig.getData();
+        ScheduleConfig infoConfig = scheduleTaskConfig.getInfo();
+        if (dataConfig.getEnabled()) {
+            //同步指标数据任务
+            fixedDelayTaskRegistrar.addFixedDelayTask(new SchedulingRunnable(this.getClass().getName(), "syncETAData", this), dataConfig.getInterval(), dataConfig.getInitialDelay());
+        }
+        if (infoConfig.getEnabled()) {
+            //同步主表基本信息任务
+            fixedDelayTaskRegistrar.addFixedDelayTask(new SchedulingRunnable(this.getClass().getName(), "syncETAInfo", this), infoConfig.getInterval(), infoConfig.getInitialDelay());
+        }
+    }
+}

+ 19 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/service/ETAQuotaService.java

@@ -0,0 +1,19 @@
+package com.qhtx.eta.domain.service;
+
+import com.qhtx.eta.domain.entity.QuotaDataUpdateBO;
+import com.qhtx.eta.domain.entity.QuotaDataDTO;
+import com.qhtx.eta.domain.entity.QuotaInfoDTO;
+
+import java.util.List;
+
+
+public interface ETAQuotaService {
+
+    void syncQuota(List<QuotaInfoDTO> quotaInfoList);
+
+    void syncData(List<QuotaDataDTO> quotaDataList);
+
+    List<QuotaDataUpdateBO> getQuotaInfoListForUpdate(QuotaInfoDTO quotaInfoDTO);
+
+    void LinkedCodeMessage(long minOperationTime);
+}

+ 158 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/service/impl/ETAQuotaServiceImpl.java

@@ -0,0 +1,158 @@
+package com.qhtx.eta.domain.service.impl;
+
+import com.google.common.collect.Lists;
+import com.qhtx.eta.domain.convert.EtaApiQuotaDataConverter;
+import com.qhtx.eta.domain.convert.EtaApiQuotaInfoConverter;
+import com.qhtx.eta.domain.entity.QuotaDataDTO;
+import com.qhtx.eta.domain.entity.QuotaDataUpdateBO;
+import com.qhtx.eta.domain.entity.QuotaInfoDTO;
+import com.qhtx.eta.domain.enums.ETADataStatus;
+import com.qhtx.eta.domain.service.ETAQuotaService;
+import com.qhtx.eta.common.config.DataSourceProperties;
+import com.qhtx.eta.common.constant.ETAConstants;
+import com.qhtx.eta.common.exception.ETAException;
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+import com.qhtx.eta.infra.service.EtaApiQuotaDataService;
+import com.qhtx.eta.infra.service.EtaApiQuotaInfoService;
+import com.qhtx.eta.infra.service.OdsDimService;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Service;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.Resource;
+import java.text.SimpleDateFormat;
+import java.time.LocalDate;
+import java.time.ZoneId;
+import java.util.*;
+import java.util.concurrent.CompletableFuture;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.stream.Collectors;
+
+@Slf4j
+@Service
+public class ETAQuotaServiceImpl implements ETAQuotaService {
+    @Resource
+    private EtaApiQuotaInfoService etaApiQuotaInfoService;
+
+    @Resource
+    private EtaApiQuotaDataService etaApiQuotaDataService;
+    @Resource(name = "ETAInfoThreadPool")
+    private ThreadPoolExecutor etaInfoThreadPool;
+
+    @Resource
+    private OdsDimService odsDimService;
+    @Resource
+    private DataSourceProperties dataSourceProperties;
+
+    @Override
+    public void syncQuota(List<QuotaInfoDTO> quotaInfoList) {
+        List<EtaApiQuotaInfo> quotaList = EtaApiQuotaInfoConverter.INSTANCE.convertEntityToBoList(quotaInfoList);
+        List<CompletableFuture<Void>> futures = new ArrayList<>();
+        Lists.partition(quotaList, dataSourceProperties.getQuota().getChunkSize()).forEach(subList -> {
+            CompletableFuture<Void> future = CompletableFuture.runAsync(() -> etaApiQuotaInfoService.batchInsertOrUpdate(subList), etaInfoThreadPool);
+            futures.add(future);
+        });
+        int size = futures.size();
+        CompletableFuture.allOf(futures.toArray(new CompletableFuture[size])).join();
+    }
+
+
+    @Override
+    public void syncData(List<QuotaDataDTO> quotaDataList) {
+        List<EtaApiQuotaData> dataList = EtaApiQuotaDataConverter.INSTANCE.convertEntityToBoList(quotaDataList);
+        dataList.sort(Comparator.comparing(EtaApiQuotaData::getDataTime));
+        List<List<EtaApiQuotaData>> chunks = Lists.partition(dataList, dataSourceProperties.getData().getChunkSize());
+        for (int i = 0; i < chunks.size(); i++) {
+            List<EtaApiQuotaData> subList = chunks.get(i);
+            int current = current(i);
+            try {
+                etaApiQuotaDataService.batchInsert(subList);
+                log.info("完成[{}]指标数据第{}部分数据同步,数据量:{}", subList.get(0).getUniqueCode(), current, subList.size());
+            } catch (ETAException e) {
+                log.error("数据库操作失败[{}]第" + current + "批次,{}", subList.get(0).getUniqueCode(), e.getErrorMessage());
+                break;
+            } catch (Exception e) {
+                log.error("数据库操作失败[{}]第" + current + "批次", subList.get(0).getUniqueCode());
+                break;
+            }
+        }
+        log.info("================================ 同步接口指标数据完成 ================================ ");
+    }
+
+    private int current(int i) {
+        return i + 1;
+    }
+
+    @Override
+    public List<QuotaDataUpdateBO> getQuotaInfoListForUpdate(QuotaInfoDTO quotaInfo) {
+        EtaApiQuotaInfo etaApiQuotaInfo = EtaApiQuotaInfoConverter.INSTANCE.convertEntityToBo(quotaInfo);
+        //一次性获取所有的指标的最新数据,减少数据库请求开销
+        List<EtaApiQuotaData> dataList = etaApiQuotaDataService.getAllLatestDataByUniqueCode();
+        List<EtaApiQuotaInfo> quotaInfoList = etaApiQuotaInfoService.queryQuotaList(etaApiQuotaInfo).stream().filter(info -> info.getLatestDate() != null && info.getUniqueCode() != null).collect(Collectors.toList());
+        List<List<QuotaDataUpdateBO>> allResults;
+        List<CompletableFuture<List<QuotaDataUpdateBO>>> completableFutureList = Lists.partition(quotaInfoList, dataSourceProperties.getData().getChunkSize()).stream().map(subList -> CompletableFuture.supplyAsync(() -> dataUpdate(subList, dataList), etaInfoThreadPool)).collect(Collectors.toList());
+        try {
+            int size = completableFutureList.size();
+            allResults = CompletableFuture.allOf(completableFutureList.toArray(new CompletableFuture[size])).thenApply(voidValue -> completableFutureList.stream().map(CompletableFuture::join).collect(Collectors.toList())).get();
+        } catch (Exception e) {
+            log.warn("{}指标数据更新失败{}{}", ETAConstants.LINE_SEPARATOR, e.getMessage(), ETAConstants.LINE_SEPARATOR);
+            return Collections.emptyList();
+        }
+        return allResults.stream().flatMap(List::stream).collect(Collectors.toList());
+    }
+
+    @Override
+    public void LinkedCodeMessage(long minOperationTime) {
+
+        odsDimService.odsDimDataUpdate(ETAConstants.ODS_DATA_TABLE_NAME, minOperationTime, 1);
+    }
+
+    private List<QuotaDataUpdateBO> dataUpdate(List<EtaApiQuotaInfo> quotaInfoList, List<EtaApiQuotaData> dataList) {
+        return quotaInfoList.stream().map(info -> {
+            //    修改为代码遍历
+//            QuotaDataUpdateBO quotaDataUpdateBO = new QuotaDataUpdateBO();
+//            EtaApiQuotaData etaApiQuotaData = etaApiQuotaDataService.getLatestDataByUniqueCode(info.getUniqueCode());
+//            quotaDataUpdateBO.setUniqueCode(info.getUniqueCode());
+//            if (etaApiQuotaData == null) {
+//                quotaDataUpdateBO.setStatus(ETADataStatus.NEW);
+//                return quotaDataUpdateBO;
+//            }
+//            quotaDataUpdateBO.setCurrentDate(new SimpleDateFormat(ETAConstants.DATE_PATTERN).format(etaApiQuotaData.getDataTime()));
+//            if (compareDate(etaApiQuotaData.getDataTime(), info.getEndDate())) {
+//                quotaDataUpdateBO.setStatus(ETADataStatus.UPDATE);
+//                return quotaDataUpdateBO;
+//            }
+//            quotaDataUpdateBO.setStatus(ETADataStatus.LATEST);
+            QuotaDataUpdateBO quotaDataUpdateBO = new QuotaDataUpdateBO();
+            quotaDataUpdateBO.setUniqueCode(info.getUniqueCode());
+            quotaDataUpdateBO.setFrequency(info.getFrequency());
+            List<EtaApiQuotaData> etaApiQuotaDataList = dataList.stream().filter(data -> data.getUniqueCode().equals(info.getUniqueCode())).collect(Collectors.toList());
+            if (CollectionUtils.isEmpty(etaApiQuotaDataList)) {
+                quotaDataUpdateBO.setStatus(ETADataStatus.NEW);
+                return quotaDataUpdateBO;
+            }
+            quotaDataUpdateBO.setCurrentDate(new SimpleDateFormat(ETAConstants.DATE_PATTERN).format(etaApiQuotaDataList.get(0).getDataTime()));
+            if (compareDate(etaApiQuotaDataList.get(0).getDataTime(), info.getLatestDate())) {
+                quotaDataUpdateBO.setStatus(ETADataStatus.UPDATE);
+                return quotaDataUpdateBO;
+            }
+            quotaDataUpdateBO.setStatus(ETADataStatus.LATEST);
+            return quotaDataUpdateBO;
+        }).collect(Collectors.toList());
+    }
+
+    /**
+     * 比较时间 src 小于 des 返回 true 否则返回false
+     *
+     * @param src
+     * @param des
+     * @return boolean
+     */
+    private boolean compareDate(Date src, Date des) {
+        LocalDate co1 = src.toInstant().atZone(ZoneId.of(ETAConstants.TIME_ZONE)).toLocalDate();
+        LocalDate co2 = des.toInstant().atZone(ZoneId.of(ETAConstants.TIME_ZONE)).toLocalDate();
+        return co1.isBefore(co2);
+    }
+
+}

+ 59 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/FixedDelayTaskRegistrar.java

@@ -0,0 +1,59 @@
+package com.qhtx.eta.domain.task;
+
+import org.springframework.beans.factory.DisposableBean;
+import org.springframework.scheduling.TaskScheduler;
+import org.springframework.scheduling.config.FixedDelayTask;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.Date;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+@Component
+public class FixedDelayTaskRegistrar implements DisposableBean {
+
+    private final Map<Runnable, ScheduledTask> scheduledTasks = new ConcurrentHashMap<>(16);
+
+    @Resource
+    private TaskScheduler taskScheduler;
+
+    @Override
+    public void destroy() throws Exception {
+        for (ScheduledTask task : this.scheduledTasks.values()) {
+            task.cancel();
+        }
+        this.scheduledTasks.clear();
+    }
+
+    public TaskScheduler getScheduler() {
+        return this.taskScheduler;
+    }
+
+    public void addFixedDelayTask(Runnable task, long interval, long initialDelay) {
+        addFixedDelayTask(new FixedDelayTask(task, interval, initialDelay));
+    }
+
+    public void addFixedDelayTask(FixedDelayTask fixedDelayTask) {
+        if (fixedDelayTask != null) {
+            Runnable task = fixedDelayTask.getRunnable();
+            if (this.scheduledTasks.containsKey(task)) {
+                removeFixedDelayTask(task);
+            }
+            this.scheduledTasks.put(task, scheduleFixedDelayTask(fixedDelayTask));
+        }
+    }
+
+    public void removeFixedDelayTask(Runnable task) {
+        ScheduledTask scheduledTask = this.scheduledTasks.remove(task);
+        if (scheduledTask != null) scheduledTask.cancel();
+    }
+
+    public ScheduledTask scheduleFixedDelayTask(FixedDelayTask fixedDelayTask) {
+        ScheduledTask scheduledTask = new ScheduledTask();
+        Date currentTime = fixedDelayTask.getInitialDelay() > 0 ? new Date(System.currentTimeMillis() + fixedDelayTask.getInitialDelay()) : new Date();
+        scheduledTask.future = this.taskScheduler.scheduleWithFixedDelay(fixedDelayTask.getRunnable(), currentTime, fixedDelayTask.getInterval());
+        return scheduledTask;
+    }
+
+}

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/ScheduledTask.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.domain.task;
+
+import java.util.concurrent.ScheduledFuture;
+
+public final class ScheduledTask {
+
+    volatile ScheduledFuture<?> future;
+
+    /**
+     * 取消定时任务
+     */
+    public void cancel() {
+        ScheduledFuture<?> future = this.future;
+        if (future != null) {
+            future.cancel(false);
+        }
+    }
+}

+ 59 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/SchedulingRunnable.java

@@ -0,0 +1,59 @@
+package com.qhtx.eta.domain.task;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.util.ReflectionUtils;
+import org.springframework.util.StringUtils;
+
+import java.lang.reflect.Method;
+import java.util.Objects;
+
+public class SchedulingRunnable implements Runnable {
+
+    private static final Logger logger = LoggerFactory.getLogger(SchedulingRunnable.class);
+
+    private String beanName;
+
+    private String methodName;
+
+    private Object target;
+
+    public SchedulingRunnable(String beanName, String methodName) {
+        this(beanName, methodName, null);
+    }
+
+    public SchedulingRunnable(String beanName, String methodName, Object target) {
+        this.beanName = beanName;
+        this.methodName = methodName;
+        this.target = target;
+    }
+
+
+    @Override
+    public void run() {
+        logger.info("定时任务开始执行 - bean:{},方法:{}", beanName, methodName);
+        long startTime = System.currentTimeMillis();
+        try {
+            Method method = target.getClass().getDeclaredMethod(methodName);
+            ReflectionUtils.makeAccessible(method);
+            method.invoke(target);
+        } catch (Exception ex) {
+            logger.error(String.format("定时任务执行异常 - bean:%s,方法:%s", beanName, methodName), ex);
+        }
+        long times = System.currentTimeMillis() - startTime;
+        logger.info("定时任务执行结束 - bean:{},方法:{},耗时:{} 毫秒", beanName, methodName, times);
+    }
+
+    @Override
+    public boolean equals(Object o) {
+        if (this == o) return true;
+        if (o == null || getClass() != o.getClass()) return false;
+        SchedulingRunnable that = (SchedulingRunnable) o;
+        return beanName.equals(that.beanName) && methodName.equals(that.methodName);
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(beanName, methodName);
+    }
+}

+ 101 - 0
qhtx-eta-integrator/qhtx-integrator-domain/src/main/java/com/qhtx/eta/domain/task/TaskConfigChangeListener.java

@@ -0,0 +1,101 @@
+package com.qhtx.eta.domain.task;
+
+import com.alibaba.cloud.nacos.NacosConfigManager;
+import com.alibaba.cloud.nacos.NacosConfigProperties;
+import com.alibaba.nacos.api.config.ConfigChangeEvent;
+import com.alibaba.nacos.api.config.ConfigChangeItem;
+import com.alibaba.nacos.api.exception.NacosException;
+import com.alibaba.nacos.client.config.listener.impl.AbstractConfigChangeListener;
+import com.qhtx.eta.domain.config.ScheduleConfig;
+import com.qhtx.eta.domain.config.ScheduleTaskConfig;
+import com.qhtx.eta.domain.job.ETADataSyncJob;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.stereotype.Component;
+import org.springframework.util.CollectionUtils;
+
+import javax.annotation.PostConstruct;
+import javax.annotation.Resource;
+import java.util.List;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+
+@Component
+@Slf4j
+public class TaskConfigChangeListener extends AbstractConfigChangeListener {
+
+    @Resource
+    private NacosConfigManager nacosConfigManager;
+
+    @Resource
+    private NacosConfigProperties nacosConfigProperties;
+
+    @Resource
+    private ETADataSyncJob etadataSyncJob;
+
+    @Resource
+    private FixedDelayTaskRegistrar fixedDelayTaskRegistrar;
+
+
+    @Resource
+    private ScheduleTaskConfig scheduleTaskConfig;
+
+    @PostConstruct
+    public void init() throws NacosException {
+        String dataId = String.format("%s-%s.%s", nacosConfigProperties.getPrefix(), nacosConfigProperties.getEnvironment().getActiveProfiles()[0], nacosConfigProperties.getFileExtension());
+        nacosConfigManager.getConfigService().addListener(dataId, "DATABASE_GROUP", this);
+    }
+
+    @Override
+    public void receiveConfigChange(ConfigChangeEvent configChangeEvent) {
+        Map<String, List<ConfigChangeItem>> taskMap = configChangeEvent.getChangeItems().stream().filter(changeItem -> changeItem.getKey().contains("eta.scheduled")).collect(Collectors.groupingBy(changeItem -> {
+            if (changeItem.getKey().startsWith("eta.scheduled.info")) return "info";
+            else if (changeItem.getKey().startsWith("eta.scheduled.data")) return "data";
+            return "other";
+        }));
+        List<ConfigChangeItem> infoTaskList = taskMap.get("info");
+        List<ConfigChangeItem> dataTaskList = taskMap.get("data");
+        if (!CollectionUtils.isEmpty(infoTaskList)) {
+            ScheduleConfig scheduleConfig = scheduleTaskConfig.getInfo();
+            infoTaskList.forEach(changeItem -> {
+                if (changeItem.getKey().endsWith("interval")) {
+                    scheduleConfig.setInterval(Integer.valueOf(changeItem.getNewValue()));
+                }
+                if (changeItem.getKey().endsWith("initialDelay")) {
+                    scheduleConfig.setInitialDelay(Integer.valueOf(changeItem.getNewValue()));
+                }
+                if (changeItem.getKey().endsWith("enabled")) {
+                    scheduleConfig.setEnabled(Boolean.valueOf(changeItem.getNewValue()));
+                }
+            });
+            if (scheduleConfig.getEnabled()) {
+                fixedDelayTaskRegistrar.removeFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAInfo", etadataSyncJob));
+                fixedDelayTaskRegistrar.addFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAInfo", etadataSyncJob), scheduleConfig.getInterval(), scheduleConfig.getInitialDelay());
+            } else {
+                fixedDelayTaskRegistrar.removeFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAInfo", etadataSyncJob));
+            }
+        }
+        if (!CollectionUtils.isEmpty(dataTaskList)) {
+            ScheduleConfig scheduleConfig = scheduleTaskConfig.getData();
+            dataTaskList.forEach(changeItem -> {
+                if (changeItem.getKey().endsWith("interval")) {
+                    scheduleConfig.setInterval(Integer.valueOf(changeItem.getNewValue()));
+                }
+                if (changeItem.getKey().endsWith("initialDelay")) {
+                    scheduleConfig.setInitialDelay(Integer.valueOf(changeItem.getNewValue()));
+                }
+                if (changeItem.getKey().endsWith("enabled")) {
+                    scheduleConfig.setEnabled(Boolean.valueOf(changeItem.getNewValue()));
+                }
+            });
+            if (scheduleConfig.getEnabled()) {
+                fixedDelayTaskRegistrar.removeFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAData", etadataSyncJob));
+                fixedDelayTaskRegistrar.addFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAData", etadataSyncJob), scheduleConfig.getInterval(), scheduleConfig.getInitialDelay());
+            } else {
+                fixedDelayTaskRegistrar.removeFixedDelayTask(new SchedulingRunnable(etadataSyncJob.getClass().getName(), "syncETAData", etadataSyncJob));
+            }
+        }
+
+    }
+}
+

+ 71 - 0
qhtx-eta-integrator/qhtx-integrator-infra/pom.xml

@@ -0,0 +1,71 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.qhtx.eta</groupId>
+        <artifactId>qhtx-eta-integrator</artifactId>
+        <version>1.0.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>qhtx-integrator-infra</artifactId>
+    <packaging>jar</packaging>
+    <properties>
+        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+    </properties>
+
+    <dependencies>
+        <!-- jdbcStarter -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-jdbc</artifactId>
+
+        </dependency>
+        <!-- druid连接池 -->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid-spring-boot-starter</artifactId>
+            <version>${durid.version}</version>
+        </dependency>
+        <!--         oracle-->
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc6</artifactId>
+            <version>${oracle.version}</version>
+        </dependency>
+        <!--        mybatisplus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.qhtx.eta</groupId>
+            <artifactId>qhtx-integrator-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <!-- Spring Boot Starter for Apache Kafka -->
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+            <version>${kafka.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+
+        <!--kafka-->
+        <dependency>
+            <groupId>org.springframework.kafka</groupId>
+            <artifactId>spring-kafka</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba.cloud</groupId>
+            <artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
+        </dependency>
+
+    </dependencies>
+</project>

+ 12 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/annotation/UseDataSource.java

@@ -0,0 +1,12 @@
+package com.qhtx.eta.infra.annotation;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+
+import java.lang.annotation.*;
+
+@Documented
+@Retention(RetentionPolicy.RUNTIME)
+@Target(ElementType.TYPE)
+public @interface UseDataSource {
+    DataSourceType dataSourceType() default DataSourceType.ODS;
+}

+ 38 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/aspect/DataSourceSwitchAspect.java

@@ -0,0 +1,38 @@
+package com.qhtx.eta.infra.aspect;
+
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.datasource.DataSourceContextHolder;
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.common.exception.ETAException;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.stereotype.Component;
+
+import java.util.Optional;
+
+@Component
+@Aspect
+public class DataSourceSwitchAspect {
+    @Around("execution(* com.qhtx.eta.infra.service.*.*(..))")
+    public Object switchDataSource(ProceedingJoinPoint joinPoint) throws Throwable {
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        UseDataSource dataSource = Optional.ofNullable(signature.getMethod().getAnnotation(UseDataSource.class)).orElseGet(() -> signature.getMethod().getDeclaringClass().getAnnotation(UseDataSource.class));
+        DataSourceType dataSourceType = dataSource != null ? dataSource.dataSourceType() : DataSourceType.ODS;
+        if (dataSourceType == null) {
+            throw new ETAException(ErrorEnum.UNKNOWN_DATASOURCE_ERROR);
+        }
+        // 切换数据源
+        DataSourceContextHolder.setDataSourceType(dataSourceType);
+
+        try {
+            // 执行目标方法
+            return joinPoint.proceed();
+        } finally {
+            // 清理ThreadLocal中的数据源信息
+            DataSourceContextHolder.clearDataSourceType();
+        }
+    }
+}

+ 69 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/config/InfraConfig.java

@@ -0,0 +1,69 @@
+package com.qhtx.eta.infra.config;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.baomidou.mybatisplus.extension.spring.MybatisSqlSessionFactoryBean;
+import com.qhtx.eta.common.constant.ETAConstants;
+import com.qhtx.eta.infra.datasource.DynamicDataSource;
+import com.qhtx.eta.common.eunms.DataSourceType;
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class InfraConfig {
+
+    @Bean(name = "odsDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.ods")
+    public DruidDataSource odsDataSource() {
+        return new DruidDataSource();
+    }
+
+    @Bean(name = "dwDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.dw")
+    public DruidDataSource dwDataSource() {
+        return new DruidDataSource();
+    }
+
+    @Bean
+    public DynamicDataSource dynamicDataSource() {
+        DynamicDataSource dataSource = new DynamicDataSource();
+        Map<Object, Object> targetDataSources = new HashMap<>();
+        targetDataSources.put(DataSourceType.ODS, odsDataSource());
+        targetDataSources.put(DataSourceType.DW, dwDataSource());
+        dataSource.setTargetDataSources(targetDataSources);
+        dataSource.setDefaultTargetDataSource(odsDataSource()); // 设置默认数据源
+        return dataSource;
+    }
+
+    @Bean
+    public DataSourceTransactionManager transactionManager() {
+        return new DataSourceTransactionManager(dynamicDataSource());
+    }
+
+    @Bean
+    public TransactionTemplate transactionTemplate() {
+        return new TransactionTemplate(transactionManager());
+    }
+
+    @Bean(name = "sqlSessionFactory")
+    public SqlSessionFactory sqlSessionFactory() throws Exception {
+        MybatisSqlSessionFactoryBean sqlSessionFactoryBean = new MybatisSqlSessionFactoryBean();
+        sqlSessionFactoryBean.setDataSource(dynamicDataSource());
+        //此处设置为了解决找不到mapper文件的问题
+        sqlSessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(ETAConstants.MAPPER_LOCATION));
+        return sqlSessionFactoryBean.getObject();
+    }
+
+    @Bean
+    public SqlSessionTemplate sqlSessionTemplate() throws Exception {
+        return new SqlSessionTemplate(sqlSessionFactory());
+    }
+}

+ 55 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/config/SqlStatementInterceptor.java

@@ -0,0 +1,55 @@
+package com.qhtx.eta.infra.config;
+
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.plugin.*;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Properties;
+
+
+@Intercepts({
+        @Signature(type = Executor.class, method = "update", args = {MappedStatement.class,
+                Object.class}),
+        @Signature(type = Executor.class, method = "query", args = {MappedStatement.class,
+                Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}),
+        @Signature(type = Executor.class, method = "insert", args = {MappedStatement.class,
+                Object.class, RowBounds.class})})
+
+public class SqlStatementInterceptor implements Interceptor {
+
+    public static final Logger log = LoggerFactory.getLogger("sys-sql");
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+        long startTime = System.currentTimeMillis();
+        try {
+            return invocation.proceed();
+        } finally {
+            long timeConsuming = System.currentTimeMillis() - startTime;
+            log.info("执行SQL:{}ms", timeConsuming);
+            if (timeConsuming > 999 && timeConsuming < 5000) {
+                log.info("执行SQL大于1s:{}ms", timeConsuming);
+            } else if (timeConsuming >= 5000 && timeConsuming < 10000) {
+                log.info("执行SQL大于5s:{}ms", timeConsuming);
+            } else if (timeConsuming >= 10000) {
+                log.info("执行SQL大于10s:{}ms", timeConsuming);
+            }
+        }
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        return Plugin.wrap(target, this);
+    }
+
+    @Override
+    public void setProperties(Properties properties) {
+
+    }
+}

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DataSourceContextHolder.java

@@ -0,0 +1,18 @@
+package com.qhtx.eta.infra.datasource;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+
+public class DataSourceContextHolder {
+    private static final ThreadLocal<DataSourceType> contextHolder = new ThreadLocal<>();
+    public static void setDataSourceType(DataSourceType dataSourceType) {
+        contextHolder.set(dataSourceType);
+    }
+
+    public static DataSourceType getDataSourceType() {
+        return contextHolder.get();
+    }
+
+    public static void clearDataSourceType() {
+        contextHolder.remove();
+    }
+}

+ 46 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DecryptDataSourcePostProcessor.java

@@ -0,0 +1,46 @@
+package com.qhtx.eta.infra.datasource;
+
+import com.alibaba.druid.pool.DruidDataSource;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.qhtx.eta.infra.utils.DruidEncryptUtil;
+import org.springframework.beans.BeansException;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.beans.factory.config.BeanPostProcessor;
+import org.springframework.stereotype.Component;
+
+import java.util.Map;
+import java.util.Properties;
+import java.util.StringTokenizer;
+
+
+@Component
+public class DecryptDataSourcePostProcessor implements BeanPostProcessor {
+    @Value("${spring.datasource.publicKey}")
+    private String publicKey;
+
+    @Override
+    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
+        if (bean instanceof DruidDataSource) {
+            DruidDataSource dataSource = (DruidDataSource) bean;
+            Properties properties = dataSource.getConnectProperties();
+            Object decrypt = properties.get("decrypt");
+            if (dataSource.getPassword() != null && isEncrypted(decrypt)) {
+                try {
+                    String decryptedPassword = DruidEncryptUtil.decrypt(publicKey, dataSource.getPassword());
+                    dataSource.setPassword(decryptedPassword);
+                } catch (Exception e) {
+                    throw new RuntimeException(e);
+                }
+            }
+        }
+        return bean;
+    }
+
+    private boolean isEncrypted(Object decrypt) {
+        if (decrypt == null) {
+            return false;
+        }
+        return Boolean.parseBoolean(String.valueOf(decrypt));
+    }
+}

+ 12 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/datasource/DynamicDataSource.java

@@ -0,0 +1,12 @@
+package com.qhtx.eta.infra.datasource;
+
+import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
+
+public class DynamicDataSource extends AbstractRoutingDataSource {
+    @Override
+    protected Object determineCurrentLookupKey() {
+
+        return DataSourceContextHolder.getDataSourceType();
+    }
+}
+

+ 30 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/entity/EtaApiQuotaData.java

@@ -0,0 +1,30 @@
+package com.qhtx.eta.infra.entity;
+
+import lombok.Data;
+import org.apache.commons.collections4.splitmap.AbstractIterableGetMapDecorator;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.io.Serializable;
+
+/**
+ * (EtaApiQuotaData)实体类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:11
+ */
+@Data
+public class EtaApiQuotaData implements Serializable {
+    private static final long serialVersionUID = 846914555214010210L;
+
+    private Integer dataId;
+
+    private String uniqueCode;
+
+    private BigDecimal dataValue;
+
+    private Date dataTime;
+
+    private Date updateTime;
+}
+

+ 58 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/entity/EtaApiQuotaInfo.java

@@ -0,0 +1,58 @@
+package com.qhtx.eta.infra.entity;
+
+import lombok.Data;
+import lombok.Getter;
+import lombok.NoArgsConstructor;
+
+import java.util.Date;
+import java.io.Serializable;
+
+/**
+ * (EtaApiQuotaInfo)实体类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:36
+ */
+@Data
+public class EtaApiQuotaInfo implements Serializable {
+    private static final long serialVersionUID = 551271023236413437L;
+
+    private Integer quotaId;
+
+    private String uniqueCode;
+
+    private Integer edbInfoId;
+
+    private String edbCode;
+
+    private String edbName;
+
+    private String unit;
+
+    private String frequency;
+
+    private Date startDate;
+
+    private Date endDate;
+
+    private Date latestDate;
+
+    private Integer classifyId;
+
+    private Integer edbSource;
+
+    private String edbSourceName;
+
+    private Integer noUpdate;
+
+//    private Integer isDelete;
+//
+//    private Integer isQuality;
+//
+//    private Long dataCreateTime;
+//
+//    private Long dataUpdateTime;
+
+
+}
+

+ 31 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/enums/Frequency.java

@@ -0,0 +1,31 @@
+package com.qhtx.eta.infra.enums;
+
+import lombok.Getter;
+
+@Getter
+public enum Frequency {
+    DAILY(1, "日度"), WEEKLY(2, "周度"), MONTHLY(3, "月度"), QUARTERLY(6, "季度"), DECADELY(7, "旬度"),
+
+    YEARLY(4, "年度"),
+
+    SEMI_ANNUAL(5, "半年度"),
+    ;
+
+
+    private int value;
+    private String desc;
+
+    Frequency(int value, String desc) {
+        this.value = value;
+        this.desc = desc;
+    }
+
+    public static Frequency getFrequencyByDesc(String desc) {
+        for (Frequency frequency : Frequency.values()) {
+            if (frequency.getDesc().equals(desc)) {
+                return frequency;
+            }
+        }
+        return null;
+    }
+}

+ 8 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/DimIncDao.java

@@ -0,0 +1,8 @@
+package com.qhtx.eta.infra.mapper;
+
+import org.apache.ibatis.annotations.Param;
+
+public interface DimIncDao {
+
+    void insertOrUpdate(@Param("tableName") String tableName, @Param("minUpdateTime") Long minUpdateTime, @Param("sourceType") Integer sourceType);
+}

+ 55 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/EtaApiQuotaDataDao.java

@@ -0,0 +1,55 @@
+package com.qhtx.eta.infra.mapper;
+
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * (EtaApiQuotaData)表数据库访问层
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:06
+ */
+public interface EtaApiQuotaDataDao {
+
+
+    /**
+     * 统计总行数
+     *
+     * @param etaApiQuotaData 查询条件
+     * @return 总行数
+     */
+    long count(EtaApiQuotaData etaApiQuotaData);
+
+    /**
+     * 新增数据
+     *
+     * @param etaApiQuotaData 实例对象
+     * @return 影响行数
+     */
+    int insert(EtaApiQuotaData etaApiQuotaData);
+
+    /**
+     * 批量新增数据(MyBatis原生foreach方法)
+     *
+     * @param entities List<EtaApiQuotaData> 实例对象列表
+     * @return 影响行数
+     */
+    int insertBatch(@Param("entities") List<EtaApiQuotaData> entities);
+
+    /**
+     * 批量获取每条指标数据的最新一条记录
+     * @return EtaApiQuotaData 实例对象列表
+     */
+    List<EtaApiQuotaData> getAllLatestDataByUniqueCode();
+    /**
+     * 获取指标数据的最新一条记录
+     *
+     * @param uniqueCode
+     * @return EtaApiQuotaData 实例对象
+     */
+    EtaApiQuotaData getLatestDataByUniqueCode(String uniqueCode);
+
+}
+

+ 76 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/mapper/EtaApiQuotaInfoDao.java

@@ -0,0 +1,76 @@
+package com.qhtx.eta.infra.mapper;
+
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * (EtaApiQuotaInfo)表数据库访问层
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:36
+ */
+public interface EtaApiQuotaInfoDao {
+
+    /**
+     * 通过ID查询单条数据
+     *
+     * @param quoteId 主键
+     * @return 实例对象
+     */
+    EtaApiQuotaInfo queryById(Integer quoteId);
+
+    /**
+     * 统计总行数
+     *
+     * @param etaApiQuotaInfo 查询条件
+     * @return 总行数
+     */
+    long count(EtaApiQuotaInfo etaApiQuotaInfo);
+
+    /**
+     * 新增数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 影响行数
+     */
+    int insert(EtaApiQuotaInfo etaApiQuotaInfo);
+
+    /**
+     * 批量新增数据(MyBatis原生foreach方法)
+     *
+     * @param entities List<EtaApiQuotaInfo> 实例对象列表
+     * @return 影响行数
+     */
+    int insertBatch(@Param("entities") List<EtaApiQuotaInfo> entities);
+
+    /**
+     * 批量新增或按主键更新数据(MyBatis原生foreach方法)
+     *
+     * @param entities List<EtaApiQuotaInfo> 实例对象列表
+     * @return 影响行数
+     * @throws org.springframework.jdbc.BadSqlGrammarException 入参是空List的时候会抛SQL语句错误的异常,请自行校验入参
+     */
+    int insertOrUpdateBatch(@Param("entities") List<EtaApiQuotaInfo> entities);
+
+    /**
+     * 修改数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 影响行数
+     */
+    int update(EtaApiQuotaInfo etaApiQuotaInfo);
+
+    /**
+     * 通过主键删除数据
+     *
+     * @param quoteId 主键
+     * @return 影响行数
+     */
+    int deleteById(Integer quoteId);
+
+
+    List<EtaApiQuotaInfo> queryQuotaList(EtaApiQuotaInfo etaApiQuotaInfo);
+}
+

+ 27 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/EtaApiQuotaDataService.java

@@ -0,0 +1,27 @@
+package com.qhtx.eta.infra.service;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+
+import java.util.List;
+
+/**
+ * (EtaApiQuotaData)表服务接口
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:14
+ */
+
+public interface EtaApiQuotaDataService {
+
+
+    List<EtaApiQuotaData> getAllLatestDataByUniqueCode();
+
+
+    EtaApiQuotaData getLatestDataByUniqueCode(String uniqueCode);
+
+
+    void batchInsert(List<EtaApiQuotaData> dataList);
+
+}

+ 55 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/EtaApiQuotaInfoService.java

@@ -0,0 +1,55 @@
+package com.qhtx.eta.infra.service;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+
+import java.util.List;
+
+/**
+ * (EtaApiQuotaInfo)表服务接口
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:38
+ */
+
+public interface EtaApiQuotaInfoService {
+
+    /**
+     * 通过ID查询单条数据
+     *
+     * @param quoteId 主键
+     * @return 实例对象
+     */
+    EtaApiQuotaInfo queryById(Integer quoteId);
+
+
+    /**
+     * 新增数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 实例对象
+     */
+    EtaApiQuotaInfo insert(EtaApiQuotaInfo etaApiQuotaInfo);
+
+    /**
+     * 修改数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 实例对象
+     */
+    EtaApiQuotaInfo update(EtaApiQuotaInfo etaApiQuotaInfo);
+
+    /**
+     * 通过主键删除数据
+     *
+     * @param quoteId 主键
+     * @return 是否成功
+     */
+    boolean deleteById(Integer quoteId);
+
+    void batchInsertOrUpdate(List<EtaApiQuotaInfo> quotaInfoDTOS);
+
+
+    List<EtaApiQuotaInfo> queryQuotaList(EtaApiQuotaInfo etaApiQuotaInfo);
+}

+ 8 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/OdsDimService.java

@@ -0,0 +1,8 @@
+package com.qhtx.eta.infra.service;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+
+public interface OdsDimService {
+    void odsDimDataUpdate(String tableName, Long minOperationTime, Integer sourceType);
+}

+ 57 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/EtaApiQuotaDataServiceImpl.java

@@ -0,0 +1,57 @@
+package com.qhtx.eta.infra.service.impl;
+
+import com.qhtx.eta.common.annotation.DataOperator;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.entity.EtaApiQuotaData;
+import com.qhtx.eta.infra.mapper.EtaApiQuotaDataDao;
+import com.qhtx.eta.infra.service.EtaApiQuotaDataService;
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.common.eunms.ETAApiType;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * (EtaApiQuotaData)表服务实现类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:15
+ */
+@Service("etaApiQuotaDataService")
+@UseDataSource(dataSourceType = DataSourceType.ODS)
+@Slf4j
+public class EtaApiQuotaDataServiceImpl implements EtaApiQuotaDataService {
+    @Resource
+    private EtaApiQuotaDataDao etaApiQuotaDataDao;
+
+    @Resource
+    private TransactionTemplate transactionTemplate;
+
+    @Override
+    public List<EtaApiQuotaData> getAllLatestDataByUniqueCode() {
+        return etaApiQuotaDataDao.getAllLatestDataByUniqueCode();
+    }
+
+    @Override
+    public EtaApiQuotaData getLatestDataByUniqueCode(String uniqueCode) {
+        return this.etaApiQuotaDataDao.getLatestDataByUniqueCode(uniqueCode);
+    }
+
+    @Override
+    @DataOperator(apiType = ETAApiType.DATA, fields = {"uniqueCode"}, dataType = EtaApiQuotaData.class)
+    public void batchInsert(List<EtaApiQuotaData> dataList) {
+        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
+            @Override
+            protected void doInTransactionWithoutResult(@NotNull TransactionStatus transactionStatus) {
+                etaApiQuotaDataDao.insertBatch(dataList);
+            }
+        });
+
+    }
+}

+ 103 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/EtaApiQuotaInfoServiceImpl.java

@@ -0,0 +1,103 @@
+package com.qhtx.eta.infra.service.impl;
+
+import com.qhtx.eta.common.annotation.DataOperator;
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.common.eunms.ErrorEnum;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.entity.EtaApiQuotaInfo;
+import com.qhtx.eta.common.eunms.ETAApiType;
+import com.qhtx.eta.infra.mapper.EtaApiQuotaInfoDao;
+import com.qhtx.eta.infra.service.EtaApiQuotaInfoService;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * (EtaApiQuotaInfo)表服务实现类
+ *
+ * @author makejava
+ * @since 2024-04-29 13:52:38
+ */
+@Service("etaApiQuotaInfoService")
+@UseDataSource(dataSourceType = DataSourceType.ODS)
+@Slf4j
+public class EtaApiQuotaInfoServiceImpl implements EtaApiQuotaInfoService {
+    @Resource
+    private TransactionTemplate transactionTemplate;
+    @Resource
+    private EtaApiQuotaInfoDao etaApiQuotaInfoDao;
+
+    /**
+     * 通过ID查询单条数据
+     *
+     * @param quoteId 主键
+     * @return 实例对象
+     */
+    @Override
+    public EtaApiQuotaInfo queryById(Integer quoteId) {
+        return this.etaApiQuotaInfoDao.queryById(quoteId);
+    }
+
+
+    /**
+     * 新增数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 实例对象
+     */
+    @Override
+    public EtaApiQuotaInfo insert(EtaApiQuotaInfo etaApiQuotaInfo) {
+        this.etaApiQuotaInfoDao.insert(etaApiQuotaInfo);
+        return etaApiQuotaInfo;
+    }
+
+    /**
+     * 修改数据
+     *
+     * @param etaApiQuotaInfo 实例对象
+     * @return 实例对象
+     */
+    @Override
+    public EtaApiQuotaInfo update(EtaApiQuotaInfo etaApiQuotaInfo) {
+        this.etaApiQuotaInfoDao.update(etaApiQuotaInfo);
+        return this.queryById(etaApiQuotaInfo.getQuotaId());
+    }
+
+    /**
+     * 通过主键删除数据
+     *
+     * @param quoteId 主键
+     * @return 是否成功
+     */
+    @Override
+    public boolean deleteById(Integer quoteId) {
+        return this.etaApiQuotaInfoDao.deleteById(quoteId) > 0;
+    }
+
+    @Override
+    @DataOperator(apiType = ETAApiType.QUOTA, fields = {"uniqueCode"}, dataType = EtaApiQuotaInfo.class)
+    public void batchInsertOrUpdate(List<EtaApiQuotaInfo> quotaInfoDTOS) {
+        transactionTemplate.execute(new TransactionCallbackWithoutResult() {
+            @Override
+            protected void doInTransactionWithoutResult(@NotNull TransactionStatus transactionStatus) {
+                try {
+                    etaApiQuotaInfoDao.insertOrUpdateBatch(quotaInfoDTOS);
+                } catch (Exception e) {
+                    log.warn(String.format(ErrorEnum.DATASOURCE_EXECUTE_ERROR.getMsg(), e.getMessage()));
+                }
+
+            }
+        });
+    }
+
+    @Override
+    public List<EtaApiQuotaInfo> queryQuotaList(EtaApiQuotaInfo etaApiQuotaInfo) {
+        return etaApiQuotaInfoDao.queryQuotaList(etaApiQuotaInfo);
+    }
+}

+ 43 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/service/impl/OdsDimServiceImpl.java

@@ -0,0 +1,43 @@
+package com.qhtx.eta.infra.service.impl;
+
+import com.qhtx.eta.common.eunms.DataSourceType;
+import com.qhtx.eta.common.exception.ETAException;
+import com.qhtx.eta.infra.annotation.UseDataSource;
+import com.qhtx.eta.infra.mapper.DimIncDao;
+import com.qhtx.eta.infra.service.OdsDimService;
+import lombok.extern.slf4j.Slf4j;
+import org.jetbrains.annotations.NotNull;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.TransactionStatus;
+import org.springframework.transaction.support.TransactionCallbackWithoutResult;
+import org.springframework.transaction.support.TransactionTemplate;
+
+import javax.annotation.Resource;
+
+@Service("odsDimService")
+@UseDataSource(dataSourceType = DataSourceType.DW)
+@Slf4j
+public class OdsDimServiceImpl implements OdsDimService {
+    @Resource
+    private DimIncDao dimIncDao;
+    @Resource
+    private TransactionTemplate transactionTemplate;
+
+    @Override
+    public void odsDimDataUpdate(String tableName, Long minOperationTime, Integer sourceType) {
+        try {
+            transactionTemplate.execute(new TransactionCallbackWithoutResult() {
+                @Override
+                protected void doInTransactionWithoutResult(@NotNull TransactionStatus transactionStatus) {
+                    dimIncDao.insertOrUpdate(tableName, minOperationTime, sourceType);
+                    log.info("通知对接码数据更新");
+                }
+            });
+        } catch (ETAException e) {
+            log.error("数据库操作失败[{}]", e.getErrorMessage());
+        } catch (Exception e) {
+            log.error("数据库操作失败[{}]", e.getMessage());
+        }
+
+    }
+}

+ 42 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/java/com/qhtx/eta/infra/utils/DruidEncryptUtil.java

@@ -0,0 +1,42 @@
+package com.qhtx.eta.infra.utils;
+
+import com.alibaba.druid.filter.config.ConfigTools;
+import org.springframework.beans.factory.annotation.Value;
+
+import javax.annotation.Resource;
+import java.security.NoSuchAlgorithmException;
+import java.security.NoSuchProviderException;
+
+/**
+ * 数据库加密util
+ *
+ * @author: ChickenWing
+ * @date: 2023/10/1
+ */
+public class DruidEncryptUtil {
+    /**
+     * 数据库密码加密方法
+     *
+     * @param privateKey
+     * @param plainText
+     * @return
+     * @throws Exception
+     */
+    public static String encrypt(String privateKey, String plainText) throws Exception {
+        return ConfigTools.encrypt(privateKey, plainText);
+    }
+
+    /**
+     * 数据库密码解密方法
+     *
+     * @param publicKey
+     * @param encryptText
+     * @return
+     * @throws Exception
+     */
+    public static String decrypt(String publicKey, String encryptText) throws Exception {
+        return ConfigTools.decrypt(publicKey, encryptText);
+    }
+}
+
+

+ 21 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/DimIncDao.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qhtx.eta.infra.mapper.DimIncDao">
+    <sql id="tableName">T_DAMP_DEAL_DIM_INC</sql>
+
+    <insert id="insertOrUpdate">
+        merge into
+        <include refid="tableName"/>
+        to_
+        USING
+        (SELECT #{tableName} as TABLE_NAME,
+        #{minUpdateTime} as MIN_UPDATE_TIME,
+        #{sourceType} as SOURCE_TYPE from dual) from_
+        on (to_.TABLE_NAME = from_.TABLE_NAME and to_.SOURCE_TYPE = from_.SOURCE_TYPE and to_.DEAL_STATUS=0)
+        WHEN MATCHED THEN
+        UPDATE SET to_.MIN_UPDATE_TIME = from_.MIN_UPDATE_TIME where to_.MIN_UPDATE_TIME > from_.MIN_UPDATE_TIME
+        WHEN NOT MATCHED THEN
+        INSERT (ID,TABLE_NAME,MIN_UPDATE_TIME,DEAL_STATUS,SOURCE_TYPE)
+        VALUES (rawtohex(sys_guid()),from_.TABLE_NAME,from_.MIN_UPDATE_TIME,0,from_.SOURCE_TYPE)
+    </insert>
+</mapper>

+ 62 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/EtaApiQuotaDataDao.xml

@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qhtx.eta.infra.mapper.EtaApiQuotaDataDao">
+
+    <resultMap type="com.qhtx.eta.infra.entity.EtaApiQuotaData" id="EtaApiQuotaDataMap">
+        <result property="dataId" column="DATA_ID" jdbcType="INTEGER"/>
+        <result property="uniqueCode" column="unique_code" jdbcType="VARCHAR"/>
+        <result property="dataValue" column="DATA_VALUE" jdbcType="DECIMAL"/>
+        <result property="dataTime" column="DATA_TIME" jdbcType="DATE"/>
+        <result property="updateTime" column="UPDATE_TIME" jdbcType="TIMESTAMP"/>
+        <result property="isDelete" column="IS_DELETE" jdbcType="INTEGER"/>
+        <result property="isQuality" column="IS_QUALITY" jdbcType="INTEGER"/>
+        <result property="dataCreateTime" column="DATA_CREATE_TIME" jdbcType="BIGINT"/>
+        <result property="dataUpdateTime" column="DATA_UPDATE_TIME" jdbcType="BIGINT"/>
+        <result property="htUniqueCode" column="HT_UNIQUE_CODE" jdbcType="VARCHAR"/>
+    </resultMap>
+
+    <!--查询单个-->
+
+
+    <select id="getLatestDataByUniqueCode" resultMap="EtaApiQuotaDataMap">
+        SELECT *
+        FROM ( select *  from T_ETA_API_QUOTA_DATA
+        where unique_code = #{uniqueCode} order by data_time desc)
+        WHERE ROWNUM = 1
+    </select>
+
+    <select id="getAllLatestDataByUniqueCode" resultMap="EtaApiQuotaDataMap">
+        SELECT t.unique_code, t.data_time
+        FROM (
+                 SELECT unique_code, data_time,
+                        ROW_NUMBER() OVER(PARTITION BY unique_code ORDER BY data_time DESC) as rn
+                 FROM t_eta_api_quota_data
+             ) t
+        WHERE t.rn = 1
+    </select>
+
+    <update id="insertBatch" keyProperty="dataId" useGeneratedKeys="false">
+        MERGE INTO
+        T_ETA_API_QUOTA_DATA t
+        USING (
+        <foreach collection="entities" item="entity" separator="UNION ALL">
+          SELECT #{entity.uniqueCode,jdbcType=VARCHAR} AS UNIQUE_CODE,
+         #{entity.dataValue ,jdbcType=DECIMAL} AS DATA_VALUE,
+         #{entity.dataTime,jdbcType=DATE} AS DATA_TIME,
+         #{entity.updateTime,jdbcType=TIMESTAMP} AS UPDATE_TIME
+            FROM dual
+        </foreach>
+        ) s ON (t.unique_code = s.unique_code and t.data_time = s.data_time and t.is_delete = 0)
+        WHEN MATCHED THEN
+        UPDATE SET
+        t.data_value = s.data_value
+        WHEN NOT MATCHED THEN
+        INSERT
+        (UNIQUE_CODE,DATA_VALUE,DATA_TIME,UPDATE_TIME)
+        VALUES
+        (s.UNIQUE_CODE,s.DATA_VALUE,s.DATA_TIME,s.UPDATE_TIME)
+
+    </update>
+
+</mapper>
+

+ 73 - 0
qhtx-eta-integrator/qhtx-integrator-infra/src/main/resources/mapper/EtaApiQuotaInfoDao.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.qhtx.eta.infra.mapper.EtaApiQuotaInfoDao">
+
+    <resultMap type="com.qhtx.eta.infra.entity.EtaApiQuotaInfo" id="EtaApiQuotaInfoMap">
+        <id property="quotaId" column="QUOTE_ID" jdbcType="INTEGER"/>
+        <result property="edbInfoId" column="EDB_INFO_ID" jdbcType="INTEGER"/>
+        <result property="edbCode" column="EDB_CODE" jdbcType="VARCHAR"/>
+        <result property="uniqueCode" column="UNIQUE_CODE" jdbcType="VARCHAR"/>
+        <result property="edbName" column="EDB_NAME" jdbcType="VARCHAR"/>
+        <result property="unit" column="UNIT" jdbcType="VARCHAR"/>
+        <result property="frequency" column="FREQUENCY" jdbcType="VARCHAR"/>
+        <result property="startDate" column="START_DATE" jdbcType="DATE"/>
+        <result property="endDate" column="END_DATE" jdbcType="DATE"/>
+        <result property="latestDate" column="LATEST_DATE" jdbcType="DATE"/>
+        <result property="classifyId" column="CLASSIFY_ID" jdbcType="INTEGER"/>
+        <result property="edbSource" column="EDB_SOURCE" jdbcType="TIMESTAMP"/>
+        <result property="edbSourceName" column="EDB_SOURCE_NAME" jdbcType="VARCHAR"/>
+        <result property="noUpdate" column="NO_UPDATE" jdbcType="INTEGER"/>
+        <result property="isDelete" column="IS_DELETE" jdbcType="INTEGER"/>
+        <result property="isQuality" column="IS_QUALITY" jdbcType="INTEGER"/>
+        <result property="dataCreateTime" column="DATA_CREATE_TIME" jdbcType="BIGINT"/>
+        <result property="dataUpdateTime" column="DATA_UPDATE_TIME" jdbcType="BIGINT"/>
+        <result property="htUniqueCode" column="HT_UNIQUE_CODE" jdbcType="VARCHAR"/>
+    </resultMap>
+
+
+    <!-- 批量插入或更新-->
+    <update id="insertOrUpdateBatch" keyProperty="quoteId" useGeneratedKeys="false">
+        MERGE INTO
+        T_ETA_API_QUOTA_INFO t
+        USING (
+        <foreach item="item" separator="UNION ALL" collection="entities">
+            SELECT #{item.edbInfoId,jdbcType=INTEGER} as EDB_INFO_ID,
+            #{item.edbCode,jdbcType=VARCHAR} AS EDB_CODE,
+            #{item.uniqueCode,jdbcType=VARCHAR} AS UNIQUE_CODE,
+            #{item.edbName,jdbcType=VARCHAR} AS EDB_NAME,
+            #{item.unit,jdbcType=VARCHAR} AS UNIT,
+            #{item.frequency,jdbcType=VARCHAR} AS FREQUENCY,
+            #{item.startDate,jdbcType=DATE} AS START_DATE,
+            #{item.endDate,jdbcType=DATE} AS END_DATE,
+            #{item.latestDate,jdbcType=DATE} AS LATEST_DATE,
+            #{item.classifyId,jdbcType=INTEGER} AS CLASSIFY_ID,
+            #{item.edbSource,jdbcType=VARCHAR} AS EDB_SOURCE,
+            #{item.edbSourceName,jdbcType=VARCHAR} AS EDB_SOURCE_NAME,
+            #{item.noUpdate,jdbcType=INTEGER} AS NO_UPDATE
+            FROM dual
+        </foreach>
+        ) s ON (t.unique_code = s.unique_code)
+        WHEN MATCHED THEN
+        UPDATE SET
+        t.latest_date = s.latest_date,
+        t.NO_UPDATE = s.NO_UPDATE
+        WHEN NOT MATCHED THEN
+        INSERT
+        (EDB_INFO_ID,EDB_CODE,UNIQUE_CODE,EDB_NAME,UNIT,FREQUENCY,START_DATE,END_DATE,LATEST_DATE,CLASSIFY_ID,EDB_SOURCE,EDB_SOURCE_NAME,NO_UPDATE)
+        VALUES
+        (s.EDB_INFO_ID,s.EDB_CODE,s.UNIQUE_CODE,s.EDB_NAME,s.UNIT,s.FREQUENCY,s.START_DATE,s.END_DATE,s.LATEST_DATE,s.CLASSIFY_ID,s.EDB_SOURCE,s.EDB_SOURCE_NAME,s.NO_UPDATE)
+    </update>
+
+
+    <select id="queryQuotaList" resultMap="EtaApiQuotaInfoMap">
+        select unique_code,end_date,latest_date,frequency from T_ETA_API_QUOTA_INFO
+        <where>
+            <if test="noUpdate != null">
+                and no_update = #{noUpdate}
+            </if>
+            and IS_DELETE = 0
+        </where>
+        order by quota_id asc
+    </select>
+</mapper>
+

+ 18 - 0
qhtx-eta-integrator/qhtx-integrator-starter/Dockerfile

@@ -0,0 +1,18 @@
+# 使用官方的Java基础镜像
+FROM openjdk:8-jdk-alpine
+
+# 设置工作目录
+WORKDIR /app
+
+# 将本地项目构建生成的jar文件复制到容器的/app目录下
+COPY target/eta-integrator.jar app.jar
+
+# 声明运行时环境变量(例如,配置端口、环境模式等)
+ENV SERVER_PORT=8081
+ENV SPRING_PROFILES_ACTIVE=dev
+
+# 暴露端口
+EXPOSE $SERVER_PORT
+
+# 容器启动时运行Spring Boot应用
+ENTRYPOINT ["java", "-jar", "app.jar"]

+ 73 - 0
qhtx-eta-integrator/qhtx-integrator-starter/pom.xml

@@ -0,0 +1,73 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>com.qhtx.eta</groupId>
+        <artifactId>qhtx-eta-integrator</artifactId>
+        <version>1.0.0.0-SNAPSHOT</version>
+    </parent>
+
+    <artifactId>qhtx-integrator-starter</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+            <version>2.4.2</version>
+            <exclusions>
+                <exclusion>
+                    <artifactId>spring-boot-starter-logging</artifactId>
+                    <groupId>org.springframework.boot</groupId>
+                </exclusion>
+            </exclusions>
+        </dependency>
+        <!--spring cloud 启动类-->
+        <dependency>
+            <groupId>org.springframework.cloud</groupId>
+            <artifactId>spring-cloud-starter-bootstrap</artifactId>
+        </dependency>
+
+
+        <dependency>
+            <groupId>com.qhtx.eta</groupId>
+            <artifactId>qhtx-integrator-domain</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>4.13.2</version>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <version>2.4.2</version>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+
+    <build>
+        <finalName>${project.artifactId}</finalName>
+        <!--打包成jar包时的名字-->
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+                <version>2.3.0.RELEASE</version>
+                <executions>
+                    <execution>
+                        <goals>
+                            <goal>repackage</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 20 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/ETAIntegratorApplication.java

@@ -0,0 +1,20 @@
+package com.qhtx.eta;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
+import org.springframework.context.annotation.ComponentScan;
+import org.springframework.scheduling.annotation.EnableScheduling;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
+@EnableScheduling
+@EnableTransactionManagement
+@MapperScan("com.qhtx.eta.**.mapper")
+@ComponentScan(basePackages = {"com.qhtx.eta.**.service", "com.qhtx.eta.**", "com.qhtx.eta.infra"})
+public class ETAIntegratorApplication {
+    public static void main(String[] args) {
+        SpringApplication.run(ETAIntegratorApplication.class);
+    }
+}

+ 41 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/config/HttpClientConfig.java

@@ -0,0 +1,41 @@
+package com.qhtx.eta.config;
+
+import com.alibaba.druid.util.StringUtils;
+import com.qhtx.eta.common.config.OkHttpClientProperties;
+import com.qhtx.eta.common.interceptor.RetryInterceptor;
+import com.qhtx.eta.common.utils.HttpClient;
+import okhttp3.OkHttpClient;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+@Configuration
+public class HttpClientConfig {
+
+    @Resource
+    private OkHttpClientProperties okHttpClientProperties;
+
+    @Bean
+    public OkHttpClient okHttpClient() {
+        RetryInterceptor httpRetryInterceptor = new RetryInterceptor
+                .Builder()
+                .retryInterval(okHttpClientProperties.getRetryInterval())
+                .retryTimes(okHttpClientProperties.getRetryTimes())
+                .build();
+        return new OkHttpClient
+                .Builder()
+                .addInterceptor(httpRetryInterceptor)
+                .connectTimeout(okHttpClientProperties.getConnectTimeout(), TimeUnit.SECONDS)
+                .readTimeout(okHttpClientProperties.getReadTimeout(), TimeUnit.SECONDS)
+                .build();
+    }
+
+    @Bean
+    public HttpClient HttpClient() {
+        return new HttpClient(okHttpClient());
+    }
+
+}
+

+ 26 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/config/RateLimiterConfig.java

@@ -0,0 +1,26 @@
+package com.qhtx.eta.config;
+
+import com.google.common.util.concurrent.RateLimiter;
+import com.qhtx.eta.common.config.DataSourceProperties;
+import com.qhtx.eta.common.eunms.LimiterType;
+import com.qhtx.eta.common.limiter.LimiterProvider;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.annotation.Resource;
+
+@Configuration
+public class RateLimiterConfig {
+    @Resource
+    private DataSourceProperties dataSourceProperties;
+
+    @Bean(name = "dataRateLimiter")
+    public RateLimiter dataRateLimiter() {
+        return (RateLimiter) LimiterProvider.INSTANCE.getLimiter(LimiterType.GUAVA_RATE_LIMITER).offer(dataSourceProperties.getData().getPermitsPerSecond());
+    }
+
+    @Bean(name = "quotaRateLimiter")
+    public RateLimiter quotaRateLimiter() {
+        return (RateLimiter) LimiterProvider.INSTANCE.getLimiter(LimiterType.GUAVA_RATE_LIMITER).offer(dataSourceProperties.getQuota().getPermitsPerSecond());
+    }
+}

+ 42 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/java/com/qhtx/eta/init/ETAEnvironmentInit.java

@@ -0,0 +1,42 @@
+package com.qhtx.eta.init;
+
+import com.qhtx.eta.domain.api.ApiServiceHolder;
+import com.qhtx.eta.domain.api.http.ETAHttpClient;
+import com.qhtx.eta.domain.enums.ETAInterfaceEnum;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+
+/**
+ * @description: 系统初始化api接口参数代理
+ */
+@Component
+@Slf4j
+public class ETAEnvironmentInit implements CommandLineRunner {
+
+    @Resource
+    private ApiServiceHolder apiServiceHolder;
+    @Resource
+    private ETAHttpClient httpClientHandler;
+
+
+    @Override
+    public void run(String... args) {
+        log.info("============================ 初始化系统API接口 ============================");
+        for (ETAInterfaceEnum etaInterfaceEnum : ETAInterfaceEnum.values()) {
+            if (etaInterfaceEnum.getEnable()) {
+                if (etaInterfaceEnum.getProxy() == null) {
+                    log.info("接口{}无需参数代理", etaInterfaceEnum.name());
+                    continue;
+                }
+                log.info("接口{}代理类{}", etaInterfaceEnum.name(), etaInterfaceEnum.getProxy().getName());
+                apiServiceHolder.register(etaInterfaceEnum);
+            }
+        }
+        // ETAHttpClient etaHttpClient = ETARetryProxyFactory.createProxy(httpClientHandler, ETAHttpClient.class);
+        apiServiceHolder.registerClient(httpClientHandler);
+        log.info("============================ 初始化系统API结束 ============================");
+    }
+}

+ 1 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/META-INF/services/com.qhtx.eta.common.limiter.Limiter

@@ -0,0 +1 @@
+com.qhtx.eta.common.limiter.impl.GuavaRateLimiter

+ 27 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/banner.txt

@@ -0,0 +1,27 @@
+ _____ _____ ______   _____  _     _ _______ _________
+(  ___) (  ___)  __ \ (  ___)( \   / )(  ____ \\__   __/
+| (   )| (   )|  | \/ | (   ) | \ ( /  ) (    \/   ) (
+| |   | |   | |  |    | (___) | |\ \ / /| (_____    | |
+| |   | |   | |  |    |  ___) | | \ V / |  _____)   | |
+| |   | |   | |  |    | (      | | | | | (        | |
+| (___| (___) |__|    | )      | | (_) | )_____) _| |_
+(_______)\____)_____/  |/       \_)\___/ |/ \_____/ \___/
+
+ _____ _____ ______   _____  _     _ _______ _________
+(  ___) (  ___)  __ \ (  ___)( \   / )(  ____ \\__   __/
+| (   )| (   )|  | \/ | (   ) | \ ( /  ) (    \/   ) (
+| |   | |   | |  |    | (___) | |\ \ / /| (_____    | |
+| |   | |   | |  |    |  ___) | | \ V / |  _____)   | |
+| |   | |   | |  |    | (      | | | | | (        | |
+| (___| (___) |__|    | )      | | (_) | )_____) _| |_
+(_______)\____)_____/  |/       \_)\___/ |/ \_____/ \___/
+
+ _______ _______ _________ _     _ _______ _________
+(  ____ \(  ___  )\__   __/( \   / )(  ____ \\__   __/
+| (    \/| (   ) |   ) (   |  \ ( /  ) (    \/   ) (
+| (_____ | (___) |   | |   |   \ | /   | (_____    | |
+(_____  )|  ___  |   | |   | (\ \ / /|  _____)   | |
+      ) || (   ) |   | |   | | \ V / | (        | |
+/\____) || )___) |___) (___| )  \_/  | )_____) _| |_
+\_______)(/ \___)_____/_____/ \_/\_/  |/ \_____/ \___/
+============================ ETA ODS 服务 ============================

+ 12 - 0
qhtx-eta-integrator/qhtx-integrator-starter/src/main/resources/bootstrap-dev.yml

@@ -0,0 +1,12 @@
+server:
+  port: 8081
+spring:
+  cloud:
+    nacos:
+      config:
+        server-addr: 192.168.77.130:8848
+        namespace: f448f995-0813-4a94-a463-028ee1d4f46e
+        group: DATABASE_GROUP
+        prefix: ${spring.application.name}
+        file-extension: yaml
+        refresh-enabled: true

部分文件因为文件数量过多而无法显示