108 Commits db29faeb46 ... 6da51af66c

Author SHA1 Message Date
  欧阳劲驰 6da51af66c 修改项目名称 11 months ago
  欧阳劲驰 154ffd29e4 修改influxdb端口 11 months ago
  欧阳劲驰 0ec0cfab0e 修改设备导出字段 11 months ago
  欧阳劲驰 6019617aaa 实现监利iot数据采集 11 months ago
  欧阳劲驰 86a212a784 删除内部类 11 months ago
  欧阳劲驰 8108e43dcd 枣阳iot增加设备 11 months ago
  欧阳劲驰 84fb7bcd9f 修改数据源配置 11 months ago
  欧阳劲驰 f26ab9b835 scada数据迁移增加并行处理 11 months ago
  欧阳劲驰 d8dfe271e1 增加日志 11 months ago
  欧阳劲驰 8fad4285b7 修复采集空指针 11 months ago
  欧阳劲驰 fbe09f6d09 营销户表信息,增加公共用水类型、是否计费、是否计量 11 months ago
  欧阳劲驰 08daba68cd 数据库增加并行 11 months ago
  欧阳劲驰 49c5887730 数据迁移排除空数据和空传感器code,完善传感器code配置,删除重复设备 11 months ago
  欧阳劲驰 78d4406fe2 实现中环scada历史数据迁移 11 months ago
  欧阳劲驰 f24f8b4ace 实现中环scada历史数据迁移 11 months ago
  欧阳劲驰 0e11437857 实现中环scada历史数据迁移 11 months ago
  欧阳劲驰 8de2242291 实现中环scada历史数据迁移 11 months ago
  欧阳劲驰 49edb3cf32 实现中环scada历史数据迁移 11 months ago
  欧阳劲驰 7214e8d08f 实现公式配置处理,二汽水厂设备录入 11 months ago
  欧阳劲驰 9686237be0 增加抄表周期修改 11 months ago
  欧阳劲驰 d317450e41 修复时间截断问题 11 months ago
  欧阳劲驰 70d29b98ed 营销户表信息导入,增加表类型 11 months ago
  欧阳劲驰 4b5dd6964f 营销户表信息导入,增加表类型 11 months ago
  欧阳劲驰 298cdcb638 修改返回code 11 months ago
  欧阳劲驰 9f277898a5 增加忽略的返回值 11 months ago
  欧阳劲驰 4446c7531b 同步数据库 11 months ago
  欧阳劲驰 c2a7c86823 实现第三方接入 11 months ago
  欧阳劲驰 891da5b386 枣阳设备新增 11 months ago
  欧阳劲驰 90edc70bc7 枣阳设备新增 11 months ago
  欧阳劲驰 64d6ac0a54 枣阳设备新增 11 months ago
  欧阳劲驰 2a4f197aee 使用用户角色列表接口获取用户的角色信息 11 months ago
  欧阳劲驰 146d90e4a6 营销数据时间根据月份截断 11 months ago
  欧阳劲驰 14674039c1 数据时间不以原始数据中的时间为准,改为使用采集程序执行时的时间 11 months ago
  欧阳劲驰 52f7d53d42 数据时间不以原始数据中的时间为准,改为使用采集程序执行时的时间 11 months ago
  欧阳劲驰 600d951bb9 枣阳物联网数据查询,增加时间滚动查询 11 months ago
  欧阳劲驰 6bfe0ddb60 枣阳物联网增加设备 11 months ago
  欧阳劲驰 452154068d 删除导入开放权限 11 months ago
  欧阳劲驰 ffbaa8f55b 修改日志 11 months ago
  欧阳劲驰 cb63393fca 增加单用户职能信息过滤 11 months ago
  欧阳劲驰 c966533283 实现户表数据导入 11 months ago
  欧阳劲驰 dde4953ca8 实现户表信息导入 11 months ago
  欧阳劲驰 043cc92493 删除中环重复设备 11 months ago
  欧阳劲驰 abb4d2a07d 修复中环scads数据采集,时间解析失败的问题,修改中环scads数据采集为多线程采集 11 months ago
  欧阳劲驰 4752210914 实现职能信息同步 11 months ago
  欧阳劲驰 43a80edf0d 修复临时token生成失败的问题 11 months ago
  欧阳劲驰 496dd07db4 修改result 11 months ago
  欧阳劲驰 07f186c0ad 中环添加设备 11 months ago
  欧阳劲驰 034ac6a089 增加异常处理 11 months ago
  欧阳劲驰 fa4614ade6 添加ticket参数使用 11 months ago
  欧阳劲驰 30893cb284 修改序列化信息 11 months ago
  欧阳劲驰 3c501ecb49 实现根据门户token生成临时token 11 months ago
  欧阳劲驰 d9f9543970 修改数据库配置 11 months ago
  欧阳劲驰 3930584220 修改数据库配置 11 months ago
  欧阳劲驰 297db4ae6f 枣阳iot平台增加设备 11 months ago
  欧阳劲驰 aec59f2ab2 修改中环采集频率 11 months ago
  欧阳劲驰 e6b4fbb9fc 中环增加压力计 11 months ago
  欧阳劲驰 4aecd38240 更新数据库 11 months ago
  欧阳劲驰 cb71447db3 更新数据库 11 months ago
  欧阳劲驰 b8528df1af 中环采集改为按设备采集,规避批量查询报错的问题 #暂时处理 11 months ago
  欧阳劲驰 965764bee2 中环采集改为按设备采集,规避批量查询报错的问题 #暂时处理 11 months ago
  欧阳劲驰 230084e571 修改厂家名称 11 months ago
  欧阳劲驰 e5c3b7c5d9 枣阳增加设备时添加厂家信息 11 months ago
  欧阳劲驰 30e33921cd 枣阳设备新增设备增加厂家 11 months ago
  欧阳劲驰 4521003a6f 枣阳设备新增 11 months ago
  欧阳劲驰 e090415245 枣阳设备新增 11 months ago
  欧阳劲驰 c0ff9a1e17 枣阳设备新增 11 months ago
  欧阳劲驰 5fbc003683 修改日期格式化 11 months ago
  欧阳劲驰 0a8a23406c 修改注释 11 months ago
  欧阳劲驰 d42fe8cd02 修改配置文件 11 months ago
  欧阳劲驰 83757288bc 导出设备增加采集标签字段 11 months ago
  欧阳劲驰 192567c574 导出设备增加采集标签字段 11 months ago
  欧阳劲驰 59d1afeb52 录入中环sacada设备 11 months ago
  欧阳劲驰 a4348619b6 实现设备和采集标签过滤 11 months ago
  欧阳劲驰 9286ccdd6a 实现采集标签同步 11 months ago
  欧阳劲驰 06491ad020 增加设备标签表 11 months ago
  欧阳劲驰 1bc5303b0e dma增加po 11 months ago
  欧阳劲驰 8a934c2a9a 嵌入式数据库增加service层 11 months ago
  欧阳劲驰 2fa534cf8b 修改注入 11 months ago
  欧阳劲驰 2564f80964 增加请求失败处理 11 months ago
  欧阳劲驰 ab1bedcb9f 实现中环Scada采集 11 months ago
  欧阳劲驰 b7a2df8f17 修改日志 11 months ago
  欧阳劲驰 9d6affdd9b 删除无用的schema 11 months ago
  欧阳劲驰 92d5fd0da9 删除静态引入 1 year ago
  欧阳劲驰 7248060bde 增加模块切换配置 1 year ago
  欧阳劲驰 cc14b097dc 增加模块切换配置 1 year ago
  欧阳劲驰 91700f739d 重命名模块 1 year ago
  欧阳劲驰 c6903a637f 优化配置文件 1 year ago
  欧阳劲驰 86cbf1db22 增加压力流量计类型 1 year ago
  欧阳劲驰 5b93a36234 中环项目初始化 1 year ago
  欧阳劲驰 14dd2ab136 更新data文件 1 year ago
  欧阳劲驰 98727fa77d 设备id生成增加区号和种类 1 year ago
  欧阳劲驰 4eaef18ecc 优化注入 1 year ago
  欧阳劲驰 af4c1406fa 实现访问密钥生成 1 year ago
  欧阳劲驰 947fd5b9bc 更新数据库文件 1 year ago
  欧阳劲驰 8a92110083 修改gbase内容,删除json依赖 1 year ago
  欧阳劲驰 46621db1f1 修改mapper.xml文件加载 1 year ago
  欧阳劲驰 e52b981b4d 修改数据库配置文件 1 year ago
  欧阳劲驰 6b33fd8761 修改数据库配置文件名称 1 year ago
  欧阳劲驰 c5b86073d6 增加db文件 1 year ago
  欧阳劲驰 afd7a7b949 支持多数据源,设备标识序列使用嵌入式数据库 1 year ago
  欧阳劲驰 b1d14386c7 todo 增加用户角色信息 1 year ago
  欧阳劲驰 cb1f099ad3 简化物联网数据对象转换 1 year ago
  欧阳劲驰 34718f8d08 优化批量写入 1 year ago
  欧阳劲驰 47a91e5e04 修改采集频率,优化influxdb写入 1 year ago
  欧阳劲驰 e87a568826 增加设备厂家,增加瞬时压力字段 1 year ago
  欧阳劲驰 2a7d3c88c6 重命名 1 year ago
  欧阳劲驰 b8759a5cd0 实现物联网平台采集 1 year ago
  欧阳劲驰 783b10ec40 修改签名生成方法 1 year ago
100 changed files with 4508 additions and 178 deletions
  1. 10 8
      custom-gateway-app/pom.xml
  2. 3 3
      custom-gateway-app/src/main/java/com/shkpr/service/customgateway/CustomGatewayApplication.java
  3. 0 0
      bespoke-gateway-app/src/main/resources/alam_server.pfx
  4. 29 0
      bespoke-gateway-app/src/main/resources/application-jldma.yml
  5. 39 0
      bespoke-gateway-app/src/main/resources/application-zhscada.yml
  6. 42 0
      bespoke-gateway-app/src/main/resources/application-zydma.yml
  7. 88 0
      bespoke-gateway-app/src/main/resources/application.yml
  8. 0 0
      bespoke-gateway-app/src/main/resources/logback.xml
  9. 33 0
      bespoke-gateway-app/src/main/resources/zhscada-backup/application-zhscada.yml
  10. 94 0
      bespoke-gateway-app/src/main/resources/zhscada-backup/application.yml
  11. 17 0
      bespoke-gateway-app/src/test/java/com/shkpr/service/bespokegateway/BespokeGatewayApplicationTests.java
  12. 83 28
      custom-gateway-core/pom.xml
  13. 9 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/annotation/ExcelMapping.java
  14. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/annotation/InfluxDbMapping.java
  15. 89 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/AccessKeyGenerator.java
  16. 109 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/DeviceIdGenerator.java
  17. 434 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/DeviceRegistry.java
  18. 83 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/InfluxDBClients.java
  19. 3 3
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/AsyncConfig.java
  20. 2 2
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/CallingConfig.java
  21. 82 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/DataSourceConfig.java
  22. 45 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/DeviceConfig.java
  23. 2 2
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/GatewayConfig.java
  24. 2 2
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/GlobalConfig.java
  25. 52 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/InfluxDbConfig.java
  26. 44 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/JdbcRepositoriesConfig.java
  27. 70 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/PrimaryMybatisConfig.java
  28. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/SchedulingConfig.java
  29. 49 28
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/SecurityConfig.java
  30. 2 2
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/TempFileConfig.java
  31. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/ValidatorConfig.java
  32. 3 3
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/WebConfig.java
  33. 67 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/AccessMetadata.java
  34. 33 27
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/Api.java
  35. 21 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/AreaCode.java
  36. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/CommDefine.java
  37. 45 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerBillingType.java
  38. 26 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerInfoStatus.java
  39. 44 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerMeterType.java
  40. 45 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerMeteringType.java
  41. 45 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerPublicServiceType.java
  42. 67 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerReadType.java
  43. 14 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DataSourceNames.java
  44. 54 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DeviceField.java
  45. 44 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DeviceKind.java
  46. 20 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelEnum.java
  47. 14 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelMetadata.java
  48. 22 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelType.java
  49. 15 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/InfluxdbMetadata.java
  50. 11 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/IntegrationMetadata.java
  51. 3 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/LogFlagBusiType.java
  52. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/LoginUserRoleType.java
  53. 23 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ProtocolType.java
  54. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/ResponseCode.java
  55. 7 2
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/TokenMetadata.java
  56. 41 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ValueType.java
  57. 25 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/controller/RouteController.java
  58. 106 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/AccessResult.java
  59. 72 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/AccessToken.java
  60. 25 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/CallingEndpoint.java
  61. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/CommonToken.java
  62. 80 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/Device.java
  63. 50 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/DeviceExcel.java
  64. 61 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/DeviceTag.java
  65. 28 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/InfluxDbClient.java
  66. 33 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/IntegrationKey.java
  67. 24 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/IntegrationKeyLoader.java
  68. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/LatLngBean.java
  69. 36 29
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/PageRequest.java
  70. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/PageResponse.java
  71. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/Result.java
  72. 84 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/ResultResponse.java
  73. 103 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/TmpTokenData.java
  74. 5 5
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/TokenData.java
  75. 41 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/AccessKeys.java
  76. 168 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/CustomerInfo.java
  77. 89 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/CustomerMeterRead.java
  78. 95 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceKind.java
  79. 47 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceSequences.java
  80. 33 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceTags.java
  81. 54 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/FunctionInfo.java
  82. 10 2
      custom-gateway-zydma/src/main/java/com/shkpr/service/customgateway/zydma/domain/PersonnelInfo.java
  83. 67 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/TypeDefine.java
  84. 172 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/exception/GlobalSelfExceptionHandler.java
  85. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/exception/SelfAuthFilterException.java
  86. 25 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/exception/SelfException.java
  87. 106 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/filter/AccessFilter.java
  88. 7 7
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/filter/JWTControllerCheck.java
  89. 15 10
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/filter/TokenFilter.java
  90. 109 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomMultiLineStringTypeHandlePg.java
  91. 120 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomPointTypeHandlePg.java
  92. 108 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomTypeHandlePg.java
  93. 107 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/StringListTypeHandle.java
  94. 1 1
      custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/io/YamlPropertySourceFactory.java
  95. 125 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/manager/IntegrationKeyManager.java
  96. 21 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/CustomerInfoMapper.java
  97. 21 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/CustomerMeterReadMapper.java
  98. 24 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/DeviceKindMapper.java
  99. 21 0
      bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/FunctionInfoMapper.java
  100. 0 0
      custom-gateway-zydma/src/main/java/com/shkpr/service/customgateway/zydma/mapper/PersonnelInfoMapper.java

+ 10 - 8
custom-gateway-app/pom.xml

@@ -4,27 +4,27 @@
     <!--父工程信息-->
     <parent>
         <groupId>com.shkpr.service</groupId>
-        <artifactId>kpr-custom-gateway</artifactId>
-        <version>1.0.0-dev</version>
+        <artifactId>kpr-bespoke-gateway</artifactId>
+        <version>1.0.0</version>
     </parent>
 
     <!--工件名-->
-    <artifactId>custom-gateway-app</artifactId>
+    <artifactId>bespoke-gateway-app</artifactId>
     <!--版本号-->
     <version>${project.version}</version>
     <!--打包方式-->
     <packaging>jar</packaging>
     <!--项目名-->
-    <name>CustomGatewayApp</name>
+    <name>BespokeGatewayApp</name>
     <!--项目描述-->
     <description>启动模块</description>
 
     <!--依赖项-->
     <dependencies>
-        <!--枣阳漏控-->
+        <!--启用模块-->
         <dependency>
             <groupId>com.shkpr.service</groupId>
-            <artifactId>custom-gateway-zydma</artifactId>
+            <artifactId>bespoke-gateway-${enable.module}</artifactId>
             <version>${project.version}</version>
         </dependency>
     </dependencies>
@@ -75,7 +75,9 @@
                 <configuration>
                     <skipTests>true</skipTests>
                     <systemPropertyVariables>
-                        <global.sql-config-path>../db.yml</global.sql-config-path>
+                        <device.map-path>../dev_${enable.module}.yml</device.map-path>
+                        <spring.datasource.multi.embedded.url>jdbc:h2:file:../data
+                        </spring.datasource.multi.embedded.url>
                     </systemPropertyVariables>
                 </configuration>
             </plugin>
@@ -87,7 +89,7 @@
                 <configuration>
                     <fork>true</fork>
                     <executable>true</executable>
-                    <mainClass>com.shkpr.service.customgateway.CustomGatewayApplication</mainClass>
+                    <mainClass>com.shkpr.service.bespokegateway.BespokeGatewayApplication</mainClass>
                 </configuration>
                 <executions>
                     <execution>

+ 3 - 3
custom-gateway-app/src/main/java/com/shkpr/service/customgateway/CustomGatewayApplication.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway;
+package com.shkpr.service.bespokegateway;
 
 import org.springframework.boot.SpringApplication;
 import org.springframework.boot.autoconfigure.SpringBootApplication;
@@ -10,8 +10,8 @@ import org.springframework.boot.autoconfigure.SpringBootApplication;
  * @since 1.0.0
  */
 @SpringBootApplication
