108 Commity db29faeb46 ... 6da51af66c

Autor SHA1 Správa Dátum
  欧阳劲驰 6da51af66c 修改项目名称 1 mesiac pred
  欧阳劲驰 154ffd29e4 修改influxdb端口 1 mesiac pred
  欧阳劲驰 0ec0cfab0e 修改设备导出字段 1 mesiac pred
  欧阳劲驰 6019617aaa 实现监利iot数据采集 1 mesiac pred
  欧阳劲驰 86a212a784 删除内部类 1 mesiac pred
  欧阳劲驰 8108e43dcd 枣阳iot增加设备 1 mesiac pred
  欧阳劲驰 84fb7bcd9f 修改数据源配置 1 mesiac pred
  欧阳劲驰 f26ab9b835 scada数据迁移增加并行处理 1 mesiac pred
  欧阳劲驰 d8dfe271e1 增加日志 1 mesiac pred
  欧阳劲驰 8fad4285b7 修复采集空指针 1 mesiac pred
  欧阳劲驰 fbe09f6d09 营销户表信息,增加公共用水类型、是否计费、是否计量 1 mesiac pred
  欧阳劲驰 08daba68cd 数据库增加并行 1 mesiac pred
  欧阳劲驰 49c5887730 数据迁移排除空数据和空传感器code,完善传感器code配置,删除重复设备 1 mesiac pred
  欧阳劲驰 78d4406fe2 实现中环scada历史数据迁移 1 mesiac pred
  欧阳劲驰 f24f8b4ace 实现中环scada历史数据迁移 1 mesiac pred
  欧阳劲驰 0e11437857 实现中环scada历史数据迁移 1 mesiac pred
  欧阳劲驰 8de2242291 实现中环scada历史数据迁移 1 mesiac pred
  欧阳劲驰 49edb3cf32 实现中环scada历史数据迁移 1 mesiac pred
  欧阳劲驰 7214e8d08f 实现公式配置处理,二汽水厂设备录入 1 mesiac pred
  欧阳劲驰 9686237be0 增加抄表周期修改 1 mesiac pred
  欧阳劲驰 d317450e41 修复时间截断问题 1 mesiac pred
  欧阳劲驰 70d29b98ed 营销户表信息导入,增加表类型 1 mesiac pred
  欧阳劲驰 4b5dd6964f 营销户表信息导入,增加表类型 1 mesiac pred
  欧阳劲驰 298cdcb638 修改返回code 1 mesiac pred
  欧阳劲驰 9f277898a5 增加忽略的返回值 1 mesiac pred
  欧阳劲驰 4446c7531b 同步数据库 1 mesiac pred
  欧阳劲驰 c2a7c86823 实现第三方接入 1 mesiac pred
  欧阳劲驰 891da5b386 枣阳设备新增 1 mesiac pred
  欧阳劲驰 90edc70bc7 枣阳设备新增 1 mesiac pred
  欧阳劲驰 64d6ac0a54 枣阳设备新增 1 mesiac pred
  欧阳劲驰 2a4f197aee 使用用户角色列表接口获取用户的角色信息 1 mesiac pred
  欧阳劲驰 146d90e4a6 营销数据时间根据月份截断 1 mesiac pred
  欧阳劲驰 14674039c1 数据时间不以原始数据中的时间为准,改为使用采集程序执行时的时间 1 mesiac pred
  欧阳劲驰 52f7d53d42 数据时间不以原始数据中的时间为准,改为使用采集程序执行时的时间 1 mesiac pred
  欧阳劲驰 600d951bb9 枣阳物联网数据查询,增加时间滚动查询 1 mesiac pred
  欧阳劲驰 6bfe0ddb60 枣阳物联网增加设备 1 mesiac pred
  欧阳劲驰 452154068d 删除导入开放权限 1 mesiac pred
  欧阳劲驰 ffbaa8f55b 修改日志 1 mesiac pred
  欧阳劲驰 cb63393fca 增加单用户职能信息过滤 1 mesiac pred
  欧阳劲驰 c966533283 实现户表数据导入 1 mesiac pred
  欧阳劲驰 dde4953ca8 实现户表信息导入 1 mesiac pred
  欧阳劲驰 043cc92493 删除中环重复设备 1 mesiac pred
  欧阳劲驰 abb4d2a07d 修复中环scads数据采集,时间解析失败的问题,修改中环scads数据采集为多线程采集 1 mesiac pred
  欧阳劲驰 4752210914 实现职能信息同步 1 mesiac pred
  欧阳劲驰 43a80edf0d 修复临时token生成失败的问题 1 mesiac pred
  欧阳劲驰 496dd07db4 修改result 1 mesiac pred
  欧阳劲驰 07f186c0ad 中环添加设备 1 mesiac pred
  欧阳劲驰 034ac6a089 增加异常处理 1 mesiac pred
  欧阳劲驰 fa4614ade6 添加ticket参数使用 1 mesiac pred
  欧阳劲驰 30893cb284 修改序列化信息 1 mesiac pred
  欧阳劲驰 3c501ecb49 实现根据门户token生成临时token 1 mesiac pred
  欧阳劲驰 d9f9543970 修改数据库配置 1 mesiac pred
  欧阳劲驰 3930584220 修改数据库配置 1 mesiac pred
  欧阳劲驰 297db4ae6f 枣阳iot平台增加设备 1 mesiac pred
  欧阳劲驰 aec59f2ab2 修改中环采集频率 1 mesiac pred
  欧阳劲驰 e6b4fbb9fc 中环增加压力计 1 mesiac pred
  欧阳劲驰 4aecd38240 更新数据库 1 mesiac pred
  欧阳劲驰 cb71447db3 更新数据库 1 mesiac pred
  欧阳劲驰 b8528df1af 中环采集改为按设备采集,规避批量查询报错的问题 #暂时处理 1 mesiac pred
  欧阳劲驰 965764bee2 中环采集改为按设备采集,规避批量查询报错的问题 #暂时处理 1 mesiac pred
  欧阳劲驰 230084e571 修改厂家名称 1 mesiac pred
  欧阳劲驰 e5c3b7c5d9 枣阳增加设备时添加厂家信息 1 mesiac pred
  欧阳劲驰 30e33921cd 枣阳设备新增设备增加厂家 1 mesiac pred
  欧阳劲驰 4521003a6f 枣阳设备新增 1 mesiac pred
  欧阳劲驰 e090415245 枣阳设备新增 1 mesiac pred
  欧阳劲驰 c0ff9a1e17 枣阳设备新增 1 mesiac pred
  欧阳劲驰 5fbc003683 修改日期格式化 1 mesiac pred
  欧阳劲驰 0a8a23406c 修改注释 1 mesiac pred
  欧阳劲驰 d42fe8cd02 修改配置文件 1 mesiac pred
  欧阳劲驰 83757288bc 导出设备增加采集标签字段 1 mesiac pred
  欧阳劲驰 192567c574 导出设备增加采集标签字段 1 mesiac pred
  欧阳劲驰 59d1afeb52 录入中环sacada设备 1 mesiac pred
  欧阳劲驰 a4348619b6 实现设备和采集标签过滤 2 mesiacov pred
  欧阳劲驰 9286ccdd6a 实现采集标签同步 2 mesiacov pred
  欧阳劲驰 06491ad020 增加设备标签表 2 mesiacov pred
  欧阳劲驰 1bc5303b0e dma增加po 2 mesiacov pred
  欧阳劲驰 8a934c2a9a 嵌入式数据库增加service层 2 mesiacov pred
  欧阳劲驰 2fa534cf8b 修改注入 2 mesiacov pred
  欧阳劲驰 2564f80964 增加请求失败处理 2 mesiacov pred
  欧阳劲驰 ab1bedcb9f 实现中环Scada采集 2 mesiacov pred
  欧阳劲驰 b7a2df8f17 修改日志 2 mesiacov pred
  欧阳劲驰 9d6affdd9b 删除无用的schema 2 mesiacov pred
  欧阳劲驰 92d5fd0da9 删除静态引入 2 mesiacov pred
  欧阳劲驰 7248060bde 增加模块切换配置 2 mesiacov pred
  欧阳劲驰 cc14b097dc 增加模块切换配置 2 mesiacov pred
  欧阳劲驰 91700f739d 重命名模块 2 mesiacov pred
  欧阳劲驰 c6903a637f 优化配置文件 2 mesiacov pred
  欧阳劲驰 86cbf1db22 增加压力流量计类型 2 mesiacov pred
  欧阳劲驰 5b93a36234 中环项目初始化 2 mesiacov pred
  欧阳劲驰 14dd2ab136 更新data文件 2 mesiacov pred
  欧阳劲驰 98727fa77d 设备id生成增加区号和种类 2 mesiacov pred
  欧阳劲驰 4eaef18ecc 优化注入 2 mesiacov pred
  欧阳劲驰 af4c1406fa 实现访问密钥生成 2 mesiacov pred
  欧阳劲驰 947fd5b9bc 更新数据库文件 2 mesiacov pred
  欧阳劲驰 8a92110083 修改gbase内容,删除json依赖 2 mesiacov pred
  欧阳劲驰 46621db1f1 修改mapper.xml文件加载 2 mesiacov pred
  欧阳劲驰 e52b981b4d 修改数据库配置文件 2 mesiacov pred
  欧阳劲驰 6b33fd8761 修改数据库配置文件名称 2 mesiacov pred
  欧阳劲驰 c5b86073d6 增加db文件 2 mesiacov pred
  欧阳劲驰 afd7a7b949 支持多数据源,设备标识序列使用嵌入式数据库 2 mesiacov pred
  欧阳劲驰 b1d14386c7 todo 增加用户角色信息 2 mesiacov pred
  欧阳劲驰 cb1f099ad3 简化物联网数据对象转换 2 mesiacov pred
  欧阳劲驰 34718f8d08 优化批量写入 2 mesiacov pred
  欧阳劲驰 47a91e5e04 修改采集频率,优化influxdb写入 2 mesiacov pred
  欧阳劲驰 e87a568826 增加设备厂家,增加瞬时压力字段 2 mesiacov pred
  欧阳劲驰 2a7d3c88c6 重命名 2 mesiacov pred
  欧阳劲驰 b8759a5cd0 实现物联网平台采集 2 mesiacov pred
  欧阳劲驰 783b10ec40 修改签名生成方法 2 mesiacov pred
100 zmenil súbory, kde vykonal 4508 pridanie a 178 odobranie
  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


Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov