Pārlūkot izejas kodu

update 模块分组

18339543638 3 gadi atpakaļ
vecāks
revīzija
3b42861c57
100 mainītis faili ar 3354 papildinājumiem un 883 dzēšanām
  1. 67 84
      nb-admin/pom.xml
  2. 4 2
      nb-admin/src/main/java/com/nb/AdminApplication.java
  3. 2 2
      nb-admin/src/main/java/com/nb/admin/StartUpRunner.java
  4. 0 37
      nb-admin/src/main/java/com/nb/admin/controller/system/vo/UserPassVo.java
  5. 0 1
      nb-admin/src/main/resources/application-dev.yml
  6. 0 1
      nb-admin/src/main/resources/application.yml
  7. 24 0
      nb-admin/src/main/resources/assembly.xml
  8. 2 2
      nb-admin/src/main/test/java/com/coffee/admin/BusDeviceRegisterTest.java
  9. 7 7
      nb-admin/src/test/java/com/nb/admin/AliyunTest.java
  10. 8 8
      nb-admin/src/test/java/com/nb/admin/BusClinicTest.java
  11. 8 8
      nb-admin/src/test/java/com/nb/admin/BusDeviceAlarmTest.java
  12. 5 5
      nb-admin/src/test/java/com/nb/admin/BusDeviceTest.java
  13. 3 3
      nb-admin/src/test/java/com/nb/admin/BusHospitalLogTest.java
  14. 9 9
      nb-admin/src/test/java/com/nb/admin/BusHospitalTest.java
  15. 2 2
      nb-admin/src/test/java/com/nb/admin/BusNetpumpTest.java
  16. 12 12
      nb-admin/src/test/java/com/nb/admin/BusPatientTest.java
  17. 2 2
      nb-admin/src/test/java/com/nb/admin/DelayMessageTest.java
  18. 2 2
      nb-admin/src/test/java/com/nb/admin/DeviceOperateTest.java
  19. 6 6
      nb-admin/src/test/java/com/nb/admin/HisStrategyTest.java
  20. 1 1
      nb-admin/src/test/java/com/nb/admin/NotifyTest.java
  21. 3 3
      nb-admin/src/test/java/com/nb/admin/SpringBootApplicationTests.java
  22. 0 15
      nb-api/pom.xml
  23. 2 2
      nb-auth/pom.xml
  24. 37 0
      nb-auth/src/main/java/com/nb/auth/bean/UserPassVo.java
  25. 44 0
      nb-auth/src/main/java/com/nb/auth/config/AuthDocConfig.java
  26. 12 16
      nb-auth/src/main/java/com/nb/auth/controller/AccountController.java
  27. 2 0
      nb-auth/src/main/java/com/nb/auth/granter/IAccountOperator.java
  28. 3 5
      nb-common/config-common/pom.xml
  29. 1 1
      nb-common/config-common/src/main/java/com/nb/common/config/apply/ApplyManager.java
  30. 4 2
      nb-common/config-common/src/main/java/com/nb/common/config/notice/wechat/EnterpriseWeChatNotify.java
  31. 0 55
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/DefaultMessageListener.java
  32. 0 20
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/DefaultRedisCallBack.java
  33. 0 28
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/HospitalCodeCheck.java
  34. 0 22
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/MessageResponse.java
  35. 0 44
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/MessagingRequest.java
  36. 0 16
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/TopicMessage.java
  37. 0 115
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/WebSocketConstant.java
  38. 0 156
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/Subscribe.java
  39. 0 24
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/TopicWrapper.java
  40. 0 28
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/WsHandler.java
  41. 0 63
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/DefaultWsServerAioListener.java
  42. 0 28
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/HeartBeatConfig.java
  43. 0 16
      nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/IWebSocketAuthFilter.java
  44. 2 1
      nb-common/log-common/pom.xml
  45. 1 0
      nb-common/pom.xml
  46. 38 0
      nb-common/ws-common/pom.xml
  47. 55 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultMessageListener.java
  48. 20 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultRedisCallBack.java
  49. 146 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultWebSocketMsgHandler.java
  50. 28 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/HospitalCodeCheck.java
  51. 22 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/MessageResponse.java
  52. 39 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/MessagingRequest.java
  53. 16 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/TopicMessage.java
  54. 115 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/WebSocketConstant.java
  55. 14 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/WsAutoConfiguration.java
  56. 13 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/HisMsgHandler.java
  57. 156 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/Subscribe.java
  58. 24 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/TopicWrapper.java
  59. 28 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/WsHandler.java
  60. 63 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/DefaultWsServerAioListener.java
  61. 28 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/HeartBeatConfig.java
  62. 16 0
      nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/IWebSocketAuthFilter.java
  63. 3 0
      nb-common/ws-common/src/main/resources/META-INF/spring.factories
  64. 5 2
      nb-core/pom.xml
  65. 2 19
      nb-core/src/main/java/com/nb/core/doc/SwaggerDocConfig.java
  66. 11 6
      nb-oss/pom.xml
  67. 2 2
      nb-oss/src/main/java/com/nb/oss/strategy/context/FileStorageContext.java
  68. 40 0
      nb-service-api/iot-service-api/pom.xml
  69. 24 0
      nb-service-api/iot-service-api/src/main/java/com/nb/aliyun/api/bean/PlatformAccount.java
  70. 328 0
      nb-service-api/iot-service-api/src/main/java/com/nb/aliyun/api/service/AliyunIotSdk.java
  71. 21 0
      nb-service-api/pom.xml
  72. 42 0
      nb-service-api/web-service-api/pom.xml
  73. 18 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/AliIotConfig.java
  74. 15 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/GeoPoint.java
  75. 24 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/Script.java
  76. 112 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/BusDeviceEntity.java
  77. 68 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/BusHospitalLogEntity.java
  78. 225 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/BusDeviceRunningEntity.java
  79. 115 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/CommonDeviceParam.java
  80. 167 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/DeviceProperties.java
  81. 44 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceAlarmEnum.java
  82. 43 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceStatusEnum.java
  83. 30 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceStatusEnum2.java
  84. 32 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceTypeEnum.java
  85. 42 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/FlowStatusEnum.java
  86. 32 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/HospitalLogEnum.java
  87. 20 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IDeviceClient.java
  88. 14 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IHospitalLogClient.java
  89. 16 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IIotMsgHandler.java
  90. 16 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/Constants.java
  91. 48 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceAlarmUtils.java
  92. 32 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceRunStatusUtils.java
  93. 25 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceTypeUtils.java
  94. 29 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/EnumUtils.java
  95. 44 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/Items.java
  96. 67 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/PumpParams.java
  97. 36 0
      nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/WarnFlowUtils.java
  98. 31 0
      nb-service/iot-service/pom.xml
  99. 230 0
      nb-service/iot-service/src/main/java/com/nb/aliyun/AliyunConsumerGroupService.java
  100. 205 0
      nb-service/iot-service/src/main/java/com/nb/aliyun/AliyunIotSubscribeClient.java

+ 67 - 84
nb-admin/pom.xml

@@ -12,10 +12,13 @@
     <artifactId>nb-admin</artifactId>
 
     <dependencies>
-        <!-- 核心模块 -->
         <dependency>
             <groupId>com.tuoren</groupId>
-            <artifactId>nb-system</artifactId>
+            <artifactId>config-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>web-service</artifactId>
         </dependency>
         <!-- OSS文件存储模块 -->
         <dependency>
@@ -36,121 +39,101 @@
             <groupId>junit</groupId>
             <artifactId>junit</artifactId>
         </dependency>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>iot-service</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+        </dependency>
     </dependencies>
 
-    <!--<build>-->
-        <!--<plugins>-->
-            <!--<plugin>-->
-                <!--<groupId>org.springframework.boot</groupId>-->
-                <!--<artifactId>spring-boot-maven-plugin</artifactId>-->
-            <!--</plugin>-->
-        <!--</plugins>-->
-    <!--</build>-->
-    <!--<build>-->
-        <!--<finalName>${project.name}</finalName>-->
-        <!--<resources>-->
-            <!--<resource>-->
-                <!--<directory>src/main/resources</directory>-->
-                <!--<filtering>true</filtering>-->
-            <!--</resource>-->
-        <!--</resources>-->
-        <!--<pluginManagement>-->
-            <!--<plugins>-->
-                <!--&lt;!&ndash;<plugin>&ndash;&gt;-->
-                    <!--&lt;!&ndash;<groupId>org.springframework.boot</groupId>&ndash;&gt;-->
-                    <!--&lt;!&ndash;<artifactId>spring-boot-maven-plugin</artifactId>&ndash;&gt;-->
-                    <!--&lt;!&ndash;<version>${spring-boot.version}</version>&ndash;&gt;-->
-                    <!--&lt;!&ndash;<configuration>&ndash;&gt;-->
-                        <!--&lt;!&ndash;<mainClass>com.nb.AdminApplication</mainClass>&ndash;&gt;-->
-                        <!--&lt;!&ndash;<finalName>${project.build.finalName}</finalName>&ndash;&gt;-->
-                        <!--&lt;!&ndash;<layers>&ndash;&gt;-->
-                            <!--&lt;!&ndash;<enabled>true</enabled>&ndash;&gt;-->
-                        <!--&lt;!&ndash;</layers>&ndash;&gt;-->
-                    <!--&lt;!&ndash;</configuration>&ndash;&gt;-->
-                    <!--&lt;!&ndash;<executions>&ndash;&gt;-->
-                        <!--&lt;!&ndash;<execution>&ndash;&gt;-->
-                            <!--&lt;!&ndash;<goals>&ndash;&gt;-->
-                                <!--&lt;!&ndash;<goal>repackage</goal>&ndash;&gt;-->
-                            <!--&lt;!&ndash;</goals>&ndash;&gt;-->
-                        <!--&lt;!&ndash;</execution>&ndash;&gt;-->
-                    <!--&lt;!&ndash;</executions>&ndash;&gt;-->
-                <!--&lt;!&ndash;</plugin>&ndash;&gt;-->
-
-                <!--<plugin>-->
-                    <!--<artifactId>maven-assembly-plugin</artifactId>-->
-                    <!--<configuration>-->
-                        <!--<archive>-->
-                            <!--<manifest>-->
-                                <!--<mainClass>com.nb.AdminApplication</mainClass>-->
-                            <!--</manifest>-->
-                            <!--<manifestEntries>-->
-                                <!--<Class-Path>.</Class-Path>-->
-                            <!--</manifestEntries>-->
-                        <!--</archive>-->
-                        <!--<descriptorRefs>-->
-                            <!--<descriptorRef>jar-with-dependencies</descriptorRef>-->
-                        <!--</descriptorRefs>-->
-                    <!--</configuration>-->
-                    <!--<executions>-->
-                        <!--<execution>-->
-                            <!--<id>make-assembly</id>-->
-                            <!--<phase>package</phase>-->
-                            <!--<goals>-->
-                                <!--<goal>single</goal>-->
-                            <!--</goals>-->
-                            <!--<configuration>-->
-                                <!--<descriptors>-->
-                                    <!--<descriptor>src/main/resources/assembly.xml</descriptor>-->
-                                <!--</descriptors>-->
-                            <!--</configuration>-->
-                        <!--</execution>-->
-                    <!--</executions>-->
-                <!--</plugin>-->
-            <!--</plugins>-->
-        <!--</pluginManagement>-->
-    <!--</build>-->
 
     <build>
         <resources>
             <resource>
                 <directory>src/main/resources</directory>
+                <!--开启过滤,用指定的参数替换directory下的文件中的参数-->
                 <filtering>true</filtering>
             </resource>
         </resources>
         <plugins>
             <plugin>
-                <artifactId>maven-install-plugin</artifactId>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-compiler-plugin</artifactId>
+                <configuration>
+                    <source>8</source>
+                    <target>8</target>
+                </configuration>
+            </plugin>
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-assembly-plugin</artifactId>
+                <version>2.4.1</version>
                 <configuration>
-                    <skip>true</skip>
+                    <archive>
+                        <manifest>
+                            <mainClass>com.nb.AdminApplication</mainClass>
+                        </manifest>
+                    </archive>
+                    <!--打包时,包含所有依赖的jar包-->
+                    <descriptorRefs>
+                        <descriptorRef>jar-with-dependencies</descriptorRef>
+                    </descriptorRefs>
                 </configuration>
+                <executions>
+                    <execution>
+                        <id>make-assembly</id>
+                        <phase>package</phase>
+                    </execution>
+                </executions>
+
             </plugin>
+            <!--生成javadoc文件-->
             <plugin>
-                <groupId>org.springframework.boot</groupId>
-                <artifactId>spring-boot-maven-plugin</artifactId>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-javadoc-plugin</artifactId>
+                <version>3.2.0</version>
                 <configuration>
-                    <mainClass>com.nb.AdminApplication</mainClass>
-                    <layout>ZIP</layout>
-                    <layers>
-                        <enabled>true</enabled>
-                    </layers>
+                    <encoding>UTF-8</encoding>
+                    <charset>UTF-8</charset>
+                    <docencoding>UTF-8</docencoding>
+                    <doclint>none</doclint>
                 </configuration>
                 <executions>
                     <execution>
+                        <id>attach-javadocs</id>
+                        <goals>
+                            <goal>jar</goal>
+                        </goals>
+                    </execution>
+                </executions>
+            </plugin>
+            <!--生成source文件-->
+            <plugin>
+                <groupId>org.apache.maven.plugins</groupId>
+                <artifactId>maven-source-plugin</artifactId>
+                <version>2.4</version>
+                <executions>
+                    <execution>
+                        <id>attach-sources</id>
                         <goals>
-                            <goal>repackage</goal>
+                            <goal>jar</goal>
                         </goals>
                     </execution>
                 </executions>
             </plugin>
         </plugins>
     </build>
+
     <profiles>
         <profile>
             <id>dev</id>
             <properties>
                 <!-- 环境标识,需要与配置文件的名称相对应 -->
                 <profiles.active>dev</profiles.active>
-                <!--<profiles.active>prod</profiles.active>-->
                 <logging.level>debug</logging.level>
             </properties>
             <activation>

+ 4 - 2
nb-admin/src/main/java/com/nb/AdminApplication.java

@@ -19,13 +19,15 @@ import org.tio.websocket.starter.EnableTioWebSocketServer;
  * @author Kevin
  */
 @SpringBootApplication(scanBasePackages ={
-        "com.nb",
+        "com.nb.aliyun",
+        "com.nb.web",
+        "com.nb.auth",
         "springfox.documentation.schema"})
 @Import(cn.hutool.extra.spring.SpringUtil.class)
 @EnableTioWebSocketServer
 @EnableScheduling
 @EnableAsync