-public class CustomGatewayApplication {
+public class BespokeGatewayApplication {
     public static void main(String[] args) {
-        SpringApplication.run(CustomGatewayApplication.class, args);
+        SpringApplication.run(BespokeGatewayApplication.class, args);
     }
 }

custom-gateway-app/src/main/resources/alam_server.pfx → bespoke-gateway-app/src/main/resources/alam_server.pfx


+ 29 - 0
bespoke-gateway-app/src/main/resources/application-jldma.yml

@@ -0,0 +1,29 @@
+#spring
+spring:
+  #数据源
+  datasource:
+    #多数据源
+    multi:
+      #主要
+      primary:
+        url: jdbc:postgresql://119.36.149.8:5433/watersmart?useSSL=false&useAffectedRows=false&allowMultiQueries=true&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
+        username: postgres
+        password: kpr.23417.postgres
+        driver-class-name: org.postgresql.Driver
+  #influx
+  influx:
+    read-timeout: 30000
+    clients:
+      #监利
+      - url: http://192.168.10.103:8061/
+        user: kpr
+        password: kpr.2025@117.influxdb
+        database: iot
+#对接
+calling:
+  #对接点
+  endpoints:
+    jianli-iot:
+      url: https://iot.cscec3b-iti.com
+      access-key: sKUJoJbisVJg7ei8NSKtPQ
+      secret-key: HtSU0Ul2NdJqLhK9uTa5BLetgzst0N4j9sIJ7dys

+ 39 - 0
bespoke-gateway-app/src/main/resources/application-zhscada.yml

@@ -0,0 +1,39 @@
+#spring
+spring:
+  #数据源
+  datasource:
+    #多数据源
+    multi:
+      #主要
+      primary:
+        url: jdbc:postgresql://140.246.183.164:5432/water_smart_develop_branch?useSSL=false&useAffectedRows=false&allowMultiQueries=true&useUnicode=true&characterEncoding=utf-8
+        username: postgres
+        password: kpr.23417.postgres
+        driver-class-name: org.postgresql.Driver
+      #scada
+      scada:
+        url: jdbc:oracle:thin:@//140.246.183.164:1521/FREEPDB1
+        username: zh_scada
+        password: kpr.65231.zh_scada
+        driver-class-name: oracle.jdbc.OracleDriver
+  #influx
+  influx:
+    read-timeout: 30000
+    clients:
+      #中环
+      - url: http://111.170.129.117:8086/
+        user: kpr
+        password: kpr.2025@117.influxdb
+        database: iot
+#对接
+calling:
+  #对接点
+  endpoints:
+    zhonghuan-scada:
+      url: http://119.96.174.191:9434
+#迁移
+migrate:
+  #模式
+  schema: zh_scada
+  #传感器映射文件
+  sensor-map-path: classpath*:sensor-id.yml

+ 42 - 0
bespoke-gateway-app/src/main/resources/application-zydma.yml

@@ -0,0 +1,42 @@
+#spring
+spring:
+  #数据源
+  datasource:
+    #多数据源
+    multi:
+      #主要
+      primary:
+        url: jdbc:postgresql://223.75.194.87:6057/watersmart?useSSL=false&useAffectedRows=false&allowMultiQueries=true&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
+        username: postgres
+        password: kpr.23417.postgres
+        driver-class-name: org.postgresql.Driver
+  #influx
+  influx:
+    read-timeout: 30000
+    clients:
+      #枣阳
+      - url: http://192.168.44.58:8086/
+        user: kpr
+        password: kpr.2025@117.influxdb
+        database: iot
+      #测试
+      - url: http://119.96.165.176:8086/
+        user: kpr
+        password: kpr.2024@117.influxdb
+        database: iot
+#对接
+calling:
+  #对接点
+  endpoints:
+    zaoyang-middle:
+      url: http://223.75.194.87:8200
+      access-key: lousunkongzhi
+      secret-key: g+4UWJ6360SxDVu+9BRRQfOg0/tT+33o3S8Q5APMLIn+JQirprtdGd0cf5Y3WO7iiKo24T5mN1U697zHp/iGNA==
+    zaoyang-iot:
+      url: http://223.75.194.87:8200/pdserver
+      access-key: Data
+      secret-key: panda666.
+#认证
+security:
+  permit-pattern:
+    - ${gateway.routes.zydma}/users/ticket-exchange

+ 88 - 0
bespoke-gateway-app/src/main/resources/application.yml

@@ -0,0 +1,88 @@
+#web
+server:
+  port: 9011
+  servlet:
+    context-path: /bespoke-gw/
+#网关
+gateway:
+  routes:
+    zydma: /zy-dma
+#spring
+spring:
+  #app
+  application:
+    name: KprBespokeGateway
+  #servlet
+  servlet:
+    multipart:
+      max-file-size: 200MB
+      max-request-size: 200MB
+  #启用配置
+  profiles:
+    active: @enable.module@
+  #thymeleaf
+  thymeleaf:
+    prefix: classpath*:/templates/
+  #任务
+  task:
+    #任务线程池
+    execution:
+      thread-name-prefix: task-
+      pool:
+        core-size: 8
+        max-size: 0x7fffffff
+        queue-capacity: 0x7fffffff
+        keep-alive: PT30S
+        allow-core-thread-timeout: true
+    #定时线程池
+    scheduling:
+      thread-name-prefix: scheduling-
+      pool:
+        size: 2
+  #数据源
+  datasource:
+    #连接池
+    hikari:
+      maximum-pool-size: 200
+      minimum-idle: 1
+      connection-test-query: SELECT 1
+      max-lifetime: 120000
+      idle-timeout: 30000
+      connection-timeout: 30000
+      validation-timeout: 30000
+      initialization-fail-timeout: -1
+    #多数据源
+    multi:
+      #嵌入式
+      embedded:
+        url: jdbc:h2:file:./data
+        driver-class-name: org.h2.Driver
+        username: sa
+        password: kpr.25535.sa
+#mybatis
+mybatis:
+  configuration:
+    call-setters-on-nulls: true
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+#security
+security:
+  expiration: P7D
+  secret: TRICP_ALAM_DMA
+#对接
+calling:
+  connect-timeout: PT30S
+  read-timeout: PT30S
+#异步
+async:
+  result-path-pattern: /common/async-results
+  result-resource-location: ./async-results/
+#临时文件
+temp-file:
+  path-pattern: /common/temp-files
+  resource-location: ./temp-files/
+  cleanup-interval: PT1M
+  max-age: PT4H
+#设备
+device:
+  map-path: ./dev_@enable.module@.yml

custom-gateway-app/src/main/resources/logback.xml → bespoke-gateway-app/src/main/resources/logback.xml


+ 33 - 0
bespoke-gateway-app/src/main/resources/zhscada-backup/application-zhscada.yml

@@ -0,0 +1,33 @@
+#spring
+spring:
+  #数据源
+  datasource:
+    #多数据源
+    multi:
+      #scada
+      scada:
+        url: jdbc:oracle:thin:@//119.96.190.182:1521/orcl
+        username: scada
+        password: scada
+        driver-class-name: oracle.jdbc.OracleDriver
+  #influx
+  influx:
+    read-timeout: 30000
+    clients:
+      #中环
+      - url: http://111.170.129.117:8086/
+        user: kpr
+        password: kpr.2025@117.influxdb
+        database: iot
+#对接
+calling:
+  #对接点
+  endpoints:
+    zhonghuan-scada:
+      url: http://119.96.174.191:9434
+#迁移
+migrate:
+  #模式
+  schema: scada
+  #传感器映射文件
+  sensor-map-path: file:E:\kpr\kpr-bespoke-gateway\sensor-id.yml

+ 94 - 0
bespoke-gateway-app/src/main/resources/zhscada-backup/application.yml

@@ -0,0 +1,94 @@
+#web
+server:
+  port: 9011
+  servlet:
+    context-path: /bespoke-gw/
+#网关
+gateway:
+  routes:
+    zydma: /zy-dma
+#spring
+spring:
+  #app
+  application:
+    name: KprBespokeGateway
+  #servlet
+  servlet:
+    multipart:
+      max-file-size: 200MB
+      max-request-size: 200MB
+  #启用配置
+  profiles:
+    active: @enable.module@
+  #thymeleaf
+  thymeleaf:
+    prefix: classpath*:/templates/
+  #任务
+  task:
+    #任务线程池
+    execution:
+      thread-name-prefix: task-
+      pool:
+        core-size: 8
+        max-size: 0x7fffffff
+        queue-capacity: 0x7fffffff
+        keep-alive: PT30S
+        allow-core-thread-timeout: true
+    #定时线程池
+    scheduling:
+      thread-name-prefix: scheduling-
+      pool:
+        size: 2
+  #数据源
+  datasource:
+    #连接池
+    hikari:
+      maximum-pool-size: 200
+      minimum-idle: 1
+      connection-test-query: SELECT 1
+      max-lifetime: 120000
+      idle-timeout: 30000
+      connection-timeout: 30000
+      validation-timeout: 30000
+      initialization-fail-timeout: -1
+    #多数据源
+    multi:
+      #主要
+      primary:
+        url: jdbc:postgresql://223.75.194.87:6057/watersmart?useSSL=false&useAffectedRows=false&allowMultiQueries=true&rewriteBatchedStatements=true&serverTimezone=Asia/Shanghai
+        username: postgres
+        password: kpr.23417.postgres
+        driver-class-name: org.postgresql.Driver
+      #嵌入式
+      embedded:
+        url: jdbc:h2:file:E:\kpr\kpr-bespoke-gateway\data
+        driver-class-name: org.h2.Driver
+        username: sa
+        password: kpr.25535.sa
+#mybatis
+mybatis:
+  configuration:
+    call-setters-on-nulls: true
+    map-underscore-to-camel-case: true
+    cache-enabled: false
+#security
+security:
+  expiration: P7D
+  secret: TRICP_ALAM_DMA
+#对接
+calling:
+  connect-timeout: PT30S
+  read-timeout: PT30S
+#异步
+async:
+  result-path-pattern: /common/async-results
+  result-resource-location: ./async-results/
+#临时文件
+temp-file:
+  path-pattern: /common/temp-files
+  resource-location: ./temp-files/
+  cleanup-interval: PT1M
+  max-age: PT4H
+#设备
+device:
+  map-path: E:\kpr\kpr-bespoke-gateway\dev_@enable.module@.yml

+ 17 - 0
bespoke-gateway-app/src/test/java/com/shkpr/service/bespokegateway/BespokeGatewayApplicationTests.java

@@ -0,0 +1,17 @@
+package com.shkpr.service.bespokegateway;
+
+import org.junit.jupiter.api.Test;
+import org.springframework.boot.test.context.SpringBootTest;
+
+/**
+ * 测试启动类
+ */
+@SpringBootTest(classes = BespokeGatewayApplication.class)
+public class BespokeGatewayApplicationTests {
+
+    @Test
+    public void test() {
+
+    }
+
+}

+ 83 - 28
custom-gateway-core/pom.xml

@@ -4,40 +4,37 @@
     <!--父工程信息-->
     <parent>
         <groupId>com.shkpr.service</groupId>
-        <artifactId>kpr-custom-gateway</artifactId>
-        <version>1.0.0-dev</version>
+        <artifactId>kpr-bespoke-gateway</artifactId>
+        <version>1.0.0</version>
     </parent>
 
     <!--工件名-->
-    <artifactId>custom-gateway-core</artifactId>
+    <artifactId>bespoke-gateway-core</artifactId>
     <!--版本号-->
     <version>${project.version}</version>
     <!--打包方式-->
     <packaging>jar</packaging>
     <!--项目名-->
-    <name>CustomGatewayCore</name>
+    <name>BespokeGatewayCore</name>
     <!--项目描述-->
     <description>核心模块</description>
 
     <!--依赖项-->
     <dependencies>
-        <!--base-->
-        <dependency>
-            <groupId>com.global</groupId>
-            <artifactId>gbase</artifactId>
-            <version>${gbase.version}</version>
-            <scope>system</scope>
-            <systemPath>${project.basedir}/../libs/gbase.${gbase.version}.jar</systemPath>
-        </dependency>
         <!--spring-security-->
         <dependency>
             <groupId>org.springframework.boot</groupId>
             <artifactId>spring-boot-starter-security</artifactId>
         </dependency>
-        <!--spring-data-kv-->
+        <!--spring-validation-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-validation</artifactId>
+        </dependency>
+        <!--spring-data-->
         <dependency>
             <groupId>org.springframework.data</groupId>
-            <artifactId>spring-data-keyvalue</artifactId>
+            <artifactId>spring-data-jdbc</artifactId>
         </dependency>
         <!--mybatis-->
         <dependency>
@@ -50,16 +47,57 @@
             <groupId>org.postgresql</groupId>
             <artifactId>postgresql</artifactId>
         </dependency>
+        <!--oracle-->
+        <dependency>
+            <groupId>com.oracle.database.jdbc</groupId>
+            <artifactId>ojdbc8</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.oracle.database.nls</groupId>
+            <artifactId>orai18n</artifactId>
+        </dependency>
+        <!--influxdb-->
+        <dependency>
+            <groupId>org.influxdb</groupId>
+            <artifactId>influxdb-java</artifactId>
+        </dependency>
+        <!--h2-->
+        <dependency>
+            <groupId>com.h2database</groupId>
+            <artifactId>h2</artifactId>
+        </dependency>
+        <!--jts-->
+        <dependency>
+            <groupId>org.locationtech.jts</groupId>
+            <artifactId>jts-core</artifactId>
+            <version>${jts.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.locationtech.jts.io</groupId>
+            <artifactId>jts-io-common</artifactId>
+            <version>${jts.version}</version>
+        </dependency>
+        <!--geotools-->
+        <dependency>
+            <groupId>org.geotools</groupId>
+            <artifactId>gt-shapefile</artifactId>
+            <version>${geotools.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.geotools</groupId>
+            <artifactId>gt-epsg-hsql</artifactId>
+            <version>${geotools.version}</version>
+        </dependency>
         <!--jjwt-->
         <dependency>
             <groupId>io.jsonwebtoken</groupId>
             <artifactId>jjwt</artifactId>
             <version>${jjwt.version}</version>
         </dependency>
-        <!--influxdb-->
+        <!--json-yml-->
         <dependency>
-            <groupId>org.influxdb</groupId>
-            <artifactId>influxdb-java</artifactId>
+            <groupId>com.fasterxml.jackson.dataformat</groupId>
+            <artifactId>jackson-dataformat-yaml</artifactId>
         </dependency>
         <!--okhttp-->
         <dependency>
@@ -67,23 +105,40 @@
             <artifactId>okhttp</artifactId>
             <version>${okhttp.version}</version>
         </dependency>
+        <!--httpclient-->
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>httpclient</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.httpcomponents</groupId>
+            <artifactId>fluent-hc</artifactId>
+        </dependency>
+        <!--poi-->
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.poi</groupId>
+            <artifactId>poi-ooxml</artifactId>
+            <version>${poi.version}</version>
+        </dependency>
+        <!--base-->
+        <dependency>
+            <groupId>com.global</groupId>
+            <artifactId>gbase</artifactId>
+            <version>${gbase.version}</version>
+            <scope>system</scope>
+            <systemPath>${project.basedir}/../libs/gbase.${gbase.version}.jar</systemPath>
+        </dependency>
     </dependencies>
 
     <!--构建脚本-->
     <build>
         <!--插件项-->
         <plugins>
-            <!--maven-jar-->
-            <plugin>
-                <groupId>org.apache.maven.plugins</groupId>
-                <artifactId>maven-jar-plugin</artifactId>
-                <executions>
-                    <execution>
-                        <id>default-jar</id>
-                        <phase>none</phase>
-                    </execution>
-                </executions>
-            </plugin>
             <!--maven-install-->
             <plugin>
                 <groupId>org.apache.maven.plugins</groupId>

+ 9 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/annotation/ExcelMapping.java

@@ -1,4 +1,6 @@
-package com.shkpr.service.customgateway.core.annotation;
+package com.shkpr.service.bespokegateway.core.annotation;
+
+import com.shkpr.service.bespokegateway.core.constants.ExcelEnum;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;
@@ -18,4 +20,10 @@ public @interface ExcelMapping {
      * @return excel表头
      */
     String value();
+
+    /**
+     * excel枚举类
+     * <p>如设置枚举类,则尝试从枚举中匹配值</p>
+     */
+    Class<? extends ExcelEnum> enumClass() default ExcelEnum.class;
 }

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/annotation/InfluxDbMapping.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.annotation;
+package com.shkpr.service.bespokegateway.core.annotation;
 
 import java.lang.annotation.ElementType;
 import java.lang.annotation.Retention;

+ 89 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/AccessKeyGenerator.java

@@ -0,0 +1,89 @@
+package com.shkpr.service.bespokegateway.core.components;
+
+import com.shkpr.service.bespokegateway.core.domain.po.AccessKeys;
+import com.shkpr.service.bespokegateway.core.service.AccessKeysService;
+import com.shkpr.service.bespokegateway.core.utils.HexUtil;
+import org.springframework.security.crypto.keygen.BytesKeyGenerator;
+import org.springframework.security.crypto.keygen.KeyGenerators;
+
+/**
+ * 访问密钥生成器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class AccessKeyGenerator {
+    /**
+     * 访问密钥生成器
+     */
+    private final static BytesKeyGenerator accessKeyGenerator = KeyGenerators.secureRandom(10);
+    /**
+     * 认证密钥生成器
+     */
+    private final static BytesKeyGenerator securityKeyGenerator = KeyGenerators.secureRandom(20);
+    /**
+     * 存服务
+     */
+    private final AccessKeysService service;
+
+    public AccessKeyGenerator(Builder builder) {
+        this.service = builder.service;
+    }
+
+    /**
+     * @return 构建
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * 生成密钥
+     *
+     * @return 集成密钥
+     */
+    public AccessKeys generateKey(String description) {
+        //生成密钥
+        byte[] access = accessKeyGenerator.generateKey();
+        byte[] security = securityKeyGenerator.generateKey();
+        //转换字符串
+        String accessKey = HexUtil.encode(access).toUpperCase();
+        String securityKey = HexUtil.encode(security).toUpperCase();
+        //构建并保存
+        AccessKeys accessKeys = AccessKeys.of(accessKey, securityKey, description);
+        service.save(accessKeys);
+
+        return accessKeys;
+    }
+
+    /**
+     * 构建器
+     */
+    public static class Builder {
+        /**
+         * 存服务
+         */
+        private AccessKeysService service;
+
+        public Builder() {
+        }
+
+        /**
+         * 配置存服务
+         */
+        public Builder service(AccessKeysService service) {
+            this.service = service;
+            return this;
+        }
+
+        /**
+         * 构建
+         */
+        public AccessKeyGenerator build() {
+            // 参数验证
+            if (service == null) throw new IllegalStateException("存储服务不能为空");
+
+            return new AccessKeyGenerator(this);
+        }
+    }
+}

+ 109 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/DeviceIdGenerator.java

@@ -0,0 +1,109 @@
+package com.shkpr.service.bespokegateway.core.components;
+
+import com.shkpr.service.bespokegateway.core.constants.AreaCode;
+import com.shkpr.service.bespokegateway.core.constants.DeviceKind;
+import com.shkpr.service.bespokegateway.core.domain.Device;
+import com.shkpr.service.bespokegateway.core.domain.DeviceTag;
+import com.shkpr.service.bespokegateway.core.service.DeviceSequencesService;
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+/**
+ * 设备id生成器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class DeviceIdGenerator {
+    /**
+     * 日期格式
+     */
+    private static final DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyMMdd");
+    /**
+     * 存储服务
+     */
+    private final DeviceSequencesService service;
+
+    public DeviceIdGenerator(Builder builder) {
+        this.service = builder.service;
+    }
+
+    /**
+     * @return 构建
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * 生成设备
+     *
+     * @param areaCode 区号
+     * @param kind     种类
+     * @param platform 所属平台
+     * @param sn       远传设备id
+     * @param name     设备名称
+     * @return 设备
+     */
+    public synchronized Device generateDevice(AreaCode areaCode, DeviceKind kind, String platform, List<DeviceTag> fields
+            , String sn, String name) {
+        if (areaCode == null || kind == null || StringUtils.isAnyBlank(sn, name)) return null;
+
+        //构建设备
+        return new Device(generateDeviceId(areaCode, kind), name, sn, kind.getKey(), platform, null, LocalDateTime.now(), fields);
+    }
+
+    /**
+     * 生成设备id
+     *
+     * @param areaCode 区号
+     * @param kind     设备种类
+     * @return 设备id
+     */
+    public synchronized String generateDeviceId(AreaCode areaCode, DeviceKind kind) {
+        //当前日期
+        LocalDate now = LocalDate.now();
+        //下一个序列
+        int sequence = service.getNextSequence(areaCode, kind, now);
+        //组装id
+        return String.format("%03d%02d%s%04d", areaCode.getCode(), kind.getCode(), now.format(formatter), sequence);
+    }
+
+
+    /**
+     * 构建器
+     */
+    public static class Builder {
+        /**
+         * 存储服务
+         */
+        private DeviceSequencesService service;
+
+
+        public Builder() {
+        }
+
+        /**
+         * 配置存储服务
+         */
+        public Builder service(DeviceSequencesService service) {
+            this.service = service;
+            return this;
+        }
+
+
+        /**
+         * 构建
+         */
+        public DeviceIdGenerator build() {
+            // 参数验证
+            if (service == null) throw new IllegalStateException("存储服务不能为空");
+
+            return new DeviceIdGenerator(this);
+        }
+    }
+}

+ 434 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/DeviceRegistry.java

@@ -0,0 +1,434 @@
+package com.shkpr.service.bespokegateway.core.components;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.bespokegateway.core.constants.DeviceField;
+import com.shkpr.service.bespokegateway.core.constants.DeviceKind;
+import com.shkpr.service.bespokegateway.core.constants.ExcelType;
+import com.shkpr.service.bespokegateway.core.constants.LogFlagBusiType;
+import com.shkpr.service.bespokegateway.core.domain.Device;
+import com.shkpr.service.bespokegateway.core.domain.DeviceExcel;
+import com.shkpr.service.bespokegateway.core.domain.DeviceTag;
+import com.shkpr.service.bespokegateway.core.service.DeviceTagsService;
+import com.shkpr.service.bespokegateway.core.utils.ExcelUtil;
+import org.apache.commons.collections4.CollectionUtils;
+import org.apache.commons.lang3.ObjectUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * 设备管理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class DeviceRegistry {
+    /**
+     * log
+     */
+    private static final String CLASS_NAME = "DeviceRegistry";
+    private static final String BIZ_TYPE = LogFlagBusiType.BUSI_ALL.toStrValue();
+
+    /**
+     * yml对象映射
+     */
+    private final ObjectMapper yamlMapper;
+    /**
+     * 配置文件
+     */
+    private final File configFile;
+    /**
+     * 标签服务
+     */
+    private final DeviceTagsService tagsService;
+    /**
+     * 设备列表
+     */
+    private List<Device> devices;
+
+    public DeviceRegistry(Builder builder) {
+        this.yamlMapper = builder.yamlMapper;
+        this.configFile = builder.configFile;
+        this.tagsService = builder.tagsService;
+        this.devices = new ArrayList<>();
+        if (builder.autoLoad) this.loadDevices();
+    }
+
+    /**
+     * @return 构建
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+
+    /**
+     * 注册设备
+     *
+     * @param device 设备
+     */
+    public boolean registerDevice(Device device) {
+        if (!ObjectUtils.allNotNull(device, device.getDeviceId(), device.getDeviceSn())) return false;
+
+        // 检查设备是否已存在
+        if (containsDevice(device.getDeviceId())) {
+            return updateDevice(device);
+        }
+
+        //添加设备并同步
+        devices.add(device);
+        syncDevices();
+
+
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                String.format("设备注册成功: %s", device.getDeviceId()));
+        return true;
+    }
+
+    /**
+     * 注销设备
+     *
+     * @param deviceId 设备id
+     */
+    public boolean unregisterDevice(String deviceId) {
+        if (StringUtils.isBlank(deviceId)) return false;
+
+        //删除设备
+        boolean removed = devices.removeIf(device -> Objects.equals(device.getDeviceId(), deviceId));
+        if (removed) {
+            syncDevices();
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                    String.format("设备注销成功: %s", deviceId));
+        }
+
+        return removed;
+    }
+
+    /**
+     * 更新设备
+     *
+     * @param updatedDevice 设备
+     */
+    public boolean updateDevice(Device updatedDevice) {
+        if (!ObjectUtils.allNotNull(updatedDevice, updatedDevice.getDeviceId(), updatedDevice.getDeviceSn()))
+            return false;
+        //设备id
+        String deviceId = updatedDevice.getDeviceId();
+        //更新状态
+        boolean updated = false;
+
+        //查找并更新现有设备
+        for (int i = 0; i < devices.size(); i++) {
+            if (Objects.equals(devices.get(i).getDeviceId(), deviceId)) {
+                devices.set(i, updatedDevice);
+                updated = true;
+                break;
+            }
+        }
+
+        if (!updated) return false;
+
+        syncDevices();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                String.format("设备更新成功: %s", deviceId));
+        return true;
+    }
+
+    /**
+     * 查询全部
+     *
+     * @return 设备列表
+     */
+    public List<Device> findAll(String platform) {
+        //采集标签
+        List<String> tags = tagsService.findAll(platform);
+        //返回过滤的设备
+        return new ArrayList<>(devices).stream()
+                //过滤平台
+                .filter(device -> device != null && Objects.equals(device.getPlatform(), platform))
+                //过滤采集标签
+                .peek(device -> device.setTags(
+                        device.getTags().stream()
+                                .filter(tag -> tags.contains(tag.getTag()))
+                                .collect(Collectors.toList())))
+                .filter(device -> CollectionUtils.isNotEmpty(device.getTags()))
+                .collect(Collectors.toList());
+    }
+
+
+    /**
+     * 根据设备id查询
+     *
+     * @return 设备
+     */
+    public Device findById(String deviceId) {
+        return devices.stream()
+                .filter(device -> Objects.equals(device.getDeviceId(), deviceId))
+                .findFirst()
+                .orElse(null);
+    }
+
+
+    /**
+     * 获取设备数量
+     */
+    public int getDeviceCount() {
+        return devices.size();
+    }
+
+    /**
+     * 检查设备是否存在
+     */
+    public boolean containsDevice(String deviceId) {
+        return devices.stream().anyMatch(device -> Objects.equals(device.getDeviceId(), deviceId));
+    }
+
+    /**
+     * 查找需要新增的设备
+     *
+     * @param deviceSns 新设备远传id
+     * @return 需要新增的设备远传id
+     */
+    public Set<String> findAddedDevices(Set<String> deviceSns) {
+        //已存在的设备id
+        Set<String> existingDeviceSns = devices.stream()
+                .map(Device::getDeviceSn)
+                .collect(Collectors.toSet());
+
+        //过滤不存在的设备
+        return deviceSns.stream()
+                .filter(StringUtils::isNoneBlank)
+                .filter(sn -> !existingDeviceSns.contains(sn))
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * 查找需要更新的设备
+     *
+     * @param deviceInfo 设备
+     * @return 需要新增的设备远传id
+     */
+    public Set<Device> findUpdatedDevices(Map<String, Set<String>> deviceInfo) {
+        //已存在的设备,k:设备SN,v:标签字段集合
+        Map<String, Set<String>> existingDeviceInfo = this.devices.stream()
+                .collect(Collectors.toMap(
+                        Device::getDeviceSn,
+                        it -> it.getTags().stream()
+                                .map(DeviceTag::getField)
+                                .collect(Collectors.toSet())
+                ));
+
+        //过滤不同的设备
+        return deviceInfo.entrySet().stream()
+                //过滤不通标签
+                .filter(entry -> {
+                    //新标签
+                    Set<String> newTags = entry.getValue();
+                    //已存在的标签
+                    Set<String> existingTags = existingDeviceInfo.get(entry.getKey());
+                    if (existingTags == null) return true;
+
+                    //比较标签
+                    return !existingTags.equals(newTags);
+                })
+                //提取当前设备
+                .map(entry -> this.devices.stream()
+                        .filter(device -> device.getDeviceSn().equals(entry.getKey()))
+                        .findFirst()
+                )
+                .filter(Optional::isPresent)
+                .map(Optional::get)
+                .collect(Collectors.toSet());
+    }
+
+    /**
+     * 加载设备
+     */
+    public void loadDevices() {
+        try {
+            if (configFile.exists() && configFile.isFile()) {
+                //配置文件存在,读取并设置设备列表
+                devices = yamlMapper.readValue(configFile, yamlMapper.getTypeFactory()
+                        .constructCollectionType(List.class, Device.class));
+                LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME
+                        , String.format("加载设备列表成功,设备数量:%d", devices.size()));
+            } else {
+                //不存在,设置空列表,并同步
+                devices = new ArrayList<>();
+                syncDevices();
+                LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                        "配置文件不存在或为空,初始化空设备列表");
+            }
+        } catch (IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, BIZ_TYPE, CLASS_NAME
+                    , String.format("加载设备列表失败,error:%s", e));
+        }
+    }
+
+    /**
+     * 同步设备
+     */
+    private void syncDevices() {
+        try {
+            //确保父目录存在
+            File parentDir = configFile.getParentFile();
+            if (parentDir != null && !parentDir.exists()) {
+                boolean made = configFile.getParentFile().mkdirs();
+                if (made) LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME
+                        , String.format("创建设备列表配置文件成功:%s", configFile.getAbsoluteFile()));
+            }
+
+            //配置文件存在,写入设备列表
+            yamlMapper.writerWithDefaultPrettyPrinter().writeValue(configFile, devices);
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME
+                    , String.format("同步设备列表成功,设备数量:%d", devices.size()));
+        } catch (IOException e) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, BIZ_TYPE, CLASS_NAME
+                    , String.format("同步设备列表失败,error:%s", e));
+        }
+    }
+
+    /**
+     * 导出设备
+     *
+     * @param path 路径
+     */
+    public void exportDevice(Path path) {
+        //种类映射
+        Map<String, String> kindMap = Arrays.stream(DeviceKind.values())
+                .collect(Collectors.toMap(DeviceKind::getKey, DeviceKind::getName));
+        //字段映射
+        Map<String, String> fieldMap = Arrays.stream(DeviceField.values())
+                .collect(Collectors.toMap(DeviceField::getKey, DeviceField::getName));
+        List<DeviceExcel> excels = this.devices.stream().map(device -> {
+            //构建excel对象
+            DeviceExcel deviceExcel = new DeviceExcel();
+            deviceExcel.setDeviceId(device.getDeviceId());
+            deviceExcel.setDeviceName(device.getDeviceName());
+            deviceExcel.setDeviceSn(device.getDeviceSn());
+            deviceExcel.setDeviceKind(kindMap.get(device.getDeviceKind()));
+            deviceExcel.setMfrs(device.getMfrs());
+            //设置字段
+            deviceExcel.setField(
+                    device.getTags().stream()
+                            .map(it -> fieldMap.get(it.getField()))
+                            .collect(Collectors.joining("/"))
+            );
+            //设置标签
+            deviceExcel.setTags(
+                    device.getTags().stream()
+                            .map(DeviceTag::getTag)
+                            .collect(Collectors.joining("/"))
+            );
+            return deviceExcel;
+        }).collect(Collectors.toList());
+
+        try (OutputStream outputStream = Files.newOutputStream(path.toFile().toPath())) {
+
+            ExcelUtil.writeExcel(excels, DeviceExcel.class, outputStream, ExcelType.XLSX);
+
+        } catch (IOException e) {
+            throw new RuntimeException(e);
+        }
+    }
+
+    /**
+     * 构建器
+     */
+    public static class Builder {
+        /**
+         * 映射
+         */
+        private ObjectMapper yamlMapper;
+        /**
+         * 配置文件
+         */
+        private File configFile;
+        /**
+         * 标签服务
+         */
+        private DeviceTagsService tagsService;
+        /**
+         * 自动加载配置文件
+         */
+        private Boolean autoLoad = true;
+
+        public Builder() {
+            // 默认的mapper
+            YAMLFactory yamlFactory = new YAMLFactory();
+            this.yamlMapper = new ObjectMapper(yamlFactory);
+            this.yamlMapper.findAndRegisterModules();
+        }
+
+        /**
+         * object映射
+         */
+        public Builder yamlMapper(ObjectMapper yamlMapper) {
+            this.yamlMapper = yamlMapper;
+            return this;
+        }
+
+        /**
+         * 配置文件路径
+         */
+        public Builder configFile(String configPath) {
+            this.configFile = new File(configPath);
+            return this;
+        }
+
+        /**
+         * 配置文件对象
+         */
+        public Builder configFile(File configFile) {
+            this.configFile = configFile;
+            return this;
+        }
+
+        /**
+         * 标签服务
+         */
+        public Builder tagsService(DeviceTagsService tagsService) {
+            this.tagsService = tagsService;
+            return this;
+        }
+
+        /**
+         * 是否自动加载设备列表
+         */
+        public Builder autoLoad(boolean autoLoad) {
+            this.autoLoad = autoLoad;
+            return this;
+        }
+
+        /**
+         * 构建
+         */
+        public DeviceRegistry build() {
+            // 参数验证
+            if (yamlMapper == null) throw new IllegalStateException("YAML Mapper 不能为空");
+            if (configFile == null) throw new IllegalStateException("配置文件路径不能为空");
+            if (tagsService == null) throw new IllegalStateException("采集标签服务不能为空");
+            if (autoLoad == null) autoLoad = true;
+
+            //文件验证
+            if (configFile.exists()) {
+                if (!configFile.isFile())
+                    throw new IllegalStateException("配置文件路径不是文件: " + configFile.getAbsolutePath());
+                if (!configFile.canRead() || !configFile.canWrite())
+                    throw new IllegalStateException("配置文件无法读写: " + configFile.getAbsolutePath());
+            } else LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                    "配置文件不存在,将在初始化时创建");
+
+            return new DeviceRegistry(this);
+        }
+    }
+}

+ 83 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/components/InfluxDBClients.java

@@ -0,0 +1,83 @@
+package com.shkpr.service.bespokegateway.core.components;
+
+import com.shkpr.service.bespokegateway.core.domain.InfluxDbClient;
+import org.apache.commons.collections4.CollectionUtils;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * influxDb客户端管理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class InfluxDBClients {
+    /**
+     * 客户端集合
+     */
+    List<InfluxDbClient> clients;
+
+
+    public InfluxDBClients(Builder builder) {
+        this.clients = builder.clients;
+    }
+
+    /**
+     * @return 构建
+     */
+    public static Builder builder() {
+        return new Builder();
+    }
+
+    /**
+     * 查询客户端集合
+     *
+     * @return 客户端集合
+     */
+    public List<InfluxDbClient> clients() {
+        return new ArrayList<>(clients);
+    }
+
+
+    /**
+     * 构建器
+     */
+    public static class Builder {
+        /**
+         * 客户端
+         */
+        private final List<InfluxDbClient> clients;
+
+        public Builder() {
+            clients = new ArrayList<>();
+        }
+
+        /**
+         * 添加客户端
+         */
+        public Builder addClient(InfluxDbClient client) {
+            this.clients.add(client);
+            return this;
+        }
+
+        /**
+         * 添加客户端
+         */
+        public Builder addClients(List<InfluxDbClient> clients) {
+            this.clients.addAll(clients);
+            return this;
+        }
+
+
+        /**
+         * 构建
+         */
+        public InfluxDBClients build() {
+            // 参数验证
+            if (CollectionUtils.isEmpty(this.clients)) throw new IllegalStateException("客户端不能为空");
+
+            return new InfluxDBClients(this);
+        }
+    }
+}

+ 3 - 3
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/AsyncConfig.java

@@ -1,9 +1,9 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
-import com.shkpr.service.customgateway.core.constants.LogFlagBusiType;
-import com.shkpr.service.customgateway.core.properties.AsyncProperties;
+import com.shkpr.service.bespokegateway.core.constants.LogFlagBusiType;
+import com.shkpr.service.bespokegateway.core.properties.AsyncProperties;
 import org.springframework.aop.interceptor.AsyncUncaughtExceptionHandler;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;

+ 2 - 2
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/CallingConfig.java

@@ -1,6 +1,6 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.properties.CallingProperties;
+import com.shkpr.service.bespokegateway.core.properties.CallingProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 

+ 82 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/DataSourceConfig.java

@@ -0,0 +1,82 @@
+package com.shkpr.service.bespokegateway.core.config;
+
+import com.shkpr.service.bespokegateway.core.properties.DataSourceProperties;
+import com.zaxxer.hikari.HikariConfig;
+import com.zaxxer.hikari.HikariDataSource;
+import org.h2.jdbcx.JdbcDataSource;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.boot.jdbc.DataSourceBuilder;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.sql.DataSource;
+
+import static com.shkpr.service.bespokegateway.core.constants.DataSourceNames.EMBEDDED;
+import static com.shkpr.service.bespokegateway.core.constants.DataSourceNames.PRIMARY;
+
+/**
+ * 数据源配置
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Configuration
+@EnableConfigurationProperties(DataSourceProperties.class)
+public class DataSourceConfig {
+    /**
+     * @param properties 属性
+     * @return 主要数据源
+     */
+    @Bean(name = PRIMARY + "DataSource")
+    public DataSource primaryDataSource(DataSourceProperties properties) {
+        //获取配置
+        DataSourceProperties.DataSource source = properties.getMulti().get(PRIMARY);
+        //构建数据源
+        HikariDataSource dataSource = DataSourceBuilder.create()
+                .type(HikariDataSource.class)
+                .url(source.getUrl())
+                .username(source.getUsername())
+                .password(source.getPassword())
+                .driverClassName(source.getDriverClassName())
+                .build();
+
+        configHikari(properties.getHikari(), dataSource);
+
+        return dataSource;
+    }
+
+    /**
+     * @param properties 属性
+     * @return 嵌入数据源
+     */
+    @Bean(name = EMBEDDED + "DataSource")
+    public DataSource embeddedDataSource(DataSourceProperties properties) {
+        //获取配置
+        DataSourceProperties.DataSource source = properties.getMulti().get(EMBEDDED);
+        //构建数据源
+        return DataSourceBuilder.create()
+                .type(JdbcDataSource.class)
+                .url(source.getUrl())
+                .username(source.getUsername())
+                .password(source.getPassword())
+                .driverClassName(source.getDriverClassName())
+                .build();
+    }
+
+    /**
+     * 配置Hikari
+     *
+     * @param config     配置
+     * @param dataSource 数据源
+     */
+    private void configHikari(HikariConfig config, HikariDataSource dataSource) {
+        dataSource.setMaximumPoolSize(config.getMaximumPoolSize());
+        dataSource.setMinimumIdle(config.getMinimumIdle());
+        dataSource.setConnectionTestQuery(config.getConnectionTestQuery());
+        dataSource.setMaxLifetime(config.getMaxLifetime());
+        dataSource.setIdleTimeout(config.getIdleTimeout());
+        dataSource.setConnectionTimeout(config.getConnectionTimeout());
+        dataSource.setValidationTimeout(config.getValidationTimeout());
+        dataSource.setInitializationFailTimeout(config.getInitializationFailTimeout());
+    }
+}

+ 45 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/DeviceConfig.java

@@ -0,0 +1,45 @@
+package com.shkpr.service.bespokegateway.core.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
+import com.shkpr.service.bespokegateway.core.components.DeviceIdGenerator;
+import com.shkpr.service.bespokegateway.core.components.DeviceRegistry;
+import com.shkpr.service.bespokegateway.core.properties.DeviceProperties;
+import com.shkpr.service.bespokegateway.core.service.DeviceSequencesService;
+import com.shkpr.service.bespokegateway.core.service.DeviceTagsService;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * 设备配置
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Configuration
+@EnableConfigurationProperties(DeviceProperties.class)
+public class DeviceConfig {
+    /**
+     * @return 设备注册器
+     */
+    @Bean
+    public DeviceRegistry deviceRegistry(DeviceProperties properties, DeviceTagsService tagsService) {
+        return DeviceRegistry.builder()
+                .yamlMapper(new ObjectMapper(new YAMLFactory()))
+                .configFile(properties.getMapPath())
+                .tagsService(tagsService)
+                .autoLoad(true)
+                .build();
+    }
+
+    /**
+     * @return 设备id生成器
+     */
+    @Bean
+    public DeviceIdGenerator deviceIdGenerator(DeviceSequencesService service) {
+        return DeviceIdGenerator.builder()
+                .service(service)
+                .build();
+    }
+}