-@MapperScan({"${mybatis-plus.mapperPackage}","com.nb.system.mapper"})
+@MapperScan({"com.nb.**.mapper"})
 @EnableConfigurationProperties({RequestCheckProperties.class, DruidProperties.class})
 @ServletComponentScan(basePackages = "com.nb.common.config")
 public class AdminApplication {

+ 2 - 2
nb-admin/src/main/java/com/nb/admin/StartUpRunner.java

@@ -1,7 +1,7 @@
 package com.nb.admin;
 
-import com.nb.system.service.ISysConfigService;
-import com.nb.system.service.ISysDictService;
+import com.nb.web.service.system.service.ISysConfigService;
+import com.nb.web.service.system.service.ISysDictService;
 import org.springframework.boot.CommandLineRunner;
 import org.springframework.stereotype.Component;
 

+ 0 - 37
nb-admin/src/main/java/com/nb/admin/controller/system/vo/UserPassVo.java

@@ -1,37 +0,0 @@
-/*
- *  Copyright 2019-2020 Zheng Jie
- *
- *  Licensed under the Apache License, Version 2.0 (the "License");
- *  you may not use this file except in compliance with the License.
- *  You may obtain a copy of the License at
- *
- *  http://www.apache.org/licenses/LICENSE-2.0
- *
- *  Unless required by applicable law or agreed to in writing, software
- *  distributed under the License is distributed on an "AS IS" BASIS,
- *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- *  See the License for the specific language governing permissions and
- *  limitations under the License.
- */
-package com.nb.admin.controller.system.vo;
-
-import io.swagger.annotations.ApiModel;
-import io.swagger.annotations.ApiModelProperty;
-import lombok.Data;
-
-import javax.validation.constraints.NotBlank;
-
-/**
- * 修改密码的 Vo 类
- * @author Zheng Jie
- * @date 2019年7月11日13:59:49
- */
-@Data
-@ApiModel("密码修改")
-public class UserPassVo {
-    @ApiModelProperty("旧密码")
-    private String oldPass;
-    @ApiModelProperty("新密码")
-    @NotBlank(message = "新密码不能为空")
-    private String newPass;
-}

+ 0 - 1
nb-admin/src/main/resources/application-dev.yml

@@ -12,7 +12,6 @@ app:
   uploadDir: D:/${app.name}-files
   # 缓存前缀
   cachePrefix: ${app.name}:dev
-
 # MinIO相关配置
 minio:
   endpoint: 192.168.100.32

+ 0 - 1
nb-admin/src/main/resources/application.yml

@@ -66,7 +66,6 @@ logging:
     console: UTF-8
 
 mybatis-plus:
-  mapperPackage: com.nb.**.mapper
   mapperLocations: classpath*:mapper/**/*Mapper.xml
   checkConfigLocation: false
   global-config:

+ 24 - 0
nb-admin/src/main/resources/assembly.xml

@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<assembly>
+    <id>jar-with-dependencies</id>
+    <formats>
+        <format>jar</format>
+    </formats>
+    <includeBaseDirectory>false</includeBaseDirectory>
+    <dependencySets>
+        <!-- 默认的配置 -->
+        <dependencySet>
+            <outputDirectory>/</outputDirectory>
+            <useProjectArtifact>true</useProjectArtifact>
+            <unpack>true</unpack>
+            <scope>runtime</scope>
+        </dependencySet>
+        <!-- 增加scope类型为system的配置 -->
+        <dependencySet>
+            <outputDirectory>/</outputDirectory>
+            <useProjectArtifact>true</useProjectArtifact>
+            <unpack>true</unpack>
+            <scope>system</scope>
+        </dependencySet>
+    </dependencySets>
+</assembly>

+ 2 - 2
nb-admin/src/main/test/java/com/coffee/admin/BusDeviceRegisterTest.java

@@ -1,7 +1,7 @@
 package com.nb.admin;
 
-import com.nb.bus.entity.BusDeviceEntity;
-import com.nb.bus.service.LocalBusDeviceService;
+import com.nb.web.service.bus.entity.BusDeviceEntity;
+import com.nb.web.service.bus.service.LocalBusDeviceService;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;

+ 7 - 7
nb-admin/src/test/java/com/nb/admin/AliyunTest.java

@@ -2,13 +2,13 @@ package com.nb.admin;
 
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.AdminApplication;
-import com.nb.aliyun.sdk.AliyunIotSdk;
-import com.nb.bus.entity.BusDeviceEntity;
-import com.nb.bus.entity.BusDeviceRunningEntity;
-import com.nb.bus.entity.BusInfusionHistoryEntity;
-import com.nb.bus.listener.event.bean.DeviceInfoEvent;
-import com.nb.bus.service.LocalBusDeviceService;
-import com.nb.bus.service.LocalBusInfusionHistoryService;
+import com.nb.aliyun.api.service.AliyunIotSdk;
+import com.nb.web.api.entity.BusDeviceEntity;
+import com.nb.web.service.bus.entity.BusInfusionHistoryEntity;
+import com.nb.web.service.bus.listener.event.bean.DeviceInfoEvent;
+import com.nb.web.service.bus.service.LocalBusDeviceService;
+import com.nb.web.service.bus.service.LocalBusInfusionHistoryService;
+import com.nb.web.api.entity.common.BusDeviceRunningEntity;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;

+ 8 - 8
nb-admin/src/test/java/com/nb/admin/BusClinicTest.java

@@ -6,14 +6,14 @@ import cn.hutool.json.JSONObject;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
 import com.nb.AdminApplication;
-import com.nb.bus.controller.vo.ClinicStatsVo;
-import com.nb.bus.entity.BusClinicEntity;
-import com.nb.bus.entity.BusDocEntity;
-import com.nb.bus.entity.BusInfusionHistoryEntity;
-import com.nb.bus.service.LocalBusClinicService;
-import com.nb.bus.service.LocalBusDocService;
-import com.nb.bus.service.LocalBusInfusionHistoryService;
-import com.nb.bus.service.dto.ClinicStatsReturnResult;
+import com.nb.web.service.bus.controller.vo.ClinicStatsVo;
+import com.nb.web.service.bus.entity.BusClinicEntity;
+import com.nb.web.service.bus.entity.BusDocEntity;
+import com.nb.web.service.bus.entity.BusInfusionHistoryEntity;
+import com.nb.web.service.bus.service.LocalBusClinicService;
+import com.nb.web.service.bus.service.LocalBusDocService;
+import com.nb.web.service.bus.service.LocalBusInfusionHistoryService;
+import com.nb.web.service.bus.service.dto.ClinicStatsReturnResult;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Test;
 import org.junit.runner.RunWith;

+ 8 - 8
nb-admin/src/test/java/com/nb/admin/BusDeviceAlarmTest.java

@@ -1,14 +1,14 @@
 package com.nb.admin;
 
 import com.nb.AdminApplication;
-import com.nb.bus.controller.BusDeviceHistoryController;
-import com.nb.bus.entity.BusDeviceAlarmEntity;
-import com.nb.bus.entity.BusInfusionHistoryEntity;
-import com.nb.bus.enums.DeviceStatusEnum;
-import com.nb.bus.mapper.BusDeviceAlarmMapper;
-import com.nb.bus.service.LocalBusDeviceAlarmService;
-import com.nb.bus.service.LocalBusInfusionHistoryService;
-import com.nb.bus.service.dto.DeviceAlarmQuery;
+import com.nb.web.service.bus.controller.BusDeviceHistoryController;
+import com.nb.web.service.bus.entity.BusDeviceAlarmEntity;
+import com.nb.web.service.bus.entity.BusInfusionHistoryEntity;
+import com.nb.web.api.enums.DeviceStatusEnum;
+import com.nb.web.service.bus.mapper.BusDeviceAlarmMapper;
+import com.nb.web.service.bus.service.LocalBusDeviceAlarmService;
+import com.nb.web.service.bus.service.LocalBusInfusionHistoryService;
+import com.nb.web.service.bus.service.dto.DeviceAlarmQuery;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.Test;
 import org.junit.runner.RunWith;

+ 5 - 5
nb-admin/src/test/java/com/nb/admin/BusDeviceTest.java

@@ -4,11 +4,11 @@ import cn.hutool.core.bean.BeanUtil;
 import cn.hutool.core.date.DateUtil;
 import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
 import com.nb.AdminApplication;
-import com.nb.bus.entity.BusDeviceEntity;
-import com.nb.bus.entity.BusDeviceHistoryEntity;
-import com.nb.bus.service.LocalBusDeviceHistoryService;
-import com.nb.bus.service.LocalBusDeviceService;
-import com.nb.bus.service.dto.ClinicAnalInfusionRecord;
+import com.nb.web.api.entity.BusDeviceEntity;
+import com.nb.web.service.bus.entity.BusDeviceHistoryEntity;
+import com.nb.web.service.bus.service.LocalBusDeviceHistoryService;
+import com.nb.web.service.bus.service.LocalBusDeviceService;
+import com.nb.web.service.bus.service.dto.ClinicAnalInfusionRecord;
 import com.nb.common.config.utils.RedissonUtil;
 import lombok.extern.slf4j.Slf4j;
 import org.junit.Test;

+ 3 - 3
nb-admin/src/test/java/com/nb/admin/BusHospitalLogTest.java

@@ -1,9 +1,9 @@
 package com.nb.admin;
 
 import com.nb.AdminApplication;
-import com.nb.bus.controller.BusHospitalLogController;
-import com.nb.bus.entity.BusHospitalLogEntity;
-import com.nb.bus.service.LocalBusHospitalLogService;
+import com.nb.web.service.bus.controller.BusHospitalLogController;
+import com.nb.web.api.entity.BusHospitalLogEntity;
+import com.nb.web.service.bus.service.LocalBusHospitalLogService;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;

+ 9 - 9
nb-admin/src/test/java/com/nb/admin/BusHospitalTest.java

@@ -1,15 +1,15 @@
 package com.nb.admin;
 
 import com.nb.AdminApplication;
-import com.nb.bus.bean.GeoPoint;
-import com.nb.bus.bean.Script;
-import com.nb.bus.controller.BusHospitalController;
-import com.nb.bus.entity.BusHospitalEntity;
-import com.nb.bus.service.LocalBusHospitalService;
-import com.nb.bus.service.LocalBusPatientService;
-import com.nb.bus.service.constant.LocalBusConMixService;
-import com.nb.bus.service.dto.MonitorStatusStatsCountResult;
-import com.nb.bus.utils.CodeUtils;
+import com.nb.web.api.bean.GeoPoint;
+import com.nb.web.api.bean.Script;
+import com.nb.web.service.bus.controller.BusHospitalController;
+import com.nb.web.service.bus.entity.BusHospitalEntity;
+import com.nb.web.service.bus.service.LocalBusHospitalService;
+import com.nb.web.service.bus.service.LocalBusPatientService;
+import com.nb.web.service.bus.service.constant.LocalBusConMixService;
+import com.nb.web.service.bus.service.dto.MonitorStatusStatsCountResult;
+import com.nb.web.service.bus.utils.CodeUtils;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;

+ 2 - 2
nb-admin/src/test/java/com/nb/admin/BusNetpumpTest.java

@@ -3,8 +3,8 @@ package com.nb.admin;
 import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.AdminApplication;
-import com.nb.bus.entity.BusDeviceEntity;
-import com.nb.bus.service.LocalBusDeviceService;
+import com.nb.web.api.entity.BusDeviceEntity;
+import com.nb.web.service.bus.service.LocalBusDeviceService;
 import com.fasterxml.jackson.core.JsonProcessingException;
 import com.fasterxml.jackson.databind.ObjectMapper;
 import org.junit.Test;

+ 12 - 12
nb-admin/src/test/java/com/nb/admin/BusPatientTest.java

@@ -6,18 +6,18 @@ import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.AdminApplication;
-import com.nb.bus.controller.BusDeviceManualController;
-import com.nb.bus.controller.vo.ClinicEditVo;
-import com.nb.bus.entity.BusClinicEntity;
-import com.nb.bus.entity.BusDeviceManualEntity;
-import com.nb.bus.entity.BusInfusionHistoryEntity;
-import com.nb.bus.entity.BusPatientEntity;
-import com.nb.bus.enums.DeviceManualEnum;
-import com.nb.bus.hospital.his.strategy.all.EqualsStrategyHandler;
-import com.nb.bus.service.LocalBusClinicService;
-import com.nb.bus.service.LocalBusInfusionHistoryService;
-import com.nb.bus.service.LocalBusPatientService;
-import com.nb.bus.service.dto.PatientDeviceRepeatResult;
+import com.nb.web.service.bus.controller.BusDeviceManualController;
+import com.nb.web.service.bus.controller.vo.ClinicEditVo;
+import com.nb.web.service.bus.entity.BusClinicEntity;
+import com.nb.web.service.bus.entity.BusDeviceManualEntity;
+import com.nb.web.service.bus.entity.BusInfusionHistoryEntity;
+import com.nb.web.service.bus.entity.BusPatientEntity;
+import com.nb.web.service.bus.enums.DeviceManualEnum;
+import com.nb.web.service.bus.hospital.his.strategy.all.EqualsStrategyHandler;
+import com.nb.web.service.bus.service.LocalBusClinicService;
+import com.nb.web.service.bus.service.LocalBusInfusionHistoryService;
+import com.nb.web.service.bus.service.LocalBusPatientService;
+import com.nb.web.service.bus.service.dto.PatientDeviceRepeatResult;
 import com.nb.core.enums.SexEnum;
 import org.junit.Test;
 import org.junit.runner.RunWith;

+ 2 - 2
nb-admin/src/test/java/com/nb/admin/DelayMessageTest.java

@@ -1,8 +1,8 @@
 package com.nb.admin;
 
 import com.nb.AdminApplication;
-import com.nb.bus.hospital.config.HospitalDeviceAutoUndoConfigHandler;
-import com.nb.bus.hospital.config.handler.HandlerConstant;
+import com.nb.web.service.bus.hospital.config.HospitalDeviceAutoUndoConfigHandler;
+import com.nb.web.service.bus.hospital.config.handler.HandlerConstant;
 import com.nb.core.Value;
 import com.nb.common.queue.delay.manager.DelayMessageManager;
 import com.nb.common.queue.delay.message.DelayMessage;

+ 2 - 2
nb-admin/src/test/java/com/nb/admin/DeviceOperateTest.java

@@ -1,8 +1,8 @@
 package com.nb.admin;
 
 import com.nb.AdminApplication;
-import com.nb.bus.registry.device.DeviceOperator;
-import com.nb.bus.registry.device.DeviceRegistry;
+import com.nb.web.service.bus.registry.device.DeviceOperator;
+import com.nb.web.service.bus.registry.device.DeviceRegistry;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.springframework.beans.factory.annotation.Autowired;

+ 6 - 6
nb-admin/src/test/java/com/nb/admin/HisStrategyTest.java

@@ -6,12 +6,12 @@ import cn.hutool.core.util.EnumUtil;
 import cn.hutool.core.util.RandomUtil;
 import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
 import com.nb.AdminApplication;
-import com.nb.bus.entity.BusClinicEntity;
-import com.nb.bus.hospital.his.strategy.HisStrategyEnum;
-import com.nb.bus.hospital.his.strategy.HisStrategyHandler;
-import com.nb.bus.hospital.his.strategy.HisStrategyManager;
-import com.nb.bus.hospital.his.strategy.HisStrategyManagerRegister;
-import com.nb.bus.service.LocalBusClinicService;
+import com.nb.web.service.bus.entity.BusClinicEntity;
+import com.nb.web.service.bus.hospital.his.strategy.HisStrategyEnum;
+import com.nb.web.service.bus.hospital.his.strategy.HisStrategyHandler;
+import com.nb.web.service.bus.hospital.his.strategy.HisStrategyManager;
+import com.nb.web.service.bus.hospital.his.strategy.HisStrategyManagerRegister;
+import com.nb.web.service.bus.service.LocalBusClinicService;
 import com.nb.core.enums.SexEnum;
 import org.junit.Test;
 import org.junit.runner.RunWith;

+ 1 - 1
nb-admin/src/test/java/com/nb/admin/NotifyTest.java

@@ -2,7 +2,7 @@ package com.nb.admin;
 
 import cn.hutool.json.JSONUtil;
 import com.nb.AdminApplication;
-import com.nb.bus.job.DeviceFlowStatsJob;
+import com.nb.web.service.bus.job.DeviceFlowStatsJob;
 import com.nb.common.config.notice.msg.DiskMsg;
 import com.nb.common.config.notice.wechat.EnterpriseWeChatNotify;
 import org.junit.Test;

+ 3 - 3
nb-admin/src/test/java/com/nb/admin/SpringBootApplicationTests.java

@@ -2,9 +2,9 @@ package com.nb.admin;
 
 import cn.hutool.json.JSONUtil;
 import com.nb.AdminApplication;
-import com.nb.bus.hospital.HospitalManagerRegister;
-import com.nb.bus.hospital.config.HospitalDeviceAutoUndoConfigHandler;
-import com.nb.bus.hospital.config.handler.DeputyDeviceAutoUndoHandler;
+import com.nb.web.service.bus.hospital.HospitalManagerRegister;
+import com.nb.web.service.bus.hospital.config.HospitalDeviceAutoUndoConfigHandler;
+import com.nb.web.service.bus.hospital.config.handler.DeputyDeviceAutoUndoHandler;
 import com.nb.core.Value;
 import com.nb.common.queue.delay.message.DelayMessage;
 import org.junit.Test;

+ 0 - 15
nb-api/pom.xml

@@ -1,15 +0,0 @@
-<?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0"
-         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
-         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
-    <parent>
-        <artifactId>nb-root</artifactId>
-        <groupId>com.tuoren</groupId>
-        <version>1.0</version>
-    </parent>
-    <modelVersion>4.0.0</modelVersion>
-
-    <artifactId>nb-api</artifactId>
-
-
-</project>

+ 2 - 2
nb-auth/pom.xml

@@ -19,8 +19,8 @@
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <optional>true</optional>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.projectlombok</groupId>

+ 37 - 0
nb-auth/src/main/java/com/nb/auth/bean/UserPassVo.java

@@ -0,0 +1,37 @@
+/*
+ *  Copyright 2019-2020 Zheng Jie
+ *
+ *  Licensed under the Apache License, Version 2.0 (the "License");
+ *  you may not use this file except in compliance with the License.
+ *  You may obtain a copy of the License at
+ *
+ *  http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *  Unless required by applicable law or agreed to in writing, software
+ *  distributed under the License is distributed on an "AS IS" BASIS,
+ *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *  See the License for the specific language governing permissions and
+ *  limitations under the License.
+ */
+package com.nb.auth.bean;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.NotBlank;
+
+/**
+ * 修改密码的 Vo 类
+ * @author Zheng Jie
+ * @date 2019年7月11日13:59:49
+ */
+@Data
+@ApiModel("密码修改")
+public class UserPassVo {
+    @ApiModelProperty("旧密码")
+    private String oldPass;
+    @ApiModelProperty("新密码")
+    @NotBlank(message = "新密码不能为空")
+    private String newPass;
+}

+ 44 - 0
nb-auth/src/main/java/com/nb/auth/config/AuthDocConfig.java

@@ -0,0 +1,44 @@
+package com.nb.auth.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Profile;
+import org.springframework.stereotype.Component;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName SwaggerDocConfig.java
+ * @Description TODO
+ * @createTime 2022年08月01日 22:01:00
+ */
+@Component
+public class AuthDocConfig {
+
+
+    @Bean
+    public Docket admin(){
+        ParameterBuilder ticketPar = new ParameterBuilder();
+        List<Parameter> pars = new ArrayList<Parameter>();
+        ticketPar.name("tenantId").description("租户id")
+                .modelRef(new ModelRef("string")).parameterType("query")
+                .required(true).build();
+        pars.add(ticketPar.build());
+
+        return new Docket(DocumentationType.SWAGGER_2)
+                .select()
+                .apis(RequestHandlerSelectors.basePackage("com.nb.auth.controller"))
+                .paths(PathSelectors.any())
+                .build()
+                .groupName("授权模块");
+    }
+}

+ 12 - 16
nb-auth/src/main/java/com/nb/auth/controller/AccountController.java

@@ -1,8 +1,11 @@
 package com.nb.auth.controller;
 
+import com.nb.auth.bean.UserPassVo;
 import com.nb.auth.granter.IAccountOperator;
 import com.nb.auth.controller.vo.AccountInfoVO;
+import com.nb.auth.utils.SecurityUtil;
 import com.nb.core.annotation.Log;
+import com.nb.core.exception.CustomException;
 import com.nb.core.result.R;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
@@ -26,22 +29,15 @@ import org.springframework.web.bind.annotation.RestController;
 public class AccountController {
     private final IAccountOperator accountOperator;
 
-    //    @ApiOperation("修改密码")
-//    @PostMapping(value = "/updatePass")
-//    public R<Boolean> updatePass(@RequestBody @Validated UserPassVo passVo) {
-//        // 密码解密
-//        Long userId = SecurityUtil.getSysUser().getId();
-//        SysUser sysUser = sysUserService.getById(userId);
-//        if (!SecurityUtil.matchesPassword(passVo.getOldPass(), sysUser.getPassword())) {
-//            throw new CustomException("旧密码不正确");
-//        }
-//        String encryptPassword = SecurityUtil.encryptPassword(passVo.getNewPass());
-//        sysUserService
-//                .update(new UpdateWrapper<SysUser>()
-//                        .lambda().eq(SysUser::getId,userId)
-//                        .set(SysUser::getPassword,encryptPassword));
-//        return R.success(true);
-//    }
+    @ApiOperation("修改密码")
+    @PostMapping(value = "/updatePass")
+    public R<Boolean> updatePass(@RequestBody @Validated UserPassVo passVo) {
+        if (accountOperator.updatePass(passVo.getOldPass(),passVo.getNewPass())) {
+            return R.success();
+        }else {
+            throw new CustomException("修改失败,请重试");
+        }
+    }
 
     @Log(title = "获取当前用户信息")
     @ApiOperation("获取当前用户信息")

+ 2 - 0
nb-auth/src/main/java/com/nb/auth/granter/IAccountOperator.java

@@ -51,4 +51,6 @@ public interface IAccountOperator {
      * @return Set<String>
      */
     void saveAccountInfo(AccountInfoVO req);
+
+    boolean updatePass(String oldPass, String newPass);
 }

+ 3 - 5
nb-common/config-common/pom.xml

@@ -30,13 +30,11 @@
             <groupId>org.redisson</groupId>
             <artifactId>redisson-spring-boot-starter</artifactId>
         </dependency>
-        <dependency>
-            <groupId>org.t-io</groupId>
-            <artifactId>tio-websocket-spring-boot-starter</artifactId>
-        </dependency>
+
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>

+ 1 - 1
nb-common/config-common/src/main/java/com/nb/common/config/apply/ApplyManager.java

@@ -7,7 +7,7 @@ import java.util.Collection;
  * @version 1.0.0
  * @ClassName ApplyManagerc.java
  * @Description
- * @see  com.nb.system.config.DefaultApplyManager
+ * @see  com.nb.web.service.system.config.DefaultApplyManager
  * @createTime 2022年07月27日 10:46:00
  */
 public interface ApplyManager {

+ 4 - 2
nb-common/config-common/src/main/java/com/nb/common/config/notice/wechat/EnterpriseWeChatNotify.java

@@ -10,8 +10,10 @@ import org.springframework.beans.factory.annotation.Autowired;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.boot.actuate.health.Health;
 import org.springframework.boot.actuate.system.DiskSpaceHealthIndicator;
+import org.springframework.context.annotation.Profile;
 import org.springframework.scheduling.annotation.Async;
 import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
 
 
 /**
@@ -21,8 +23,8 @@ import org.springframework.scheduling.annotation.Scheduled;
  * @Description 企业微信通知
  * @createTime 2022年07月19日 15:21:00
  */
-//@Component
-//@Profile("prod")
+@Component
+@Profile("prod")
 public class EnterpriseWeChatNotify {
     @Autowired
     private DiskSpaceHealthIndicator spaceHealthIndicator;

+ 0 - 55
nb-common/config-common/src/main/java/com/nb/common/config/websocket/DefaultMessageListener.java

@@ -1,55 +0,0 @@
-package com.nb.common.config.websocket;
-
-import cn.hutool.json.JSONUtil;
-import com.fasterxml.jackson.core.JsonProcessingException;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.Data;
-import lombok.extern.slf4j.Slf4j;
-import org.redisson.api.RPatternTopic;
-import org.redisson.api.listener.PatternMessageListener;
-import org.tio.core.ChannelContext;
-import org.tio.core.Tio;
-import org.tio.core.utils.TioUtils;
-import org.tio.websocket.common.WsPacket;
-import org.tio.websocket.common.WsResponse;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName DefaultMessageListener.java
- * @Description TODO
- * @createTime 2022年03月25日 14:42:00
- */
-@Data
-@Slf4j
-public class DefaultMessageListener implements PatternMessageListener<TopicMessage> {
-    private final String id;
-    private final ObjectMapper objectMapper;
-    private final ChannelContext channelContext;
-    private final RPatternTopic rPatternTopic;
-
-
-    @Override
-    public void onMessage(CharSequence pattern, CharSequence channel, TopicMessage msg) {
-        if (TioUtils.checkBeforeIO(channelContext)) {
-            String json = null;
-            try {
-                json = objectMapper.writeValueAsString(MessageResponse.of(id, "result", msg.getParam(),
-                        msg.getMessage()));
-                Tio.send(channelContext, WsResponse.fromText(json, WsPacket.CHARSET_NAME));
-                if(log.isDebugEnabled()){
-                    log.debug("通道【{}】发送消息【{}】",channelContext.toString(),json);
-                }
-            } catch (JsonProcessingException e) {
-                log.error("ws消息订阅,解析失败,message:【】", JSONUtil.toJsonStr(msg));
-            }
-        }else {
-            channelContext.setClosed(true);
-            rPatternTopic.removeListener(this);
-            Tio.remove(channelContext,"通道已关闭,移除该通道");
-            if(log.isDebugEnabled()){
-                log.debug("通道已关闭【{}】",channel.toString());
-            }
-        }
-    }
-}

+ 0 - 20
nb-common/config-common/src/main/java/com/nb/common/config/websocket/DefaultRedisCallBack.java

@@ -1,20 +0,0 @@
-package com.nb.common.config.websocket;
-
-import org.springframework.dao.DataAccessException;
-import org.springframework.data.redis.connection.RedisConnection;
-import org.springframework.data.redis.core.RedisCallback;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName DefaultRedisCallBack.java
- * @Description TODO
- * @createTime 2022年03月25日 16:14:00
- */
-public class DefaultRedisCallBack implements RedisCallback<Object> {
-    @Override
-    public Object doInRedis(RedisConnection connection) throws DataAccessException {
-
-        return null;
-    }
-}

+ 0 - 28
nb-common/config-common/src/main/java/com/nb/common/config/websocket/HospitalCodeCheck.java

@@ -1,28 +0,0 @@
-package com.nb.common.config.websocket;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName HospitalCodeCheck.java
- * @Description 医院编码检测
- * @createTime 2022年05月26日 15:31:00
- */
-public interface HospitalCodeCheck {
-    /**
-     * 描述: 检测该医院编码是否存在
-     * @author lifang
-     * @date 2022/5/26 15:31
-     * @param code 医院编码
-     * @return boolean
-     */
-    boolean isExistCode(String code);
-
-    /**
-     * 描述: 获取医院编码对应的医院id
-     * @author lifang
-     * @date 2022/5/26 15:31
-     * @param code 医院编码
-     * @return boolean
-     */
-    String getHospitalId(String code);
-}

+ 0 - 22
nb-common/config-common/src/main/java/com/nb/common/config/websocket/MessageResponse.java

@@ -1,22 +0,0 @@
-package com.nb.common.config.websocket;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-import java.io.Serializable;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName MessageResponse.java
- * @Description TODO
- * @createTime 2022年03月25日 16:25:00
- */
-@Data
-@AllArgsConstructor(staticName = "of")
-public class MessageResponse implements Serializable {
-    private String id;
-    private String type;
-    private String param;
-    private Object payload;
-}

+ 0 - 44
nb-common/config-common/src/main/java/com/nb/common/config/websocket/MessagingRequest.java

@@ -1,44 +0,0 @@
-package com.nb.common.config.websocket;
-
-import cn.hutool.core.util.StrUtil;
-import lombok.Data;
-
-import java.util.*;
-@Data
-public class MessagingRequest {
-
-    /**
-     * 心跳、设备或报警信息,例如ping、device,alarm,patient
-     */
-    private String id;
-
-    /**
-     * 订阅/取消订阅
-     */
-    private Type type;
-
-    /**
-     * 产品名称
-     */
-    private String productName;
-    /**
-     * 订阅id,如设备id、病人id、报警类型、设备状态类型
-     */
-    private List<String> params;
-
-
-    private String tenantId;
-
-    public static enum Type{
-        sub,unsub
-    }
-
-    public void validate(){
-        if(StrUtil.isNullOrUndefined(id)){
-            throw new RuntimeException("MessageRequest id不能为空");
-        }
-        if(StrUtil.isNullOrUndefined(tenantId)){
-            throw new RuntimeException("tenantId不能为空");
-        }
-    }
-}

+ 0 - 16
nb-common/config-common/src/main/java/com/nb/common/config/websocket/TopicMessage.java

@@ -1,16 +0,0 @@
-package com.nb.common.config.websocket;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-import lombok.NoArgsConstructor;
-
-import java.io.Serializable;
-
-@Data
-@AllArgsConstructor(staticName = "of")
-@NoArgsConstructor
-public class TopicMessage implements Serializable {
-    private Object message;
-    private String param;
-
-}

+ 0 - 115
nb-common/config-common/src/main/java/com/nb/common/config/websocket/WebSocketConstant.java

@@ -1,115 +0,0 @@
-package com.nb.common.config.websocket;
-
-import cn.hutool.core.util.StrUtil;
-import com.nb.common.config.websocket.handler.TopicWrapper;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName WebSocketConstants.java
- * @Description websocket订阅所用常量
- * @createTime 2022年03月25日 14:25:00
- */
-public class WebSocketConstant {
-    public static final String MONITOR_TIME_COUNT ="monitor-time-count";
-
-    public static final String MONITOR_STATE_COUNT ="monitor-state-count";
-
-    /**
-     * 病人监控数量订阅
-     */
-    public static final String MONITOR_TOTAL_COUNT ="monitor-total-count";
-
-    public static final String PATIENT_UPDATE ="patient-update";
-
-    public static final String DEVICE_REPEAT ="device-repeat";
-
-    public static final String DEVICE_NONE ="device-none";
-
-    public static final String UNSUB_ALL ="all";
-
-    /**
-     * 病人监控订阅
-     */
-    public static final String PATIENT_MONITOR="patient-monitor";
-
-    /**
-     * his脚本连接通道
-     */
-    public static final String HIS_CONNECTION ="his-connection";
-    /**
-     * 主题格式为 device-info-detail:default:45789215623:医院id
-     *             alarm-count:default:电量不足:医院id
-     * @param id
-     * @param productName
-     * @param param
-     * @return
-     */
-    public static TopicWrapper getTopic(String id,String productName,String param,String tenantId){
-        productName=StrUtil.isEmptyIfStr(productName)?"default":productName;
-        tenantId=StrUtil.isNullOrUndefined(tenantId)?"*":tenantId;
-        return TopicWrapper.of(id+"-"+productName+"-"+param+"-"+tenantId,param);
-    }
-
-
-    /**
-     * 获取 设备状态变化主题
-     * @param tenantId 设备所属医院
-     * @return
-     */
-    public static TopicWrapper getMonitorStateCount(String tenantId){
-        return getTopic(MONITOR_STATE_COUNT,null,null,tenantId);
-    }
-
-    /**
-     * 获取 监控总数主题
-     * @param tenantId 设备所属医院
-     * @return
-     */
-    public static TopicWrapper getMonitorTotalCount(String tenantId){
-        return getTopic(MONITOR_TOTAL_COUNT,null,null,tenantId);
-    }
-
-    /**
-     * 获取 病人监护变化主题
-     * @param productName
-     * @param param
-     * @param tenantId
-     * @return
-     */
-    public static TopicWrapper getPatientMonitor(String productName,String param,String tenantId){
-        return getTopic(PATIENT_MONITOR,productName,param,tenantId);
-    }
-
-    /**
-     * 获取 病人新增主题
-     * @param tenantId 设备所属医院
-     * @return
-     */
-    public static TopicWrapper getPatientUpdate(String tenantId){
-        return getTopic(PATIENT_UPDATE,null,null,tenantId);
-    }
-
-
-    /**
-     * 描述: 获取医院临床设备重复数量统计
-     * @author lifang
-     * @date 2022/5/13 9:50
-     * @param tenantId
-     * @return TopicWrapper
-     */
-    public static TopicWrapper getDeviceRepeat(String tenantId){
-        return getTopic(DEVICE_REPEAT,null,null,tenantId);
-    }
-
-    /**
-     * 描述: 获取医院临床设备无绑定数量统计
-     * @author lifang
-     * @date 2022/5/13 9:50
-     * @param tenantId
-     * @return TopicWrapper
-     */
-    public static TopicWrapper getDeviceNone(String tenantId){
-        return getTopic(DEVICE_NONE,null,null,tenantId);
-    }
-}

+ 0 - 156
nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/Subscribe.java

@@ -1,156 +0,0 @@
-package com.nb.common.config.websocket.handler;
-
-import cn.hutool.core.collection.CollectionUtil;
-import cn.hutool.core.util.StrUtil;
-import com.nb.auth.bean.LoginUser;
-import com.nb.common.config.utils.RedissonUtil;
-import com.nb.core.Constants;
-import com.nb.common.config.websocket.DefaultMessageListener;
-import com.nb.common.config.websocket.MessagingRequest;
-import com.nb.common.config.websocket.TopicMessage;
-import com.nb.common.config.websocket.WebSocketConstant;
-import com.fasterxml.jackson.databind.ObjectMapper;
-import lombok.extern.slf4j.Slf4j;
-import org.redisson.api.RPatternTopic;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.util.ConcurrentReferenceHashMap;
-import org.tio.core.ChannelContext;
-
-import java.util.*;
-import java.util.stream.Collectors;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName Subscribe.java
- * @Description TODO
- * @createTime 2022年03月25日 14:18:00
- */
-@Slf4j
-public abstract class Subscribe implements WsHandler {
-    @Autowired
-    private ObjectMapper objectMapper;
-
-    @Autowired
-    private RedissonUtil redissonUtil;
-    /**
-     * 存储主题与redis通道关联
-     */
-    private static Map<String, RPatternTopic> topicMap=new ConcurrentReferenceHashMap<>();
-
-
-    public TopicWrapper getTopic(String productName,String param,String tenantId){
-        return  WebSocketConstant.getTopic(this.getId(),productName, param, tenantId);
-
-    };
-
-
-    @Override
-    public void onMessage(MessagingRequest message, ChannelContext channelContext) {
-        LoginUser loginUser = (LoginUser) channelContext.get(Constants.LOGIN_USER_KEY);
-        if(loginUser==null){
-            channelContext.setClosed(true);
-            return;
-        }
-        //获取所有设备id
-        List<String> params = message.getParams();
-        if(CollectionUtil.isEmpty(params)&&this.needParam()){
-            return;
-        }
-        List<TopicWrapper> subScribeTopic =null;
-        //需要处理的主题
-        if (CollectionUtil.isNotEmpty(params)) {
-            subScribeTopic =
-                    params.stream().map(param -> getTopic(message.getProductName(), param, message.getTenantId()))
-                            .collect(Collectors.toList());
-        }
-        else {
-            subScribeTopic = Collections.singletonList(getTopic(message.getProductName(), null, message.getTenantId()));
-        }
-
-        MessagingRequest.Type type = message.getType();
-        if(MessagingRequest.Type.sub==type){
-            //订阅主题
-            subScribeTopic.forEach(topicWrapper->this.subscribe(channelContext,topicWrapper));
-        }else {
-            //取消订阅主题
-            subScribeTopic.forEach(topicWrapper->this.unsubscribe(channelContext,topicWrapper.getTopic()));
-        }
-        if(log.isDebugEnabled()){
-            log.debug("订阅成功{}",subScribeTopic.stream().map(TopicWrapper::getTopic).collect(Collectors.toList()));
-        }
-    }
-
-    /**
-     * ws 订阅主题
-     * @param channelContext
-     * @param topicWrapper
-     */
-    public void subscribe(ChannelContext channelContext, TopicWrapper topicWrapper){
-        getChannelTopic(channelContext).add(topicWrapper.getTopic());
-        //同一主题只订阅一次
-        RPatternTopic rTopic = topicMap.computeIfAbsent(topicWrapper.getTopic(),topic->redissonUtil.getPatternTopic(topicWrapper.getTopic()));
-        addTopicListener(rTopic,channelContext, topicWrapper.getTopic());
-    };
-
-    /**
-     * ws取消订阅主题
-     * @param channelContext
-     * @param topic
-     */
-    public void unsubscribe(ChannelContext channelContext, String topic){
-        if(StrUtil.isEmpty(topic)){
-            return;
-        }
-        Set<String> allTopics=new HashSet<>();
-
-        if(topic.startsWith("all")){
-            allTopics.addAll(getChannelTopic(channelContext));
-        }
-
-        //取消订阅
-        for (String subTopic : allTopics) {
-            topicMap.computeIfPresent(subTopic,(k,rTopic)->{
-                rTopic.removeListener( getTopicListener(channelContext,k));
-                return rTopic;
-            });
-            Map<String, DefaultMessageListener> topicListeners = getTopicListeners(channelContext);
-            topicListeners.remove(subTopic);
-        }
-
-    };
-
-
-    public Map<String,DefaultMessageListener> getTopicListeners(ChannelContext channelContext){
-        Object result = Optional.ofNullable(channelContext.get("topic")).orElse(new HashMap<String,DefaultMessageListener>());
-        channelContext.set("topic",result);
-        return  (Map<String,DefaultMessageListener>) result;
-    }
-
-    public DefaultMessageListener getTopicListener(ChannelContext channelContext,String topic){
-        Map<String,DefaultMessageListener> result = (Map<String, DefaultMessageListener>) Optional.ofNullable(channelContext.get("topic")).orElse(new HashMap<>());
-        return  result.get(topic);
-    }
-
-    public DefaultMessageListener addTopicListener(RPatternTopic rTopic,ChannelContext channelContext,String topic){
-        Map<String, DefaultMessageListener> topicByChannel = getTopicListeners(channelContext);
-        DefaultMessageListener messageListener = topicByChannel.computeIfAbsent(topic, k -> {
-            DefaultMessageListener defaultMessageListener = new DefaultMessageListener(getId(), objectMapper, channelContext,rTopic);
-            rTopic.addListenerAsync(TopicMessage.class, defaultMessageListener);
-            return defaultMessageListener;
-        });
-        return  messageListener;
-    }
-
-    private Set<String> getChannelTopic(ChannelContext channelContext){
-        Set<String> topics=null;
-        Object topicSet = channelContext.getAttribute("subtopic");
-        if(topicSet==null){
-            topics=new HashSet<>();
-        }else {
-            topics= (Set<String>) topicSet;
-        }
-        channelContext.setAttribute("subtopic",topics);
-        return topics;
-    }
-}

+ 0 - 24
nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/TopicWrapper.java

@@ -1,24 +0,0 @@
-package com.nb.common.config.websocket.handler;
-
-import lombok.AllArgsConstructor;
-import lombok.Data;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName Topic.java
- * @Description ws订阅主题
- * @createTime 2022年05月07日 17:14:00
- */
-@Data
-@AllArgsConstructor(staticName = "of")
-public class TopicWrapper {
-    /**
-     * 主题
-     */
-    private String topic;
-    /**
-     * 订阅参数
-     */
-    private String param;
-}

+ 0 - 28
nb-common/config-common/src/main/java/com/nb/common/config/websocket/handler/WsHandler.java

@@ -1,28 +0,0 @@
-package com.nb.common.config.websocket.handler;
-
-import com.nb.common.config.websocket.MessagingRequest;
-import org.tio.core.ChannelContext;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName WsHandler.java
- * @Description TODO
- * @createTime 2022年03月25日 10:27:00
- */
-public interface WsHandler {
-    String getId();
-
-    void onMessage(MessagingRequest message, ChannelContext channelContext);
-
-    void close(ChannelContext channelContext);
-
-    /**
-     * 描述: 参数是否为必输的
-     * @author lifang
-     * @date 2022/5/9 11:20
-     * @param
-     * @return boolean
-     */
-    boolean needParam();
-}

+ 0 - 63
nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/DefaultWsServerAioListener.java

@@ -1,63 +0,0 @@
-package com.nb.common.config.websocket.ws;
-
-import com.nb.common.config.websocket.handler.WsHandler;
-import lombok.extern.slf4j.Slf4j;
-import org.tio.core.ChannelContext;
-import org.tio.core.intf.Packet;
-import org.tio.websocket.server.WsServerAioListener;
-
-import java.util.*;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName ChannelHeartBeatCheck.java
- * @Description 检查通道是否存活心跳
- * @createTime 2022年06月10日 20:13:00
- */
-@Slf4j
-public class DefaultWsServerAioListener extends WsServerAioListener {
-
-
-    private List<WsHandler> wsHandlers;
-
-    public DefaultWsServerAioListener( List<WsHandler> wsHandlers) {
-        this.wsHandlers = wsHandlers;
-    }
-
-    @Override
-    public boolean onHeartbeatTimeout(ChannelContext channelContext, Long interval, int heartbeatTimeoutCount) {
-        //连接关闭时进行业务处理
-        log.info("{},心跳超时,通道关闭", channelContext);
-        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
-        return false;
-    }
-
-
-    @Override
-    public void onAfterDecoded(ChannelContext channelContext, Packet packet, int packetSize) throws Exception {
-    }
-
-    @Override
-    public void onAfterReceivedBytes(ChannelContext channelContext, int receivedBytes) throws Exception {
-
-    }
-
-    @Override
-    public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess) throws Exception {
-
-    }
-
-    @Override
-    public void onAfterHandled(ChannelContext channelContext, Packet packet, long cost) throws Exception {
-
-    }
-
-    @Override
-    public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
-        if(log.isDebugEnabled()){
-            log.debug("{},通道关闭", channelContext);
-        }
-        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
-    }
-}

+ 0 - 28
nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/HeartBeatConfig.java

@@ -1,28 +0,0 @@
-package com.nb.common.config.websocket.ws;
-
-import com.nb.common.config.websocket.handler.WsHandler;
-import lombok.AllArgsConstructor;
-import org.springframework.boot.CommandLineRunner;
-import org.springframework.context.annotation.Configuration;
-import org.tio.websocket.starter.TioWebSocketServerBootstrap;
-
-import java.util.List;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName HeartBeatConfig.java
- * @Description ws心跳业务配置
- * @createTime 2022年06月10日 22:47:00
- */
-@Configuration
-@AllArgsConstructor
-public class HeartBeatConfig implements CommandLineRunner {
-    private final TioWebSocketServerBootstrap serverTioConfig;
-    private final List<WsHandler> wsHandlers;
-
-    @Override
-    public void run(String... args) {
-        serverTioConfig.getServerTioConfig().setServerAioListener(new DefaultWsServerAioListener(wsHandlers));
-    }
-}

+ 0 - 16
nb-common/config-common/src/main/java/com/nb/common/config/websocket/ws/IWebSocketAuthFilter.java

@@ -1,16 +0,0 @@
-package com.nb.common.config.websocket.ws;
-
-import org.tio.http.common.HttpRequest;
-import org.tio.http.common.HttpResponse;
-import org.tio.core.ChannelContext;
-
-/**
- * @author lifang
- * @version 1.0.0
- * @ClassName IWebSocketAuth.java
- * @Description websocket授权
- * @createTime 2022年07月18日 10:06:00
- */
-public interface IWebSocketAuthFilter {
-    boolean auth(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext);
-}

+ 2 - 1
nb-common/log-common/pom.xml

@@ -35,7 +35,8 @@
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.tuoren</groupId>

+ 1 - 0
nb-common/pom.xml

@@ -17,6 +17,7 @@
         <module>crud-common</module>
         <module>delay-queue-common</module>
         <module>config-common</module>
+        <module>ws-common</module>
     </modules>
 
 

+ 38 - 0
nb-common/ws-common/pom.xml

@@ -0,0 +1,38 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nb-common</artifactId>
+        <groupId>com.tuoren</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>ws-common</artifactId>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.t-io</groupId>
+            <artifactId>tio-websocket-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>cn.hutool</groupId>
+            <artifactId>hutool-all</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>nb-auth</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.redisson</groupId>
+            <artifactId>redisson-spring-boot-starter</artifactId>
+            <scope>provided</scope>
+        </dependency>
+    </dependencies>
+
+</project>

+ 55 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultMessageListener.java

@@ -0,0 +1,55 @@
+package com.nb.common.websocket;
+
+import cn.hutool.json.JSONUtil;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.Data;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RPatternTopic;
+import org.redisson.api.listener.PatternMessageListener;
+import org.tio.core.ChannelContext;
+import org.tio.core.Tio;
+import org.tio.core.utils.TioUtils;
+import org.tio.websocket.common.WsPacket;
+import org.tio.websocket.common.WsResponse;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultMessageListener.java
+ * @Description TODO
+ * @createTime 2022年03月25日 14:42:00
+ */
+@Data
+@Slf4j
+public class DefaultMessageListener implements PatternMessageListener<TopicMessage> {
+    private final String id;
+    private final ObjectMapper objectMapper;
+    private final ChannelContext channelContext;
+    private final RPatternTopic rPatternTopic;
+
+
+    @Override
+    public void onMessage(CharSequence pattern, CharSequence channel, TopicMessage msg) {
+        if (TioUtils.checkBeforeIO(channelContext)) {
+            String json = null;
+            try {
+                json = objectMapper.writeValueAsString(MessageResponse.of(id, "result", msg.getParam(),
+                        msg.getMessage()));
+                Tio.send(channelContext, WsResponse.fromText(json, WsPacket.CHARSET_NAME));
+                if(log.isDebugEnabled()){
+                    log.debug("通道【{}】发送消息【{}】",channelContext.toString(),json);
+                }
+            } catch (JsonProcessingException e) {
+                log.error("ws消息订阅,解析失败,message:【】", JSONUtil.toJsonStr(msg));
+            }
+        }else {
+            channelContext.setClosed(true);
+            rPatternTopic.removeListener(this);
+            Tio.remove(channelContext,"通道已关闭,移除该通道");
+            if(log.isDebugEnabled()){
+                log.debug("通道已关闭【{}】",channel.toString());
+            }
+        }
+    }
+}

+ 20 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultRedisCallBack.java

@@ -0,0 +1,20 @@
+package com.nb.common.websocket;
+
+import org.springframework.dao.DataAccessException;
+import org.springframework.data.redis.connection.RedisConnection;
+import org.springframework.data.redis.core.RedisCallback;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DefaultRedisCallBack.java
+ * @Description TODO
+ * @createTime 2022年03月25日 16:14:00
+ */
+public class DefaultRedisCallBack implements RedisCallback<Object> {
+    @Override
+    public Object doInRedis(RedisConnection connection) throws DataAccessException {
+
+        return null;
+    }
+}

+ 146 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/DefaultWebSocketMsgHandler.java

@@ -0,0 +1,146 @@
+package com.nb.common.websocket;
+
+import cn.hutool.core.collection.CollUtil;
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.ObjectUtil;
+import cn.hutool.json.JSONUtil;
+import com.nb.common.websocket.handler.HisMsgHandler;
+import com.nb.common.websocket.ws.IWebSocketAuthFilter;
+import com.nb.core.Constants;
+import com.nb.common.websocket.handler.WsHandler;
+import com.nb.core.result.R;
+import lombok.AllArgsConstructor;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.boot.autoconfigure.AutoConfigureAfter;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Component;
+import org.tio.core.ChannelContext;
+import org.tio.core.Tio;
+import org.tio.http.common.HttpRequest;
+import org.tio.http.common.HttpResponse;
+import org.tio.websocket.common.WsPacket;
+import org.tio.websocket.common.WsRequest;
+import org.tio.websocket.common.WsResponse;
+import org.tio.websocket.server.handler.IWsMsgHandler;
+import java.util.*;
+import java.util.stream.Collectors;
+
+@Component
+@Slf4j
+@AllArgsConstructor
+@AutoConfigureAfter(RedisTemplate.class)
+public class DefaultWebSocketMsgHandler implements IWsMsgHandler {
+    private final List<WsHandler> messageHandlers;
+    private final List<HisMsgHandler> hisMsgHandlers;
+    private final List<IWebSocketAuthFilter> authFilters;
+
+    @Override
+    public HttpResponse handshake(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) {
+        return httpResponse;
+    }
+
+    @Override
+    public void onAfterHandshaked(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext) throws Exception {
+        //用户授权码
+        String authorization = httpRequest.getParam("Authorization");
+        if(log.isDebugEnabled()){
+            log.debug("websocket 握手成功,开始进行权限校验,Authorization:{}",authorization);
+        }
+        if(CharSequenceUtil.isNullOrUndefined(authorization)){
+            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")), WsPacket.CHARSET_NAME));
+            Thread.sleep(20);
+            Tio.remove(channelContext,  "接受数据不符合业务规范");
+            return;
+        }
+        boolean match = authFilters.stream().anyMatch(filter -> Boolean.TRUE.equals(filter.auth(httpRequest, httpResponse, channelContext)));
+        if(match){
+            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.success("连接成功")),"utf-8"));
+        }else {
+            Tio.send(channelContext,WsResponse.fromText(JSONUtil.toJsonStr(R.fail("授权失败")), WsPacket.CHARSET_NAME));
+            Thread.sleep(20);
+            Tio.remove(channelContext,  "接受数据不符合业务规范");
+        }
+    }
+
+    @Override
+    public Object onBytes(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext){
+        return null;
+    }
+
+    @Override
+    public Object onClose(WsRequest wsRequest, byte[] bytes, ChannelContext channelContext) {
+        messageHandlers.forEach(wsHandler -> wsHandler.close(channelContext));
+        return null;
+    }
+
+    @Override
+    public Object onText(WsRequest wsRequest, String message, ChannelContext channelContext) {
+        if (CharSequenceUtil.isEmpty(message)) {
+            channelContext.setClosed(true);
+            Tio.remove(channelContext,  "接受数据不符合业务规范");
+            return null;
+        }
+        //心跳请求
+        if("ping".equalsIgnoreCase(message.trim())){
+            Tio.send(channelContext,WsResponse.fromText("pong","utf-8"));
+            return null;
+        }
+        try {
+            synchronized (channelContext.getId()){
+                if(log.isDebugEnabled()){
+                    log.debug("websocket 接收到消息,message:{},token:{},userId:{}",message,channelContext.getToken(),JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
+                }
+                Object user = channelContext.get(Constants.LOGIN_USER_KEY);
+                if(ObjectUtil.isNotNull(user)){
+                    handleUserMessage(message,channelContext);
+                }else {
+                    handleHospitalMessage(message,String.valueOf(channelContext.get(Constants.HOSPITAL_ID)));
+                }
+            }
+        }catch (Exception e){
+            log.warn("websocket 接收到异常请求,token:{},message:{},userId:{}",channelContext.getToken(),message,JSONUtil.toJsonStr(channelContext.get(Constants.LOGIN_USER_KEY)));
+            channelContext.setCloseCode(ChannelContext.CloseCode.HEARTBEAT_TIMEOUT);
+            Tio.remove(channelContext,  "接受数据不符合业务规范");
+        }
+
+        return null;
+    }
+
+
+    /**
+     * 描述: 处理用户请求
+     * @author lifang
+     * @date 2022/5/27 9:54
+     * @param message
+     * @param channelContext
+     * @return void
+     */
+    private void handleUserMessage( String message, ChannelContext channelContext){
+        MessagingRequest messagingRequest = JSONUtil.toBean(message, MessagingRequest.class);
+        if(messagingRequest.isFromHis()){
+            return;
+        }
+        List<WsHandler> collect = messageHandlers
+                .parallelStream()
+                .filter(handler -> messagingRequest.getId().equals(handler.getId()))
+                .collect(Collectors.toList());
+        //传入格式错误,不支持该订阅id
+        if(CollUtil.isEmpty(collect)){
+            channelContext.setClosed(true);
+            Tio.remove(channelContext,  "接受数据不符合业务规范");
+            return;
+        }
+        collect.forEach(handler->handler.onMessage(messagingRequest,channelContext));
+    }
+
+    /**
+     * 描述: 处理医院响应请求
+     * @author lifang
+     * @date 2022/5/27 9:54
+     * @param message
+     * @return void
+     */
+    private void handleHospitalMessage(String message,String hospitalId){
+        hisMsgHandlers.forEach(handle->handle.handle(message,hospitalId));
+    }
+}