+ 2 - 2
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/GatewayConfig.java

@@ -1,6 +1,6 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.properties.GatewayProperties;
+import com.shkpr.service.bespokegateway.core.properties.GatewayProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 

+ 2 - 2
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/GlobalConfig.java

@@ -1,6 +1,6 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.properties.GlobalProperties;
+import com.shkpr.service.bespokegateway.core.properties.GlobalProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 

+ 52 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/InfluxDbConfig.java

@@ -0,0 +1,52 @@
+package com.shkpr.service.bespokegateway.core.config;
+
+import com.shkpr.service.bespokegateway.core.components.InfluxDBClients;
+import com.shkpr.service.bespokegateway.core.domain.InfluxDbClient;
+import com.shkpr.service.bespokegateway.core.properties.InfluxDbProperties;
+import okhttp3.OkHttpClient;
+import org.springframework.beans.factory.ObjectProvider;
+import org.springframework.boot.autoconfigure.influx.InfluxDbOkHttpClientBuilderProvider;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.List;
+import java.util.stream.Collectors;
+
+/**
+ * influxDb配置
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Configuration
+@EnableConfigurationProperties(InfluxDbProperties.class)
+public class InfluxDbConfig {
+    /**
+     * influxDb注册器
+     *
+     * @param properties 属性
+     * @param providers  构建器提供
+     * @return influxDb注册器
+     */
+    @Bean
+    public InfluxDBClients influxDBClients(InfluxDbProperties properties, ObjectProvider<InfluxDbOkHttpClientBuilderProvider> providers) {
+        //构建器
+        OkHttpClient.Builder builder = determineBuilder(providers.getIfAvailable());
+        builder.readTimeout(properties.getReadTimeout());
+        //客户端集合
+        List<InfluxDbClient> clients = properties.getClients().stream()
+                .map(client -> new InfluxDbClient(client.getUrl(), client.getUser(), client.getPassword()
+                        , client.getDatabase(), builder))
+                .collect(Collectors.toList());
+        //注册
+        return InfluxDBClients.builder()
+                .addClients(clients)
+                .build();
+    }
+
+    private OkHttpClient.Builder determineBuilder(InfluxDbOkHttpClientBuilderProvider builder) {
+        if (builder != null) return builder.get();
+        return new OkHttpClient.Builder();
+    }
+}

+ 44 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/JdbcRepositoriesConfig.java

@@ -0,0 +1,44 @@
+package com.shkpr.service.bespokegateway.core.config;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.jdbc.repository.config.EnableJdbcRepositories;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcOperations;
+import org.springframework.jdbc.core.namedparam.NamedParameterJdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import javax.sql.DataSource;
+
+import static com.shkpr.service.bespokegateway.core.constants.DataSourceNames.EMBEDDED;
+
+/**
+ * jdbc配置
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Configuration
+@EnableJdbcRepositories(jdbcOperationsRef = EMBEDDED + "JdbcOperations",
+        transactionManagerRef = EMBEDDED + "TransactionManager",
+        basePackages = "com.shkpr.service.bespokegateway.core.repository." + EMBEDDED)
+public class JdbcRepositoriesConfig {
+    /**
+     * @param dataSource 数据源
+     * @return jdbc操作器
+     */
+    @Bean(EMBEDDED + "JdbcOperations")
+    public NamedParameterJdbcOperations embeddedJdbcOperations(@Qualifier(EMBEDDED + "DataSource") DataSource dataSource) {
+        return new NamedParameterJdbcTemplate(dataSource);
+    }
+
+    /**
+     * @param dataSource 数据源
+     * @return 事务管理器
+     */
+    @Bean(EMBEDDED + "TransactionManager")
+    public PlatformTransactionManager embeddedTransactionManager(@Qualifier(EMBEDDED + "DataSource") DataSource dataSource) {
+        return new DataSourceTransactionManager(dataSource);
+    }
+}

+ 70 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/config/PrimaryMybatisConfig.java

@@ -0,0 +1,70 @@
+package com.shkpr.service.bespokegateway.core.config;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.SqlSessionTemplate;
+import org.mybatis.spring.annotation.MapperScan;
+import org.mybatis.spring.boot.autoconfigure.MybatisProperties;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.core.io.support.ResourcePatternResolver;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+
+import javax.sql.DataSource;
+
+import static com.shkpr.service.bespokegateway.core.constants.DataSourceNames.PRIMARY;
+
+/**
+ * mybatis配置
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Configuration
+@EnableConfigurationProperties(MybatisProperties.class)
+@MapperScan(sqlSessionTemplateRef = PRIMARY + "SqlSessionTemplate", basePackages = "com.shkpr.service.bespokegateway.**.mapper." + PRIMARY)
+public class PrimaryMybatisConfig {
+    private static final ResourcePatternResolver resourceResolver = new PathMatchingResourcePatternResolver();
+
+    /**
+     * @param dataSource 数据源
+     * @return SQL会话工厂
+     * @throws Exception NotInitializedException
+     */
+    @Bean(PRIMARY + "SqlSessionFactory")
+    public SqlSessionFactory mainSqlSessionFactoryBean(MybatisProperties properties
+            , @Qualifier(PRIMARY + "DataSource") DataSource dataSource) throws Exception {
+        //配置工厂
+        SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
+        sessionFactoryBean.setDataSource(dataSource);
+        sessionFactoryBean.setMapperLocations(resourceResolver.getResources("classpath*:mapper/*.xml"));
+        //配置session
+        org.apache.ibatis.session.Configuration configuration = new org.apache.ibatis.session.Configuration();
+        configuration.setCallSettersOnNulls(properties.getConfiguration().isCallSettersOnNulls());
+        configuration.setMapUnderscoreToCamelCase(properties.getConfiguration().isMapUnderscoreToCamelCase());
+        configuration.setCacheEnabled(properties.getConfiguration().isCacheEnabled());
+        sessionFactoryBean.setConfiguration(configuration);
+        return sessionFactoryBean.getObject();
+    }
+
+    /**
+     * @param sessionFactory SQL会话工厂
+     * @return SQL会话模版
+     */
+    @Bean(PRIMARY + "SqlSessionTemplate")
+    public SqlSessionTemplate mainSqlSessionTemplate(@Qualifier(PRIMARY + "SqlSessionFactory") SqlSessionFactory sessionFactory) {
+        return new SqlSessionTemplate(sessionFactory);
+    }
+
+    /**
+     * @param dataSource 数据源
+     * @return 事物管理器
+     */
+    @Bean(PRIMARY + "DbTransactionManager")
+    public DataSourceTransactionManager mainDbTransactionManager(@Qualifier(PRIMARY + "DataSource") DataSource dataSource) {
+        return new DataSourceTransactionManager(dataSource);
+    }
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/SchedulingConfig.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
 import lombok.extern.slf4j.Slf4j;
 import org.springframework.boot.task.TaskSchedulerCustomizer;

+ 49 - 28
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/SecurityConfig.java

@@ -1,19 +1,25 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.constants.ResponseCode;
-import com.shkpr.service.customgateway.core.filter.TokenFilter;
-import com.shkpr.service.customgateway.core.properties.GlobalProperties;
-import com.shkpr.service.customgateway.core.properties.SecurityProperties;
-import com.shkpr.service.customgateway.core.utils.ResponseUtil;
-import com.shkpr.service.customgateway.core.utils.TokenUtil;
+import com.shkpr.service.bespokegateway.core.components.AccessKeyGenerator;
+import com.shkpr.service.bespokegateway.core.constants.AccessMetadata;
+import com.shkpr.service.bespokegateway.core.constants.ResponseCode;
+import com.shkpr.service.bespokegateway.core.constants.TokenMetadata;
+import com.shkpr.service.bespokegateway.core.filter.AccessFilter;
+import com.shkpr.service.bespokegateway.core.filter.TokenFilter;
+import com.shkpr.service.bespokegateway.core.properties.GlobalProperties;
+import com.shkpr.service.bespokegateway.core.properties.SecurityProperties;
+import com.shkpr.service.bespokegateway.core.service.AccessKeysService;
+import com.shkpr.service.bespokegateway.core.utils.ResponseUtil;
+import com.shkpr.service.bespokegateway.core.utils.TokenUtil;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
 import org.springframework.security.config.annotation.web.builders.HttpSecurity;
-import org.springframework.security.config.annotation.web.builders.WebSecurity;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
-import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityCustomizer;
 import org.springframework.security.config.http.SessionCreationPolicy;
+import org.springframework.security.web.SecurityFilterChain;
 import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
 
 /**
@@ -26,36 +32,41 @@ import org.springframework.security.web.authentication.AnonymousAuthenticationFi
 @EnableWebSecurity
 @EnableGlobalMethodSecurity(prePostEnabled = true)
 @EnableConfigurationProperties(SecurityProperties.class)
-public class SecurityConfig extends WebSecurityConfigurerAdapter {
+public class SecurityConfig {
     final
     GlobalProperties globalProperties;
     final
     SecurityProperties securityProperties;
     final
+    AccessKeysService accessKeysService;
+    final
     TokenUtil tokenUtil;
 
-    public SecurityConfig(GlobalProperties globalProperties, SecurityProperties securityProperties, TokenUtil tokenUtil) {
+    public SecurityConfig(GlobalProperties globalProperties, SecurityProperties securityProperties, AccessKeysService accessKeysService, TokenUtil tokenUtil) {
         this.globalProperties = globalProperties;
         this.securityProperties = securityProperties;
+        this.accessKeysService = accessKeysService;
         this.tokenUtil = tokenUtil;
     }
 
-
     /**
-     * http安全配置
-     * {@inheritDoc}
+     * @return 过滤器链配置
      */
-    @Override
-    protected void configure(HttpSecurity http) throws Exception {
-        //权限
-        http.authorizeRequests()
-                .antMatchers(securityProperties.getPermitPattern().toArray(new String[0]))
-                .permitAll()
-                .anyRequest()
-                .authenticated()
+    @Bean
+    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
+        return http
+                //权限
+                .authorizeRequests()
+                //公开
+                .antMatchers(securityProperties.getPermitPattern().toArray(new String[0])).permitAll()
+                //api
+                .antMatchers(AccessMetadata.ANT_PATTERN).hasAuthority(AccessMetadata.AUTHORITY)
+                //通用
+                .anyRequest().hasAuthority(TokenMetadata.AUTHORITY)
                 .and()
                 //过滤器
                 .addFilterBefore(new TokenFilter(globalProperties, securityProperties, tokenUtil), AnonymousAuthenticationFilter.class)
+                .addFilterBefore(new AccessFilter(securityProperties, accessKeysService), TokenFilter.class)
                 //跨域防伪
                 .csrf().disable()
                 //frame
@@ -76,16 +87,26 @@ public class SecurityConfig extends WebSecurityConfigurerAdapter {
                 .authenticationEntryPoint((request, response, authenticationException) ->
                         ResponseUtil.writeResponseCode(response, ResponseCode.STATUS_NOT_LOGGED_IN, globalProperties.getHttpStatusAlready200())
                 )
-        ;
-
+                .and()
+                .build();
     }
 
     /**
-     * web安全配置
-     * {@inheritDoc}
+     * @return web安全配置
      */
-    @Override
-    public void configure(WebSecurity web) {
+    @Bean
+    public WebSecurityCustomizer webSecurityCustomizer() {
+        return (web) -> {
+        };
+    }
 
+    /**
+     * @return 访问密钥生成器
+     */
+    @Bean
+    public AccessKeyGenerator accessKeyGenerator(AccessKeysService service) {
+        return AccessKeyGenerator.builder()
+                .service(service)
+                .build();
     }
 }

+ 2 - 2
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/TempFileConfig.java

@@ -1,6 +1,6 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.properties.TempFileProperties;
+import com.shkpr.service.bespokegateway.core.properties.TempFileProperties;
 import org.springframework.boot.context.properties.EnableConfigurationProperties;
 import org.springframework.context.annotation.Configuration;
 

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/ValidatorConfig.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
 import org.hibernate.validator.HibernateValidator;
 import org.springframework.context.annotation.Bean;

+ 3 - 3
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/config/WebConfig.java

@@ -1,7 +1,7 @@
-package com.shkpr.service.customgateway.core.config;
+package com.shkpr.service.bespokegateway.core.config;
 
-import com.shkpr.service.customgateway.core.properties.AsyncProperties;
-import com.shkpr.service.customgateway.core.properties.TempFileProperties;
+import com.shkpr.service.bespokegateway.core.properties.AsyncProperties;
+import com.shkpr.service.bespokegateway.core.properties.TempFileProperties;
 import lombok.NonNull;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.core.Ordered;

+ 67 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/AccessMetadata.java

@@ -0,0 +1,67 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 接入元数据
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface AccessMetadata {
+    /**
+     * uri模式
+     */
+    String ANT_PATTERN = "/*/api/**";
+    /**
+     * 权限
+     */
+    String AUTHORITY = "api";
+
+    /**
+     * 响应码
+     */
+    @Getter
+    @AllArgsConstructor
+    enum ResponseCode {
+        SUCCESS(200, "ok"),
+        FAILURE(500, "Bad result,see the message/data for reason."),
+
+        ACCESS_KEY_MISS(2000, "访问密钥缺失"),
+        ACCESS_KEY_INVALID(2001, "访问密钥无效"),
+        ACCESS_KEY_DISABLED(2002, "访问密钥已禁用"),
+        TIMESTAMP_MISS(2003, "时间戳缺失"),
+        TIMESTAMP_EXPIRED(2004, "时间戳过期"),
+        TIMESTAMP_INVALID(2005, "时间戳格式错误"),
+        SIGNATURE_MISS(2006, "签名参数缺失"),
+        SIGNATURE_INVALID(2007, "签名验证失败"),
+        ;
+        /**
+         * 编码
+         */
+        private final int code;
+        /**
+         * 信息
+         */
+        private final String message;
+    }
+
+    /**
+     * 头
+     */
+    interface Headers {
+        /**
+         * 访问密钥
+         */
+        String ACCESS_KEY = "Access-Key";
+        /**
+         * 时间戳
+         */
+        String TIMESTAMP = "Timestamp";
+        /**
+         * 签名
+         */
+        String SIGNATURE = "Signature";
+    }
+}

+ 33 - 27
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/Api.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 /**
  * api
@@ -7,7 +7,7 @@ package com.shkpr.service.customgateway.core.constants;
  * @since 1.0.0
  */
 public interface Api {
-    String EXCEPTION_FORMAT = "{%s:%s}:%s"; //{(ios/apk/pc):url}:error reason
+
     String WORKSPACE = "Workspace";
     String URI_XXX_NEW_INFO = "new-info";//新增
     String URI_XXX_LISTS = "lists"; //分页查询
@@ -44,13 +44,12 @@ public interface Api {
     String URI_ACCESS_TOKEN_CHECK = "/kpr-plugin/apply/access-token-check";
     String URI_FILE_BUSI_XXX = "/files/**";
     String URI_IMAGE_SHOW_XXX = "/imageShow/**";
+
     String URI_ALL_BUSI_XXX = "/kpr-plugin/**";
     String URI_GIS_SURVEY_H = "/kpr-plugin/gis-survey";
     String URI_GIS_SURVEY_XXX = URI_GIS_SURVEY_H + "/**";
     String URI_PIPE_BURST_H = "/kpr-plugin/pipe_burst";
     String URI_PIPE_BURST_XXX = URI_PIPE_BURST_H + "/**";
-    String URI_USERS_H = "/kpr-plugin/users";
-    String URI_USERS_XXX = URI_USERS_H + "/**";
     String URI_COMMON_H = "/kpr-plugin/common";
     String URI_COMMON_XXX = URI_COMMON_H + "/**";
     String URI_FILES_H = "/kpr-plugin/files";
@@ -58,29 +57,36 @@ public interface Api {
     String URI_INTERNAL_H = "/kpr-plugin/internal";
     String URI_INTERNAL_XXX = URI_INTERNAL_H + "/**";
     String URI_INTERNAL_OPS_XXX = "/ops/**";
-    /**
-     * 请求头
-     */
-    interface Headers {
-        //验证口令
-        String AUTH_VERIFY = "Auth-Verify";
-        //ip地址
-        String X_SOURCE_IP = "X-Source-IP";
-        String BIZ_TYPE = "Biz-Type";
-        String CLIENT_TYPE = "Client-Type";
-        String USER_AGENT = "user-agent";
-        String SIGN_KEY = "tri_coorperation_tech_task";
-        String TIMESTAMP = "Timestamp";
-        String SEQUENCE = "Sequence";
-        String SIGNATURE = "Signature";
-        //认证
-        String AUTHORIZATION = "Authorization";
-    }
 
-    /**
-     * 请求属性
-     */
-    interface Attributes {
+    //用户
+    String URI_USERS_H = "/users";
+    //户表
+    String URI_CUSTOMER_H = "/customer";
+
+    //ticket交换临时令牌
+    String URI_XXX_TICKET_EXCHANGE = "ticket-exchange";
+    //户表信息导入
+    String URI_XXX_CUSTOMER_INFO_IMPORT = "customer-info-import";
+    //户表数据导入
+    String URI_XXX_CUSTOMER_DATA_IMPORT = "customer-data-import";
+
+
+
+    //==========================请求头==========================
+    //验证口令
+    String HEADER_AUTH_VERIFY = "Auth-Verify";
+    //ip地址
+    String HEADER_X_SOURCE_IP = "X-Source-IP";
+    String HEADER_BIZ_TYPE = "Biz-Type";
+    String HEADER_CLIENT_TYPE = "Client-Type";
+    String HEADER_USER_AGENT = "user-agent";
+    String HEADER_SIGN_KEY = "tri_coorperation_tech_task";
+    String HEADER_TIMESTAMP = "Timestamp";
+    String HEADER_SEQUENCE = "Sequence";
+    String HEADER_SIGNATURE = "Signature";
+    //认证
+    String HEADER_AUTHORIZATION = "Authorization";
+    //==========================日志格式==========================
+    String EXCEPTION_FORMAT = "{%s:%s}:%s"; //{(ios/apk/pc):url}:error reason
 
-    }
 }

+ 21 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/AreaCode.java

@@ -0,0 +1,21 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 区号
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum AreaCode {
+    //枣阳
+    ZAO_YANG(710),
+    //监利
+    JIAN_LI(716),
+    ;
+    private final Integer code;
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/CommDefine.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 /**
  * 通用定义

+ 45 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerBillingType.java

@@ -0,0 +1,45 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 计费类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerBillingType implements ExcelEnum {
+    // 计费的
+    CHARGED((short) 0, "是"),
+    // 免费的
+    FREE((short) 1, "否"),
+    ;
+
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+
+    /**
+     * @return 单元格值
+     */
+    @Override
+    public String getLabel() {
+        return this.name;
+    }
+
+    /**
+     * @return 对象值
+     */
+    @Override
+    public Object getValue() {
+        return this.code;
+    }
+}

+ 26 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerInfoStatus.java

@@ -0,0 +1,26 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 营销户表状态
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerInfoStatus {
+    //正常
+    NORMAL((short) 1, "正常"),
+    ;
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+}

+ 44 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerMeterType.java

@@ -0,0 +1,44 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 营销表类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerMeterType  implements  ExcelEnum{
+    //机械表
+    NO_CYCLE_INFO((short) 0, "机械表"),
+    //远传表
+    MONTHLY((short) 1, "远传水表"),
+    ;
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+
+    /**
+     * @return 单元格值
+     */
+    @Override
+    public String getLabel() {
+        return this.name;
+    }
+
+    /**
+     * @return 对象值
+     */
+    @Override
+    public Object getValue() {
+        return this.code;
+    }
+}

+ 45 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerMeteringType.java

@@ -0,0 +1,45 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 未计量类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerMeteringType implements ExcelEnum {
+    // 计量的
+    METERED((short) 0, "是"),
+    // 未计量的
+    UNMETERED((short) 1, "否"),
+    ;
+
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+
+    /**
+     * @return 单元格值
+     */
+    @Override
+    public String getLabel() {
+        return this.name;
+    }
+
+    /**
+     * @return 对象值
+     */
+    @Override
+    public Object getValue() {
+        return this.code;
+    }
+}

+ 45 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerPublicServiceType.java

@@ -0,0 +1,45 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 公共用水类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerPublicServiceType implements ExcelEnum {
+    // 非公共用水
+    NOT_PUBLIC_SERVICE((short) 0, "非公共用水"),
+    // 公共用水
+    PUBLIC_SERVICE((short) 1, "公共用水"),
+    ;
+
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+
+    /**
+     * @return 单元格值
+     */
+    @Override
+    public String getLabel() {
+        return this.name;
+    }
+
+    /**
+     * @return 对象值
+     */
+    @Override
+    public Object getValue() {
+        return this.code;
+    }
+}

+ 67 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/CustomerReadType.java

@@ -0,0 +1,67 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+import java.util.Arrays;
+
+/**
+ * 营销抄表类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum CustomerReadType implements ExcelEnum {
+    //无抄表周期信息
+    NO_CYCLE_INFO((short) 0, "无抄表周期信息"),
+    //每月抄表
+    MONTHLY((short) 1, "月抄"),
+    //单月抄表
+    SINGLE_MONTH((short) 2, "单月抄"),
+    //双月抄表
+    DOUBLE_MONTH((short) 3, "双月抄"),
+    //季度上抄表
+    QUARTER_FIRST((short) 4, "季度上抄"),
+    //季度中抄表
+    QUARTER_MID((short) 5, "季度中抄"),
+    //季度下抄表
+    QUARTER_LAST((short) 6, "季度下抄"),
+    //半年抄表
+    SEMI_ANNUAL((short) 7, "半年抄"),
+    //一月多抄
+    MULTIPLE_PER_MONTH((short) 9, "一月多抄"),
+    ;
+    /**
+     * 码
+     */
+    private final Short code;
+    /**
+     * 名称
+     */
+    private final String name;
+
+    /**
+     * 获取code
+     *
+     * @param name 名称
+     * @return code
+     */
+    public static short getCode(String name) {
+        return Arrays.stream(values())
+                .filter(it -> it.getName().equals(name))
+                .findFirst().orElse(NO_CYCLE_INFO)
+                .getCode();
+    }
+
+    @Override
+    public String getLabel() {
+        return this.name;
+    }
+
+    @Override
+    public Object getValue() {
+        return this.code;
+    }
+}

+ 14 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DataSourceNames.java

@@ -0,0 +1,14 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+/**
+ * 数据源名称
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface DataSourceNames {
+    //主要
+    String PRIMARY = "primary";
+    //嵌入
+    String EMBEDDED = "embedded";
+}

+ 54 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DeviceField.java

@@ -0,0 +1,54 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 设备字段
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum DeviceField {
+    //瞬时流量
+    FLOW_CUR("flow_cur", "瞬时流量"),
+    //正向累积流量读数
+    FLOW_TOTAL_POS("flow_total_pos", "正向累计流量读数"),
+    //反向累积流量读数
+    FLOW_TOTAL_REV("flow_total_rev", "反向累计流量读数"),
+    //净累积流量读数
+    FLOW_TOTAL_NET("flow_total_net", "净累积流量读数"),
+
+    //瞬时压力
+    PRESS_CUR("press_cur", "瞬时压力"),
+    //电池电压
+    BATTERY_VOLTAGE("battery_voltage", "电池电压"),
+
+    //ph
+    PH("ph", "PH值"),
+    //余氯
+    CHLORINE("chlorine", "余氯"),
+    //浊度
+    TURBIDITY("turbidity", "浊度"),
+    //水温
+    TEMPERATURE("temperature", "水温"),
+
+    //液位
+    LEVEL("level", "液位"),
+
+    //运行状态
+    RUNNING("running", "运行状态"),
+    //频率
+    FREQUENCY("frequency", "频率(水泵)"),
+    ;
+    /**
+     * 标识
+     */
+    private final String key;
+    /**
+     * 名称
+     */
+    private final String name;
+}

+ 44 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/DeviceKind.java

@@ -0,0 +1,44 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 设备种类
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+@AllArgsConstructor
+public enum DeviceKind {
+    //压力流量计
+    FLOW_PRESS("flow_press", "流量计", 1, "WaterMeter"),
+    //流量计
+    FLOW("flow", "流量计", 2, "WaterMeter"),
+    //压力计
+    PRESS("press", "压力计", 3, "WaterMeter"),
+    //水质仪
+    QUALITY("quality", "多参数水质仪", 10, "WaterQuality"),
+    //液位计
+    LEVEL("level", "液位计", 11, "LiquidLevel"),
+    //水泵
+    WATER_PUMP("water_pump","水泵", 20, "WaterPump"),
+    ;
+    /**
+     * 标识
+     */
+    private final String key;
+    /**
+     * 名称
+     */
+    private final String name;
+    /**
+     * 代码
+     */
+    private final Integer code;
+    /**
+     * 表名
+     */
+    private final String measurement;
+}

+ 20 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelEnum.java

@@ -0,0 +1,20 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+/**
+ * excel枚举
+ * <p>用于excel导入时匹配枚举中的值</p>
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface ExcelEnum {
+    /**
+     * @return 单元格值
+     */
+    String getLabel();
+
+    /**
+     * @return 对象值
+     */
+    Object getValue();
+}

+ 14 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelMetadata.java

@@ -0,0 +1,14 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+/**
+ * excel元数据
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface ExcelMetadata {
+    //头所在行
+    Integer HEADER_ROW_NUM = 1;
+    //数据开始行
+    Integer DATA_ROW_NUM = 2;
+}

+ 22 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ExcelType.java

@@ -0,0 +1,22 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+/**
+ * excel类型
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public enum ExcelType {
+    /**
+     * csv
+     */
+    CSV,
+    /**
+     * xls
+     */
+    XLS,
+    /**
+     * xlsx
+     */
+    XLSX
+}

+ 15 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/InfluxdbMetadata.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 /**
  * influxdb元数据
@@ -22,6 +22,20 @@ public interface InfluxdbMetadata {
     }
 
     /**
+     * 标识
+     */
+    interface Tags {
+        /**
+         * 设备编码
+         */
+        String DEVICE_ID = "dev_id";
+        /**
+         * 设备编码
+         */
+        String DEVICE_SN = "dev_sn";
+    }
+
+    /**
      * Sql
      */
     interface Sql {

+ 11 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/IntegrationMetadata.java

@@ -0,0 +1,11 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+/**
+ * 集成元数据
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public abstract class IntegrationMetadata {
+
+}

+ 3 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/LogFlagBusiType.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 public enum LogFlagBusiType {
     BUSI_INIT(0,"Init Busi"),
@@ -41,6 +41,8 @@ public enum LogFlagBusiType {
     BUSI_GIS_SURVEY(37,"Gis Survey Biz"),
     BUSI_PIPE_BURST(38,"Pipe Burst Biz"),
     ZAO_YANG_DMA(39,"Zao Yang Dma"),
+    ZHONG_HUAN_SACADA(40,"Zhong Huan Sacada"),
+    JIAN_LI_DMA(41,"Jian Li Dma"),
 
     BUSI_INTERNAL(99,"Internal Busi"),
 

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/LoginUserRoleType.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 public enum LoginUserRoleType {
     ROOT_ADMIN(0,"admin"),

+ 23 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ProtocolType.java

@@ -0,0 +1,23 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 协议类型
+ *
+ * @author 欧阳劲驰
+ * @since 0.0.1
+ */
+@Getter
+@AllArgsConstructor
+public enum ProtocolType {
+    //json
+    JSON("json"),
+    //modbus
+    MODBUS("modbus");
+    /**
+     * 标识
+     */
+    private final String key;
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/ResponseCode.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 import lombok.AllArgsConstructor;
 import lombok.Getter;

+ 7 - 2
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/constants/TokenMetadata.java

@@ -1,13 +1,18 @@
-package com.shkpr.service.customgateway.core.constants;
+package com.shkpr.service.bespokegateway.core.constants;
 
 /**
  * influxdb元数据
  *
  * @author 欧阳劲驰
- * @since 0.0.1-dev
+ * @since 1.0.0
  */
 public interface TokenMetadata {
     /**
+     * 权限
+     */
+    String AUTHORITY = "common";
+
+    /**
      * 参数
      */
     interface Claims {

+ 41 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/constants/ValueType.java

@@ -0,0 +1,41 @@
+package com.shkpr.service.bespokegateway.core.constants;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * 值类型枚举
+ *
+ * @author 欧阳劲驰
+ * @since 0.1.0
+ */
+@Getter
+@AllArgsConstructor
+public enum ValueType {
+    /**
+     * 无符号整型
+     */
+    UNSIGNED_INT("uint"),
+    /**
+     * 有符号整型
+     */
+    SIGNED_INT("int"),
+    /**
+     * 单经度浮点
+     */
+    SINGLE_FLOAT("float"),
+    /**
+     * 双精度浮点
+     */
+    DOUBLE_FLOAT("double"),
+    /**
+     * 字符串
+     */
+    ASCII("ascii"),
+    /**
+     * 布尔
+     */
+    BOOLEAN("bool"),
+    ;
+    private final String key;
+}

+ 25 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/controller/RouteController.java

@@ -0,0 +1,25 @@
+package com.shkpr.service.bespokegateway.core.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+
+/**
+ * 路由controller
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Controller
+@RequestMapping("/")
+public class RouteController {
+    /**
+     * 首页
+     *
+     * @return 首页路径
+     */
+    @GetMapping("/")
+    public String index() {
+        return "index";
+    }
+}

+ 106 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/AccessResult.java

@@ -0,0 +1,106 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.shkpr.service.bespokegateway.core.constants.AccessMetadata;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.http.HttpStatus;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+/**
+ * 接入响应
+ *
+ * @param <T> 数据类型
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class AccessResult<T> implements Result<T> {
+    /**
+     * 编码
+     */
+    private Integer code;
+    /**
+     * 信息
+     */
+    private String message;
+    /**
+     * 数据
+     */
+    private T data;
+    /**
+     * 时间戳
+     */
+    private long timestamp;
+
+    /**
+     * 成功
+     *
+     * @param data 数据
+     * @param <T>  数据类型
+     * @return 访问结果
+     */
+    public static <T> AccessResult<T> ok(T data) {
+        return new AccessResult<>(AccessMetadata.ResponseCode.SUCCESS.getCode(), "ok", data,
+                LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
+    }
+
+
+    /**
+     * 失败
+     *
+     * @param message 消息
+     * @param <T>     数据类型
+     * @return 访问结果
+     */
+    public static <T> AccessResult<T> fail(String message) {
+        return new AccessResult<>(AccessMetadata.ResponseCode.FAILURE.getCode(), message, null,
+                LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
+    }
+
+    /**
+     * 获取状态码
+     *
+     * @return 状态码
+     */
+    @Override
+    public Integer getCode() {
+        return this.code;
+    }
+
+    /**
+     * 获取信息
+     *
+     * @return 信息
+     */
+    @Override
+    public String getMessage() {
+        return this.message;
+    }
+
+    /**
+     * 获取数据
+     *
+     * @return 数据
+     */
+    @Override
+    public T getData() {
+        return this.data;
+    }
+
+    /**
+     * 获取ok状态码
+     *
+     * @return ok状态码
+     */
+    @JsonIgnore
+    @Override
+    public Boolean isOk() {
+        return HttpStatus.SC_OK == this.code;
+    }
+}

+ 72 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/AccessToken.java

@@ -0,0 +1,72 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import org.springframework.security.authentication.AbstractAuthenticationToken;
+import org.springframework.security.core.GrantedAuthority;
+
+import java.io.Serializable;
+import java.util.Collection;
+
+/**
+ * 接入令牌
+ *
+ * <p>principal:集成密钥</p>
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class AccessToken extends AbstractAuthenticationToken implements Serializable {
+    /**
+     * token信息
+     */
+    private final Object principal;
+    /**
+     * 密钥
+     */
+    private final Object credentials;
+
+    public AccessToken(Object principal, Object credentials) {
+        super(null);
+        this.principal = principal;
+        this.credentials = credentials;
+        setAuthenticated(false);
+    }
+
+    public AccessToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
+        super(authorities);
+        this.principal = principal;
+        this.credentials = credentials;
+        super.setAuthenticated(true);
+    }
+
+    /**
+     * 未认证
+     *
+     * @param principal   token信息
+     * @param credentials 密码
+     * @return 未认证的token
+     */
+    public static AccessToken unauthenticated(Object principal, Object credentials) {
+        return new AccessToken(principal, credentials);
+    }
+
+    /**
+     * 已认证
+     *
+     * @param principal   token信息
+     * @param authorities 权限
+     * @return 已认证的token
+     */
+    public static AccessToken authenticated(Object principal, Collection<? extends GrantedAuthority> authorities) {
+        return new AccessToken(principal, null, authorities);
+    }
+
+    @Override
+    public Object getCredentials() {
+        return this.credentials;
+    }
+
+    @Override
+    public Object getPrincipal() {
+        return this.principal;
+    }
+}

+ 25 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/CallingEndpoint.java

@@ -0,0 +1,25 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import lombok.Data;
+
+/**
+ * 对接信息
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class CallingEndpoint {
+    /**
+     * 地址
+     */
+    private String url;
+    /**
+     * 账号
+     */
+    private String accessKey;
+    /**
+     * 密码
+     */
+    private String secretKey;
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/CommonToken.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 import org.springframework.security.authentication.AbstractAuthenticationToken;
 import org.springframework.security.core.GrantedAuthority;

+ 80 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/Device.java

@@ -0,0 +1,80 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * 设备信息
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class Device {
+    /**
+     * 设备id
+     */
+    private String deviceId;
+    /**
+     * 设备名称
+     */
+    private String deviceName;
+    /**
+     * 远传id
+     */
+    private String deviceSn;
+    /**
+     * 设备种类
+     */
+    private String deviceKind;
+    /**
+     * 所属平台
+     */
+    private String platform;
+    /**
+     * 设备厂家
+     */
+    private String mfrs;
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh_CN", timezone = "Asia/Shanghai")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    @JsonSerialize(using = LocalDateTimeSerializer.class)
+    @JsonDeserialize(using = LocalDateTimeDeserializer.class)
+    private LocalDateTime createTime;
+    /**
+     * 字段
+     */
+    private List<DeviceTag> tags;
+
+    @Override
+    public boolean equals(Object o) {
+        if (o == null || getClass() != o.getClass()) return false;
+        Device device = (Device) o;
+        return Objects.equals(deviceId, device.deviceId) && Objects.equals(deviceKind, device.deviceKind) &&
+                Objects.equals(
+                        tags.stream().map(DeviceTag::getField).collect(Collectors.joining()),
+                        device.tags.stream().map(DeviceTag::getField).collect(Collectors.joining())
+                );
+    }
+
+    @Override
+    public int hashCode() {
+        return Objects.hash(deviceId, deviceKind, tags.stream().map(DeviceTag::getField).collect(Collectors.joining()));
+    }
+}

+ 50 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/DeviceExcel.java

@@ -0,0 +1,50 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import com.shkpr.service.bespokegateway.core.annotation.ExcelMapping;
+import lombok.Data;
+
+/**
+ * 设备excel信息
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class DeviceExcel {
+    /**
+     * 设备名称
+     */
+    @ExcelMapping("设备名称")
+    private String deviceName;
+    /**
+     * 设备id
+     */
+    @ExcelMapping("设备编号")
+    private String deviceId;
+    /**
+     * 远传id
+     */
+    @ExcelMapping("远传ID")
+    private String deviceSn;
+    /**
+     * 设备类型
+     */
+    @ExcelMapping("设备种类")
+    private String deviceKind;
+    /**
+     * 设备厂家
+     */
+    @ExcelMapping("设备厂家")
+    private String mfrs;
+    /**
+     * 字段
+     */
+    @ExcelMapping("字段")
+    private String field;
+    /**
+     * 标签
+     */
+    @ExcelMapping("标签")
+    private String tags;
+
+}

+ 61 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/DeviceTag.java

@@ -0,0 +1,61 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 设备标签
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class DeviceTag {
+    /**
+     * 标签
+     */
+    private String tag;
+    /**
+     * 协议标识
+     */
+    private String protocol;
+    /**
+     * 表名
+     */
+    private String measurement;
+    /**
+     * 字段key
+     */
+    private String field;
+    /**
+     * 值类型
+     */
+    private String valueType;
+    /**
+     * 最小值
+     */
+    private Double minValue;
+    /**
+     * 最大值
+     */
+    private Double maxValue;
+    /**
+     * 同步key
+     */
+    private String syncField;
+    /**
+     * 计算
+     */
+    private String calcFormula;
+
+    public DeviceTag(String tag, String protocol, String measurement, String field, String valueType) {
+        this.tag = tag;
+        this.protocol = protocol;
+        this.measurement = measurement;
+        this.field = field;
+        this.valueType = valueType;
+    }
+}

+ 28 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/InfluxDbClient.java

@@ -0,0 +1,28 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import lombok.Getter;
+import okhttp3.OkHttpClient;
+import org.influxdb.impl.InfluxDBImpl;
+
+/**
+ * influxDb客户端
+ * <p>
+ * {@link org.influxdb.impl.InfluxDBImpl}
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Getter
+public class InfluxDbClient extends InfluxDBImpl {
+    /**
+     * 数据库
+     */
+    private final String database;
+
+    public InfluxDbClient(String url, String username, String password, String database, OkHttpClient.Builder client) {
+        super(url, username, password, client);
+        super.setDatabase(database);
+        super.enableGzip();
+        this.database = database;
+    }
+}

+ 33 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/IntegrationKey.java

@@ -0,0 +1,33 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+/**
+ * 集成密钥
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class IntegrationKey {
+    /**
+     * 时间戳
+     */
+    private Long timestamp;
+    /**
+     * key
+     */
+    private String accessKey;
+    /**
+     * Secret
+     */
+    private String secretKey;
+    /**
+     * 签名
+     */
+    private String signature;
+}