+ 28 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/HospitalCodeCheck.java

@@ -0,0 +1,28 @@
+package com.nb.common.websocket;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HospitalCodeCheck.java
+ * @Description 医院编码检测
+ * @createTime 2022年05月26日 15:31:00
+ */
+public interface HospitalCodeCheck {
+    /**
+     * 描述: 检测该医院编码是否存在
+     * @author lifang
+     * @date 2022/5/26 15:31
+     * @param code 医院编码
+     * @return boolean
+     */
+    boolean isExistCode(String code);
+
+    /**
+     * 描述: 获取医院编码对应的医院id
+     * @author lifang
+     * @date 2022/5/26 15:31
+     * @param code 医院编码
+     * @return boolean
+     */
+    String getHospitalId(String code);
+}

+ 22 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/MessageResponse.java

@@ -0,0 +1,22 @@
+package com.nb.common.websocket;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName MessageResponse.java
+ * @Description TODO
+ * @createTime 2022年03月25日 16:25:00
+ */
+@Data
+@AllArgsConstructor(staticName = "of")
+public class MessageResponse implements Serializable {
+    private String id;
+    private String type;
+    private String param;
+    private Object payload;
+}

+ 39 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/MessagingRequest.java

@@ -0,0 +1,39 @@
+package com.nb.common.websocket;
+
+import cn.hutool.core.util.StrUtil;
+import lombok.Data;
+
+import java.util.*;
+@Data
+public class MessagingRequest {
+
+    /**
+     * 心跳、设备或报警信息,例如ping、device,alarm,patient
+     */
+    private String id;
+
+    /**
+     * 订阅/取消订阅
+     */
+    private Type type;
+
+    /**
+     * 产品名称
+     */
+    private String productName;
+    /**
+     * 订阅id,如设备id、病人id、报警类型、设备状态类型
+     */
+    private List<String> params;
+
+
+    private String tenantId;
+
+    public static enum Type{
+        sub,unsub
+    }
+
+    public boolean isFromHis(){
+        return StrUtil.isNullOrUndefined(id)||StrUtil.isNullOrUndefined(tenantId);
+    }
+}