+ 24 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/IntegrationKeyLoader.java

@@ -0,0 +1,24 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+/**
+ * 密钥加载器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public interface IntegrationKeyLoader {
+    /**
+     * 获取平台名称
+     *
+     * @return 平台名称
+     */
+    String getPlatformName();
+
+    /**
+     * 加载密钥
+     *
+     * @param endpoint 对接信息
+     * @return 密钥
+     */
+    IntegrationKey loadKey(CallingEndpoint endpoint);
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/LatLngBean.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 import lombok.Getter;
 import lombok.Setter;

+ 36 - 29
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/PageRequest.java

@@ -1,7 +1,8 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 import lombok.Data;
 import lombok.NonNull;
+import org.jetbrains.annotations.NotNull;
 import org.springframework.data.domain.Pageable;
 import org.springframework.data.domain.Sort;
 
@@ -45,6 +46,34 @@ public class PageRequest implements Pageable {
         this.sort = sort != null ? sort : Sort.unsorted();
     }
 
+    /**
+     * 创建带排序的PageRequest
+     */
+    public static PageRequest defaultPage() {
+        return of(0, 99, Sort.unsorted());
+    }
+
+    /**
+     * 创建带排序的PageRequest
+     */
+    public static PageRequest of(int page, int size) {
+        return of(page, size, Sort.unsorted());
+    }
+
+    /**
+     * 创建带排序的PageRequest
+     */
+    public static PageRequest of(int page, int size, Sort sort) {
+        return new PageRequest(page, size, sort);
+    }
+
+    /**
+     * 创建带排序的PageRequest
+     */
+    public static PageRequest of(int page, int size, Sort.Direction direction, String... properties) {
+        return of(page, size, Sort.by(direction, properties));
+    }
+
     @Override
     public int getPageNumber() {
         return this.pageNumber;
@@ -85,35 +114,13 @@ public class PageRequest implements Pageable {
     }
 
     @Override
-    public boolean hasPrevious() {
-        return pageNumber > 0;
+    @NotNull
+    public Pageable withPage(int pageNumber) {
+        return new PageRequest(pageNumber, getPageSize(), getSort());
     }
 
-    /**
-     * 创建带排序的PageRequest
-     */
-    public static PageRequest defaultPage() {
-        return of(0, 99, Sort.unsorted());
-    }
-
-    /**
-     * 创建带排序的PageRequest
-     */
-    public static PageRequest of(int page, int size) {
-        return of(page, size, Sort.unsorted());
-    }
-
-    /**
-     * 创建带排序的PageRequest
-     */
-    public static PageRequest of(int page, int size, Sort sort) {
-        return new PageRequest(page, size, sort);
-    }
-
-    /**
-     * 创建带排序的PageRequest
-     */
-    public static PageRequest of(int page, int size, Sort.Direction direction, String... properties) {
-        return of(page, size, Sort.by(direction, properties));
+    @Override
+    public boolean hasPrevious() {
+        return pageNumber > 0;
     }
 }

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/PageResponse.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 import lombok.Data;
 import lombok.NoArgsConstructor;

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/Result.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 /**
  * 结果

+ 84 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/ResultResponse.java

@@ -0,0 +1,84 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.shkpr.service.bespokegateway.core.constants.ResponseCode;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.StringUtils;
+
+/**
+ * 结果响应
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class ResultResponse<T> implements Result<T> {
+    /**
+     * 时间戳
+     */
+    private long timestamp;
+    /**
+     * 编码
+     */
+    private String rescode;
+    /**
+     * 信息
+     */
+    private String resmsg;
+    /**
+     * 数据
+     */
+    private T resdata;
+
+    /**
+     * 失败
+     *
+     * @param <T> 数据类型
+     * @return 结果
+     */
+    public static <T> ResultResponse<T> failed() {
+        ResultResponse<T> resultResponse = new ResultResponse<>();
+        resultResponse.setRescode(ResponseCode.RESULT_BAD.getCode() + "");
+        resultResponse.setResmsg(ResponseCode.RESULT_BAD.getMessage());
+        return resultResponse;
+    }
+
+    /**
+     * 成功
+     */
+    public void success(T data) {
+        this.setRescode(ResponseCode.RESULT_NORMAL.getCode() + "");
+        this.setResmsg(ResponseCode.RESULT_NORMAL.getMessage());
+        this.setResdata(data);
+    }
+
+    @Override
+    @JsonIgnore
+    public Integer getCode() {
+        return Integer.valueOf(this.rescode);
+    }
+
+    @Override
+    @JsonIgnore
+    public String getMessage() {
+        return this.resmsg;
+    }
+
+    @Override
+    @JsonIgnore
+    public T getData() {
+        return this.resdata;
+    }
+
+    @Override
+    @JsonIgnore
+    public Boolean isOk() {
+        return StringUtils.isNoneBlank(this.rescode) &&
+                Integer.parseInt(this.rescode) == ResponseCode.RESULT_NORMAL.getCode();
+    }
+}
+

+ 103 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/TmpTokenData.java

@@ -0,0 +1,103 @@
+package com.shkpr.service.bespokegateway.core.domain;
+
+import com.shkpr.service.bespokegateway.core.utils.AesUtil;
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.apache.commons.lang3.RandomStringUtils;
+import org.apache.commons.lang3.StringUtils;
+
+import java.time.LocalDateTime;
+import java.time.ZoneId;
+
+/**
+ * 临时token数据
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class TmpTokenData {
+    /**
+     * 模式
+     */
+    private Integer model;
+    /**
+     * 账号
+     */
+    private String account;
+    /**
+     * Token字符串
+     */
+    private String token;
+    /**
+     * 签发时间(时间戳)
+     */
+    private Long issuedAt;
+
+    /**
+     * 从账号构建
+     *
+     * @param account 账号
+     * @return 未认证的token
+     */
+    public static TmpTokenData ofAccount(String account) {
+        return new TmpTokenData(0, account, null, LocalDateTime.now().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli());
+    }
+
+    /**
+     * 从token构建
+     *
+     * @param token 秘文
+     * @return 未认证的token
+     */
+    public static TmpTokenData ofToken(String token) {
+        return new TmpTokenData(null, null, token, null);
+    }
+
+
+    /**
+     * 加密
+     *
+     */
+    public TmpTokenData encrypt(String key) {
+        final int randomLength = 8;
+
+        //构建明文
+        if (StringUtils.isAnyBlank(this.account, key)) return null;
+        String plainText = String.format("%s%d%s%s", this.model + "",
+                this.issuedAt / 1000, RandomStringUtils.randomAlphanumeric(randomLength), this.account);
+        //加密
+        this.token = AesUtil.encrypt(plainText, key);
+        return this;
+    }
+
+    /**
+     * 解密
+     *
+     */
+    public TmpTokenData decrypt(String key) {
+        final int modelLength = 1;
+        final int issuedAtLength = 10;
+        final int randomLength = 8;
+
+        //解密明文
+        if (StringUtils.isAnyBlank(this.token, key)) return null;
+        String plainText = AesUtil.decrypt(this.token, key);
+        if (StringUtils.isBlank(plainText)) return null;
+
+        //模式
+        int model = Integer.parseInt(StringUtils.substring(plainText, 0, modelLength));
+        //签发时间
+        long issuedAt = Long.parseLong(StringUtils.substring(plainText, modelLength, modelLength + issuedAtLength)) * 1000;
+        //账号
+        String account = StringUtils.substring(plainText, modelLength + issuedAtLength + randomLength);
+
+        this.model = model;
+        this.issuedAt = issuedAt;
+        this.account = account;
+        return this;
+    }
+}

+ 5 - 5
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/domain/TokenData.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.domain;
+package com.shkpr.service.bespokegateway.core.domain;
 
 import lombok.AllArgsConstructor;
 import lombok.Data;
@@ -17,7 +17,7 @@ public class TokenData {
     /**
      * 用户id
      */
-    private String flagKey = "";
+    private String userId = "";
     /**
      * 角色id
      */
@@ -25,7 +25,7 @@ public class TokenData {
     /**
      * Token字符串
      */
-    private String tokenStr = "";
+    private String token = "";
     /**
      * 签发时间(时间戳)
      */
@@ -35,8 +35,8 @@ public class TokenData {
      */
     private long expiration = 0L;
 
-    public TokenData(String flagKey, String roleId) {
-        this.flagKey = flagKey;
+    public TokenData(String userId, String roleId) {
+        this.userId = userId;
         this.roleId = roleId;
     }
 }

+ 41 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/AccessKeys.java

@@ -0,0 +1,41 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.relational.core.mapping.Table;
+
+/**
+ * 访问密钥表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Table("ACCESS_KEYS")
+public class AccessKeys {
+    /**
+     * 主键
+     */
+    @Id
+    private Long id;
+    /**
+     * 访问密钥
+     */
+    private String accessKey;
+    /**
+     * 认证密钥
+     */
+    private String securityKey;
+    /**
+     * 描述
+     */
+    private String description;
+
+    public static AccessKeys of(String accessKey, String securityKey, String description) {
+        return new AccessKeys(null, accessKey, securityKey, description);
+    }
+}

+ 168 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/CustomerInfo.java

@@ -0,0 +1,168 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import com.shkpr.service.bespokegateway.core.annotation.ExcelMapping;
+import com.shkpr.service.bespokegateway.core.constants.CustomerBillingType;
+import com.shkpr.service.bespokegateway.core.constants.CustomerMeterType;
+import com.shkpr.service.bespokegateway.core.constants.CustomerMeteringType;
+import com.shkpr.service.bespokegateway.core.constants.CustomerPublicServiceType;
+import lombok.Data;
+import org.locationtech.jts.geom.Geometry;
+
+import java.time.LocalDateTime;
+
+/**
+ * 营销用户表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class CustomerInfo {
+    /**
+     * 主键ID
+     */
+    private Integer id;
+
+    /**
+     * 用户编号
+     */
+    @ExcelMapping("用户编号")
+    private String code;
+
+    /**
+     * 户主名
+     */
+    @ExcelMapping("户主名")
+    private String name;
+
+    /**
+     * 用户地址
+     */
+    @ExcelMapping("用户地址")
+    private String address;
+
+    /**
+     * 水表口径
+     */
+    @ExcelMapping("水表口径")
+    private Short caliber;
+
+    /**
+     * 用水性质
+     */
+    @ExcelMapping("用水性质")
+    private String natureName;
+
+    /**
+     * 加压等级(名称)
+     */
+    @ExcelMapping("加压等级")
+    private String pressName;
+
+    /**
+     * 水表用途
+     */
+    @ExcelMapping("水表用途")
+    private String usedTypeName;
+
+    /**
+     * 水表编号
+     */
+    @ExcelMapping("水表编号")
+    private String stampInfo;
+
+    /**
+     * 水表类型:0机械表,1远传水表
+     */
+    @ExcelMapping(value = "表具类型", enumClass = CustomerMeterType.class)
+    private Short meterType;
+
+    /**
+     * 开户时间
+     */
+    @ExcelMapping("开户时间")
+    private LocalDateTime createdAt;
+
+    /**
+     * 换表时间
+     */
+    @ExcelMapping("换表时间")
+    private LocalDateTime updatedAt;
+
+    /**
+     * 用户手机号
+     */
+    @ExcelMapping("用户手机号")
+    private String mobile;
+
+    /**
+     * 用户状态名
+     */
+    @ExcelMapping("用户状态名")
+    private String statusName;
+
+    /**
+     * 用户状态ID
+     */
+    @ExcelMapping("用户状态ID")
+    private Short statusCode;
+
+    /**
+     * 抄表周期ID
+     */
+    @ExcelMapping("抄表周期ID")
+    private Short readCycle;
+
+    /**
+     * 抄表周期名
+     */
+    @ExcelMapping("抄表周期名")
+    private String readCycleName;
+
+    /**
+     * 抄表人员
+     */
+    @ExcelMapping("抄表人员")
+    private String readerName;
+
+    /**
+     * 抄表册
+     */
+    @ExcelMapping("抄表册")
+    private String readBookName;
+
+    /**
+     * 抄表册类型
+     */
+    @ExcelMapping("抄表册类型")
+    private Short readBookType;
+
+    /**
+     * 水表GIS经纬度
+     */
+    @ExcelMapping("水表GIS经纬度")
+    private String gis;
+
+    /**
+     * 水表GIS空间几何信息
+     */
+    private Geometry geomGis;
+
+    /**
+     * 公共用水类型:0非公共用水,1公共用水
+     */
+    @ExcelMapping(value = "公共用水类型", enumClass = CustomerPublicServiceType.class)
+    private Short publicServType;
+
+    /**
+     * 计费类型:0计费的,1免费的
+     */
+    @ExcelMapping(value = "是否计费", enumClass = CustomerBillingType.class)
+    private Short billingType;
+
+    /**
+     * 未计量类型:0计量的,1未计量的
+     */
+    @ExcelMapping(value = "是否计量", enumClass = CustomerMeteringType.class)
+    private Short meteringType;
+}

+ 89 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/CustomerMeterRead.java

@@ -0,0 +1,89 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import com.shkpr.service.bespokegateway.core.annotation.ExcelMapping;
+import com.shkpr.service.bespokegateway.core.constants.CustomerReadType;
+import lombok.Data;
+
+import java.time.LocalDate;
+import java.time.LocalDateTime;
+
+/**
+ * 营销抄表数据表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class CustomerMeterRead {
+    /**
+     * 主键ID
+     */
+    private Long id;
+
+    /**
+     * 用户编码
+     */
+    @ExcelMapping("用户编号")
+    private String code;
+
+    /**
+     * 记录日期
+     */
+    private LocalDate forDate;
+
+    /**
+     * 抄见量
+     */
+    @ExcelMapping("抄见量(本月用水量)")
+    private Float readValue;
+
+    /**
+     * 抄表周期:0无抄表周期信息,1月抄,2单月抄,3双月抄,4季度上抄,5季度中抄,6季度下抄,7半年抄,8一月多抄
+     */
+    @ExcelMapping(value = "抄表周期", enumClass = CustomerReadType.class)
+    private Short readType;
+
+    /**
+     * 抄表时间
+     */
+    @ExcelMapping("抄表时间")
+    private LocalDateTime readDate;
+
+    /**
+     * 计算数据
+     */
+    private Float calcValue;
+
+    /**
+     * 参数1
+     */
+    private String param1;
+
+    /**
+     * 参数2
+     */
+    private String param2;
+
+    /**
+     * 抄表员
+     */
+    private String reader;
+
+    /**
+     * 抄表员姓名
+     */
+    @ExcelMapping("抄表人")
+    private String readerName;
+
+    /**
+     * 抄表本名称
+     */
+    @ExcelMapping("抄表册")
+    private String readbookName;
+
+    /**
+     * 抄表数量
+     */
+    @ExcelMapping("抄表止码")
+    private Float readAmount;
+}

+ 95 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceKind.java

@@ -0,0 +1,95 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.Data;
+import org.springframework.format.annotation.DateTimeFormat;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备种类
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class DeviceKind {
+    /**
+     * 主键ID
+     */
+    private Integer id;
+
+    /**
+     * 全局唯一id
+     */
+    private String uid;
+
+    /**
+     * 设备种类名称
+     */
+    private String name;
+
+    /**
+     * 指定种类下的默认特征参数,取值格式为json串
+     */
+    private String feature;
+
+    /**
+     * 参数1
+     */
+    private String param1;
+
+    /**
+     * 参数2
+     */
+    private String param2;
+
+    /**
+     * 备注说明
+     */
+    private String remark;
+
+    /**
+     * 设备种类唯一标识符
+     */
+    private String key;
+
+    /**
+     * 对应gis中的点图层类型列表JSON串
+     */
+    private String gisType;
+
+    /**
+     * 标签
+     */
+    private String tags;
+
+    /**
+     * 对应的调度预案事件类型
+     */
+    private Integer warn;
+
+    /**
+     * 必须的采集字段列表
+     */
+    private String musts;
+
+    /**
+     * 对应influxdb中的表名
+     */
+    private String measurement;
+
+    /**
+     * 创建时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh_CN", timezone = "Asia/Shanghai")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime createTime;
+
+    /**
+     * 更新时间
+     */
+    @JsonFormat(pattern = "yyyy-MM-dd HH:mm:ss", locale = "zh_CN", timezone = "Asia/Shanghai")
+    @DateTimeFormat(pattern = "yyyy-MM-dd HH:mm:ss")
+    private LocalDateTime updateTime;
+}

+ 47 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceSequences.java

@@ -0,0 +1,47 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.relational.core.mapping.Table;
+
+import java.time.LocalDate;
+
+/**
+ * 设备序列表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Table("DEVICE_SEQUENCES")
+public class DeviceSequences {
+    /**
+     * 主键
+     */
+    @Id
+    private Long id;
+    /**
+     * 区号
+     */
+    private Integer areaCode;
+    /**
+     * 种类
+     */
+    private Integer kind;
+    /**
+     * 时间
+     */
+    private LocalDate date;
+    /**
+     * 序列
+     */
+    private Integer seq;
+
+    public static DeviceSequences of(Integer areaCode, Integer kind, LocalDate date, Integer seq) {
+        return new DeviceSequences(null, areaCode, kind, date, seq);
+    }
+}

+ 33 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/DeviceTags.java

@@ -0,0 +1,33 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import org.springframework.data.annotation.Id;
+import org.springframework.data.relational.core.mapping.Table;
+
+/**
+ * 设备标签表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+@Table("DEVICE_TAGS")
+public class DeviceTags {
+    /**
+     * 主键
+     */
+    @Id
+    private Long id;
+    /**
+     * 所属平台
+     */
+    private String platform;
+    /**
+     * 标签
+     */
+    private String tag;
+}

+ 54 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/FunctionInfo.java

@@ -0,0 +1,54 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 职能信息表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class FunctionInfo {
+    /**
+     * 主键
+     */
+    private Long id;
+
+    /**
+     * 职能唯一ID
+     */
+    private String uid;
+
+    /**
+     * 职能名称
+     */
+    private String name;
+
+    /**
+     * 相关描述
+     */
+    private String remark;
+
+    /**
+     * 预留参数1
+     */
+    private String param1;
+
+    /**
+     * 预留参数2
+     */
+    private String param2;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 修改时间
+     */
+    private LocalDateTime updateTime;
+}

+ 10 - 2
custom-gateway-zydma/src/main/java/com/shkpr/service/customgateway/zydma/domain/PersonnelInfo.java

@@ -1,8 +1,10 @@
-package com.shkpr.service.customgateway.zydma.domain;
+package com.shkpr.service.bespokegateway.core.domain.po;
 
+import com.fasterxml.jackson.annotation.JsonIgnore;
 import lombok.Data;
 
 import java.time.LocalDateTime;
+import java.util.List;
 
 /**
  * 用户信息表
@@ -15,6 +17,7 @@ public class PersonnelInfo {
     /**
      * 用户uid
      */
+    @JsonIgnore
     private String uid;
     /**
      * 登录账号
@@ -59,7 +62,7 @@ public class PersonnelInfo {
     /**
      * 用户职位uid
      */