+ 16 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/TopicMessage.java

@@ -0,0 +1,16 @@
+package com.nb.common.websocket;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor(staticName = "of")
+@NoArgsConstructor
+public class TopicMessage implements Serializable {
+    private Object message;
+    private String param;
+
+}

+ 115 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/WebSocketConstant.java

@@ -0,0 +1,115 @@
+package com.nb.common.websocket;
+
+import cn.hutool.core.util.StrUtil;
+import com.nb.common.websocket.handler.TopicWrapper;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName WebSocketConstants.java
+ * @Description websocket订阅所用常量
+ * @createTime 2022年03月25日 14:25:00
+ */
+public class WebSocketConstant {
+    public static final String MONITOR_TIME_COUNT ="monitor-time-count";
+
+    public static final String MONITOR_STATE_COUNT ="monitor-state-count";
+
+    /**
+     * 病人监控数量订阅
+     */
+    public static final String MONITOR_TOTAL_COUNT ="monitor-total-count";
+
+    public static final String PATIENT_UPDATE ="patient-update";
+
+    public static final String DEVICE_REPEAT ="device-repeat";
+
+    public static final String DEVICE_NONE ="device-none";
+
+    public static final String UNSUB_ALL ="all";
+
+    /**
+     * 病人监控订阅
+     */
+    public static final String PATIENT_MONITOR="patient-monitor";
+
+    /**
+     * his脚本连接通道
+     */
+    public static final String HIS_CONNECTION ="his-connection";
+    /**
+     * 主题格式为 device-info-detail:default:45789215623:医院id
+     *             alarm-count:default:电量不足:医院id
+     * @param id
+     * @param productName
+     * @param param
+     * @return
+     */
+    public static TopicWrapper getTopic(String id,String productName,String param,String tenantId){
+        productName=StrUtil.isEmptyIfStr(productName)?"default":productName;
+        tenantId=StrUtil.isNullOrUndefined(tenantId)?"*":tenantId;
+        return TopicWrapper.of(id+"-"+productName+"-"+param+"-"+tenantId,param);
+    }
+
+
+    /**
+     * 获取 设备状态变化主题
+     * @param tenantId 设备所属医院
+     * @return
+     */
+    public static TopicWrapper getMonitorStateCount(String tenantId){
+        return getTopic(MONITOR_STATE_COUNT,null,null,tenantId);
+    }
+
+    /**
+     * 获取 监控总数主题
+     * @param tenantId 设备所属医院
+     * @return
+     */
+    public static TopicWrapper getMonitorTotalCount(String tenantId){
+        return getTopic(MONITOR_TOTAL_COUNT,null,null,tenantId);
+    }
+
+    /**
+     * 获取 病人监护变化主题
+     * @param productName
+     * @param param
+     * @param tenantId
+     * @return
+     */
+    public static TopicWrapper getPatientMonitor(String productName,String param,String tenantId){
+        return getTopic(PATIENT_MONITOR,productName,param,tenantId);
+    }
+
+    /**
+     * 获取 病人新增主题
+     * @param tenantId 设备所属医院
+     * @return
+     */
+    public static TopicWrapper getPatientUpdate(String tenantId){
+        return getTopic(PATIENT_UPDATE,null,null,tenantId);
+    }
+
+
+    /**
+     * 描述: 获取医院临床设备重复数量统计
+     * @author lifang
+     * @date 2022/5/13 9:50
+     * @param tenantId
+     * @return TopicWrapper
+     */
+    public static TopicWrapper getDeviceRepeat(String tenantId){
+        return getTopic(DEVICE_REPEAT,null,null,tenantId);
+    }
+
+    /**
+     * 描述: 获取医院临床设备无绑定数量统计
+     * @author lifang
+     * @date 2022/5/13 9:50
+     * @param tenantId
+     * @return TopicWrapper
+     */
+    public static TopicWrapper getDeviceNone(String tenantId){
+        return getTopic(DEVICE_NONE,null,null,tenantId);
+    }
+}

+ 14 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/WsAutoConfiguration.java

@@ -0,0 +1,14 @@
+package com.nb.common.websocket;
+
+import org.springframework.context.annotation.ComponentScan;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName WsAutoConfiguration.java
+ * @Description TODO
+ * @createTime 2022年08月02日 16:29:00
+ */
+@ComponentScan("com.nb.common.websocket")
+public class WsAutoConfiguration {
+}

+ 13 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/HisMsgHandler.java

@@ -0,0 +1,13 @@
+package com.nb.common.websocket.handler;
+
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HisMsgHandler.java
+ * @Description TODO
+ * @createTime 2022年08月02日 16:33:00
+ */
+public interface HisMsgHandler {
+    void handle(String message, String hospitalId);
+}

+ 156 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/Subscribe.java

@@ -0,0 +1,156 @@
+package com.nb.common.websocket.handler;
+
+import cn.hutool.core.collection.CollectionUtil;
+import cn.hutool.core.util.StrUtil;
+import com.nb.auth.bean.LoginUser;
+import com.nb.core.Constants;
+import com.nb.common.websocket.DefaultMessageListener;
+import com.nb.common.websocket.MessagingRequest;
+import com.nb.common.websocket.TopicMessage;
+import com.nb.common.websocket.WebSocketConstant;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import lombok.extern.slf4j.Slf4j;
+import org.redisson.api.RPatternTopic;
+import org.redisson.api.RedissonClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.util.ConcurrentReferenceHashMap;
+import org.tio.core.ChannelContext;
+
+import java.util.*;
+import java.util.stream.Collectors;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName Subscribe.java
+ * @Description TODO
+ * @createTime 2022年03月25日 14:18:00
+ */
+@Slf4j
+public abstract class Subscribe implements WsHandler {
+    @Autowired
+    private ObjectMapper objectMapper;
+
+    @Autowired
+    private RedissonClient redissonClient;
+    /**
+     * 存储主题与redis通道关联
+     */
+    private static Map<String, RPatternTopic> topicMap=new ConcurrentReferenceHashMap<>();
+
+
+    public TopicWrapper getTopic(String productName,String param,String tenantId){
+        return  WebSocketConstant.getTopic(this.getId(),productName, param, tenantId);
+
+    };
+
+
+    @Override
+    public void onMessage(MessagingRequest message, ChannelContext channelContext) {
+        LoginUser loginUser = (LoginUser) channelContext.get(Constants.LOGIN_USER_KEY);
+        if(loginUser==null){
+            channelContext.setClosed(true);
+            return;
+        }
+        //获取所有设备id
+        List<String> params = message.getParams();
+        if(CollectionUtil.isEmpty(params)&&this.needParam()){
+            return;
+        }
+        List<TopicWrapper> subScribeTopic =null;
+        //需要处理的主题
+        if (CollectionUtil.isNotEmpty(params)) {
+            subScribeTopic =
+                    params.stream().map(param -> getTopic(message.getProductName(), param, message.getTenantId()))
+                            .collect(Collectors.toList());
+        }
+        else {
+            subScribeTopic = Collections.singletonList(getTopic(message.getProductName(), null, message.getTenantId()));
+        }
+
+        MessagingRequest.Type type = message.getType();
+        if(MessagingRequest.Type.sub==type){
+            //订阅主题
+            subScribeTopic.forEach(topicWrapper->this.subscribe(channelContext,topicWrapper));
+        }else {
+            //取消订阅主题
+            subScribeTopic.forEach(topicWrapper->this.unsubscribe(channelContext,topicWrapper.getTopic()));
+        }
+        if(log.isDebugEnabled()){
+            log.debug("订阅成功{}",subScribeTopic.stream().map(TopicWrapper::getTopic).collect(Collectors.toList()));
+        }
+    }
+
+    /**
+     * ws 订阅主题
+     * @param channelContext
+     * @param topicWrapper
+     */
+    public void subscribe(ChannelContext channelContext, TopicWrapper topicWrapper){
+        getChannelTopic(channelContext).add(topicWrapper.getTopic());
+        //同一主题只订阅一次
+        RPatternTopic rTopic = topicMap.computeIfAbsent(topicWrapper.getTopic(),topic->redissonClient.getPatternTopic(topicWrapper.getTopic()));
+        addTopicListener(rTopic,channelContext, topicWrapper.getTopic());
+    };
+
+    /**
+     * ws取消订阅主题
+     * @param channelContext
+     * @param topic
+     */
+    public void unsubscribe(ChannelContext channelContext, String topic){
+        if(StrUtil.isEmpty(topic)){
+            return;
+        }
+        Set<String> allTopics=new HashSet<>();
+
+        if(topic.startsWith("all")){
+            allTopics.addAll(getChannelTopic(channelContext));
+        }
+
+        //取消订阅
+        for (String subTopic : allTopics) {
+            topicMap.computeIfPresent(subTopic,(k,rTopic)->{
+                rTopic.removeListener( getTopicListener(channelContext,k));
+                return rTopic;
+            });
+            Map<String, DefaultMessageListener> topicListeners = getTopicListeners(channelContext);
+            topicListeners.remove(subTopic);
+        }
+
+    };
+
+
+    public Map<String,DefaultMessageListener> getTopicListeners(ChannelContext channelContext){
+        Object result = Optional.ofNullable(channelContext.get("topic")).orElse(new HashMap<String,DefaultMessageListener>());
+        channelContext.set("topic",result);
+        return  (Map<String,DefaultMessageListener>) result;
+    }
+
+    public DefaultMessageListener getTopicListener(ChannelContext channelContext,String topic){
+        Map<String,DefaultMessageListener> result = (Map<String, DefaultMessageListener>) Optional.ofNullable(channelContext.get("topic")).orElse(new HashMap<>());
+        return  result.get(topic);
+    }
+
+    public DefaultMessageListener addTopicListener(RPatternTopic rTopic,ChannelContext channelContext,String topic){
+        Map<String, DefaultMessageListener> topicByChannel = getTopicListeners(channelContext);
+        DefaultMessageListener messageListener = topicByChannel.computeIfAbsent(topic, k -> {
+            DefaultMessageListener defaultMessageListener = new DefaultMessageListener(getId(), objectMapper, channelContext,rTopic);
+            rTopic.addListenerAsync(TopicMessage.class, defaultMessageListener);
+            return defaultMessageListener;
+        });
+        return  messageListener;
+    }
+
+    private Set<String> getChannelTopic(ChannelContext channelContext){
+        Set<String> topics=null;
+        Object topicSet = channelContext.getAttribute("subtopic");
+        if(topicSet==null){
+            topics=new HashSet<>();
+        }else {
+            topics= (Set<String>) topicSet;
+        }
+        channelContext.setAttribute("subtopic",topics);
+        return topics;
+    }
+}