-    private String postId;
+    private List<String> postId;
     /**
      * 当前状态:-1 -- 注销; 0 -- 禁用;1 -- 启用
      */
@@ -67,21 +70,26 @@ public class PersonnelInfo {
     /**
      * 参数1
      */
+    @JsonIgnore
     private String param1;
     /**
      * 参数2
      */
+    @JsonIgnore
     private String param2;
     /**
      * 创建时间
      */
+    @JsonIgnore
     private LocalDateTime createTime;
     /**
      * 更新时间
      */
+    @JsonIgnore
     private LocalDateTime updateTime;
     /**
      * 所属组织机构
      */
+    @JsonIgnore
     private String org;
 }

+ 67 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/domain/po/TypeDefine.java

@@ -0,0 +1,67 @@
+package com.shkpr.service.bespokegateway.core.domain.po;
+
+import lombok.Data;
+
+/**
+ * 自定义类型集合表
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Data
+public class TypeDefine {
+    /**
+     *
+     */
+    private Integer id;
+
+    /**
+     * 自定义类型中的唯一标识符
+     */
+    private String key;
+
+    /**
+     * 自定义类型所属种类;0 -- 设备标记字段;1 -- 分区主类型; 2 -- 分区子类型; 3 -- 用水类型;4 -- 站点类型
+     */
+    private Short kind;
+
+    /**
+     * 自定义类型名称
+     */
+    private String name;
+
+    /**
+     * 备注说明
+     */
+    private String remark;
+
+    /**
+     * 参数1
+     */
+    private String param1;
+
+    /**
+     * 参数2
+     */
+    private String param2;
+
+    /**
+     * 排列顺序
+     */
+    private Short ordering;
+
+    /**
+     *
+     */
+    private String alias;
+
+    /**
+     * 性质用途
+     */
+    private String nature;
+
+    /**
+     * 特性
+     */
+    private String feature;
+}

+ 172 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/exception/GlobalSelfExceptionHandler.java

@@ -0,0 +1,172 @@
+package com.shkpr.service.bespokegateway.core.exception;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.bespokegateway.core.constants.ResponseCode;
+import com.shkpr.service.bespokegateway.core.domain.ResultResponse;
+import org.apache.catalina.connector.ClientAbortException;
+import org.springframework.beans.ConversionNotSupportedException;
+import org.springframework.beans.TypeMismatchException;
+import org.springframework.http.converter.HttpMessageNotReadableException;
+import org.springframework.http.converter.HttpMessageNotWritableException;
+import org.springframework.security.access.AccessDeniedException;
+import org.springframework.web.HttpMediaTypeNotAcceptableException;
+import org.springframework.web.HttpRequestMethodNotSupportedException;
+import org.springframework.web.bind.MissingServletRequestParameterException;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import javax.servlet.http.HttpServletRequest;
+import java.io.IOException;
+
+/**
+ * Controller的全局异常捕获类
+ * 前置异常增强(在Controller的方法调用之前若有异常进行捕获),处理结果以JSON的形式返回给客服端
+ * 异常增强类型:NullPointerException,RunTimeException,ClassCastException,
+ *          NoSuchMethodException,IOException,IndexOutOfBoundsException
+ *          以及springmvc自定义异常等,如下:
+ * SpringMVC自定义异常对应的status code
+ * Exception                       HTTP Status Code
+ * ConversionNotSupportedException         500 (Internal Server Error)
+ * HttpMessageNotWritableException         500 (Internal Server Error)
+ * HttpMediaTypeNotSupportedException      415 (Unsupported Media Type)
+ * HttpMediaTypeNotAcceptableException     406 (Not Acceptable)
+ * HttpRequestMethodNotSupportedException  405 (Method Not Allowed)
+ * NoSuchRequestHandlingMethodException    404 (Not Found)
+ * TypeMismatchException                   400 (Bad Request)
+ * HttpMessageNotReadableException         400 (Bad Request)
+ * MissingServletRequestParameterException 400 (Bad Request)
+ *
+ */
+@ControllerAdvice
+public class GlobalSelfExceptionHandler {
+
+    public static ResultResponse<String> createResParam(String strCode, String strMsg) {
+        ResultResponse<String> resResult = new ResultResponse<>();
+        resResult.setTimestamp(System.currentTimeMillis());
+        resResult.setRescode(strCode);
+        resResult.setResmsg(strMsg);
+        resResult.setResdata("");
+        return resResult;
+    }
+
+    public static ResultResponse<String> createResParam(String strCode, String strMsg, String strData) {
+        ResultResponse<String> resResult = new ResultResponse<>();
+        resResult.setTimestamp(System.currentTimeMillis());
+        resResult.setRescode(strCode);
+        resResult.setResmsg(strMsg);
+        resResult.setResdata((strData == null) ? "" : strData);
+        return resResult;
+    }
+
+    //自定义异常
+    @ExceptionHandler(value = SelfException.class)
+    @ResponseBody
+    public ResultResponse<String> jsonErrorHandler(HttpServletRequest req, SelfException ex) throws Exception {
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_WARN
+                , "Self Exception"
+                , "GlobalSelfExceptionHandler"
+                , String.format("url:{%s}, code(%s):{%s}", req.getRequestURI(), ex.getStrErrorCode(), ex.getMessage()));
+        return createResParam(ex.getStrErrorCode(), ex.getMessage(), ex.getStrErrorData());
+    }
+
+    //访问异常
+    @ExceptionHandler(AccessDeniedException.class)
+    @ResponseBody
+    public ResultResponse<String> accessDeniedExceptionHandler(RuntimeException runtimeException) {
+        LogPrintMgr.getInstance().printExceptionObject(LogLevelFlag.LOG_ERROR, runtimeException);
+        return createResParam(ResponseCode.STATUS_ACCESS_DENY.getCode() + "", ResponseCode.STATUS_ACCESS_DENY.getMessage());
+    }
+
+    //运行时异常
+    @ExceptionHandler(RuntimeException.class)
+    @ResponseBody
+    public ResultResponse<String> runtimeExceptionHandler(RuntimeException runtimeException) {
+        LogPrintMgr.getInstance().printExceptionObject(LogLevelFlag.LOG_ERROR, runtimeException);
+        return createResParam(ResponseCode.STATUS_SERVER_RUN_ERROR.getCode() + "", ResponseCode.STATUS_SERVER_RUN_ERROR.getMessage());
+    }
+
+    //空指针异常
+    @ExceptionHandler(NullPointerException.class)
+    @ResponseBody
+    public ResultResponse<String> nullPointerExceptionHandler(NullPointerException ex) {
+        LogPrintMgr.getInstance().printExceptionObject(LogLevelFlag.LOG_ERROR, ex);
+        return createResParam(ResponseCode.STATUS_NULL_POINT_EXCEPTION.getCode() + "", ResponseCode.STATUS_NULL_POINT_EXCEPTION.getMessage());
+    }
+
+    //类型转换异常
+    @ExceptionHandler(ClassCastException.class)
+    @ResponseBody
+    public ResultResponse<String> classCastExceptionHandler(ClassCastException ex) {
+        LogPrintMgr.getInstance().printExceptionObject(LogLevelFlag.LOG_ERROR, ex);
+        return createResParam(ResponseCode.STATUS_ERROR_DATA_TYPE.getCode() + "", ResponseCode.STATUS_ERROR_DATA_TYPE.getMessage());
+    }
+
+    //IO异常
+    @ExceptionHandler({IOException.class, ClientAbortException.class})
+    @ResponseBody
+    public ResultResponse<String> iOExceptionHandler() {
+        return createResParam(ResponseCode.STATUS_IO_EXCEPTION.getCode() + "", ResponseCode.STATUS_IO_EXCEPTION.getMessage());
+    }
+
+    //未知方法异常
+    @ExceptionHandler(NoSuchMethodException.class)
+    @ResponseBody
+    public ResultResponse<String> noSuchMethodExceptionHandler(NoSuchMethodException ex) {
+        return createResParam(ResponseCode.STATUS_NO_SUCH_METHOD.getCode() + "", ResponseCode.STATUS_NO_SUCH_METHOD.getMessage());
+    }
+
+    //数组越界异常
+    @ExceptionHandler(IndexOutOfBoundsException.class)
+    @ResponseBody
+    public ResultResponse<String> indexOutOfBoundsExceptionHandler(IndexOutOfBoundsException ex) {
+        LogPrintMgr.getInstance().printExceptionObject(LogLevelFlag.LOG_ERROR, ex);
+        return createResParam(ResponseCode.STATUS_INDEX_OUT_OF_BOUNDS.getCode() + "", ResponseCode.STATUS_INDEX_OUT_OF_BOUNDS.getMessage());
+    }
+
+    //400错误
+    @ExceptionHandler({HttpMessageNotReadableException.class})
+    @ResponseBody
+    public ResultResponse<String> requestNotReadable(HttpMessageNotReadableException ex) {
+        return createResParam(ResponseCode.STATUS_BAD_REQUEST.getCode() + "", "Request not readable, please check [URI or Param].");
+    }
+
+    //400错误
+    @ExceptionHandler({TypeMismatchException.class})
+    @ResponseBody
+    public ResultResponse<String> requestTypeMismatch(TypeMismatchException ex) {
+        return createResParam(ResponseCode.STATUS_BAD_REQUEST.getCode() + "", "Type mismatch exception, please check [URI or Param].");
+    }
+
+    //400错误
+    @ExceptionHandler({MissingServletRequestParameterException.class})
+    @ResponseBody
+    public ResultResponse<String> requestMissingServletRequest(MissingServletRequestParameterException ex) {
+        return createResParam(ResponseCode.STATUS_BAD_REQUEST.getCode() + "", "Missing servlet request, please check [URI or Param].");
+    }
+
+    //405错误
+    @ExceptionHandler({HttpRequestMethodNotSupportedException.class})
+    @ResponseBody
+    public ResultResponse<String> request405() {
+        return createResParam(ResponseCode.STATUS_METHOD_NOT_ALLOWED.getCode() + ""
+                , ResponseCode.STATUS_METHOD_NOT_ALLOWED.getMessage());
+    }
+
+    //406错误
+    @ExceptionHandler({HttpMediaTypeNotAcceptableException.class})
+    @ResponseBody
+    public ResultResponse<String> request406() {
+        return createResParam(ResponseCode.STATUS_HTTP_TYPE_NOT_ACCEPTABLE.getCode() + ""
+                , ResponseCode.STATUS_HTTP_TYPE_NOT_ACCEPTABLE.getMessage() + "Please check [URI or Param].");
+    }
+
+    //500错误
+    @ExceptionHandler({ConversionNotSupportedException.class, HttpMessageNotWritableException.class})
+    @ResponseBody
+    public ResultResponse<String> server500(RuntimeException runtimeException) {
+        return createResParam(ResponseCode.STATUS_HTTP_TYPE_NOT_ACCEPTABLE.getCode() + ""
+                , ResponseCode.STATUS_HTTP_TYPE_NOT_ACCEPTABLE.getMessage() + "Please check [URI or Param].");
+    }
+}

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/exception/SelfAuthFilterException.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.exception;
+package com.shkpr.service.bespokegateway.core.exception;
 
 public class SelfAuthFilterException extends Exception {
     private int nErrorCode;

+ 25 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/exception/SelfException.java

@@ -0,0 +1,25 @@
+package com.shkpr.service.bespokegateway.core.exception;
+
+
+public class SelfException extends Exception{
+    private String mStrErrorCode = "";
+    private String mStrErrorData = "";
+    public SelfException(String strErrorCode, String strErrorMsg){
+        super(strErrorMsg);
+        this.mStrErrorCode = strErrorCode;
+    }
+
+    public SelfException(String strErrorCode, String strErrorMsg, String strErrorData){
+        super(strErrorMsg);
+        this.mStrErrorCode = strErrorCode;
+        this.mStrErrorData = strErrorData;
+    }
+
+    public String getStrErrorCode() {
+        return mStrErrorCode;
+    }
+
+    public String getStrErrorData() {
+        return mStrErrorData;
+    }
+}

+ 106 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/filter/AccessFilter.java

@@ -0,0 +1,106 @@
+package com.shkpr.service.bespokegateway.core.filter;
+
+import com.shkpr.service.bespokegateway.core.constants.AccessMetadata;
+import com.shkpr.service.bespokegateway.core.constants.AccessMetadata.ResponseCode;
+import com.shkpr.service.bespokegateway.core.domain.AccessToken;
+import com.shkpr.service.bespokegateway.core.domain.po.AccessKeys;
+import com.shkpr.service.bespokegateway.core.properties.SecurityProperties;
+import com.shkpr.service.bespokegateway.core.service.AccessKeysService;
+import com.shkpr.service.bespokegateway.core.utils.AccessUtil;
+import com.shkpr.service.bespokegateway.core.utils.SecurityUtil;
+import lombok.NonNull;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.commons.lang3.math.NumberUtils;
+import org.springframework.http.HttpMethod;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.time.Instant;
+import java.time.temporal.ChronoUnit;
+import java.util.Collections;
+import java.util.Map;
+import java.util.stream.Collectors;
+
+/**
+ * 接入过滤器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+public class AccessFilter extends OncePerRequestFilter {
+    private final SecurityProperties securityProperties;
+    private final AccessKeysService accessKeysService;
+
+    public AccessFilter(SecurityProperties securityProperties, AccessKeysService accessKeysService) {
+        this.securityProperties = securityProperties;
+        this.accessKeysService = accessKeysService;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain chain) throws IOException, ServletException {
+        //忽略非get请求
+        if (!request.getMethod().equals(HttpMethod.GET.name())) {
+            chain.doFilter(request, response);
+            return;
+        }
+        //如果忽略列表包含该url,则直接放行
+        if (securityProperties.getPermitPattern().stream()
+                .anyMatch(s -> new AntPathRequestMatcher(s).matches(request))) {
+            chain.doFilter(request, response);
+            return;
+        }
+        //已登陆,则直接放行
+        if (SecurityUtil.isAuthenticated()) {
+            chain.doFilter(request, response);
+            return;
+        }
+        //匹配接入请求
+        if (!new AntPathRequestMatcher(AccessMetadata.ANT_PATTERN).matches(request)) {
+            chain.doFilter(request, response);
+            return;
+        }
+
+        //请求头访问密钥
+        String accessKey = request.getHeader(AccessMetadata.Headers.ACCESS_KEY);
+        if (StringUtils.isBlank(accessKey)) AccessUtil.writeResponseCode(response, ResponseCode.ACCESS_KEY_MISS);
+        //访问密钥
+        AccessKeys accessKeys = accessKeysService.findByAccessKey(accessKey);
+        if (accessKeys == null || accessKeys.getSecurityKey() == null)
+            AccessUtil.writeResponseCode(response, ResponseCode.ACCESS_KEY_INVALID);
+        //请求头时间戳
+        String timestampStr = request.getHeader(AccessMetadata.Headers.TIMESTAMP);
+        if (StringUtils.isBlank(timestampStr)) AccessUtil.writeResponseCode(response, ResponseCode.TIMESTAMP_MISS);
+        if (!NumberUtils.isDigits(timestampStr)) AccessUtil.writeResponseCode(response, ResponseCode.TIMESTAMP_INVALID);
+        //时间戳
+        long timestamp = Long.parseLong(timestampStr);
+        if (ChronoUnit.MINUTES.between(Instant.ofEpochMilli(timestamp), Instant.now()) > 5 ||
+                ChronoUnit.MINUTES.between(Instant.ofEpochMilli(timestamp), Instant.now()) < -1)
+            AccessUtil.writeResponseCode(response, ResponseCode.TIMESTAMP_EXPIRED);
+        //签名
+        String signature = request.getHeader(AccessMetadata.Headers.SIGNATURE);
+        if (StringUtils.isBlank(signature)) AccessUtil.writeResponseCode(response, ResponseCode.SIGNATURE_MISS);
+        //参数
+        Map<String, String> params = request.getParameterMap().entrySet().stream()
+                .collect(Collectors.toMap(Map.Entry::getKey, e -> e.getValue()[0]));
+
+        //签名验证
+        if (accessKeys != null && accessKeys.getSecurityKey() != null) {
+            boolean matched = AccessUtil.matchesSignature(params, timestamp, accessKeys.getSecurityKey(), signature);
+            //签发token
+            if (matched)
+                SecurityUtil.setAuthentication(AccessToken.authenticated(accessKey, Collections.singletonList(new SimpleGrantedAuthority(AccessMetadata.AUTHORITY))));
+            else AccessUtil.writeResponseCode(response, ResponseCode.SIGNATURE_INVALID);
+        }
+
+        chain.doFilter(request, response);
+    }
+}

+ 7 - 7
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/filter/JWTControllerCheck.java

@@ -1,15 +1,15 @@
-package com.shkpr.service.customgateway.core.filter;
+package com.shkpr.service.bespokegateway.core.filter;
 
 
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
 import com.global.base.tools.FastJsonUtil;
-import com.shkpr.service.customgateway.core.constants.LogFlagBusiType;
-import com.shkpr.service.customgateway.core.constants.ResponseCode;
-import com.shkpr.service.customgateway.core.storage.GlobalData;
-import com.shkpr.service.customgateway.core.utils.CommTool;
-import com.shkpr.service.customgateway.core.utils.RequestUtil;
-import com.shkpr.service.customgateway.core.utils.ResponseUtil;
+import com.shkpr.service.bespokegateway.core.constants.LogFlagBusiType;
+import com.shkpr.service.bespokegateway.core.constants.ResponseCode;
+import com.shkpr.service.bespokegateway.core.storage.GlobalData;
+import com.shkpr.service.bespokegateway.core.utils.CommTool;
+import com.shkpr.service.bespokegateway.core.utils.RequestUtil;
+import com.shkpr.service.bespokegateway.core.utils.ResponseUtil;
 
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;

+ 15 - 10
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/filter/TokenFilter.java

@@ -1,20 +1,20 @@
-package com.shkpr.service.customgateway.core.filter;
+package com.shkpr.service.bespokegateway.core.filter;
 
 import com.global.base.log.LogLevelFlag;
 import com.global.base.log.LogPrintMgr;
-import com.shkpr.service.customgateway.core.constants.LogFlagBusiType;
-import com.shkpr.service.customgateway.core.constants.ResponseCode;
-import com.shkpr.service.customgateway.core.properties.GlobalProperties;
-import com.shkpr.service.customgateway.core.properties.SecurityProperties;
-import com.shkpr.service.customgateway.core.utils.ResponseUtil;
-import com.shkpr.service.customgateway.core.utils.SecurityUtil;
-import com.shkpr.service.customgateway.core.utils.TokenUtil;
+import com.shkpr.service.bespokegateway.core.constants.LogFlagBusiType;
+import com.shkpr.service.bespokegateway.core.constants.ResponseCode;
+import com.shkpr.service.bespokegateway.core.properties.GlobalProperties;
+import com.shkpr.service.bespokegateway.core.properties.SecurityProperties;
+import com.shkpr.service.bespokegateway.core.utils.ResponseUtil;
+import com.shkpr.service.bespokegateway.core.utils.SecurityUtil;
+import com.shkpr.service.bespokegateway.core.utils.TokenUtil;
 import lombok.NonNull;
 import org.springframework.security.authentication.AccountExpiredException;
 import org.springframework.security.authentication.BadCredentialsException;
 import org.springframework.security.authentication.CredentialsExpiredException;
 import org.springframework.security.core.Authentication;
-import org.springframework.util.AntPathMatcher;
+import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
 import org.springframework.web.filter.OncePerRequestFilter;
 
 import javax.servlet.FilterChain;
@@ -47,7 +47,12 @@ public class TokenFilter extends OncePerRequestFilter {
     protected void doFilterInternal(@NonNull HttpServletRequest request, @NonNull HttpServletResponse response, @NonNull FilterChain chain) throws IOException, ServletException {
         //如果忽略列表包含该url,则直接放行
         if (securityProperties.getPermitPattern().stream()
-                .anyMatch(s -> new AntPathMatcher().match(String.format("%s%s", request.getContextPath(), s), request.getRequestURI()))) {
+                .anyMatch(s -> new AntPathRequestMatcher(s).matches(request))) {
+            chain.doFilter(request, response);
+            return;
+        }
+        //已登陆,则直接放行
+        if (SecurityUtil.isAuthenticated()) {
             chain.doFilter(request, response);
             return;
         }

+ 109 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomMultiLineStringTypeHandlePg.java

@@ -0,0 +1,109 @@
+package com.shkpr.service.bespokegateway.core.io;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.shkpr.service.bespokegateway.core.utils.GeomUtil;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+import org.locationtech.jts.geom.MultiLineString;
+
+import java.io.IOException;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * 地理多线类型处理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@MappedTypes({MultiLineString.class})
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class GeomMultiLineStringTypeHandlePg extends BaseTypeHandler<MultiLineString> {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 解析
+     *
+     * @param lineStr 值
+     * @return 多线
+     * @throws SQLException sql异常
+     */
+    public static MultiLineString parseString(String lineStr) throws SQLException {
+        //非空校验
+        if (lineStr == null || lineStr.isEmpty()) return null;
+        try {
+            //序列化
+            double[][][] array = objectMapper.readValue(lineStr, double[][][].class);
+            //构建线
+            return GeomUtil.ofArray(array);
+        } catch (IOException e) {
+            throw new SQLException("多线格式无效: " + lineStr);
+        }
+    }
+
+    /**
+     * 从多线对象转数据库字符串
+     *
+     * @param multiLineString 多线
+     * @return 字符串
+     * @throws SQLException sql异常
+     */
+    public static String toString(MultiLineString multiLineString) throws SQLException {
+        if (multiLineString == null) return null;
+        try {
+            //转数组
+            double[][][] array = GeomUtil.toArray(multiLineString);
+            //反序列化
+            return objectMapper.writeValueAsString(array);
+        } catch (IOException e) {
+            throw new SQLException("多线格式无效: " + multiLineString);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, MultiLineString multiLineString, JdbcType jdbcType)
+            throws SQLException {
+        if (multiLineString != null && multiLineString.getCoordinates() != null) {
+            //将点序列化化为字符串
+            String lineStr = toString(multiLineString);
+            if (lineStr != null) {
+                ps.setString(i, lineStr);
+                return;
+            }
+        }
+        //处理空值
+        ps.setNull(i, JdbcType.VARCHAR.TYPE_CODE);
+
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public MultiLineString getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        return rs.wasNull() ? null : parseString(rs.getString(columnName));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public MultiLineString getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return rs.wasNull() ? null : parseString(rs.getString(columnIndex));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public MultiLineString getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return cs.wasNull() ? null : parseString(cs.getString(columnIndex));
+    }
+}

+ 120 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomPointTypeHandlePg.java

@@ -0,0 +1,120 @@
+package com.shkpr.service.bespokegateway.core.io;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.shkpr.service.bespokegateway.core.utils.GeomUtil;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+import org.locationtech.jts.geom.Coordinate;
+import org.locationtech.jts.geom.GeometryFactory;
+import org.locationtech.jts.geom.Point;
+import org.locationtech.jts.geom.PrecisionModel;
+
+import java.io.IOException;
+import java.sql.*;
+
+/**
+ * 地理点类型处理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@MappedTypes({Point.class})
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class GeomPointTypeHandlePg extends BaseTypeHandler<Point> {
+    private static final GeometryFactory factory = new GeometryFactory(new PrecisionModel(), 4490);
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 从数据库字符串解析为Point对象
+     *
+     * @param pointStr 值
+     * @return 点
+     * @throws SQLException sql异常
+     */
+    public static Point parseString(String pointStr) throws SQLException {
+        //非空校验
+        if (pointStr == null || pointStr.isEmpty()) return null;
+        try {
+            //序列化
+            double[] array = objectMapper.readValue(pointStr, double[].class);
+            //判断格式
+            if (array.length == 2) {
+                //转坐标
+                Coordinate coordinate = GeomUtil.ofArray(array);
+                //构建点
+                return factory.createPoint(coordinate);
+            }
+        } catch (IOException e) {
+            throw new SQLException("点格式无效: " + pointStr);
+        }
+        throw new SQLException("点格式无效: " + pointStr);
+    }
+
+    /**
+     * 从Point对象转数据库字符串
+     *
+     * @param point 点
+     * @return 字符串
+     * @throws SQLException sql异常
+     */
+    public static String toString(Point point) throws SQLException {
+        if (point == null) return null;
+        //获取坐标
+        Coordinate coordinate = point.getCoordinate();
+        if (coordinate == null) return null;
+        try {
+            //转数组
+            double[] array = GeomUtil.toArray(coordinate);
+            //反序列化
+            return objectMapper.writeValueAsString(array);
+        } catch (IOException e) {
+            throw new SQLException("点格式无效: " + point);
+        }
+    }
+
+    /**
+     * 将Java类型Point写入数据库
+     */
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, Point point, JdbcType jdbcType) throws SQLException {
+        if (point != null && point.getCoordinate() != null) {
+            //将点序列化化为字符串
+            String pointStr = toString(point);
+            if (pointStr != null) {
+                ps.setString(i, pointStr);
+                return;
+            }
+        }
+        //处理空值
+        ps.setNull(i, Types.VARCHAR);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Point getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        String pointStr = rs.getString(columnName);
+        return rs.wasNull() ? null : parseString(pointStr);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Point getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        String pointStr = rs.getString(columnIndex);
+        return rs.wasNull() ? null : parseString(pointStr);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public Point getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        String pointStr = cs.getString(columnIndex);
+        return cs.wasNull() ? null : parseString(pointStr);
+    }
+}

+ 108 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/GeomTypeHandlePg.java

@@ -0,0 +1,108 @@
+package com.shkpr.service.bespokegateway.core.io;
+
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+import org.locationtech.jts.geom.Geometry;
+import org.locationtech.jts.geom.MultiLineString;
+import org.locationtech.jts.geom.Point;
+
+import java.io.IOException;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+
+/**
+ * 地理类型处理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@MappedTypes({Geometry.class})
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class GeomTypeHandlePg extends BaseTypeHandler<Geometry> {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 解析
+     *
+     * @param geomStr 值
+     * @return 地理对象
+     * @throws SQLException sql异常
+     */
+    public static Geometry parseGeom(String geomStr) throws SQLException {
+        //非空校验
+        if (geomStr == null || geomStr.isEmpty()) return null;
+        try {
+            JsonNode jsonNode = objectMapper.readTree(geomStr);
+            if (jsonNode.isArray() && !jsonNode.isEmpty()) {
+                //点处理
+                if (jsonNode.get(0).isNumber() && jsonNode.get(1).isNumber()) {
+                    return GeomPointTypeHandlePg.parseString(geomStr);
+                }
+                //线处理
+                else if (jsonNode.get(0).isArray()) {
+                    return GeomMultiLineStringTypeHandlePg.parseString(geomStr);
+                }
+            }
+
+        } catch (IOException e) {
+            throw new SQLException("地理数据格式无效: " + geomStr);
+        }
+        throw new SQLException("地理数据格式无效: " + geomStr);
+    }
+
+    /**
+     * 从Geometry对象转数据库字符串
+     *
+     * @param geometry 点
+     * @return 字符串
+     * @throws SQLException sql异常
+     */
+    public static String toGeomString(Geometry geometry) throws SQLException {
+        if (geometry instanceof Point) {
+            Point point = (Point) geometry;
+            //转字符串
+            return GeomPointTypeHandlePg.toString(point);
+
+        } else if (geometry instanceof MultiLineString) {
+            MultiLineString multiLineString = (MultiLineString) geometry;
+            //转字符串
+            return GeomMultiLineStringTypeHandlePg.toString(multiLineString);
+        }
+        return null;
+    }
+
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, Geometry geometry, JdbcType jdbcType) throws SQLException {
+        if (geometry != null && geometry.getCoordinate() != null) {
+            //将geom序列化化为字符串
+            String geomString = toGeomString(geometry);
+            if (geomString != null) {
+                ps.setString(i, geomString);
+                return;
+            }
+        }
+        //处理空值
+        ps.setNull(i, JdbcType.VARCHAR.TYPE_CODE);
+    }
+
+    @Override
+    public Geometry getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        return rs.wasNull() ? null : parseGeom(rs.getString(columnName));
+    }
+
+    @Override
+    public Geometry getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return rs.wasNull() ? null : parseGeom(rs.getString(columnIndex));
+    }
+
+    @Override
+    public Geometry getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return cs.wasNull() ? null : parseGeom(cs.getString(columnIndex));
+    }
+}

+ 107 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/io/StringListTypeHandle.java

@@ -0,0 +1,107 @@
+package com.shkpr.service.bespokegateway.core.io;
+
+import com.fasterxml.jackson.core.type.TypeReference;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.type.BaseTypeHandler;
+import org.apache.ibatis.type.JdbcType;
+import org.apache.ibatis.type.MappedJdbcTypes;
+import org.apache.ibatis.type.MappedTypes;
+
+import java.io.IOException;
+import java.sql.CallableStatement;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.util.List;
+
+/**
+ * 字符串数组类型处理器
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@MappedTypes({List.class})
+@MappedJdbcTypes(JdbcType.VARCHAR)
+public class StringListTypeHandle extends BaseTypeHandler<List<String>> {
+    private static final ObjectMapper objectMapper = new ObjectMapper();
+
+    /**
+     * 解析字符串
+     *
+     * @param str 字符串
+     * @return 数据
+     * @throws SQLException sql异常
+     */
+    public static List<String> parseString(String str) throws SQLException {
+        //非空校验
+        if (StringUtils.isBlank(str)) return null;
+        try {
+            //序列化
+            return objectMapper.readValue(str, new TypeReference<List<String>>() {
+            });
+        } catch (IOException e) {
+            throw new SQLException("字符串数组格式无效: " + str);
+        }
+    }
+
+    /**
+     * 转字符串
+     *
+     * @param data 数据
+     * @return 字符串
+     * @throws SQLException sql异常
+     */
+    public static String toString(List<String> data) throws SQLException {
+        if (data == null) return null;
+        try {
+            //反序列化
+            return objectMapper.writeValueAsString(data);
+        } catch (IOException e) {
+            throw new SQLException("字符串数组格式无效: " + data);
+        }
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public void setNonNullParameter(PreparedStatement ps, int i, List<String> data, JdbcType jdbcType)
+            throws SQLException {
+        if (data != null) {
+            //列化化为字符串
+            String string = toString(data);
+            if (StringUtils.isNotBlank(string)) {
+                ps.setString(i, string);
+                return;
+            }
+        }
+        //处理空值
+        ps.setNull(i, JdbcType.VARCHAR.TYPE_CODE);
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getNullableResult(ResultSet rs, String columnName) throws SQLException {
+        return rs.wasNull() ? null : parseString(rs.getString(columnName));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getNullableResult(ResultSet rs, int columnIndex) throws SQLException {
+        return rs.wasNull() ? null : parseString(rs.getString(columnIndex));
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public List<String> getNullableResult(CallableStatement cs, int columnIndex) throws SQLException {
+        return cs.wasNull() ? null : parseString(cs.getString(columnIndex));
+    }
+}
+

+ 1 - 1
custom-gateway-core/src/main/java/com/shkpr/service/customgateway/core/io/YamlPropertySourceFactory.java

@@ -1,4 +1,4 @@
-package com.shkpr.service.customgateway.core.io;
+package com.shkpr.service.bespokegateway.core.io;
 
 import lombok.NonNull;
 import org.springframework.boot.env.YamlPropertySourceLoader;

+ 125 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/manager/IntegrationKeyManager.java

@@ -0,0 +1,125 @@
+package com.shkpr.service.bespokegateway.core.manager;
+
+import com.global.base.log.LogLevelFlag;
+import com.global.base.log.LogPrintMgr;
+import com.shkpr.service.bespokegateway.core.constants.LogFlagBusiType;
+import com.shkpr.service.bespokegateway.core.domain.CallingEndpoint;
+import com.shkpr.service.bespokegateway.core.domain.IntegrationKey;
+import com.shkpr.service.bespokegateway.core.domain.IntegrationKeyLoader;
+import com.shkpr.service.bespokegateway.core.properties.CallingProperties;
+import org.apache.commons.collections4.MapUtils;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.PostConstruct;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * 密钥管理器
+ *
+ * @author 欧阳劲驰
+ * @serial 1.0.0
+ */
+@Component
+public class IntegrationKeyManager {
+    /**
+     * log
+     */
+    private static final String CLASS_NAME = "IntegrationKeyManager";
+    private static final String BIZ_TYPE = LogFlagBusiType.BUSI_ALL.toStrValue();
+
+    final
+    ThreadPoolTaskExecutor taskScheduler;
+    final
+    CallingProperties callingProperties;
+
+    //密钥加载器
+    private final Map<String, IntegrationKeyLoader> keyLoaders = new ConcurrentHashMap<>();
+    //密钥缓存
+    private final Map<String, IntegrationKey> keyCache = new ConcurrentHashMap<>();
+
+    public IntegrationKeyManager(ThreadPoolTaskExecutor taskScheduler, CallingProperties callingProperties, List<IntegrationKeyLoader> loaders) {
+        this.taskScheduler = taskScheduler;
+        this.callingProperties = callingProperties;
+        // 注册所有密钥加载器
+        loaders.forEach(loader -> keyLoaders.put(loader.getPlatformName(), loader));
+    }
+
+    /**
+     * 初始化
+     */
+    @PostConstruct
+    public void init() {
+        taskScheduler.execute(this::refreshAllKeys);
+    }
+
+    /**
+     * 日任务
+     */
+    @Scheduled(cron = "0 0 0 * * ?")
+    public void minuteTask() {
+        taskScheduler.execute(this::refreshAllKeys);
+    }
+
+    /**
+     * 获取密钥
+     *
+     * @param platformName 平台名称
+     * @return 密钥
+     */
+    public IntegrationKey getKey(String platformName) {
+        IntegrationKey key = keyCache.get(platformName);
+        if (key == null) refreshKey(platformName);
+        return keyCache.get(platformName);
+    }
+
+    /**
+     * 刷新密钥
+     *
+     * @param platformName 平台名称
+     */
+    public void refreshKey(String platformName) {
+        //密钥加载器
+        IntegrationKeyLoader loader = keyLoaders.getOrDefault(platformName, null);
+        if (loader == null) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, BIZ_TYPE, CLASS_NAME,
+                    String.format("刷新密钥失败,加载器不存在,未找到平台[%s]对应的密钥加载器", platformName));
+            return;
+        }
+        //对接信息
+        CallingEndpoint endpoint = callingProperties.getEndpoint(platformName);
+        if (endpoint == null) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, BIZ_TYPE, CLASS_NAME,
+                    String.format("刷新密钥失败,对接信息不存在,未找到平台[%s]的对接信息", platformName));
+            return;
+        }
+        //加载密钥
+        IntegrationKey key = loader.loadKey(endpoint);
+        if (key == null) {
+            LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_ERROR, BIZ_TYPE, CLASS_NAME,
+                    String.format("刷新密钥失败,平台[%s]密钥加载返回空值", platformName));
+            return;
+        }
+        keyCache.put(platformName, key);
+    }
+
+    /**
+     * 刷新所有平台密钥
+     */
+    public void refreshAllKeys() {
+        if (MapUtils.isEmpty(keyLoaders)) return;
+
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME,
+                String.format("开始刷新所有平台密钥,共%d个平台", keyLoaders.size()));
+        long begin = System.currentTimeMillis();
+
+        for (String platformName : keyLoaders.keySet()) taskScheduler.execute(() -> refreshKey(platformName));
+
+        long end = System.currentTimeMillis();
+        LogPrintMgr.getInstance().printLogMsg(LogLevelFlag.LOG_INFO, BIZ_TYPE, CLASS_NAME
+                , String.format("结束刷新所有平台密钥,用时(毫秒):%d", (end - begin)));
+    }
+}

+ 21 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/CustomerInfoMapper.java

@@ -0,0 +1,21 @@
+package com.shkpr.service.bespokegateway.core.mapper.primary;
+
+import com.shkpr.service.bespokegateway.core.domain.po.CustomerInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 户表信息mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface CustomerInfoMapper {
+    /**
+     * 合并
+     *
+     * @param record 对象
+     * @return 保存数量
+     */
+    int upsert(CustomerInfo record);
+}

+ 21 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/CustomerMeterReadMapper.java

@@ -0,0 +1,21 @@
+package com.shkpr.service.bespokegateway.core.mapper.primary;
+
+import com.shkpr.service.bespokegateway.core.domain.po.CustomerMeterRead;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 户表抄表数据mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface CustomerMeterReadMapper {
+    /**
+     * 合并
+     *
+     * @param record 对象
+     * @return 保存数量
+     */
+    int upsert(CustomerMeterRead record);
+}

+ 24 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/DeviceKindMapper.java

@@ -0,0 +1,24 @@
+package com.shkpr.service.bespokegateway.core.mapper.primary;
+
+import com.shkpr.service.bespokegateway.core.domain.po.DeviceKind;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+
+import java.util.List;
+
+/**
+ * 设备种类表mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface DeviceKindMapper {
+    /**
+     * 根据key查询
+     *
+     * @param keys key集合
+     * @return 实体
+     */
+    List<DeviceKind> findByKeys(@Param("keys") List<String> keys);
+}

+ 21 - 0
bespoke-gateway-core/src/main/java/com/shkpr/service/bespokegateway/core/mapper/primary/FunctionInfoMapper.java

@@ -0,0 +1,21 @@
+package com.shkpr.service.bespokegateway.core.mapper.primary;
+
+import com.shkpr.service.bespokegateway.core.domain.po.FunctionInfo;
+import org.apache.ibatis.annotations.Mapper;
+
+/**
+ * 用户信息mapper
+ *
+ * @author 欧阳劲驰
+ * @since 1.0.0
+ */
+@Mapper
+public interface FunctionInfoMapper {
+    /**
+     * 合并
+     *
+     * @param record 对象
+     * @return 保存数量
+     */
+    int upsert(FunctionInfo record);
+}

+ 0 - 0
custom-gateway-zydma/src/main/java/com/shkpr/service/customgateway/zydma/mapper/PersonnelInfoMapper.java


Some files were not shown because too many files changed in this diff