+ 24 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/TopicWrapper.java

@@ -0,0 +1,24 @@
+package com.nb.common.websocket.handler;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName Topic.java
+ * @Description ws订阅主题
+ * @createTime 2022年05月07日 17:14:00
+ */
+@Data
+@AllArgsConstructor(staticName = "of")
+public class TopicWrapper {
+    /**
+     * 主题
+     */
+    private String topic;
+    /**
+     * 订阅参数
+     */
+    private String param;
+}

+ 28 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/handler/WsHandler.java

@@ -0,0 +1,28 @@
+package com.nb.common.websocket.handler;
+
+import com.nb.common.websocket.MessagingRequest;
+import org.tio.core.ChannelContext;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName WsHandler.java
+ * @Description TODO
+ * @createTime 2022年03月25日 10:27:00
+ */
+public interface WsHandler {
+    String getId();
+
+    void onMessage(MessagingRequest message, ChannelContext channelContext);
+
+    void close(ChannelContext channelContext);
+
+    /**
+     * 描述: 参数是否为必输的
+     * @author lifang
+     * @date 2022/5/9 11:20
+     * @param
+     * @return boolean
+     */
+    boolean needParam();
+}

+ 63 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/DefaultWsServerAioListener.java

@@ -0,0 +1,63 @@
+package com.nb.common.websocket.ws;
+
+import com.nb.common.websocket.handler.WsHandler;
+import lombok.extern.slf4j.Slf4j;
+import org.tio.core.ChannelContext;
+import org.tio.core.intf.Packet;
+import org.tio.websocket.server.WsServerAioListener;
+
+import java.util.*;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName ChannelHeartBeatCheck.java
+ * @Description 检查通道是否存活心跳
+ * @createTime 2022年06月10日 20:13:00
+ */
+@Slf4j
+public class DefaultWsServerAioListener extends WsServerAioListener {
+
+
+    private List<WsHandler> wsHandlers;
+
+    public DefaultWsServerAioListener( List<WsHandler> wsHandlers) {
+        this.wsHandlers = wsHandlers;
+    }
+
+    @Override
+    public boolean onHeartbeatTimeout(ChannelContext channelContext, Long interval, int heartbeatTimeoutCount) {
+        //连接关闭时进行业务处理
+        log.info("{},心跳超时,通道关闭", channelContext);
+        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
+        return false;
+    }
+
+
+    @Override
+    public void onAfterDecoded(ChannelContext channelContext, Packet packet, int packetSize) throws Exception {
+    }
+
+    @Override
+    public void onAfterReceivedBytes(ChannelContext channelContext, int receivedBytes) throws Exception {
+
+    }
+
+    @Override
+    public void onAfterSent(ChannelContext channelContext, Packet packet, boolean isSentSuccess) throws Exception {
+
+    }
+
+    @Override
+    public void onAfterHandled(ChannelContext channelContext, Packet packet, long cost) throws Exception {
+
+    }
+
+    @Override
+    public void onBeforeClose(ChannelContext channelContext, Throwable throwable, String remark, boolean isRemove) throws Exception {
+        if(log.isDebugEnabled()){
+            log.debug("{},通道关闭", channelContext);
+        }
+        wsHandlers.parallelStream().forEach(wsHandler -> wsHandler.close(channelContext));
+    }
+}

+ 28 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/HeartBeatConfig.java

@@ -0,0 +1,28 @@
+package com.nb.common.websocket.ws;
+
+import com.nb.common.websocket.handler.WsHandler;
+import lombok.AllArgsConstructor;
+import org.springframework.boot.CommandLineRunner;
+import org.springframework.context.annotation.Configuration;
+import org.tio.websocket.starter.TioWebSocketServerBootstrap;
+
+import java.util.List;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HeartBeatConfig.java
+ * @Description ws心跳业务配置
+ * @createTime 2022年06月10日 22:47:00
+ */
+@Configuration
+@AllArgsConstructor
+public class HeartBeatConfig implements CommandLineRunner {
+    private final TioWebSocketServerBootstrap serverTioConfig;
+    private final List<WsHandler> wsHandlers;
+
+    @Override
+    public void run(String... args) {
+        serverTioConfig.getServerTioConfig().setServerAioListener(new DefaultWsServerAioListener(wsHandlers));
+    }
+}

+ 16 - 0
nb-common/ws-common/src/main/java/com/nb/common/websocket/ws/IWebSocketAuthFilter.java

@@ -0,0 +1,16 @@
+package com.nb.common.websocket.ws;
+
+import org.tio.http.common.HttpRequest;
+import org.tio.http.common.HttpResponse;
+import org.tio.core.ChannelContext;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName IWebSocketAuth.java
+ * @Description websocket授权
+ * @createTime 2022年07月18日 10:06:00
+ */
+public interface IWebSocketAuthFilter {
+    boolean auth(HttpRequest httpRequest, HttpResponse httpResponse, ChannelContext channelContext);
+}

+ 3 - 0
nb-common/ws-common/src/main/resources/META-INF/spring.factories

@@ -0,0 +1,3 @@
+# LogAutoConfiguration ×Ô¶¯×°ÅäÉùÃ÷
+org.springframework.boot.autoconfigure.EnableAutoConfiguration=\
+com.nb.common.websocket.WsAutoConfiguration

+ 5 - 2
nb-core/pom.xml

@@ -47,10 +47,13 @@
         </dependency>
         <dependency>
             <groupId>org.springframework.boot</groupId>
-            <artifactId>spring-boot-starter-web</artifactId>
-            <optional>true</optional>
+            <artifactId>spring-boot-starter-undertow</artifactId>
             <scope>compile</scope>
         </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
         <dependency>
             <groupId>com.github.xiaoymin</groupId>
             <artifactId>knife4j-spring-boot-starter</artifactId>

+ 2 - 19
nb-core/src/main/java/com/nb/core/doc/SwaggerDocConfig.java

@@ -28,7 +28,7 @@ public class SwaggerDocConfig {
     public Docket system(){
         return new Docket(DocumentationType.SWAGGER_2)
                 .select()
-                .apis(RequestHandlerSelectors.basePackage("com.nb.system.controller"))
+                .apis(RequestHandlerSelectors.basePackage("com.nb.web.service.system.controller"))
                 .paths(PathSelectors.any())
                 .build()
                 .groupName("系统模块");
@@ -38,27 +38,10 @@ public class SwaggerDocConfig {
     public Docket bus(){
         return new Docket(DocumentationType.SWAGGER_2)
                 .select()
-                .apis(RequestHandlerSelectors.basePackage("com.nb.bus.controller"))
+                .apis(RequestHandlerSelectors.basePackage("com.nb.web.service.bus.controller"))
                 .paths(PathSelectors.any())
                 .build()
                 .groupName("业务模块");
     }
 
-
-    @Bean
-    public Docket admin(){
-        ParameterBuilder ticketPar = new ParameterBuilder();
-        List<Parameter> pars = new ArrayList<Parameter>();
-        ticketPar.name("tenantId").description("租户id")
-                .modelRef(new ModelRef("string")).parameterType("query")
-                .required(true).build();
-        pars.add(ticketPar.build());
-
-        return new Docket(DocumentationType.SWAGGER_2)
-                .select()
-                .apis(RequestHandlerSelectors.basePackage("com.nb.auth.controller"))
-                .paths(PathSelectors.any())
-                .build()
-                .groupName("授权模块");
-    }
 }

+ 11 - 6
nb-oss/pom.xml

@@ -12,19 +12,24 @@
     <artifactId>nb-oss</artifactId>
 
     <dependencies>
+
         <dependency>
-            <groupId>com.tuoren</groupId>
-            <artifactId>all-common</artifactId>
-            <version>1.0</version>
+            <groupId>io.minio</groupId>
+            <artifactId>minio</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-undertow</artifactId>
+            <scope>provided</scope>
         </dependency>
         <dependency>
             <groupId>com.tuoren</groupId>
             <artifactId>crud-common</artifactId>
-            <version>1.0</version>
         </dependency>
         <dependency>
-            <groupId>com.tuoren</groupId>
-            <artifactId>nb-common</artifactId>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <scope>provided</scope>
         </dependency>
     </dependencies>
 

+ 2 - 2
nb-oss/src/main/java/com/nb/oss/strategy/context/FileStorageContext.java

@@ -3,9 +3,9 @@ package com.nb.oss.strategy.context;
 import com.nb.core.AppProperties;
 import com.nb.core.exception.CustomException;
 import com.nb.oss.strategy.FileStorageStrategy;
-import com.google.common.collect.Maps;
 import org.springframework.stereotype.Component;
 
+import java.util.HashMap;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -18,7 +18,7 @@ import java.util.Objects;
 @Component
 public class FileStorageContext {
 
-    Map<String, FileStorageStrategy> fileStorageStrategyMap = Maps.newHashMap();
+    Map<String, FileStorageStrategy> fileStorageStrategyMap = new HashMap<>();
 
     public FileStorageContext(List<FileStorageStrategy> list) {
         list.forEach(item -> {

+ 40 - 0
nb-service-api/iot-service-api/pom.xml

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nb-service-api</artifactId>
+        <groupId>com.tuoren</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>iot-service-api</artifactId>
+
+    <description>阿里云物联网平台api</description>
+
+    <dependencies>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-iot</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-core</artifactId>
+        </dependency>
+        <!-- amqp 1.0 qpid client -->
+        <dependency>
+            <groupId>org.apache.qpid</groupId>
+            <artifactId>qpid-jms-client</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>nb-core</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 24 - 0
nb-service-api/iot-service-api/src/main/java/com/nb/aliyun/api/bean/PlatformAccount.java

@@ -0,0 +1,24 @@
+package com.nb.aliyun.api.bean;
+
+import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+/**
+ * @Author XX
+ * @Date 2022-01-05 17:33:29
+ * @Version 1.0
+ * @Description XXX
+ */
+@Data
+@ConfigurationProperties(prefix = "aliyun")
+@Configuration
+public class PlatformAccount {
+    private String accessKey = "LTAI4FhB19MgQuviGxwA3aod";
+    private String accessSecret = "cQQVkATR0yv2G9CEtfjAhEGBepPDRs";
+    private String consumerGroupId = "nalavzBm4RuVJc0BUij7000100";
+    private String aliyunUid = "1177450762772738";
+    private String regionId = "cn-shanghai";
+    //iotInstanceId:企业版实例请填写实例ID,公共实例请填空字符串""。
+    private String iotInstanceId = "";
+}

+ 328 - 0
nb-service-api/iot-service-api/src/main/java/com/nb/aliyun/api/service/AliyunIotSdk.java

@@ -0,0 +1,328 @@
+package com.nb.aliyun.api.service;
+
+import cn.hutool.json.JSONUtil;
+import com.aliyuncs.DefaultAcsClient;
+import com.aliyuncs.exceptions.ClientException;
+import com.aliyuncs.iot.model.v20180120.*;
+import com.aliyuncs.profile.DefaultProfile;
+import com.aliyuncs.profile.IClientProfile;
+import com.nb.core.utils.ExceptionUtil;
+import com.nb.aliyun.api.bean.PlatformAccount;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+//import com.tuoren.common.utils.StringUtils;
+
+/**
+ * @Author 龙三郎
+ * @Date 2021-06-11 08:10:58
+ * @Version 1.0
+ * @Description XXX
+ */
+@Configuration
+@EnableConfigurationProperties(PlatformAccount.class)
+@Slf4j
+public class AliyunIotSdk {
+
+
+    @Value("${aliyun.product.productKey:a1ALlsBa2ZK}")
+    private String productKey;
+
+    private String accessKey;
+    private String accessSecret;
+    private String regionId;
+    private String iotInstanceId;
+    // client
+    private DefaultAcsClient client;
+    public AliyunIotSdk(PlatformAccount platformAccount){
+        this.accessKey = platformAccount.getAccessKey();
+        this.accessSecret = platformAccount.getAccessSecret();
+        this.regionId = platformAccount.getRegionId();
+        this.iotInstanceId = platformAccount.getIotInstanceId();
+    }
+
+    /**
+     * 获取阿里云客户端
+     * @return
+     */
+    protected final DefaultAcsClient getAliyuniotClient(){
+        if (client != null){
+            return client;
+        }
+        IClientProfile profile = DefaultProfile.getProfile(regionId, accessKey, accessSecret);
+        DefaultAcsClient client = new DefaultAcsClient(profile); //初始化SDK客户端。
+        this.client = client;
+        return client;
+    }
+
+    /**
+     * 	查询产品列表。
+     * @return
+     */
+    public List<QueryProductListResponse.Data.ProductInfo> queryProductList(){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+        List<QueryProductListResponse.Data.ProductInfo> products = new ArrayList<>();
+        Integer pageSize = 100,currentPage = 1;
+        while (true){
+            QueryProductListRequest queryProductListRequest = new QueryProductListRequest();
+            queryProductListRequest.setPageSize(pageSize);
+            queryProductListRequest.setCurrentPage(currentPage);
+            try {
+                QueryProductListResponse queryProductListResponse = client.getAcsResponse(queryProductListRequest);
+                System.out.println(queryProductListResponse.getSuccess());
+                // 获取失败直接跳出循环
+                if (!queryProductListResponse.getSuccess()){
+                    break;
+                }
+                QueryProductListResponse.Data data = queryProductListResponse.getData();
+                // 添加到列表
+                products.addAll(data.getList());
+                // 判断是否获取了全部
+                if (data.getCurrentPage() < data.getPageCount()){
+                    // 当前页小于总页数,说明没有获取完
+                    currentPage++;
+                }else {
+                    break;
+                }
+            } catch (ClientException e) {
+                e.printStackTrace();
+            }
+        }
+        return products;
+    }
+
+
+    /**
+     * 注册设备
+     * @param
+     * @return
+     */
+    public RegisterDeviceResponse.Data registerDevice(String productKey, String name){
+
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+        List<QueryDeviceResponse.DeviceInfo> list = new ArrayList<>();
+        Integer pageSize = 100,currentPage = 1;
+
+        RegisterDeviceRequest request = new RegisterDeviceRequest();
+        // 产品key,必需
+        request.setProductKey(productKey);
+        // 产品名称,非必需
+        request.setDeviceName(name);
+        try {
+            RegisterDeviceResponse response = client.getAcsResponse(request);
+            System.out.println(response.getSuccess());
+            // 获取失败直接跳出循环
+            if (!response.getSuccess()){
+                return null;
+            }
+            RegisterDeviceResponse.Data data = response.getData();
+            return data;
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+        return null;
+    }
+
+    /**
+     * 删除设备
+     * @param
+     * @return
+     */
+    public boolean deleteDevice(String deviceName){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+        DeleteDeviceRequest request = new DeleteDeviceRequest();
+        request.setIotInstanceId(iotInstanceId);
+        request.setProductKey(productKey);
+        request.setDeviceName(deviceName);
+        boolean result=false;
+        try {
+            DeleteDeviceResponse response = client.getAcsResponse(request);
+            // 获取失败直接跳出循环
+            if (response.getSuccess()){
+                result=true;
+            }else {
+                log.warn("删除设备【{}】失败,阿里云相应【{}】",deviceName, JSONUtil.toJsonStr(response));
+            }
+        } catch (ClientException e) {
+            log.error("删除设备【{}】失败,报错:【{}】",deviceName, ExceptionUtil.getExceptionMsg(e));
+        }
+        return result;
+    }
+
+    /**
+     * 获取设备
+     * @return
+     */
+    public List<QueryDeviceResponse.DeviceInfo> queryDevice(){
+        long startTime = System.currentTimeMillis();
+
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+        List<QueryDeviceResponse.DeviceInfo> list = new ArrayList<>();
+        Integer pageSize = 100,currentPage = 1;
+        while (true){
+            QueryDeviceRequest request = new QueryDeviceRequest();
+            request.setPageSize(pageSize);
+            request.setCurrentPage(currentPage);
+            request.setProductKey(productKey);
+            request.setIotInstanceId(iotInstanceId);
+            try {
+                QueryDeviceResponse response = client.getAcsResponse(request);
+                System.out.println(response.getSuccess());
+                // 获取失败直接跳出循环
+                if (!response.getSuccess()){
+                    break;
+                }
+                List<QueryDeviceResponse.DeviceInfo> data = response.getData();
+                // 添加到列表
+                list.addAll(data);
+                // 判断是否获取了全部
+                if (response.getPage() < response.getPageCount()){
+                    // 当前页小于总页数,说明没有获取完
+                    currentPage++;
+                }else {
+                    break;
+                }
+            } catch (ClientException e) {
+                e.printStackTrace();
+            }
+        }
+        log.info("从阿里云拉取设备信息耗时【{}】",System.currentTimeMillis()-startTime);
+        return list;
+    }
+
+
+    /**
+     * 获取阿里云消费组
+     * @return
+     */
+    public List<QueryConsumerGroupListResponse.ConsumerGroupDTO> queryConsumerGroupList(){
+
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+
+        QueryConsumerGroupListRequest _request = new QueryConsumerGroupListRequest();
+        _request.setPageSize(100);
+        _request.setCurrentPage(1);
+
+        List<QueryConsumerGroupListResponse.ConsumerGroupDTO> list = null;
+
+        try {
+            QueryConsumerGroupListResponse _response = client.getAcsResponse(_request);
+            list = _response.getData();
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+
+        return list;
+
+    }
+
+    /**
+     * 创建一个消费组
+     * @param groupName
+     * @return
+     */
+    public CreateConsumerGroupResponse createConsumerGroup(String groupName){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+
+        CreateConsumerGroupRequest _request = new CreateConsumerGroupRequest();
+        _request.setGroupName(groupName);
+
+        CreateConsumerGroupResponse acsResponse = null;
+        try {
+            acsResponse = client.getAcsResponse(_request);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return acsResponse;
+    }
+
+    /**
+     * 创建一个云产品流转规则
+     * @param ruleName
+     * @param productKey
+     * @param device_list
+     * @return
+     */
+    public CreateRuleResponse createRule(String ruleName, String productKey, String[] device_list){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+
+        CreateRuleRequest _request = new CreateRuleRequest();
+        _request.setName(ruleName);
+        _request.setSelect("*");
+        _request.setShortTopic("+/thing/event/property/post");
+        _request.setProductKey(productKey);
+//        _request.setWhere("deviceName() in ("+ StringUtils.arrayToString(device_list,"'",",") +")");
+
+
+        CreateRuleResponse acsResponse = null;
+        try {
+            acsResponse = client.getAcsResponse(_request);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return acsResponse;
+    }
+
+    public CreateRuleActionResponse createRuleAction(Long ruleId, String groupId){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+
+        CreateRuleActionRequest _request = new CreateRuleActionRequest();
+        _request.setRuleId(ruleId);
+        _request.setType("AMQP");
+
+        Map<String, Object> map = new HashMap<>();
+        map.put("groupId",groupId);
+
+        _request.setConfiguration(JSONUtil.toJsonStr(map));
+
+
+        CreateRuleActionResponse acsResponse = null;
+        try {
+            acsResponse = client.getAcsResponse(_request);
+        }catch (Exception e){
+            e.printStackTrace();
+        }
+        return acsResponse;
+    }
+
+
+
+    /**
+     * 获取设备的详细信息
+     * @param deviceName
+     */
+    public QueryDeviceDetailResponse queryDeviceDetail(String deviceName){
+        // 获取阿里云SDK客户端
+        DefaultAcsClient client = this.getAliyuniotClient();
+
+        QueryDeviceDetailRequest _request = new QueryDeviceDetailRequest();
+        _request.setProductKey(productKey);
+        _request.setDeviceName(deviceName);
+        _request.setIotInstanceId(iotInstanceId);
+
+        QueryDeviceDetailResponse acsResponse = null;
+        try {
+            acsResponse = client.getAcsResponse(_request);
+        } catch (ClientException e) {
+            e.printStackTrace();
+        }
+        return acsResponse;
+    }
+
+
+}

+ 21 - 0
nb-service-api/pom.xml

@@ -0,0 +1,21 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nb-root</artifactId>
+        <groupId>com.tuoren</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>nb-service-api</artifactId>
+    <packaging>pom</packaging>
+
+    <modules>
+        <module>web-service-api</module>
+        <module>iot-service-api</module>
+    </modules>
+
+
+</project>

+ 42 - 0
nb-service-api/web-service-api/pom.xml

@@ -0,0 +1,42 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nb-service-api</artifactId>
+        <groupId>com.tuoren</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>web-service-api</artifactId>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.github.xiaoymin</groupId>
+            <artifactId>knife4j-spring-boot-starter</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>config-common</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>com.aliyun</groupId>
+            <artifactId>aliyun-java-sdk-iot</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+        </dependency>
+    </dependencies>
+</project>

+ 18 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/AliIotConfig.java

@@ -0,0 +1,18 @@
+package com.nb.web.api.bean;
+
+import lombok.Data;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AliIotConfig.java
+ * @Description 阿里云物联网注册设备返回配置结果
+ * @createTime 2022年04月01日 15:43:00
+ */
+@Data
+public class AliIotConfig {
+    private String deviceName;
+    private String deviceSecret;
+    private String productKey;
+    private String iotId;
+}

+ 15 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/GeoPoint.java

@@ -0,0 +1,15 @@
+package com.nb.web.api.bean;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class  GeoPoint implements Serializable {
+    private String lon;
+    private String lat;
+}

+ 24 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/bean/Script.java

@@ -0,0 +1,24 @@
+package com.nb.web.api.bean;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName Script.java
+ * @Description TODO
+ * @createTime 2022年03月28日 14:19:00
+ */
+@Data
+public class Script implements Serializable {
+    @JsonIgnore
+    private String id="python";
+    private String content;
+    /**
+     * json xml soap
+     */
+    private String type;
+}

+ 112 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/BusDeviceEntity.java

@@ -0,0 +1,112 @@
+package com.nb.web.api.entity;
+
+import com.aliyuncs.iot.model.v20180120.QueryDeviceDetailResponse;
+import com.aliyuncs.iot.model.v20180120.QueryDeviceResponse;
+import com.baomidou.mybatisplus.annotation.*;
+import com.baomidou.mybatisplus.extension.handlers.FastjsonTypeHandler;
+import com.nb.web.api.bean.AliIotConfig;
+import com.nb.web.api.enums.DeviceStatusEnum2;
+import com.nb.web.api.enums.DeviceTypeEnum;
+import com.nb.common.config.mybatisplus.TenantNameHandler;
+import com.nb.core.entity.TenantGenericEntity;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.nb.web.api.utils.EnumUtils;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import org.hibernate.validator.constraints.Length;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName BusDeviceEntity.java
+ * @Description TODO
+ * @createTime 2022年03月21日 11:17:00
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName(value = "bus_device",autoResultMap = true)
+@ApiModel(value="设备经销商管理", description="设备与医院关系管理")
+@ToString
+public class BusDeviceEntity extends TenantGenericEntity<String,String> {
+
+
+    @ApiModelProperty(value = "设备唯一id")
+    private String deviceId;
+
+
+    @ApiModelProperty(value = "mqtt通道信息")
+    @JsonIgnore
+    private String mqttConnInfo;
+
+    @ApiModelProperty(value = "设备别名")
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    @Length(max = 255,message = "设备别名不得超过255个字符")
+    private String alias;
+
+    @ApiModelProperty(value = "输注id")
+    @JsonIgnore
+    private String infusionId;
+
+    @ApiModelProperty(value = "设备类型")
+    @Deprecated
+    @Length(max = 255,message = "设备类型不得超过255个字符")
+    private DeviceTypeEnum type;
+
+    @ApiModelProperty(value = "第三方平台返回配置")
+    @TableField(typeHandler = FastjsonTypeHandler.class,updateStrategy = FieldStrategy.DEFAULT)
+    private AliIotConfig config;
+
+
+    @ApiModelProperty(value = "sim卡卡号")
+    @Length(max = 255,message = "sim卡卡号不得超过255个字符")
+    private String simIccid;
+
+    @ApiModelProperty(value = "移动网络运营商")
+    @Length(max = 255,message = "移动网络运营商不得超过255个字符")
+    private String simMno;
+
+    @ApiModelProperty(value = "是否启用,0、不启用 1、启用 ")
+    private Boolean enable;
+
+
+    @TableField(fill = FieldFill.INSERT)
+    @TableLogic
+    private Integer isDelete;
+
+    @ApiModelProperty(value = "设备在线状态,0未激活,1在线,2离线",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private DeviceStatusEnum2 status;
+
+    @TableField(value = "tenant_id",typeHandler = TenantNameHandler.class,updateStrategy = FieldStrategy.NEVER,insertStrategy = FieldStrategy.NEVER)
+    private String tenantName;
+
+    /**
+     * @author 龙三郎
+     * 根据阿里云返回的数据更新设备对象
+     * @param data 由queryDeviceDetail接口返回的数据
+     */
+    public void updateFields(QueryDeviceDetailResponse.Data data) {
+        this.deviceId = data.getDeviceName();
+        this.config.setProductKey(data.getProductKey());
+        this.config.setIotId(data.getIotId());
+        this.config.setDeviceSecret(data.getDeviceSecret());
+        this.config.setDeviceName(data.getDeviceName());
+        this.setStatus(EnumUtils.getDeviceStatusEnum2(data.getStatus()));
+    }
+
+    /**
+     * @author 龙三郎
+     * 根据设备查询接口返回的数据,更新设备对象
+     * @param item
+     */
+    public void updateFields(QueryDeviceResponse.DeviceInfo item) {
+        this.deviceId = item.getDeviceName();
+        this.config.setProductKey(item.getProductKey());
+        this.config.setIotId(item.getIotId());
+        this.config.setDeviceSecret(item.getDeviceSecret());
+        this.config.setDeviceName(item.getDeviceName());
+        this.setStatus(EnumUtils.getDeviceStatusEnum2(item.getDeviceStatus()));
+    }
+}

+ 68 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/BusHospitalLogEntity.java

@@ -0,0 +1,68 @@
+package com.nb.web.api.entity;
+
+
+import cn.hutool.json.JSONObject;
+import com.baomidou.mybatisplus.annotation.TableName;
+import com.nb.web.api.enums.HospitalLogEnum;
+import com.nb.core.entity.TenantGenericEntity;
+import com.nb.core.exception.ExecuteResult;
+
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+import java.util.Optional;
+
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName BusHospitalLogEntity.java
+ * @Description TODO
+ * @createTime 2022年03月21日 11:25:00
+ */
+@EqualsAndHashCode(callSuper = true)
+@Data
+@TableName(value = "bus_hospital_log",autoResultMap = true)
+@ApiModel(value="医院数据传输日志", description="医院数据传输日志")
+public class BusHospitalLogEntity extends TenantGenericEntity<String,String> {
+
+    @ApiModelProperty("脚本是否执行成功")
+    private boolean success;
+
+    @ApiModelProperty("消息id")
+    private String msgId;
+
+    @ApiModelProperty("标识码(设备号、住院号)")
+    private String identityCode;
+
+    @ApiModelProperty("信息类型")
+    private HospitalLogEnum type;
+
+    @ApiModelProperty("输入参数")
+    private String input;
+
+    @ApiModelProperty(value = "医院数据处理结果")
+    private String result;
+
+    @ApiModelProperty("错误消息")
+    private String message;
+
+    @ApiModelProperty("本消息处理运行时间")
+    private long useTime;
+
+    public static BusHospitalLogEntity of(ExecuteResult source,String tenantId,String patientCode){
+        BusHospitalLogEntity result = new BusHospitalLogEntity();
+        result.setMsgId(source.getMsgId());
+        result.setTenantId(tenantId);
+        result.setInput(source.getInput());
+        result.setMessage(source.getMessage());
+        result.setResult(Optional.ofNullable(source.getResult()).orElse(new JSONObject()).toString());
+        result.setSuccess(source.isSuccess());
+        result.setUseTime(source.getUseTime());
+        result.setIdentityCode(patientCode);
+        result.setType(HospitalLogEnum.HIS);
+        return result;
+    }
+}

+ 225 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/BusDeviceRunningEntity.java

@@ -0,0 +1,225 @@
+package com.nb.web.api.entity.common;
+
+
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.nb.web.api.enums.DeviceTypeEnum;
+import com.nb.core.enums.SexEnum;
+import com.fasterxml.jackson.annotation.*;
+import com.nb.web.api.utils.*;
+import io.swagger.annotations.ApiModel;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+import lombok.experimental.Accessors;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.Optional;
+
+/**
+ * @Author lifang
+ * @Date 16:02 2022/4/8
+ * @Description
+ * @Param
+ * @return
+ **/
+@ToString
+@Data
+@EqualsAndHashCode(callSuper = true)
+@Accessors(chain = true)
+@ApiModel(value="设备运行状态", description="设备运行状态")
+public class BusDeviceRunningEntity extends CommonDeviceParam<String,String> {
+
+    @ApiModelProperty(value = "阿里云传输过来的消息id")
+    private String msgId;
+
+    @ApiModelProperty(value = "公共-此次输注过程中到此为止的总追加量")
+    private BigDecimal totalAppendDose;
+
+    @ApiModelProperty(value = "输注记录")
+    private String infusionId;
+
+    @ApiModelProperty(value = "临床号")
+    private String clinicId;
+
+    /***************临床固定数据*****************/
+    @ApiModelProperty(value = "病人名称")
+    private String patientName;
+
+    @ApiModelProperty(value = "病人性别")
+    private SexEnum patientSex;
+
+    /***************临床固定数据*****************/
+
+    @ApiModelProperty(value = "设备别名")
+    private String alias;
+
+    @ApiModelProperty(value = "输注开始时间,即本次运行开机时间",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Date startTime;
+
+    @ApiModelProperty(value = "是否已撤泵,0、未撤泵1、已撤泵")
+    @JsonIgnoreProperties(allowSetters = true)
+    private Boolean isUndo;
+
+    @ApiModelProperty(value = "备注")
+    private String remark;
+
+    @ApiModelProperty(value = "监护类型,1、有泵监护 0、无泵监护")
+    @JsonIgnoreProperties
+    private Boolean monitorType;
+
+    @ApiModelProperty(value = "是否为主泵数据, 0、副泵 1、主泵(即当前临床绑定的泵)")
+    @JsonIgnoreProperties(allowSetters = true)
+    private Boolean master;
+
+
+    @ApiModelProperty(value = "数据上传时间",accessMode = ApiModelProperty.AccessMode.READ_ONLY,hidden = true)
+    @JsonIgnoreProperties(allowSetters = true)
+    private Date uploadTime;
+
+    /**
+     * 当前运行状态所绑定的输注修改记录id,只在设备上传解析过程中使用,其他地方无用处
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private String infusionModifyId;
+
+    /**
+     * 当前运行状态所绑定的历史记录id,只在设备上传解析过程中使用,其他地方无用处
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+
+    private String historyId;
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private Date modifyTime;
+    /**
+     * 当前运行状态是否开启了新的输注,只在设备上传解析过程中使用,其他地方无用处
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean newInfusion;
+    /**
+     * 当前运行状态输注信息是否发生了变化,只在设备上传解析过程中使用,其他地方无用处
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean infusionModify;
+
+    /**
+     *当设备输注过程已撤泵被重新开启时,只在设备上传解析过程中使用,其他地方无用处
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean resetUndo;
+    /**
+     * 患者id
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private String patientId;
+    /**
+     * 重新开启临床信息
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean resetClinic;
+    /**
+     * 格式化之后的住院号
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private String formatPatientCode;
+
+    /**
+     * 该次数据是否可能会产生低输注
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean maybeLowInfusion;
+
+    /**
+     * 智能泵-该次输注过程中是否出现过加档受限,若出现过,则此次输注过程中出现的低输注不会消失
+     */
+    @TableField(exist = false)
+    @JsonIgnoreProperties
+    private boolean flowRestricted;
+    /**
+     * @author 龙三郎
+     * 根据阿里云传回数据的items,设置输注的属性
+     * @param deviceName
+     * @param items
+     */
+    public void updateFieldsByItems(String deviceName, Items items) {
+        // 属性上传时间
+        this.setUploadTime(items.getDate());
+
+        this.setDeviceId(deviceName);
+        this.setClassification( items.getString(PumpParams.classification));
+        this.setDataNumber(items.getInteger(PumpParams.dataNumber));
+        this.setPatientCode( items.getString(PumpParams.patientCode));
+        this.setWard(items.getString(PumpParams.ward));
+        this.setBedNo(items.getString(PumpParams.bedNo));
+        this.setTotalDose( items.getInteger(PumpParams.totalDose));
+        this.setInputDose(items.getBigDecimal(PumpParams.finishedDose));
+        this.setRemainDose(BigDecimal.valueOf(this.getTotalDose()).subtract(this.getInputDose()));
+        this.setFirstDose( items.getInteger(PumpParams.firstDosis));
+        this.setMaxDose(items.getBigDecimal(PumpParams.maxDose));
+        this.setAppendDose(items.getBigDecimal(PumpParams.singleDosis));
+
+        this.setSelfControlLockTime(items.getBigDecimal(PumpParams.lockTime));
+
+        this.setContinueDose(items.getBigDecimal(PumpParams.flow));
+        this.setType( DeviceTypeUtils.getDeviceType(items.getInteger(PumpParams.pumpType)));
+        this.setPcaValidCount(items.getInteger(PumpParams.pcaValid));
+        this.setPcaInvalidCount(items.getInteger(PumpParams.pcaInvalid));
+        this.setPcaTotalCount(this.getPcaInvalidCount()+this.getPcaValidCount());
+        this.setElectricQuantity(items.getInteger(PumpParams.electricQuantity));
+        this.setRunState(DeviceRunStatusUtils.getRunStatus(items.getInteger(PumpParams.runStatus)));
+        this.setAlarm(DeviceAlarmUtils.getAlarm(Optional.ofNullable(items.getInteger(PumpParams.alarmStatus)).orElse(0)));
+        // 预报
+        // 镇痛不足预报 此报警不从设备接收
+//        this.setWarnAnalgesicPoor(Optional.ofNullable(items.getBoolean(PumpParams.warnAnalgesicPoor)).orElse(false));
+        // 电量偏低预报
+        this.setWarnLowBattery(Optional.ofNullable(items.getBoolean(PumpParams.warnLowBattery)).orElse(false));
+        // 输液将结束预报
+        this.setWarnWillFinished(Optional.ofNullable(items.getBoolean(PumpParams.warnWillFinished)).orElse(false));
+
+        // 设置脉冲泵参数
+        if (this.getType() == DeviceTypeEnum.pulse){
+            // 脉冲锁时
+            this.setPulseLockTime(items.getInteger(PumpParams.pulseLockTime));
+            // 首次锁时
+            this.setPulseFirstLockTime(items.getInteger(PumpParams.firstLockTime));
+            // 脉冲量
+            this.setPulseDose(items.getInteger(PumpParams.pulseDose));
+        }else if (this.getType() == DeviceTypeEnum.intelligent){
+            // 设置智能泵参数
+            // 重设参数标识
+
+            // 减档时间
+            this.setFlowDownCycle(items.getBigDecimal(PumpParams.flowDownTime));
+            // 加档时间
+            this.setFlowUpCycle(items.getBigDecimal(PumpParams.flowUpTime));
+            // 触发加档pca有效次数
+            this.setFlowCount(items.getBigDecimal(PumpParams.flowUpPcaValid));
+            // 加减档百分比
+            this.setFlowAdjustRate(items.getBigDecimal(PumpParams.flowAdjuseRate));
+            // 减档下限
+            this.setFlowDownLimit(items.getBigDecimal(PumpParams.minFlow));
+            // 加档上限
+            this.setFlowUpLimit(items.getBigDecimal(PumpParams.maxFlow));
+
+            // 加减档预报
+            this.setWarnFlow(WarnFlowUtils.getAlarm(items.getInteger(PumpParams.warnFlow)));
+        }
+
+
+    }
+
+
+
+}

+ 115 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/CommonDeviceParam.java

@@ -0,0 +1,115 @@
+package com.nb.web.api.entity.common;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.core.util.StrUtil;
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.nb.web.api.enums.DeviceAlarmEnum;
+import com.nb.web.api.enums.DeviceStatusEnum;
+import com.nb.web.api.enums.FlowStatusEnum;
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName BaseDeviceParam.java
+ * @Description 设备公共参数信息
+ * @createTime 2022年05月05日 20:51:00
+ */
+@Data
+public class CommonDeviceParam<K,T>  extends DeviceProperties<K,T>  {
+
+    @ApiModelProperty(value = "泵运行状态",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private DeviceStatusEnum runState;
+
+    @ApiModelProperty(value = "报警信息",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    private DeviceAlarmEnum alarm;
+
+    @ApiModelProperty(value = "输注即将结束提醒",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    @JsonIgnore
+    private Boolean warnWillFinished;
+
+    @ApiModelProperty(value = "镇痛不足提醒",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+//    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    @JsonIgnore
+    private Boolean warnAnalgesicPoor;
+
+    @ApiModelProperty(value = "电量偏低提醒",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    @JsonIgnore
+    private Boolean warnLowBattery;
+
+    @ApiModelProperty(value = "加减档提示",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.IGNORED)
+    @JsonIgnore
+    private FlowStatusEnum warnFlow;
+
+    @TableField(exist = false)
+    @ApiModelProperty("提醒字段")
+    private String warns;
+
+    private void judgeWarnWillFinished() {
+        if(!Boolean.TRUE.equals(this.warnWillFinished)){
+            return;
+        }
+        if (CharSequenceUtil.isEmpty(this.warns)) {
+            this.warns="输注即将结束;";
+        }else {
+            this.warns=this.warns+"输注即将结束;";
+        }
+    }
+
+    private void judgeWarnAnalgesicPoor() {
+        if(!Boolean.TRUE.equals(this.warnAnalgesicPoor)){
+            return;
+        }
+        if (CharSequenceUtil.isEmpty(this.warns)) {
+            this.warns="镇痛不足;";
+        }else {
+            this.warns=this.warns+"镇痛不足;";
+        }
+    }
+
+    private void judgeWarnLowBattery() {
+        if(!Boolean.TRUE.equals(this.warnLowBattery)){
+            return;
+        }
+        if (CharSequenceUtil.isEmpty(this.warns)) {
+            this.warns="电量偏低;";
+        }else {
+            this.warns=this.warns+"电量偏低;";
+        }
+    }
+
+    private void judgeWarnFlow() {
+        if(this.warnFlow==null){
+            return;
+        }
+        if (CharSequenceUtil.isEmpty(this.warns)) {
+            this.warns=warnFlow.getText()+";";
+        }else {
+            this.warns=this.warns+warnFlow.getText()+";";
+        }
+    }
+
+    public void handleWarn(){
+        judgeWarnAnalgesicPoor();
+        judgeWarnFlow();
+        judgeWarnLowBattery();
+        judgeWarnWillFinished();
+    }
+
+    public String getWarns() {
+        handleWarn();
+        //去除多余符号
+        if (StrUtil.isNotEmpty(warns)) {
+            return warns.endsWith(";")&&warns.length()>2?warns.substring(0,warns.length()-1):warns;
+        }
+        return warns;
+    }
+}

+ 167 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/entity/common/DeviceProperties.java

@@ -0,0 +1,167 @@
+package com.nb.web.api.entity.common;
+
+import com.baomidou.mybatisplus.annotation.FieldStrategy;
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.nb.web.api.enums.DeviceTypeEnum;
+import com.nb.core.entity.TenantGenericEntity;
+import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.Data;
+
+import javax.validation.constraints.DecimalMax;
+import javax.validation.constraints.DecimalMin;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import java.math.BigDecimal;
+import java.util.Optional;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DeviceProperties.java
+ * @Description 设备上传属性(不包含报警、提醒字段)
+ * @createTime 2022年05月06日 09:06:00
+ */
+@Data
+public class DeviceProperties<K,T>  extends TenantGenericEntity<K,T> {
+    @ApiModelProperty(value = "网络泵id",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private String deviceId;
+
+    @ApiModelProperty(value = "数据分类号,标识某些数据属于同一个输注",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @JsonIgnoreProperties(allowSetters = true)
+    private String classification;
+
+    @ApiModelProperty(value = "数据编号",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @JsonIgnoreProperties(allowSetters = true)
+    private Integer dataNumber;
+
+    @ApiModelProperty(value = "泵类型",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @TableField(updateStrategy = FieldStrategy.NEVER)
+    private DeviceTypeEnum type;
+
+    @ApiModelProperty(value = "设备上传住院号")
+    private String patientCode;
+
+    @ApiModelProperty(value = "病区")
+    private String ward;
+
+    @ApiModelProperty(value = "床号")
+    private String bedNo;
+
+    @ApiModelProperty(value = "总量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @Max(value = 999,message = "总量最大值不得超过999")
+    @Min(value = 0,message ="总量最小值不得超过0" )
+    private Integer totalDose;
+
+    @ApiModelProperty(value = "公共参数-首次量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @Max(value = 50,message = "首次量最大值不得超过50")
+    @Min(value = 0,message ="首次量最小值不得超过0" )
+    private Integer firstDose;
+
+
+    @ApiModelProperty(value = "公共参数-剩余量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private BigDecimal remainDose;
+
+    @ApiModelProperty(value = "公共参数-已输入量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private BigDecimal inputDose;
+
+    @ApiModelProperty(value = "公共参数-追加量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "10",message = "PCA追加量最大值不得超过10")
+    @DecimalMin(value = "0",message ="PCA追加量最小值不得低于0" )
+    private BigDecimal appendDose;
+
+//    @ApiModelProperty(value = "公共参数-追加锁时",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+//    @DecimalMax(value = "99",message = "PCA追加量最大值不得超过99")
+//    @DecimalMin(value = "1",message ="PCA追加量最小值不得低于0" )
+//    private BigDecimal appendLockTime;
+
+    @ApiModelProperty(value = "公共参数-极限量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "90",message = "PCA追加量最大值不得超过90")
+    @DecimalMin(value = "0",message ="PCA追加量最小值不得低于0" )
+    private BigDecimal maxDose;
+
+    @ApiModelProperty(value = "公共参数-自控锁时 即单次追加锁时",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "99",message = "PCA追加量最大值不得超过99")
+    @DecimalMin(value = "1",message ="PCA追加量最小值不得低于0" )
+    private BigDecimal selfControlLockTime;
+
+    @ApiModelProperty(value = "公共参数-自控次数",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Integer selfControlCount;
+
+    @ApiModelProperty(value = "公共参数-pca有效次数",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Integer pcaValidCount;
+
+    @ApiModelProperty(value = "公共参数-pca无效次数",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Integer pcaInvalidCount;
+
+    @ApiModelProperty(value = "公共参数-pca总按次数",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Integer pcaTotalCount;
+
+    @ApiModelProperty(value = "持续泵参数-持续量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "50",message = "持续给液量最大值不得超过50")
+    @DecimalMin(value = "0",message ="持续给液量最小值不得低于0" )
+    private BigDecimal continueDose;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @Max(value = 20,message = "脉冲量最大值不得超过20")
+    @Min(value = 0,message ="脉冲量最小值不得低于0" )
+    private Integer pulseDose;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲锁时",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @Max(value = 90,message = "脉冲锁时最大值不得超过90")
+    @Min(value = 30,message ="脉冲锁时最小值不得低于30" )
+    private Integer pulseLockTime;
+
+    @ApiModelProperty(value = "脉冲泵参数-脉冲首次锁时",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @Max(value = 60,message = "脉冲首次锁时最大值不得超过60")
+    @Min(value = 0,message ="脉冲首次锁时最小值不得低于0" )
+    private Integer pulseFirstLockTime;
+
+    @ApiModelProperty(value = "智能泵参数-加档周期",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "10",message = "加档周期最大值不得超过10")
+    @DecimalMin(value = "0.5",message ="加档周期最小值不得低于0.5" )
+    private BigDecimal flowUpCycle;
+
+    @ApiModelProperty(value = "智能泵参数-减档周期",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "10",message = "减档周期最大值不得超过10")
+    @DecimalMin(value = "0.5",message ="减档周期最小值不得低于0.5" )
+    private BigDecimal flowDownCycle;
+
+    @ApiModelProperty(value = "智能泵参数-计次",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "10",message = "PCA追加量最大值不得超过10")
+    @DecimalMin(value = "1",message ="PCA追加量最小值不得低于1" )
+    private BigDecimal flowCount;
+
+    @ApiModelProperty(value = "智能泵参数-上限",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "50",message = "智能泵上限值最大值不得超过90")
+    @DecimalMin(value = "1",message ="智能泵上限值最小值不得低于0" )
+    private BigDecimal flowUpLimit;
+
+    @ApiModelProperty(value = "智能泵参数-下限",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "50",message = "智能泵下限值最大值不得超过50")
+    @DecimalMin(value = "0.1",message ="智能泵下限值最小值不得低于0.1" )
+    private BigDecimal flowDownLimit;
+
+    @ApiModelProperty(value = "智能泵参数-自调比例",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    @DecimalMax(value = "95",message = "自调比例不得超过95")
+    @DecimalMin(value = "0",message ="自调比例最小值不得低于0" )
+    private BigDecimal flowAdjustRate;
+
+    @ApiModelProperty(value = "公共参数-电量",accessMode = ApiModelProperty.AccessMode.READ_ONLY)
+    private Integer electricQuantity;
+
+
+    public Integer getPcaTotalCount() {
+        return getPcaInvalidCount()+getPcaValidCount();
+    }
+
+
+    public Integer getPcaValidCount() {
+        return Optional.ofNullable(pcaValidCount).orElse(0);
+    }
+
+
+    public Integer getPcaInvalidCount() {
+        return Optional.ofNullable(pcaInvalidCount).orElse(0);
+    }
+}

+ 44 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceAlarmEnum.java

@@ -0,0 +1,44 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AlarmEnum.java
+ * @Description 泵状态类型
+ * @createTime 2022年03月27日 09:49:00
+ */
+@AllArgsConstructor
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum DeviceAlarmEnum  implements IEnum<Integer> {
+    /**
+     * 请在添加或修改的过程中不要改变枚举的顺序!!!!!!!!!!!!!!!
+     * 如若新增,请在最后尾部新增
+     * 切记不可删除!!!!!!!!!!!!
+     */
+    //    以下为报警信息状态
+    None(0,"无报警"),
+    Bubble(1,"气泡报警"),
+    Jam(2,"堵塞报警"),
+    NotBox(3,"未装药盒报警"),
+    InfusionMax(4,"输注总量报警"),
+    Limit(5,"极限报警"),
+    Finished(6,"输液结束"),
+    LowBattery(7,"低电量报警"),
+//    OutOfControl(8,"电机失控报警"),
+    Machine(9,"机械故障"),;
+
+
+    @Getter
+    @ApiModelProperty("报警编码")
+    private Integer value;
+    @Getter
+    @ApiModelProperty("报警内容")
+    private String text;
+
+}

+ 43 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceStatusEnum.java

@@ -0,0 +1,43 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName AlarmEnum.java
+ * @Description 泵状态类型
+ * @createTime 2022年03月27日 09:49:00
+ */
+@AllArgsConstructor
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum DeviceStatusEnum  implements IEnum<Integer> {
+    /**
+     * 请在添加或修改的过程中不要改变枚举的顺序!!!!!!!!!!!!!!!
+     * 如若新增,请在最后尾部新增
+     * 切记不可删除!!!!!!!!!!!!
+     */
+    Shutdown(0,"关机"),
+    StartUp(1,"开机"),
+    Running(2,"运行"),
+    Pause(3,"暂停"),
+    Waiting(4,"待机"),
+    NoSignal(5,"不在服务区")
+    ;
+
+
+    /**
+     * 与枚举ordinal保持一致
+     */
+    @Getter
+    @ApiModelProperty("运行状态编码")
+    private Integer value;
+    @Getter
+    @ApiModelProperty("运行状态内容")
+    private String text;
+
+}

+ 30 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceStatusEnum2.java

@@ -0,0 +1,30 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-05-06 14:54:04
+ * @Version 1.0
+ * @Description 设备网络状态
+ */
+@AllArgsConstructor
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum DeviceStatusEnum2 implements IEnum<Integer> {
+
+    NOACTIVE(0,"未激活"),
+    ONLINE(1,"在线"),
+    OFFLINE(2,"离线");
+
+
+    @Getter
+    @ApiModelProperty("状态编码")
+    private Integer value;
+    @Getter
+    @ApiModelProperty("状态内容")
+    private String text;
+}

+ 32 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/DeviceTypeEnum.java

@@ -0,0 +1,32 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName DeviceEnum.java
+ * @Description TODO
+ * @createTime 2022年04月08日 15:59:00
+ */
+@AllArgsConstructor
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum DeviceTypeEnum implements IEnum<Integer> {
+    no(0,"未知"),
+    continuous(1,"持续型"),
+    intelligent(2,"智能型"),
+    pulse(3,"脉冲型"),
+    other(4,"其他");
+
+    @Getter
+    @ApiModelProperty("设备编码")
+    private Integer value;
+
+    @Getter
+    @ApiModelProperty("设备名称")
+    private String text;
+}

+ 42 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/FlowStatusEnum.java

@@ -0,0 +1,42 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import io.swagger.annotations.ApiModelProperty;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-26 09:28:34
+ * @Version 1.0
+ * @Description 智能泵提示
+ */
+@AllArgsConstructor
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum FlowStatusEnum implements IEnum<Integer> {
+    /**
+     * 0 --- 正常(默认值)
+     * 1 --- 加档受限
+     * 2 --- 流速已达上限
+     * 3 --- 加档
+     * 4 --- 减档
+     * 5 --- 低输注状态
+     */
+    None(0,"正常"),
+    Limited(1,"加档受限"),
+    MaxFlow(2,"持续量已达上限"),
+    Up(3,"加档"),
+    Down(4,"减档"),
+    Lowest(5,"低输注状态");
+
+    /**
+     * 与枚举ordinal保持一致
+     */
+    @Getter
+    @ApiModelProperty("状态编码")
+    private Integer value;
+    @Getter
+    @ApiModelProperty("状态内容")
+    private String text;
+}

+ 32 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/enums/HospitalLogEnum.java

@@ -0,0 +1,32 @@
+package com.nb.web.api.enums;
+
+import com.baomidou.mybatisplus.annotation.IEnum;
+import com.fasterxml.jackson.annotation.JsonFormat;
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName HospitalLogEnum.java
+ * @Description 枚举顺序切不可乱动!!!!!!
+ * @createTime 2022年03月21日 11:26:00
+ */
+@AllArgsConstructor
+@Getter
+@JsonFormat(shape = JsonFormat.Shape.OBJECT)
+public enum HospitalLogEnum  implements IEnum<Integer> {
+    HIS(0,"系统对接信息"),
+    @Deprecated
+    ALI(1,"阿里云平台信息"),
+    ALI_STATUS(2,"阿里云-设备上下线"),
+    ALI_LIFECYCLE(3,"阿里云-设备生命周期"),
+    ALI_DATA_UPLOAD(4,"阿里云-设备数据上传"),
+    ALI_DEL(5,"阿里云-设备删除"),;
+
+    private Integer value;
+    @Getter
+    private String text;
+
+
+}

+ 20 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IDeviceClient.java

@@ -0,0 +1,20 @@
+package com.nb.web.api.feign;
+
+import com.nb.web.api.entity.BusDeviceEntity;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName IDeviceClient.java
+ * @Description TODO
+ * @createTime 2022年08月02日 14:17:00
+ */
+public interface IDeviceClient {
+    boolean updateDevice(BusDeviceEntity source);
+
+    boolean saveDevice(BusDeviceEntity source);
+
+    void removeByDeviceId(String id);
+
+    BusDeviceEntity getByDeviceId(String id);
+}

+ 14 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IHospitalLogClient.java

@@ -0,0 +1,14 @@
+package com.nb.web.api.feign;
+
+import com.nb.web.api.entity.BusHospitalLogEntity;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName IHospitalLogClient.java
+ * @Description TODO
+ * @createTime 2022年08月02日 14:31:00
+ */
+public interface IHospitalLogClient {
+    boolean save(BusHospitalLogEntity source);
+}

+ 16 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/feign/IIotMsgHandler.java

@@ -0,0 +1,16 @@
+package com.nb.web.api.feign;
+
+import com.nb.web.api.entity.common.BusDeviceRunningEntity;
+
+/**
+ * @author lifang
+ * @version 1.0.0
+ * @ClassName IIotMsgHandler.java
+ * @Description 物联网信息处理器
+ * @createTime 2022年08月02日 14:42:00
+ */
+public interface IIotMsgHandler {
+    void async(BusDeviceRunningEntity source,String deviceId);
+
+    BusDeviceRunningEntity sync(BusDeviceRunningEntity source,String deviceId);
+}

+ 16 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/Constants.java

@@ -0,0 +1,16 @@
+package com.nb.web.api.utils;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-26 13:44:36
+ * @Version 1.0
+ * @Description XXX
+ */
+public class Constants {
+    // 默认医院
+    public static final String DefaultHospital = "1";
+    // 默认创建人
+    public static final String DefaultCreateBy = "1";
+    // 默认更新人
+    public static final String DefaultUpdateBy = "1";
+}

+ 48 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceAlarmUtils.java

@@ -0,0 +1,48 @@
+package com.nb.web.api.utils;
+
+import com.nb.web.api.enums.DeviceAlarmEnum;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-29 11:04:04
+ * @Version 1.0
+ * @Description 根据阿里云发送的报警标识,获取报警枚举对象。阿里云发送的报警是0-9的整数。
+ */
+public class DeviceAlarmUtils {
+    public static DeviceAlarmEnum getAlarm(Integer i){
+        if (i == 0){
+            // 无报警
+            return DeviceAlarmEnum.None;
+        }else if (i == 1){
+            // 气泡无液报警
+            return DeviceAlarmEnum.Bubble;
+        }else if (i == 2){
+            // 堵塞
+            return DeviceAlarmEnum.Jam;
+        }else if (i == 3){
+            // 输入总量
+            return DeviceAlarmEnum.InfusionMax;
+        }else if (i == 4){
+            // 极限量
+            return DeviceAlarmEnum.Limit;
+        }else if (i == 5){
+            // 电量耗尽
+            return DeviceAlarmEnum.LowBattery;
+        }else if (i == 6){
+            // 输液结束
+            return DeviceAlarmEnum.Finished;
+//        }else if (i == 7){
+            // 电机失控
+//            return DeviceAlarmEnum.OutOfControl;
+        }else if (i == 8){
+            // 机械故障
+            return DeviceAlarmEnum.Machine;
+        }else if (i == 9){
+            // 未装药盒
+            return DeviceAlarmEnum.NotBox;
+        }else {
+
+            return DeviceAlarmEnum.Finished;
+        }
+    }
+}

+ 32 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceRunStatusUtils.java

@@ -0,0 +1,32 @@
+package com.nb.web.api.utils;
+
+import com.nb.web.api.enums.DeviceStatusEnum;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-29 11:36:03
+ * @Version 1.0
+ * @Description 根据阿里云发送的运行标识,获取运行枚举对象。阿里云发送的运行是0-4的整数。
+ */
+public class DeviceRunStatusUtils {
+    public static DeviceStatusEnum getRunStatus(Integer i){
+        if (i == 0){
+            // 关机
+            return DeviceStatusEnum.Shutdown;
+        }else if (i == 1){
+            // 运行
+            return DeviceStatusEnum.StartUp;
+        }else if (i == 2){
+            // 运行
+            return DeviceStatusEnum.Running;
+        }else if (i == 3){
+            // 暂停
+            return DeviceStatusEnum.Pause;
+        }else if (i == 4){
+            // 待机
+            return DeviceStatusEnum.Waiting;
+        }else {
+            return DeviceStatusEnum.Shutdown;
+        }
+    }
+}

+ 25 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/DeviceTypeUtils.java

@@ -0,0 +1,25 @@
+package com.nb.web.api.utils;
+
+import com.nb.web.api.enums.DeviceTypeEnum;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-29 11:52:36
+ * @Version 1.0
+ * @Description XXX
+ */
+public class DeviceTypeUtils {
+    public static DeviceTypeEnum getDeviceType(Integer i){
+        if (i == 0){
+            return DeviceTypeEnum.no;
+        }else if (i == 1){
+            return DeviceTypeEnum.continuous;
+        }else if (i == 2){
+            return DeviceTypeEnum.pulse;
+        }else if (i == 3){
+            return DeviceTypeEnum.intelligent;
+        }else {
+            return DeviceTypeEnum.other;
+        }
+    }
+}

+ 29 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/EnumUtils.java

@@ -0,0 +1,29 @@
+package com.nb.web.api.utils;
+
+import com.nb.web.api.enums.DeviceStatusEnum2;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-05-06 15:03:48
+ * @Version 1.0
+ * @Description XXX
+ */
+public class EnumUtils {
+    /**
+     * @author 龙三郎
+     * 根据阿里云返回的状态获取枚举
+     * @param status
+     * @return
+     */
+    public static DeviceStatusEnum2 getDeviceStatusEnum2(String status){
+        status = status.toLowerCase();
+        if ("online".equals(status)){
+            return DeviceStatusEnum2.ONLINE;
+        }else if ("offline".equals(status)){
+            return DeviceStatusEnum2.OFFLINE;
+        }else{
+            return DeviceStatusEnum2.NOACTIVE;
+        }
+    }
+
+}

+ 44 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/Items.java

@@ -0,0 +1,44 @@
+package com.nb.web.api.utils;
+
+import com.alibaba.fastjson.JSONObject;
+import com.nb.web.api.utils.PumpParams;
+import lombok.AllArgsConstructor;
+
+import java.math.BigDecimal;
+import java.util.Date;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-26 10:18:08
+ * @Version 1.0
+ * @Description 方便获取阿里云数据中的items中的属性的value
+ */
+@AllArgsConstructor
+public class Items {
+    public static final String VALUE = "value";
+    public static final String TIME = "time";
+
+    private JSONObject items;
+
+    public String getString(PumpParams param){
+        return items.getJSONObject(param.getParam()).getString(VALUE);
+    }
+
+    public Integer getInteger(PumpParams param){
+        return items.getJSONObject(param.getParam()).getInteger(VALUE);
+    }
+
+    public Date getDate(){
+        long time = items.getJSONObject(PumpParams.patientCode.getParam()).getLong(TIME);
+        return new Date(time);
+    }
+
+    public BigDecimal getBigDecimal(PumpParams param){
+        return items.getJSONObject(param.getParam()).getBigDecimal(VALUE);
+    }
+
+    public Boolean getBoolean(PumpParams param){
+        return items.getJSONObject(param.getParam()).getBoolean(VALUE);
+    }
+
+}

+ 67 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/PumpParams.java

@@ -0,0 +1,67 @@
+package com.nb.web.api.utils;
+
+import lombok.AllArgsConstructor;
+import lombok.Getter;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-26 10:37:47
+ * @Version 1.0
+ * @Description 设备上传的数据参数
+ */
+@AllArgsConstructor
+public enum PumpParams {
+    protocolHeader("protocolHeader","协议头"),
+    dataLength("dataLength","数据长度"),
+    pumpType("pumpType","泵类型"),
+    classification("classification","分类标识"),
+    dataNumber("dataNumber","数据编号"),
+    patientCodeLength("patientCodeLength","住院号长度"),
+    patientCode("patientCode","住院号"),
+    ward("ward","病区"),
+    bedNo("bedNo","床号"),
+    totalDose("totalDose","总量"),
+    maxDose("maxDose","极限量"),
+    singleDosis("singleDose","追加量"),
+    lockTime("lockTime","锁时时间"),
+    flow("flow","持续量"),
+    finishedDose("finishedDose","已输入量"),
+    firstDosis("firstDose","首次量"),
+    pcaValid("pcaValid","PCA有效次数"),
+    pcaInvalid("pcaInvalid","PCA无效次数"),
+    electricQuantity("electricQuantity","电池电量"),
+    runStatus("runStatus","运行状态"),
+    alarmStatus("alarmStatus","报警"),
+    warnWillFinished("warnWillFinished","输液将结束预报"),
+    warnAnalgesicPoor("warnAnalgesicPoor","镇痛不足预报"),
+    warnLowBattery("warnLowBattery","电量偏低预报"),
+
+    // 脉冲泵属性
+    pulseLockTime("pulseLockTime","脉冲量锁时"),
+    firstLockTime("firstLockTime","首次锁时"),
+    pulseDose("pulseDose","脉冲量"),
+
+    // 智能泵属性
+    resetParams("resetParams","重设参数标志"),
+    warnFlow("warnFlow","加减档预报"),
+    flowDownTime("flowDownTime","减档时间"),
+    flowUpTime("flowUpTime","加档时间"),
+    flowUpPcaValid("flowUpPcaValid","触发加档pca有效次数"),
+    flowAdjuseRate("flowAdjuseRate","加减档百分比"),
+    minFlow("minFlow","减档下限"),
+    maxFlow("maxFlow","加档上限"),
+
+
+
+
+
+    CRC("CRC","CRC");
+
+
+
+    @Getter
+    private String param;
+    @Getter
+    private String info;
+
+}

+ 36 - 0
nb-service-api/web-service-api/src/main/java/com/nb/web/api/utils/WarnFlowUtils.java

@@ -0,0 +1,36 @@
+package com.nb.web.api.utils;
+
+import com.nb.web.api.enums.FlowStatusEnum;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-04-29 11:04:04
+ * @Version 1.0
+ * @Description 根据阿里云发送的加减档预报。阿里云发送的报警是0-5的整数。
+ */
+public class WarnFlowUtils {
+    public static FlowStatusEnum getAlarm(Integer i){
+        if (i == 0){
+            // 正常
+            return FlowStatusEnum.None;
+        }else if (i == 1){
+            // 加档受限
+            return FlowStatusEnum.Limited;
+        }else if (i == 2){
+            // 流速已达上限
+            return FlowStatusEnum.MaxFlow;
+        }else if (i == 3){
+            // 加档
+            return FlowStatusEnum.Up;
+        }else if (i == 4){
+            // 减档
+            return FlowStatusEnum.Down;
+        }else if (i == 5){
+            // 低输注状态
+            return FlowStatusEnum.Lowest;
+        }else {
+
+            return FlowStatusEnum.None;
+        }
+    }
+}

+ 31 - 0
nb-service/iot-service/pom.xml

@@ -0,0 +1,31 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <parent>
+        <artifactId>nb-service</artifactId>
+        <groupId>com.tuoren</groupId>
+        <version>1.0</version>
+    </parent>
+    <modelVersion>4.0.0</modelVersion>
+
+    <artifactId>iot-service</artifactId>
+
+    <packaging>jar</packaging>
+    <description>阿里云iot信息</description>
+
+
+    <dependencies>
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>iot-service-api</artifactId>
+            <version>1.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.tuoren</groupId>
+            <artifactId>web-service-api</artifactId>
+            <version>1.0</version>
+        </dependency>
+    </dependencies>
+</project>

+ 230 - 0
nb-service/iot-service/src/main/java/com/nb/aliyun/AliyunConsumerGroupService.java

@@ -0,0 +1,230 @@
+package com.nb.aliyun;
+
+import cn.hutool.core.text.CharSequenceUtil;
+import cn.hutool.json.JSONUtil;
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.nb.web.api.bean.AliIotConfig;
+import com.nb.web.api.entity.BusDeviceEntity;
+import com.nb.web.api.entity.BusHospitalLogEntity;
+import com.nb.web.api.entity.common.BusDeviceRunningEntity;
+import com.nb.web.api.enums.HospitalLogEnum;
+import com.nb.web.api.feign.IHospitalLogClient;
+import com.nb.web.api.feign.IIotMsgHandler;
+import com.nb.web.api.utils.EnumUtils;
+import com.nb.core.utils.ExceptionUtil;
+import com.nb.web.api.feign.IDeviceClient;
+import com.nb.web.api.utils.Items;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Lazy;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.PostConstruct;
+import javax.jms.Message;
+import javax.jms.MessageListener;
+import java.util.*;
+import java.util.concurrent.*;
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * @Author 龙三郎
+ * @Date 2022-4-06 16:22:13
+ * @Version 1.0
+ * @Description 阿里云物联网平台服务端订阅
+ */
+@Service
+@Slf4j
+public class AliyunConsumerGroupService {
+    private static final String IOTID = "iotId";
+    private static final String PRODUCTKEY = "productKey";
+    private static final String DEVICENAME = "deviceName";
+    private static final String TOPIC = "topic";
+    private static final String MESSAGEID = "messageId";
+    private static final String ITEMS = "items";
+    private static final String VALUE = "value";
+    private static final String STATUS = "status";
+    private static final String CONTENT = "content";
+
+    @Autowired
+    @Lazy
+    private AliyunIotSubscribeClient client;
+    @Autowired
+    @Lazy
+    private IDeviceClient deviceService;
+
+    @Autowired
+    private IIotMsgHandler iotMsgHandler;
+
+    @Autowired
+    @Lazy
+    private IHospitalLogClient hospitalLogService;
+    @Value("${aliyun.server-subscription.enable:false}")
+    private boolean isEnable;
+
+    // 开启服务端订阅
+    @PostConstruct
+    public void subscribe(){
+        if (!isEnable){
+            log.info("订阅禁止");
+            return;
+        }
+        log.info("允许开启订阅");
+        try {
+            // 开启订阅
+            client.start(messageListener);
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        log.info("阿里云物联网订阅成功。。。。。。。。。。。");
+    }
+
+
+
+    /**
+     * 描述:业务处理异步线程池,线程池参数可以根据您的业务特点调整,或者您也可以用其他异步方式处理接收到的消息。
+     */
+    private final static ExecutorService executorService = new ThreadPoolExecutor(
+            Runtime.getRuntime().availableProcessors(),
+            Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
+            new LinkedBlockingQueue(50000),
+            new AliYunThreadFactory());
+
+    static class AliYunThreadFactory implements ThreadFactory {
+        static final AtomicInteger poolNumber = new AtomicInteger(1);
+        final ThreadGroup group;
+        final AtomicInteger threadNumber = new AtomicInteger(1);
+        final String namePrefix;
+
+        AliYunThreadFactory() {
+            SecurityManager s = System.getSecurityManager();
+            group = (s != null)? s.getThreadGroup() :
+                    Thread.currentThread().getThreadGroup();
+            namePrefix = "ali-iot-" +
+                    poolNumber.getAndIncrement();
+        }
+        @Override
+        public Thread newThread(Runnable r) {
+            Thread t = new Thread(group, r,
+                    namePrefix + threadNumber.getAndIncrement(),
+                    0);
+            if (t.isDaemon()){
+                t.setDaemon(false);
+            }
+            if (t.getPriority() != Thread.NORM_PRIORITY){
+                t.setPriority(Thread.NORM_PRIORITY);
+            }
+            return t;
+        }
+    }
+
+    private MessageListener messageListener = (message) -> {
+        try {
+            //1.收到消息之后一定要ACK。
+            // 推荐做法:创建Session选择Session.AUTO_ACKNOWLEDGE,这里会自动ACK。
+            // 其他做法:创建Session选择Session.CLIENT_ACKNOWLEDGE,这里一定要调message.acknowledge()来ACK。
+            // message.acknowledge();
+            //2.建议异步处理收到的消息,确保onMessage函数里没有耗时逻辑。
+            // 如果业务处理耗时过程过长阻塞住线程,可能会影响SDK收到消息后的正常回调。
+            executorService.submit(()-> processMessage(message));
+        } catch (Exception e) {
+            log.error("submit task occurs exception ", e);
+        }
+    };
+
+    private void processMessage(Message message) {
+        BusHospitalLogEntity hospitalLog = new BusHospitalLogEntity();
+        long startTime = System.currentTimeMillis();
+        String deviceName=null;
+        try {
+            // 获取主题,消息id和内容
+            String topic = message.getStringProperty(TOPIC);
+            String messageId = message.getStringProperty(MESSAGEID);
+            hospitalLog.setMsgId(messageId);
+            JSONObject content = JSON.parseObject(new String(message.getBody(byte[].class)));
+            log.info("阿里云物联网发送的数据:"+JSON.toJSONString(content));
+            // 设备名称
+            deviceName = content.getString(DEVICENAME);
+            hospitalLog.setIdentityCode(deviceName);
+            hospitalLog.setInput(content.toJSONString());
+            // 创建设备对象
+            Date now = new Date();
+            // 根据topic判断数据类型,设备上下线状态
+            if (topic.matches("^/as/mqtt/status/[\\w\\/]*")){
+                BusDeviceEntity device = new BusDeviceEntity();
+                device.setDeviceId(deviceName);
+                String status = content.getString(STATUS);
+                device.setStatus(EnumUtils.getDeviceStatusEnum2(status));
+                if ("online".equalsIgnoreCase(status)){
+                    log.info(deviceName+"设备【{}】上线",deviceName);
+                }else if ("offline".equalsIgnoreCase(status)){
+                    log.info(deviceName+"设备【{}】下线",deviceName);
+                }else {
+                    log.info(deviceName+"设备【{}】未激活",deviceName);
+                }
+                hospitalLog.setType(HospitalLogEnum.ALI_STATUS);
+                // 更新设备状态
+                deviceService.updateDevice(device);
+            }else if (topic.matches("[\\w\\/]*event/property/post$")){//设备属性上报
+                // 设备属性集合
+                Items items = new Items(content.getJSONObject("items"));
+                log.info("上传设备属性:【{}】",JSONUtil.toJsonStr(items));
+                BusDeviceRunningEntity deviceRunning = new BusDeviceRunningEntity();
+                deviceRunning.updateFieldsByItems(deviceName,items);
+                deviceRunning.setMsgId(messageId);
+                hospitalLog.setType(HospitalLogEnum.ALI_DATA_UPLOAD);
+                hospitalLog.setTenantId(iotMsgHandler.sync(deviceRunning,deviceName).getTenantId());
+            }else if(topic.matches("[\\w\\/]+thing/lifecycle$")){// 设备生命周期
+                // 获取生命周期类型
+                String action = content.getString("action");
+                if ("create".equals(action)){
+                    // 创建设备
+                    BusDeviceEntity device = new BusDeviceEntity();
+                    device.setDeviceId(deviceName);
+
+                    // 配置信息
+                    AliIotConfig config = new AliIotConfig();
+                    config.setDeviceName(deviceName);
+                    config.setDeviceSecret(content.getString("deviceSecret"));
+                    config.setIotId(content.getString("iotId"));
+                    config.setProductKey(content.getString("productKey"));
+                    hospitalLog.setType(HospitalLogEnum.ALI_LIFECYCLE);
+                    // 设置配置信息
+                    device.setConfig(config);
+                    deviceService.saveDevice(device);
+                }else if ("delete".equals(action)){
+                    // 删除设备
+                    hospitalLog.setType(HospitalLogEnum.ALI_DEL);
+                    deviceService.removeByDeviceId(deviceName);
+                }
+            }else {
+                log.warn("阿里云数据【{}】,未知的topic:【{}】",content.toJSONString(),topic);
+            }
+            hospitalLog.setSuccess(true);
+        } catch (Exception e) {
+            hospitalLog.setSuccess(false);
+            hospitalLog.setMessage(ExceptionUtil.getExceptionMsg(e));
+            log.error("阿里云数据【{}】数据处理失败 ", JSONUtil.toJsonStr(message), e);
+        }finally {
+            if(CharSequenceUtil.isNotBlank(deviceName)&&CharSequenceUtil.isEmpty(hospitalLog.getTenantId())){
+                BusDeviceEntity device = deviceService.getByDeviceId(deviceName);
+                hospitalLog.setTenantId(device.getTenantId());
+            }
+            long entTime = System.currentTimeMillis();
+            hospitalLog.setUseTime(entTime-startTime);
+            hospitalLog.setId(IdWorker.getIdStr());
+            if(CharSequenceUtil.isEmpty(hospitalLog.getTenantId())){
+                log.warn("日志【{}】医院为空,进行自动填充",JSONUtil.toJsonStr(hospitalLog));
+            }
+            hospitalLogService.save(hospitalLog);
+        }
+
+    }
+
+
+
+
+
+}

+ 205 - 0
nb-service/iot-service/src/main/java/com/nb/aliyun/AliyunIotSubscribeClient.java

@@ -0,0 +1,205 @@
+package com.nb.aliyun;
+
+import com.baomidou.mybatisplus.core.toolkit.IdWorker;
+import com.nb.aliyun.api.bean.PlatformAccount;
+import lombok.Getter;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.codec.binary.Base64;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionListener;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.springframework.boot.context.properties.EnableConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.scheduling.annotation.Async;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.jms.*;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+import java.net.InetAddress;
+import java.net.URI;
+import java.net.UnknownHostException;
+import java.util.ArrayList;
+import java.util.Hashtable;
+import java.util.List;
+
+/**
+ * @Author 龙三郎
+ * @Date 2021-06-17 10:53:30
+ * @Version 1.0
+ * @Description XXX
+ */
+@Configuration
+@EnableConfigurationProperties(PlatformAccount.class)
+@Slf4j
+public class AliyunIotSubscribeClient {
+
+    private final PlatformAccount platformAccount;
+
+    public AliyunIotSubscribeClient(PlatformAccount platformAccount) {
+        this.platformAccount = platformAccount;
+        this.accessKey = platformAccount.getAccessKey();
+        this.accessSecret = platformAccount.getAccessSecret();
+        this.regionId = platformAccount.getRegionId();
+        this.consumerGroupId = platformAccount.getConsumerGroupId();
+        this.aliyunUid = platformAccount.getAliyunUid();
+        this.iotInstanceId = platformAccount.getIotInstanceId();
+
+        this.host = aliyunUid+".iot-amqp."+ regionId +".aliyuncs.com";
+        // 设置客户端id
+        setClientIdAndHost();
+    }
+
+    // 设置客户端id
+    private void setClientIdAndHost(){
+        // 获取ip地址
+        InetAddress addr = null;
+        try {
+            addr = InetAddress.getLocalHost();
+        } catch (UnknownHostException e) {
+            e.printStackTrace();
+        }
+        this.clientId = IdWorker.getIdStr();
+    }
+
+    private String accessKey;
+    private String accessSecret;
+    private String consumerGroupId;
+    private String aliyunUid;
+    private String regionId;
+
+    //iotInstanceId:企业版实例请填写实例ID,公共实例请填空字符串""。
+    private String iotInstanceId;
+
+    //控制台服务端订阅中消费组状态页客户端ID一栏将显示clientId参数。
+    //建议使用机器UUID、MAC地址、IP等唯一标识等作为clientId。便于您区分识别不同的客户端。
+    private String clientId;
+
+    //${YourHost}为接入域名,请参见AMQP客户端接入说明文档。
+    private String host;
+
+    // 指定单个进程启动的连接数
+    // 单个连接消费速率有限,请参考使用限制,最大64个连接
+    // 连接数和消费速率及rebalance相关,建议每500QPS增加一个连接
+    private static int connectionCount = 1;
+
+    @Getter
+    private List<Connection> connections = null;
+
+    @Async
+    public void start(MessageListener messageListener) throws Exception {
+        // 先关闭一下
+        close();
+        connections = new ArrayList<>();
+        //参数说明,请参见AMQP客户端接入说明文档。
+        for (int i = 0; i < connectionCount; i++) {
+            long timeStamp = System.currentTimeMillis();
+            //签名方法:支持hmacmd5、hmacsha1和hmacsha256。
+            String signMethod = "hmacsha1";
+
+            //userName组装方法,请参见AMQP客户端接入说明文档。
+            String userName = clientId + "-" + i + "|authMode=aksign"
+                    + ",signMethod=" + signMethod
+                    + ",timestamp=" + timeStamp
+                    + ",authId=" + accessKey
+                    + ",iotInstanceId=" + iotInstanceId
+                    + ",consumerGroupId=" + consumerGroupId
+                    + "|";
+            //计算签名,password组装方法,请参见AMQP客户端接入说明文档。
+            String signContent = "authId=" + accessKey + "&timestamp=" + timeStamp;
+            String password = doSign(signContent, accessSecret, signMethod);
+            String connectionUrl = "failover:(amqps://" + host + ":5671?amqp.idleTimeout=80000)"
+                    + "?failover.reconnectDelay=30";
+
+            Hashtable<String, String> hashtable = new Hashtable<>();
+            hashtable.put("connectionfactory.SBCF", connectionUrl);
+            hashtable.put("queue.QUEUE", "default");
+            hashtable.put(Context.INITIAL_CONTEXT_FACTORY, "org.apache.qpid.jms.jndi.JmsInitialContextFactory");
+            Context context = new InitialContext(hashtable);
+            ConnectionFactory cf = (ConnectionFactory)context.lookup("SBCF");
+            Destination queue = (Destination)context.lookup("QUEUE");
+            // 创建连接。
+            Connection connection = cf.createConnection(userName, password);
+            connections.add(connection);
+
+            ((JmsConnection)connection).addConnectionListener(myJmsConnectionListener);
+            // 创建会话。
+            // Session.CLIENT_ACKNOWLEDGE: 收到消息后,需要手动调用message.acknowledge()。
+            // Session.AUTO_ACKNOWLEDGE: SDK自动ACK(推荐)。
+            Session session = connection.createSession(false, Session.AUTO_ACKNOWLEDGE);
+
+            connection.start();
+            // 创建Receiver连接。
+            MessageConsumer consumer = session.createConsumer(queue);
+            consumer.setMessageListener(messageListener);
+        }
+    }
+
+    public void close() throws Exception {
+        if (connections == null){
+            return;
+        }
+        connections.forEach(c-> {
+            try {
+                c.close();
+            } catch (JMSException e) {
+                log.error("连接关闭失败", e);
+            }
+        });
+    }
+
+
+    private static JmsConnectionListener myJmsConnectionListener = new JmsConnectionListener() {
+        /**
+         * 连接成功建立。
+         */
+        @Override
+        public void onConnectionEstablished(URI remoteURI) {
+            log.info("连接成功, remoteUri:{}", remoteURI);
+        }
+        /**
+         * 尝试过最大重试次数之后,最终连接失败。
+         */
+        @Override
+        public void onConnectionFailure(Throwable error) {
+            log.error("连接失败, {}", error.getMessage());
+        }
+        /**
+         * 连接中断。
+         */
+        @Override
+        public void onConnectionInterrupted(URI remoteURI) {
+            log.info("连接中断, remoteUri:{}", remoteURI);
+        }
+        /**
+         * 连接中断后又自动重连上。
+         */
+        @Override
+        public void onConnectionRestored(URI remoteURI) {
+            log.info("自动重连, remoteUri:{}", remoteURI);
+        }
+        @Override
+        public void onInboundMessage(JmsInboundMessageDispatch envelope) {}
+        @Override
+        public void onSessionClosed(Session session, Throwable cause) {}
+        @Override
+        public void onConsumerClosed(MessageConsumer consumer, Throwable cause) {}
+        @Override
+        public void onProducerClosed(MessageProducer producer, Throwable cause) {}
+    };
+
+    /**
+     * 计算签名,password组装方法,请参见AMQP客户端接入说明文档。
+     */
+    private static String doSign(String toSignString, String secret, String signMethod) throws Exception {
+        SecretKeySpec signingKey = new SecretKeySpec(secret.getBytes(), signMethod);
+        Mac mac = Mac.getInstance(signMethod);
+        mac.init(signingKey);
+        byte[] rawHmac = mac.doFinal(toSignString.getBytes());
+        return Base64.encodeBase64String(rawHmac);
+    }
+
+
+
+}

Daži faili netika attēloti, jo izmaiņu fails ir pārāk liels