wulianwei 1 year ago
commit
0189d63711
100 changed files with 5032 additions and 0 deletions
  1. 40 0
      .classpath
  2. 3 0
      .gitignore
  3. 37 0
      .project
  4. 140 0
      forward.sql
  5. 182 0
      pom.xml
  6. 24 0
      src/main/java/com/tuoren/forward/App.java
  7. 20 0
      src/main/java/com/tuoren/forward/annotation/HandleLog.java
  8. 33 0
      src/main/java/com/tuoren/forward/annotation/SqlLimit.java
  9. 175 0
      src/main/java/com/tuoren/forward/aspect/HandleLogAspect.java
  10. 39 0
      src/main/java/com/tuoren/forward/config/GlobalCorsConfig.java
  11. 33 0
      src/main/java/com/tuoren/forward/config/GlobalExceptionHandler.java
  12. 39 0
      src/main/java/com/tuoren/forward/config/OtherDataSourceConfiguration.java
  13. 98 0
      src/main/java/com/tuoren/forward/config/PrimaryDataSourceConfiguration.java
  14. 42 0
      src/main/java/com/tuoren/forward/config/RedisConfig.java
  15. 52 0
      src/main/java/com/tuoren/forward/config/RestTemplateConfig.java
  16. 95 0
      src/main/java/com/tuoren/forward/config/SaTokenConfigure.java
  17. 55 0
      src/main/java/com/tuoren/forward/config/SpringDocConfig.java
  18. 42 0
      src/main/java/com/tuoren/forward/config/StpInterfaceImpl.java
  19. 307 0
      src/main/java/com/tuoren/forward/config/amqp/AmqpClient1.java
  20. 307 0
      src/main/java/com/tuoren/forward/config/amqp/AmqpClient2.java
  21. 39 0
      src/main/java/com/tuoren/forward/config/mqtt/MqttCallbackCustom.java
  22. 59 0
      src/main/java/com/tuoren/forward/config/mqtt/MqttConfig.java
  23. 92 0
      src/main/java/com/tuoren/forward/config/mqtt/MqttUtil.java
  24. 27 0
      src/main/java/com/tuoren/forward/constant/CodeMsg.java
  25. 36 0
      src/main/java/com/tuoren/forward/constant/CommonConstant.java
  26. 18 0
      src/main/java/com/tuoren/forward/constant/HandleLogChoice.java
  27. 96 0
      src/main/java/com/tuoren/forward/controller/DeviceController.java
  28. 80 0
      src/main/java/com/tuoren/forward/controller/HospitalController.java
  29. 38 0
      src/main/java/com/tuoren/forward/controller/LogController.java
  30. 67 0
      src/main/java/com/tuoren/forward/controller/ModelController.java
  31. 108 0
      src/main/java/com/tuoren/forward/controller/OpenController.java
  32. 91 0
      src/main/java/com/tuoren/forward/controller/PermissionController.java
  33. 84 0
      src/main/java/com/tuoren/forward/controller/ProductController.java
  34. 31 0
      src/main/java/com/tuoren/forward/controller/PublicController.java
  35. 49 0
      src/main/java/com/tuoren/forward/controller/RegionController.java
  36. 99 0
      src/main/java/com/tuoren/forward/controller/RoleController.java
  37. 115 0
      src/main/java/com/tuoren/forward/controller/UserController.java
  38. 39 0
      src/main/java/com/tuoren/forward/entity/Device.java
  39. 23 0
      src/main/java/com/tuoren/forward/entity/Dictionary.java
  40. 33 0
      src/main/java/com/tuoren/forward/entity/Hospital.java
  41. 54 0
      src/main/java/com/tuoren/forward/entity/Log.java
  42. 29 0
      src/main/java/com/tuoren/forward/entity/Model.java
  43. 32 0
      src/main/java/com/tuoren/forward/entity/Permission.java
  44. 42 0
      src/main/java/com/tuoren/forward/entity/Product.java
  45. 23 0
      src/main/java/com/tuoren/forward/entity/Region.java
  46. 17 0
      src/main/java/com/tuoren/forward/entity/Role.java
  47. 14 0
      src/main/java/com/tuoren/forward/entity/RolePermission.java
  48. 50 0
      src/main/java/com/tuoren/forward/entity/User.java
  49. 14 0
      src/main/java/com/tuoren/forward/entity/UserRole.java
  50. 20 0
      src/main/java/com/tuoren/forward/entity/dto/DeviceDto.java
  51. 20 0
      src/main/java/com/tuoren/forward/entity/dto/HospitalDto.java
  52. 25 0
      src/main/java/com/tuoren/forward/entity/dto/LogDto.java
  53. 20 0
      src/main/java/com/tuoren/forward/entity/dto/ModelDto.java
  54. 20 0
      src/main/java/com/tuoren/forward/entity/dto/ProductDto.java
  55. 17 0
      src/main/java/com/tuoren/forward/entity/dto/UserDto.java
  56. 17 0
      src/main/java/com/tuoren/forward/entity/req/CommonSearchReq.java
  57. 24 0
      src/main/java/com/tuoren/forward/entity/req/DeviceAddReq.java
  58. 22 0
      src/main/java/com/tuoren/forward/entity/req/DeviceRecordSearchReq.java
  59. 19 0
      src/main/java/com/tuoren/forward/entity/req/DeviceSearchReq.java
  60. 17 0
      src/main/java/com/tuoren/forward/entity/req/HospitalAddOpenReq.java
  61. 16 0
      src/main/java/com/tuoren/forward/entity/req/HospitalSearchReq.java
  62. 13 0
      src/main/java/com/tuoren/forward/entity/req/IdReq.java
  63. 13 0
      src/main/java/com/tuoren/forward/entity/req/IntIdReq.java
  64. 30 0
      src/main/java/com/tuoren/forward/entity/req/LogSearchReq.java
  65. 22 0
      src/main/java/com/tuoren/forward/entity/req/LoginReq.java
  66. 20 0
      src/main/java/com/tuoren/forward/entity/req/ModelSearchReq.java
  67. 21 0
      src/main/java/com/tuoren/forward/entity/req/PageReq.java
  68. 18 0
      src/main/java/com/tuoren/forward/entity/req/ProductAddReq.java
  69. 16 0
      src/main/java/com/tuoren/forward/entity/req/ProductSearchReq.java
  70. 16 0
      src/main/java/com/tuoren/forward/entity/req/RoleAuthReq.java
  71. 17 0
      src/main/java/com/tuoren/forward/entity/req/RoleSearchReq.java
  72. 31 0
      src/main/java/com/tuoren/forward/entity/req/UserAddOpenReq.java
  73. 35 0
      src/main/java/com/tuoren/forward/entity/req/UserAddReq.java
  74. 25 0
      src/main/java/com/tuoren/forward/entity/req/UserEditSelfReq.java
  75. 16 0
      src/main/java/com/tuoren/forward/entity/req/UserSearchReq.java
  76. 15 0
      src/main/java/com/tuoren/forward/entity/resp/CaptchaResp.java
  77. 17 0
      src/main/java/com/tuoren/forward/entity/resp/DeviceResp.java
  78. 45 0
      src/main/java/com/tuoren/forward/entity/resp/LoginResp.java
  79. 19 0
      src/main/java/com/tuoren/forward/entity/resp/UserResp.java
  80. 38 0
      src/main/java/com/tuoren/forward/init/AmqpInit.java
  81. 41 0
      src/main/java/com/tuoren/forward/init/MqttInit.java
  82. 30 0
      src/main/java/com/tuoren/forward/init/MybatisInit.java
  83. 176 0
      src/main/java/com/tuoren/forward/interceptor/MybatisInterceptor.java
  84. 41 0
      src/main/java/com/tuoren/forward/mapper/DeviceMapper.java
  85. 17 0
      src/main/java/com/tuoren/forward/mapper/DictionaryMapper.java
  86. 24 0
      src/main/java/com/tuoren/forward/mapper/HospitalMapper.java
  87. 22 0
      src/main/java/com/tuoren/forward/mapper/LogMapper.java
  88. 26 0
      src/main/java/com/tuoren/forward/mapper/ModelMapper.java
  89. 37 0
      src/main/java/com/tuoren/forward/mapper/PermissionMapper.java
  90. 35 0
      src/main/java/com/tuoren/forward/mapper/ProductMapper.java
  91. 21 0
      src/main/java/com/tuoren/forward/mapper/RegionMapper.java
  92. 25 0
      src/main/java/com/tuoren/forward/mapper/RoleMapper.java
  93. 12 0
      src/main/java/com/tuoren/forward/mapper/RolePermissionMapper.java
  94. 26 0
      src/main/java/com/tuoren/forward/mapper/UserMapper.java
  95. 15 0
      src/main/java/com/tuoren/forward/mapper/UserRoleMapper.java
  96. 130 0
      src/main/java/com/tuoren/forward/service/DeviceService.java
  97. 186 0
      src/main/java/com/tuoren/forward/service/HospitalService.java
  98. 35 0
      src/main/java/com/tuoren/forward/service/LogService.java
  99. 81 0
      src/main/java/com/tuoren/forward/service/ModelService.java
  100. 126 0
      src/main/java/com/tuoren/forward/service/PermissionService.java

+ 40 - 0
.classpath

@@ -0,0 +1,40 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" output="target/classes" path="src/main/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="optional" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="src" output="target/test-classes" path="src/test/java">
+		<attributes>
+			<attribute name="optional" value="true"/>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry excluding="**" kind="src" output="target/test-classes" path="src/test/resources">
+		<attributes>
+			<attribute name="maven.pomderived" value="true"/>
+			<attribute name="test" value="true"/>
+			<attribute name="optional" value="true"/>
+		</attributes>
+	</classpathentry>
+	<classpathentry kind="output" path="target/classes"/>
+</classpath>

+ 3 - 0
.gitignore

@@ -0,0 +1,3 @@
+/.settings
+/LOG_PATH_IS_UNDEFINED
+/target

+ 37 - 0
.project

@@ -0,0 +1,37 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>forward</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.wst.common.project.facet.core.builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.wst.validation.validationbuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+		<buildCommand>
+			<name>org.eclipse.m2e.core.maven2Builder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jem.workbench.JavaEMFNature</nature>
+		<nature>org.eclipse.wst.common.modulecore.ModuleCoreNature</nature>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+		<nature>org.eclipse.m2e.core.maven2Nature</nature>
+		<nature>org.eclipse.wst.common.project.facet.core.nature</nature>
+		<nature>org.eclipse.wst.jsdt.core.jsNature</nature>
+	</natures>
+</projectDescription>

File diff suppressed because it is too large
+ 140 - 0
forward.sql


+ 182 - 0
pom.xml

@@ -0,0 +1,182 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
+  <modelVersion>4.0.0</modelVersion>
+
+  <groupId>com.tuoren</groupId>
+  <artifactId>forward</artifactId>
+  <version>0.0.1-SNAPSHOT</version>
+  <packaging>jar</packaging>
+
+  <name>forward</name>
+  <url>http://maven.apache.org</url>
+
+  <properties>
+		<encoding>UTF-8</encoding>
+		<java-version>1.8</java-version>
+	</properties>
+	<parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.7.16</version>
+    </parent>
+    
+    <dependencies>
+    	<dependency>
+		    <groupId>org.springframework.boot</groupId>
+		    <artifactId>spring-boot-starter-web</artifactId>
+		</dependency>
+		
+		<dependency>
+		    <groupId>org.springframework.boot</groupId>
+		    <artifactId>spring-boot-starter-aop</artifactId>
+		</dependency>
+
+	    <dependency>
+		    <groupId>org.springframework.boot</groupId>
+		    <artifactId>spring-boot-starter-jdbc</artifactId>
+		</dependency>
+		<dependency>
+		    <groupId>org.mybatis.spring.boot</groupId>
+		    <artifactId>mybatis-spring-boot-starter</artifactId>
+		    <version>2.3.1</version>
+		</dependency>
+		<dependency>
+			<groupId>org.springframework.boot</groupId>
+			<artifactId>spring-boot-starter-data-redis</artifactId>
+		</dependency>
+		<dependency>
+		    <groupId>org.mybatis.generator</groupId>
+		    <artifactId>mybatis-generator-core</artifactId>
+		    <version>1.4.2</version>
+		</dependency>
+		<dependency>
+			<groupId>com.mysql</groupId>
+        	<artifactId>mysql-connector-j</artifactId>
+			<scope>runtime</scope>
+		</dependency>
+		<!-- SpringBoot MongoDB -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-mongodb</artifactId>
+        </dependency>
+		<dependency>
+		    <groupId>com.github.pagehelper</groupId>
+		    <artifactId>pagehelper-spring-boot-starter</artifactId>
+		    <version>1.4.7</version>
+		</dependency>
+		
+		<dependency>
+			<groupId>org.projectlombok</groupId>
+			<artifactId>lombok</artifactId>
+		</dependency>
+		
+		<dependency>
+		    <groupId>com.alibaba.fastjson2</groupId>
+		    <artifactId>fastjson2</artifactId>
+		    <version>2.0.40</version>
+		</dependency>
+
+		<dependency>
+			<groupId>org.apache.commons</groupId>
+			<artifactId>commons-lang3</artifactId>
+		</dependency>
+		<!-- 提供Redis连接池 -->
+		<dependency>
+		    <groupId>org.apache.commons</groupId>
+		    <artifactId>commons-pool2</artifactId>
+		</dependency>
+		
+		<dependency>
+		    <groupId>com.github.xiaoymin</groupId>
+		    <artifactId>knife4j-openapi3-spring-boot-starter</artifactId>
+		    <version>4.1.0</version>
+		</dependency>
+		
+		<!-- Sa-Token 权限认证, 在线文档:http://sa-token.dev33.cn/ -->
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-spring-boot-starter</artifactId>
+		    <version>1.30.0</version>
+		</dependency>
+		<dependency>
+		    <groupId>cn.dev33</groupId>
+		    <artifactId>sa-token-dao-redis-jackson</artifactId>
+		    <version>1.30.0</version>
+		</dependency>
+		
+		<dependency>
+		    <groupId>cn.hutool</groupId>
+		    <artifactId>hutool-all</artifactId>
+		    <version>5.7.22</version>
+		</dependency>
+		<!-- amqp 1.0 qpid client -->
+		 <dependency>
+		   <groupId>org.apache.qpid</groupId>
+		   <artifactId>qpid-jms-client</artifactId>
+		   <version>0.57.0</version>
+		 </dependency>
+		 <!-- util for base64-->
+		 <dependency>
+		   <groupId>commons-codec</groupId>
+		  <artifactId>commons-codec</artifactId>
+		</dependency>
+		 <!--mqtt依赖-->
+        <dependency>
+            <groupId>org.eclipse.paho</groupId>
+            <artifactId>org.eclipse.paho.client.mqttv3</artifactId>
+            <version>1.2.2</version>
+        </dependency>
+        <!-- https://mvnrepository.com/artifact/com.squareup.okhttp3/okhttp -->
+        <dependency>
+		    <groupId>com.squareup.okhttp3</groupId>
+		    <artifactId>okhttp</artifactId>
+		</dependency>
+        <!--<dependency>
+        	<groupId>com.demo</groupId>
+        	<artifactId>forward</artifactId>
+        	<version>0.0.1-SNAPSHOT</version>
+        </dependency>-->
+    </dependencies>
+    
+    <build>
+		<plugins>
+			<plugin>
+				<groupId>org.apache.maven.plugins</groupId>
+				<artifactId>maven-compiler-plugin</artifactId>
+				<configuration>
+					<source>${java-version}</source> <!-- 源代码使用的JDK版本 -->
+					<target>${java-version}</target> <!-- 需要生成的目标class文件的编译版本 -->
+					<encoding>${encoding}</encoding><!-- 字符集编码 -->
+				</configuration>
+			</plugin>
+			<plugin>
+				<groupId>org.springframework.boot</groupId>
+				<artifactId>spring-boot-maven-plugin</artifactId>
+				<executions>
+					<execution>
+						<goals>
+							<goal>repackage</goal>
+						</goals>
+					</execution>
+				</executions>
+			</plugin>
+			<plugin>
+                <groupId>org.mybatis.generator</groupId>
+                <artifactId>mybatis-generator-maven-plugin</artifactId>
+                <version>1.4.2</version>
+                <configuration>
+                   <!--  mybatis-generator 配置文件存放地址 -->
+                    <configurationFile>src/main/resources/generatorConfig.xml</configurationFile>
+                    <!-- <overwrite>true</overwrite>-->
+                </configuration>
+                <dependencies>
+                    <dependency>
+						<groupId>com.mysql</groupId>
+        				<artifactId>mysql-connector-j</artifactId>
+						<version>${mysql.version}</version>
+					</dependency>
+                </dependencies>
+            </plugin>
+		</plugins>
+	</build>
+</project>

+ 24 - 0
src/main/java/com/tuoren/forward/App.java

@@ -0,0 +1,24 @@
+package com.tuoren.forward;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.transaction.annotation.EnableTransactionManagement;
+
+/**
+ * @date 2023-09-25
+ * @author wulianwei
+ */
+@SpringBootApplication
+@EnableTransactionManagement
+//@MapperScan("com.tuoren.forward.mapper")
+public class App {
+
+	/**
+	 * @title 项目启动 
+	 * @param args
+	 */
+	public static void main(String[] args) {
+		SpringApplication.run(App.class, args);
+	}
+
+}

+ 20 - 0
src/main/java/com/tuoren/forward/annotation/HandleLog.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+import com.tuoren.forward.constant.HandleLogChoice;
+
+@Documented //用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化.Documented是一个标记注解,没有成员.
+@Target(ElementType.METHOD) 
+@Retention(RetentionPolicy.RUNTIME)
+public @interface HandleLog {
+	
+	HandleLogChoice value() default HandleLogChoice.RECORD_ANY;  //记录方式
+	
+	HandleLogChoice type() default HandleLogChoice.TYPE_COMMON; //日志类型
+	
+}

+ 33 - 0
src/main/java/com/tuoren/forward/annotation/SqlLimit.java

@@ -0,0 +1,33 @@
+package com.tuoren.forward.annotation;
+
+import java.lang.annotation.Documented;
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Inherited;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target({ElementType.METHOD,ElementType.TYPE})
+@Retention(RetentionPolicy.RUNTIME)
+@Documented
+@Inherited
+public @interface SqlLimit {
+    /**
+     * sql表别名
+     * @return
+     */
+    String alis() default "";
+ 
+    /**
+     * 通过此列名进行限制
+     * @return
+     */
+    String columnName() default "";
+    
+    /**
+     * 是否启用, 默认true, false 代表过滤无效
+     * @return
+     */
+    boolean isWork() default true;
+
+}

+ 175 - 0
src/main/java/com/tuoren/forward/aspect/HandleLogAspect.java

@@ -0,0 +1,175 @@
+package com.tuoren.forward.aspect;
+
+import java.lang.reflect.Method;
+import java.lang.reflect.Parameter;
+import java.util.Date;
+import java.util.Map;
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.aspectj.lang.JoinPoint;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.AfterThrowing;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.aspectj.lang.reflect.MethodSignature;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.constant.CodeMsg;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.constant.HandleLogChoice;
+import com.tuoren.forward.entity.Log;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.mapper.LogMapper;
+import com.tuoren.forward.util.AccessTokenUtil;
+import com.tuoren.forward.util.UUIDUtil;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+
+/**
+ * @title 提取操作日志并写入数据库
+ * @date 2024-02-22
+ * @author wulianwei
+ */
+@ConditionalOnProperty(value = "handleLog.enable")
+@Aspect
+@Component
+public class HandleLogAspect {
+		
+	@Autowired
+	private LogMapper logMapper;
+	
+	//@Pointcut("execution(* com.tuoren.forward.controller.*.*(..))")
+	@Pointcut("@annotation(com.tuoren.forward.annotation.HandleLog)")
+	public void handleLogPoint() {}
+	
+	
+	@AfterThrowing(pointcut = "handleLogPoint()",throwing = "ex")
+    public void handleLogAfterThrowing(Throwable ex) {
+        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+		Log handleLog = (Log) request.getAttribute(CommonConstant.REQUEST_LOG_ATTR);
+		if(handleLog == null) {
+			return;
+		}
+		long time = (long) request.getAttribute(CommonConstant.REQUEST_TIME_ATTR);
+		long wastetime = System.currentTimeMillis() - time;
+		handleLog.setStatus("2"); //操作异常
+		handleLog.setWaste(String.valueOf(wastetime));
+		String exString = ex.toString();
+		if(exString.length() > 500) {
+			exString = exString.substring(0, 500);
+		}
+		handleLog.setResult(exString);
+		logMapper.insert(handleLog);
+        
+    }
+	
+	@Around("handleLogPoint()")
+    public Object handleLogAround(ProceedingJoinPoint joinPoint) throws Throwable {
+        HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.getRequestAttributes()).getRequest();
+        long time = System.currentTimeMillis();
+        Log handleLog = packLog(request,joinPoint);
+        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+        Method method = signature.getMethod();
+        HandleLog logAnno = method.getAnnotation(HandleLog.class);
+		if(logAnno.value() == HandleLogChoice.RECORD_ANY  || logAnno.value() == HandleLogChoice.RECORD_EXCEPTION) {
+			request.setAttribute(CommonConstant.REQUEST_LOG_ATTR, handleLog);
+	        request.setAttribute(CommonConstant.REQUEST_TIME_ATTR, time);
+		}
+        Object result = joinPoint.proceed();
+        
+        long wastetime = System.currentTimeMillis() - time;
+        handleLog.setWaste(String.valueOf(wastetime));
+        JSONObject resultJson = JSONObject.from(result);
+        String resultStr = resultJson.toString();
+        if(resultStr.length() > 500) {
+        	resultStr = resultStr.substring(0,500);
+		}
+        handleLog.setResult(resultStr);
+        if(logAnno.type() == HandleLogChoice.TYPE_LOGIN) {//登录操作, 重新记录用户信息
+        	User user = AccessTokenUtil.getUser();
+        	if(user != null) {
+        		handleLog.setUserid(user.getId());
+        		handleLog.setUsername(user.getUsername());
+        	}
+        }
+        if(CodeMsg.SUCCESS.getCode().equals(resultJson.getInteger("code"))) {
+        	handleLog.setStatus("0"); //操作成功
+        	if(logAnno.value() == HandleLogChoice.RECORD_ANY  || logAnno.value() == HandleLogChoice.RECORD_SUC) {
+        		 logMapper.insert(handleLog);
+        	}
+        }else {
+        	handleLog.setStatus("1"); //操作失败
+        	if(logAnno.value() == HandleLogChoice.RECORD_ANY  || logAnno.value() == HandleLogChoice.RECORD_FAIL) {
+       		 	logMapper.insert(handleLog);
+        	}
+        }
+        return result;
+    }
+	
+	/**
+	 * @title 封装日志
+	 * @param request
+	 * @param joinPoint
+	 * @return
+	 */
+	@SuppressWarnings("unchecked")
+	private Log packLog(HttpServletRequest request,JoinPoint joinPoint) {
+		Log handleLog = new Log();
+		handleLog.setId(UUIDUtil.get32UUID());
+		handleLog.setCreatetime(new Date());
+		handleLog.setIp(request.getRemoteAddr());
+		handleLog.setStyle(request.getMethod());
+		handleLog.setUrl(request.getRequestURI());
+		Map<String,String[]> paramMap = request.getParameterMap();
+    	if(paramMap != null&& paramMap.size() > 0) {
+    		String paramStr =JSONObject.toJSONString(paramMap);
+    		if(paramStr.length() > 200) {
+    			paramStr = paramStr.substring(0,200);
+    		}
+    		handleLog.setParam(paramStr);
+    	}
+    	User user = AccessTokenUtil.getUser();
+    	if(user != null) {
+    		handleLog.setUserid(user.getId());
+    		handleLog.setUsername(user.getUsername());
+    	}
+		MethodSignature signature = (MethodSignature) joinPoint.getSignature();
+		String methodName = signature.getDeclaringTypeName()+"."+signature.getName();
+		handleLog.setMethod(methodName);
+		Tag tag = (Tag) signature.getDeclaringType().getDeclaredAnnotation(Tag.class);
+		 //设置模块
+        if(tag != null) {
+        	handleLog.setModule(tag.name());
+        }
+        
+        Method method = signature.getMethod();
+        Operation op = method.getDeclaredAnnotation(Operation.class);
+        //设置功能
+        if(op != null) {
+        	handleLog.setOperation(op.summary());
+        }
+        Object[] args = joinPoint.getArgs();
+        Parameter[] params = method.getParameters();
+        for(int i=0;i<params.length;i++) {
+        	Parameter param = params[i];
+        	if(param.getAnnotation(RequestBody.class) != null) {
+        		String paramStr = JSONObject.toJSONString(args[i]);
+        		if(paramStr.length() > 200) {
+        			paramStr = paramStr.substring(0,200);
+        		}
+        		handleLog.setBody(paramStr);
+        	}
+        }
+        return handleLog;
+	}
+}

+ 39 - 0
src/main/java/com/tuoren/forward/config/GlobalCorsConfig.java

@@ -0,0 +1,39 @@
+package com.tuoren.forward.config;
+
+import org.springframework.boot.web.servlet.FilterRegistrationBean;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.cors.CorsConfiguration;
+import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
+import org.springframework.web.filter.CorsFilter;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 
+ * @Description:  跨域配置   
+ * @author: Administrator     
+ * @date:   2020-04-29 11:43
+ */
+@Configuration
+public class GlobalCorsConfig implements WebMvcConfigurer {
+    //添加到容器中管理
+	private CorsConfiguration buildConfig() {  
+        CorsConfiguration corsConfiguration = new CorsConfiguration();  
+        corsConfiguration.addAllowedOrigin("*"); // 1允许任何域名使用
+        corsConfiguration.addAllowedHeader("*"); // 2允许任何头
+        corsConfiguration.addAllowedMethod("*"); // 3允许任何方法(post、get等) 
+        return corsConfiguration;  
+    }  
+
+    @Bean  
+    public FilterRegistrationBean<CorsFilter> corsFilter() {  
+    	
+        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();  
+        source.registerCorsConfiguration("/**", buildConfig()); // 4  
+        
+        FilterRegistrationBean<CorsFilter> corsBean = new FilterRegistrationBean<CorsFilter>(new CorsFilter(source));
+        corsBean.setName("crossOriginFilter");
+        corsBean.setOrder(-200);//这个顺序也有可能会有影响,尽量设置在拦截器前面
+        return corsBean;  
+    }  
+}

+ 33 - 0
src/main/java/com/tuoren/forward/config/GlobalExceptionHandler.java

@@ -0,0 +1,33 @@
+package com.tuoren.forward.config;
+
+
+import javax.servlet.http.HttpServletRequest;
+
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.constant.CodeMsg;
+import com.tuoren.forward.util.Result;
+
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.exception.NotPermissionException;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@ControllerAdvice
+public class GlobalExceptionHandler {
+	
+   @ResponseBody
+   @ExceptionHandler(Exception.class)
+    public Result exceptionHandler(HttpServletRequest request, Exception exception) throws Exception {    
+        String message =request.getRequestURL().toString();
+        if(exception instanceof NotLoginException) {
+        	return Result.fail(CodeMsg.NOLOGIN.getMsg());
+        }else if(exception instanceof NotPermissionException) {
+        	return Result.fail(CodeMsg.NORIGHT.getMsg());
+        }
+        log.error("发生异常>>"+message,exception);
+        return Result.fail(CodeMsg.EXCEPTION.getMsg());
+    }
+}

+ 39 - 0
src/main/java/com/tuoren/forward/config/OtherDataSourceConfiguration.java

@@ -0,0 +1,39 @@
+package com.tuoren.forward.config;
+
+import javax.sql.DataSource;
+
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.jdbc.core.JdbcTemplate;
+
+import com.zaxxer.hikari.HikariDataSource;
+
+//@Configuration
+public class OtherDataSourceConfiguration {
+
+	
+
+    @Bean("nbDataSourceProperties")
+    @ConfigurationProperties("spring.datasource.nb")
+    public DataSourceProperties nbDataSourceProperties() {
+        return new DataSourceProperties();
+    }
+
+    @Bean("nbDataSource")
+    @Qualifier(value = "nbDataSource")
+    // 留意下面这行
+    @ConfigurationProperties(prefix = "spring.datasource.nb.hikari")
+    public HikariDataSource nbDataSource(@Qualifier("nbDataSourceProperties") DataSourceProperties nbDataSourceProperties) {
+        return nbDataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
+    }
+
+
+    @Bean( "nbJdbcTemplate")
+    @Qualifier(value = "nbJdbcTemplate")
+    public JdbcTemplate secondaryJdbcTemplate(@Qualifier("nbDataSource") DataSource dataSource) {
+        return new JdbcTemplate(dataSource);
+    }
+
+}

+ 98 - 0
src/main/java/com/tuoren/forward/config/PrimaryDataSourceConfiguration.java

@@ -0,0 +1,98 @@
+package com.tuoren.forward.config;
+
+import javax.sql.DataSource;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.mybatis.spring.SqlSessionFactoryBean;
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.autoconfigure.jdbc.DataSourceProperties;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Primary;
+import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
+import org.springframework.jdbc.core.JdbcTemplate;
+import org.springframework.jdbc.datasource.DataSourceTransactionManager;
+import org.springframework.transaction.PlatformTransactionManager;
+
+import com.zaxxer.hikari.HikariDataSource;
+
+@Configuration
+@MapperScan(basePackages = "com.tuoren.forward.mapper", sqlSessionFactoryRef = "primarySqlSessionFactory")
+public class PrimaryDataSourceConfiguration {
+
+    /**
+     * 指定mapper xml文件路径
+     */
+    public static final String MAPPER_LOCATION = "classpath:mapper/*.xml";
+
+    /**
+     * @Author: lequal
+     * @Description 获取一级的属性
+     * @Date 2022/12/22 16:48
+     * @return org.springframework.boot.autoconfigure.jdbc.DataSourceProperties
+     */
+    @Primary
+    @Bean("primaryDataSourceProperties")
+    @ConfigurationProperties("spring.datasource.primary")
+    public DataSourceProperties primaryDataSourceProperties() {
+        return new DataSourceProperties();
+    }
+
+    /**
+     * @Author: lequal
+     * @Description 获取下一级的属性(hikari)并创建数据源
+     * @Date 2022/12/22 16:48
+     * @return com.zaxxer.hikari.HikariDataSource
+     */
+    @Primary
+    @Bean("primaryDataSource")
+    @Qualifier(value = "primaryDataSource")
+    @ConfigurationProperties(prefix = "spring.datasource.primary.hikari")
+    public HikariDataSource primaryDataSource(@Qualifier("primaryDataSourceProperties") DataSourceProperties dataSourceProperties) {
+        return dataSourceProperties.initializeDataSourceBuilder().type(HikariDataSource.class).build();
+    }
+
+	/**
+     * @Author: lequal
+     * @Description 配置事务管理器
+     * @Date 2022/12/22 16:48
+     * @param dataSource
+     * @return org.springframework.transaction.PlatformTransactionManager
+     */
+    @Bean(name = "primaryTransactionManager")
+    @Primary
+    public PlatformTransactionManager primaryTransactionManager(@Qualifier("primaryDataSource") DataSource dataSource) {
+        return new DataSourceTransactionManager(dataSource);
+    }
+
+    /**
+     * @Author: lequal
+     * @Description 自定义SQLSession工厂
+     * @Date 2022/12/22 16:50
+     * @param dataSource
+     * @return org.apache.ibatis.session.SqlSessionFactory
+     */
+    @Primary
+    @Bean(name = "primarySqlSessionFactory")
+    public SqlSessionFactory primarySqlSessionFactory(@Qualifier("primaryDataSource") DataSource dataSource) throws Exception {
+    	final SqlSessionFactoryBean sessionFactoryBean = new SqlSessionFactoryBean();
+        sessionFactoryBean.setDataSource(dataSource);
+        sessionFactoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources(PrimaryDataSourceConfiguration.MAPPER_LOCATION));
+        sessionFactoryBean.setTypeAliasesPackage("com.tuoren.forward.entity,com.tuoren.forward.entity.dto,com.tuoren.forward.entity.req,com.tuoren.forward.entity.resp");
+        return sessionFactoryBean.getObject();
+    }
+
+    /**
+     * @Author: lequal
+     * @Description 创建JDBC模板
+     * @Date 2022/12/22 16:48
+     * @param dataSource
+     * @return org.springframework.jdbc.core.JdbcTemplate
+     */
+    @Bean(name = "primaryJdbcTemplate")
+    public JdbcTemplate primaryJdbcTemplate(@Qualifier("primaryDataSource") DataSource dataSource) {
+        return new JdbcTemplate(dataSource);
+    }
+}

+ 42 - 0
src/main/java/com/tuoren/forward/config/RedisConfig.java

@@ -0,0 +1,42 @@
+package com.tuoren.forward.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.data.redis.connection.RedisConnectionFactory;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer;
+import org.springframework.data.redis.serializer.StringRedisSerializer;
+
+import com.fasterxml.jackson.annotation.JsonAutoDetect;
+import com.fasterxml.jackson.annotation.PropertyAccessor;
+import com.fasterxml.jackson.databind.ObjectMapper;
+/**
+ * @Description:    配置Redis   
+ * @author: Administrator     
+ * @date:   2020年4月28日 下午4:49:01
+ */
+@Configuration
+public class RedisConfig {
+
+	@Bean
+	@SuppressWarnings("all")
+	public RedisTemplate<String,Object> redisTemplate(RedisConnectionFactory factory){
+		RedisTemplate<String, Object> template = new RedisTemplate<String, Object>();
+		template.setConnectionFactory(factory);
+		Jackson2JsonRedisSerializer jackson2JsonRedisSerializer = new Jackson2JsonRedisSerializer(Object.class);
+		ObjectMapper om = new ObjectMapper(); 
+		om.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
+		om.activateDefaultTyping(om.getPolymorphicTypeValidator(), ObjectMapper.DefaultTyping.NON_FINAL);
+		jackson2JsonRedisSerializer.setObjectMapper(om);
+		StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
+		template.setKeySerializer(stringRedisSerializer);
+		template.setHashKeySerializer(stringRedisSerializer);
+		template.setValueSerializer(jackson2JsonRedisSerializer);
+		template.setHashValueSerializer(jackson2JsonRedisSerializer);
+		template.afterPropertiesSet();
+		return template;
+		
+	}
+
+
+}

+ 52 - 0
src/main/java/com/tuoren/forward/config/RestTemplateConfig.java

@@ -0,0 +1,52 @@
+package com.tuoren.forward.config;
+
+import java.nio.charset.StandardCharsets;
+import java.util.Iterator;
+import java.util.List;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.client.BufferingClientHttpRequestFactory;
+import org.springframework.http.client.ClientHttpRequestFactory;
+import org.springframework.http.client.OkHttp3ClientHttpRequestFactory;
+import org.springframework.http.converter.HttpMessageConverter;
+import org.springframework.http.converter.StringHttpMessageConverter;
+import org.springframework.web.client.RestTemplate;
+
+@Configuration
+public class RestTemplateConfig {
+
+	@Bean
+    public ClientHttpRequestFactory simpleClientHttpRequestFactory(){
+        OkHttp3ClientHttpRequestFactory factory = new OkHttp3ClientHttpRequestFactory();
+        /**连接超时*/
+        factory.setConnectTimeout(15000);
+        /**读超时*/
+        factory.setReadTimeout(5000);
+        return factory;
+    }
+	
+	/**
+     * 初始化请求模板
+     * @param
+     * @return
+     */
+    @Bean("restTemplate")
+    public RestTemplate restTemplate(){
+
+        RestTemplate restTemplate = new RestTemplate(new BufferingClientHttpRequestFactory(simpleClientHttpRequestFactory()));
+        /**解决中文乱码问题*/
+        List<HttpMessageConverter<?>> messageConverterList =  restTemplate.getMessageConverters();
+        Iterator<HttpMessageConverter<?>> iterator = messageConverterList.iterator();
+        while ( iterator.hasNext()){
+            HttpMessageConverter<?> converter = iterator.next();
+            // 原有的String是ISO-8859-1编码 ,设置为UTF-8
+            if (converter instanceof StringHttpMessageConverter) {
+                ((StringHttpMessageConverter) converter).setDefaultCharset(StandardCharsets.UTF_8);
+                break;
+            }
+        }
+        return restTemplate;
+    }
+
+}

+ 95 - 0
src/main/java/com/tuoren/forward/config/SaTokenConfigure.java

@@ -0,0 +1,95 @@
+package com.tuoren.forward.config;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import com.alibaba.fastjson2.JSON;
+import com.tuoren.forward.constant.CodeMsg;
+import com.tuoren.forward.mapper.PermissionMapper;
+import com.tuoren.forward.util.Result;
+
+import cn.dev33.satoken.context.SaHolder;
+import cn.dev33.satoken.exception.NotLoginException;
+import cn.dev33.satoken.filter.SaServletFilter;
+import cn.dev33.satoken.router.SaRouter;
+import cn.dev33.satoken.stp.StpUtil;
+
+@Configuration
+public class SaTokenConfigure {
+	
+	@Autowired
+	private PermissionMapper permissionMapper;
+	//路径白名单
+	static String[] excludes = {
+		//"/**",// 取消认证
+		"/user/login",  //登录页面
+		"/doc.html",  //api地址
+		"/webjars/**",  //api资源
+		"/swagger-ui/**",  //swagger
+		"/v3/**",  //swagger
+		"/favicon.ico",//swagger
+		"/open/**",//对外开放接口
+	};
+
+	/**
+	 * 注册 [Sa-Token全局过滤器]
+	 */
+	@Bean
+	public SaServletFilter getSaServletFilter() {
+		return new SaServletFilter()
+
+				// 指定 拦截路由 与 放行路由
+				.addInclude("/**").addExclude(excludes)
+
+				// 认证函数: 每次请求执行
+				.setAuth(obj -> {
+					System.out.println("---------- 进入Sa-Token全局认证 -----------");
+					String uri = SaHolder.getRequest().getRequestPath();
+					System.out.println(uri);
+					// 登录认证 -- 拦截所有路由,并排除/user/doLogin 用于开放登录
+					//非配置路径直接放行
+					StpUtil.checkLogin();
+					List<String> urls = permissionMapper.selectAllUrl();
+					if(uri.startsWith("/")) {
+						uri=uri.substring(1);
+					}
+					if(urls.contains(uri)) {
+						StpUtil.checkPermission(uri);
+					}
+					SaRouter.stop();
+					// 更多拦截处理方式,请参考“路由拦截式鉴权”章节
+				})
+
+				// 异常处理函数:每次认证函数发生异常时执行此函数
+				
+				  .setError(e -> {
+				  System.out.println("---------- 进入Sa-Token异常处理 -----------"+e.getClass());
+				 //e.printStackTrace();
+				  if(e instanceof NotLoginException) { 
+				  //SaResult.get(CodeMsg.LOGIN_PLEASE.getRetCode(),CodeMsg.LOGIN_PLEASE.getMessage(), null); 
+					  return JSON.toJSON(Result.result(CodeMsg.NOLOGIN)); 
+				  } 
+				 // return SaResult.get(CodeMsg.NO_RIGHT.getRetCode(),CodeMsg.NO_RIGHT.getMessage(),null );
+				  return JSON.toJSON(Result.result(CodeMsg.NORIGHT)); })
+
+				// 前置函数:在每次认证函数之前执行
+				.setBeforeAuth(r -> {
+					// ---------- 设置一些安全响应头 ----------
+					SaHolder.getResponse()
+							// 服务器名称
+							.setServer("sa-server")
+							// 是否可以在iframe显示视图: DENY=不可以 | SAMEORIGIN=同域下可以 | ALLOW-FROM uri=指定域名下可以
+							.setHeader("X-Frame-Options", "SAMEORIGIN")
+							// 是否启用浏览器默认XSS防护: 0=禁用 | 1=启用 | 1; mode=block 启用, 并在检查到XSS攻击时,停止渲染页面
+							.setHeader("X-XSS-Protection", "1; mode=block")
+							// 禁用浏览器内容嗅探
+							.setHeader("Content-Type", "application/json; charset=utf-8")
+							// 禁用浏览器内容嗅探
+							.setHeader("X-Content-Type-Options", "nosniff");
+				});
+	}
+
+}

+ 55 - 0
src/main/java/com/tuoren/forward/config/SpringDocConfig.java

@@ -0,0 +1,55 @@
+package com.tuoren.forward.config;
+
+import java.util.HashMap;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import io.swagger.v3.oas.models.ExternalDocumentation;
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Contact;
+import io.swagger.v3.oas.models.info.Info;
+import io.swagger.v3.oas.models.info.License;
+/**
+ * @date 2023-10-25
+ * @author wulianwei
+ */
+@Configuration
+public class SpringDocConfig {
+
+	@Bean
+    public OpenAPI myOpenAPI() {
+		
+
+        // 联系人信息(contact),构建API的联系人信息,用于描述API开发者的联系信息,包括名称、URL、邮箱等
+        // name:文档的发布者名称 url:文档发布者的网站地址,一般为企业网站 email:文档发布者的电子邮箱
+        Contact contact = new Contact()
+                .name("wulianwei")                             // 作者名称
+                .email("wulianwei.com")                   // 作者邮箱
+                .url("https://www.cnblogs.com/antLaddie/")  // 介绍作者的URL地址
+                .extensions(new HashMap<String, Object>()); // 使用Map配置信息(如key为"name","email","url")
+
+        // 授权许可信息(license),用于描述API的授权许可信息,包括名称、URL等;假设当前的授权信息为Apache 2.0的开源标准
+        License license = new License()
+                .name("Apache 2.0")                         // 授权名称
+                .url("https://www.apache.org/licenses/LICENSE-2.0.html")    // 授权信息
+                .identifier("Apache-2.0")                   // 标识授权许可
+                .extensions(new HashMap<String, Object>());// 使用Map配置信息(如key为"name","url","identifier")
+
+        //创建Api帮助文档的描述信息、联系人信息(contact)、授权许可信息(license)
+        Info info = new Info()
+                .title("Swagger3.0 (Open API)")      // Api接口文档标题(必填)
+                .description("服务接口文档")     // Api接口文档描述
+                .version("1.0.0")                                  // Api接口版本
+                .termsOfService("https://example.com/")            // Api接口的服务条款地址
+                .license(license)                                    // 授权许可信息
+                .contact(contact);                                 // 设置联系人信息
+        // 返回信息
+        return new OpenAPI()
+                .openapi("3.0.1")  // Open API 3.0.1(默认)
+                .info(info)       // 配置Swagger3.0描述信息
+		        .externalDocs(new ExternalDocumentation()
+		                .description("API首页")
+		                .url("http:// 192.168.0.103:8484/swagger-ui/index.html"));
+    }
+}

+ 42 - 0
src/main/java/com/tuoren/forward/config/StpInterfaceImpl.java

@@ -0,0 +1,42 @@
+package com.tuoren.forward.config;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import com.tuoren.forward.mapper.PermissionMapper;
+import com.tuoren.forward.mapper.RoleMapper;
+
+import cn.dev33.satoken.stp.StpInterface;
+
+@Component   
+public class StpInterfaceImpl implements StpInterface {
+
+	
+	@Autowired
+	private PermissionMapper permissionMapper;
+	
+	@Autowired
+	private RoleMapper roleMapper;
+	
+    /**
+     * 返回一个账号所拥有的权限码集合 
+     */
+    @Override
+    public List<String> getPermissionList(Object loginId, String loginType) {
+        // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询权限
+    	List<String> list = permissionMapper.selectUrlByUserId((String)loginId);
+        return list;
+    }
+
+    /**
+     * 返回一个账号所拥有的角色标识集合 (权限与角色可分开校验)
+     */
+    @Override
+    public List<String> getRoleList(Object loginId, String loginType) {
+        // 本list仅做模拟,实际项目中要根据具体业务逻辑来查询角色
+    	List<String> list = roleMapper.selectIdByUserId((String)loginId);
+        return list;
+    }
+}

+ 307 - 0
src/main/java/com/tuoren/forward/config/amqp/AmqpClient1.java

@@ -0,0 +1,307 @@
+package com.tuoren.forward.config.amqp;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionListener;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.tuoren.forward.config.mqtt.MqttUtil;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Device;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.mapper.DeviceMapper;
+import com.tuoren.forward.mapper.UserMapper;
+import com.tuoren.forward.util.RemoteUtil;
+import com.tuoren.forward.util.UUIDUtil;
+
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@ConfigurationProperties(prefix = "aliyun1")
+@Setter
+public class AmqpClient1 {
+
+	private String accessKey;
+    private String accessSecret;
+    private String consumerGroupId;
+
+    //iotInstanceId:实例ID。若是2021年07月30日之前(不含当日)开通的公共实例,请填空字符串。
+    private String iotInstanceId;
+
+    //控制台服务端订阅中消费组状态页客户端ID一栏将显示clientId参数。
+    private String clientId;
+
+    //${YourHost}为接入域名,请参见AMQP客户端接入说明文档。
+    private String amqpHost;
+    
+//    @Autowired
+//    @Qualifier("nbJdbcTemplate")
+//    private JdbcTemplate nbJdbcTemplate;
+    
+    @Autowired(required = false)
+	private MqttUtil mqttUtil;
+    
+    @Autowired
+    RemoteUtil remoteUtil;
+    
+    @Autowired
+    DeviceMapper deviceMapper;
+    
+    @Autowired
+    UserMapper userMapper;
+    
+    @Autowired
+    MongoTemplate mongoTemplate;
+    
+  //业务处理异步线程池,线程池参数可以根据您的业务特点调整,或者您也可以用其他异步方式处理接收到的消息。
+    private final static ExecutorService executorService = new ThreadPoolExecutor(
+        Runtime.getRuntime().availableProcessors(),
+        Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
+        new LinkedBlockingQueue<Runnable>(50000));
+    
+    public void connection() throws Exception{
+    	
+
+    	long timeStamp = System.currentTimeMillis();
+    	String signMethod = "hmacsha1";
+    	String userName = clientId + "-" + 0 + "|authMode=aksign"
+                + ",signMethod=" + signMethod
+                + ",timestamp=" + timeStamp
+                + ",authId=" + accessKey
+                + ",iotInstanceId=" + iotInstanceId
+                + ",consumerGroupId=" + consumerGroupId
+                + "|";
+    	 String signContent = "authId=" + accessKey + "&timestamp=" + timeStamp;
+         String password = doSign(signContent, accessSecret, signMethod);
+         String connectionUrl = "failover:(amqps://" + amqpHost + ":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);
+         
+         ((JmsConnection)connection).addConnectionListener(jmsConnectionListener);
+         // 创建会话。
+         // 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);
+    }
+    
+    private MessageListener messageListener = new MessageListener() {
+        @Override
+        public void onMessage(final Message message) {
+            try {
+                //1.收到消息之后一定要ACK。
+                // 推荐做法:创建Session选择Session.AUTO_ACKNOWLEDGE,这里会自动ACK。
+                // 其他做法:创建Session选择Session.CLIENT_ACKNOWLEDGE,这里一定要调message.acknowledge()来ACK。
+                // message.acknowledge();
+                //2.建议异步处理收到的消息,确保onMessage函数里没有耗时逻辑。
+                // 如果业务处理耗时过程过长阻塞住线程,可能会影响SDK收到消息后的正常回调。
+                executorService.submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        processMessage(message);
+                    }
+                });
+            } catch (Exception e) {
+                log.error("submit task occurs exception ", e);
+            }
+        }
+    };
+    
+    /**
+     * 在这里处理您收到消息后的具体业务逻辑。
+     */
+    private void processMessage(Message message) {
+        try {
+            String topic = message.getStringProperty("topic");
+            if(!topic.endsWith("/thing/event/property/post")) {
+            	return ;
+            }
+            byte[] body = message.getBody(byte[].class);
+            String content = new String(body);
+            log.info("下发数据内容1:"+content);
+            JSONObject json = JSONObject.parseObject(content);
+            repackJson(json);
+            String deviceName = json.getString("deviceName");
+            String productKey = json.getString("productKey");
+            String hospitalCode = "";
+            JSONObject items = json.getJSONObject("items");
+            long ci = 0;
+            long lac = 0;
+            if(items.containsKey("userId")) {
+            	hospitalCode = items.getString("userId");
+            }
+            if(items.containsKey("ci")) {
+            	ci = items.getLong("ci");
+            }
+            if(items.containsKey("lac")) {
+            	lac = items.getLong("lac");
+            }
+            if(ci > 0 && lac>0) {
+            	String location = remoteUtil.localtion(String.valueOf(ci), String.valueOf(lac));
+            	items.put("location", JSONObject.parseObject(location));
+            }
+            if(StringUtils.isEmpty(hospitalCode)) {
+//            	String sql = "SELECT h.code FROM bus_hospital h  inner join bus_device d on d.tenant_id = h.tenant_id where device_id=? limit 1";
+//             	try {
+//             		hospitalCode = nbJdbcTemplate.queryForObject(sql, String.class, deviceName);
+//             	}catch (Exception e) {
+//     				// TODO: handle exception
+//     			}
+            	hospitalCode = remoteUtil.getHospitalCode(deviceName);
+            }
+           
+			  if(StringUtils.isEmpty(hospitalCode)) {
+				  log.info("设备没有对应医院:"+deviceName);
+			  }else {
+        		User owner = userMapper.selectByCode(hospitalCode);
+        		if(owner == null) {
+        			log.info("不存在该医院:"+hospitalCode);
+        			return;
+        		}
+        		JSONObject mongoJson = new JSONObject();
+        		Device exist = deviceMapper.selectByMac(deviceName);
+        		if(exist == null) {
+        			Device record = new Device();
+        			String deviceId = UUIDUtil.get32UUID();
+        			record.setId(deviceId);
+        			record.setCreatetime(new Date());
+        			record.setMac(deviceName);
+        			record.setProductId(productKey);
+        			record.setTenantId(owner.getId());
+        			record.setData(items.toString());
+        			deviceMapper.insertSelective(record);
+        			mongoJson.put("deviceId", deviceId);
+        		}else {
+        			Device record = new Device();
+        			record.setId(exist.getId());
+        			record.setTenantId(owner.getId());
+        			record.setData( items.toString());
+        			deviceMapper.updateByPrimaryKeySelective2(record);
+        			mongoJson.put("deviceId", exist.getId());
+        		}
+        		mongoJson.put("deviceMac", deviceName);
+        		mongoJson.put("time", json.getLong("gmtCreate"));
+        		mongoJson.put("tenantId", owner.getId());
+        		mongoJson.put("items", items);
+        		mongoTemplate.insert(mongoJson, CommonConstant.MONGO_COLLECTION_DEVICE_RECORD);
+        		
+        		if(mqttUtil != null) {
+        			log.info("mqtt publish1:"+  json.toString());
+        			mqttUtil.pub(CommonConstant.MQTT_PUBLISH_PREFIX+hospitalCode, json.toString());
+        		}
+        	}
+        } catch (Exception e) {
+        	log.error("processMessage occurs error ", e);
+        }
+    }
+
+    private static JmsConnectionListener jmsConnectionListener = new JmsConnectionListener() {
+        /**
+         * 连接成功建立。
+         */
+        @Override
+        public void onConnectionEstablished(URI remoteURI) {
+            log.info("onConnectionEstablished, remoteUri:{}", remoteURI);
+        }
+
+        /**
+         * 尝试过最大重试次数之后,最终连接失败。
+         */
+        @Override
+        public void onConnectionFailure(Throwable error) {
+            log.error("onConnectionFailure, {}", error.getMessage());
+        }
+
+        /**
+         * 连接中断。
+         */
+        @Override
+        public void onConnectionInterrupted(URI remoteURI) {
+            log.info("onConnectionInterrupted, remoteUri:{}", remoteURI);
+        }
+
+        /**
+         * 连接中断后又自动重连上。
+         */
+        @Override
+        public void onConnectionRestored(URI remoteURI) {
+            log.info("onConnectionRestored, 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);
+    }
+    
+    public static void repackJson(JSONObject json) {
+    	JSONObject items = json.getJSONObject("items");
+    	for(String key:items.keySet()) {
+    		JSONObject temp = items.getJSONObject(key);
+    		items.replace(key, temp.get("value"));
+    	}
+    	json.replace("items", items);
+    }
+}

+ 307 - 0
src/main/java/com/tuoren/forward/config/amqp/AmqpClient2.java

@@ -0,0 +1,307 @@
+package com.tuoren.forward.config.amqp;
+
+import java.net.URI;
+import java.util.Date;
+import java.util.Hashtable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
+
+import javax.crypto.Mac;
+import javax.crypto.spec.SecretKeySpec;
+import javax.jms.Connection;
+import javax.jms.ConnectionFactory;
+import javax.jms.Destination;
+import javax.jms.Message;
+import javax.jms.MessageConsumer;
+import javax.jms.MessageListener;
+import javax.jms.MessageProducer;
+import javax.jms.Session;
+import javax.naming.Context;
+import javax.naming.InitialContext;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang3.StringUtils;
+import org.apache.qpid.jms.JmsConnection;
+import org.apache.qpid.jms.JmsConnectionListener;
+import org.apache.qpid.jms.message.JmsInboundMessageDispatch;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.stereotype.Component;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.tuoren.forward.config.mqtt.MqttUtil;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Device;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.mapper.DeviceMapper;
+import com.tuoren.forward.mapper.UserMapper;
+import com.tuoren.forward.util.RemoteUtil;
+import com.tuoren.forward.util.UUIDUtil;
+
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@ConfigurationProperties(prefix = "aliyun2")
+@Setter
+public class AmqpClient2 {
+
+	private String accessKey;
+    private String accessSecret;
+    private String consumerGroupId;
+
+    //iotInstanceId:实例ID。若是2021年07月30日之前(不含当日)开通的公共实例,请填空字符串。
+    private String iotInstanceId;
+
+    //控制台服务端订阅中消费组状态页客户端ID一栏将显示clientId参数。
+    private String clientId;
+
+    //${YourHost}为接入域名,请参见AMQP客户端接入说明文档。
+    private String amqpHost;
+    
+//    @Autowired
+//    @Qualifier("nbJdbcTemplate")
+//    private JdbcTemplate nbJdbcTemplate;
+    
+    @Autowired(required = false)
+	private MqttUtil mqttUtil;
+    
+    @Autowired
+    RemoteUtil remoteUtil;
+    
+    @Autowired
+    DeviceMapper deviceMapper;
+    
+    @Autowired
+    UserMapper userMapper;
+    
+    @Autowired
+    MongoTemplate mongoTemplate;
+    
+  //业务处理异步线程池,线程池参数可以根据您的业务特点调整,或者您也可以用其他异步方式处理接收到的消息。
+    private final static ExecutorService executorService = new ThreadPoolExecutor(
+        Runtime.getRuntime().availableProcessors(),
+        Runtime.getRuntime().availableProcessors() * 2, 60, TimeUnit.SECONDS,
+        new LinkedBlockingQueue<Runnable>(50000));
+    
+    public void connection() throws Exception{
+    	
+
+    	long timeStamp = System.currentTimeMillis();
+    	String signMethod = "hmacsha1";
+    	String userName = clientId + "-" + 0 + "|authMode=aksign"
+                + ",signMethod=" + signMethod
+                + ",timestamp=" + timeStamp
+                + ",authId=" + accessKey
+                + ",iotInstanceId=" + iotInstanceId
+                + ",consumerGroupId=" + consumerGroupId
+                + "|";
+    	 String signContent = "authId=" + accessKey + "&timestamp=" + timeStamp;
+         String password = doSign(signContent, accessSecret, signMethod);
+         String connectionUrl = "failover:(amqps://" + amqpHost + ":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);
+         
+         ((JmsConnection)connection).addConnectionListener(jmsConnectionListener);
+         // 创建会话。
+         // 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);
+    }
+    
+    private MessageListener messageListener = new MessageListener() {
+        @Override
+        public void onMessage(final Message message) {
+            try {
+                //1.收到消息之后一定要ACK。
+                // 推荐做法:创建Session选择Session.AUTO_ACKNOWLEDGE,这里会自动ACK。
+                // 其他做法:创建Session选择Session.CLIENT_ACKNOWLEDGE,这里一定要调message.acknowledge()来ACK。
+                // message.acknowledge();
+                //2.建议异步处理收到的消息,确保onMessage函数里没有耗时逻辑。
+                // 如果业务处理耗时过程过长阻塞住线程,可能会影响SDK收到消息后的正常回调。
+                executorService.submit(new Runnable() {
+                    @Override
+                    public void run() {
+                        processMessage(message);
+                    }
+                });
+            } catch (Exception e) {
+                log.error("submit task occurs exception ", e);
+            }
+        }
+    };
+    
+    /**
+     * 在这里处理您收到消息后的具体业务逻辑。
+     */
+    private void processMessage(Message message) {
+        try {
+            String topic = message.getStringProperty("topic");
+            if(!topic.endsWith("/thing/event/property/post")) {
+            	return ;
+            }
+            byte[] body = message.getBody(byte[].class);
+            String content = new String(body);
+            log.info("下发数据内容2:"+content);
+            JSONObject json = JSONObject.parseObject(content);
+            repackJson(json);
+            String deviceName = json.getString("deviceName");
+            String productKey = json.getString("productKey");
+            String hospitalCode = "";
+            JSONObject items = json.getJSONObject("items");
+            long ci = 0;
+            long lac = 0;
+            if(items.containsKey("userId")) {
+            	hospitalCode = items.getString("userId");
+            }
+            if(items.containsKey("ci")) {
+            	ci = items.getLong("ci");
+            }
+            if(items.containsKey("lac")) {
+            	lac = items.getLong("lac");
+            }
+            if(ci > 0 && lac>0) {
+            	String location = remoteUtil.localtion(String.valueOf(ci), String.valueOf(lac));
+            	items.put("location", JSONObject.parseObject(location));
+            }
+            if(StringUtils.isEmpty(hospitalCode)) {
+//            	String sql = "SELECT h.code FROM bus_hospital h  inner join bus_device d on d.tenant_id = h.tenant_id where device_id=? limit 1";
+//             	try {
+//             		hospitalCode = nbJdbcTemplate.queryForObject(sql, String.class, deviceName);
+//             	}catch (Exception e) {
+//     				// TODO: handle exception
+//     			}
+            	hospitalCode = remoteUtil.getHospitalCode(deviceName);
+            }
+           
+			  if(StringUtils.isEmpty(hospitalCode)) {
+				  log.info("设备没有对应医院:"+deviceName);
+			  }else {
+        		User owner = userMapper.selectByCode(hospitalCode);
+        		if(owner == null) {
+        			log.info("不存在该医院:"+hospitalCode);
+        			return;
+        		}
+        		JSONObject mongoJson = new JSONObject();
+        		Device exist = deviceMapper.selectByMac(deviceName);
+        		if(exist == null) {
+        			Device record = new Device();
+        			String deviceId = UUIDUtil.get32UUID();
+        			record.setId(deviceId);
+        			record.setCreatetime(new Date());
+        			record.setMac(deviceName);
+        			record.setProductId(productKey);
+        			record.setTenantId(owner.getId());
+        			record.setData(items.toString());
+        			deviceMapper.insertSelective(record);
+        			mongoJson.put("deviceId", deviceId);
+        		}else {
+        			Device record = new Device();
+        			record.setId(exist.getId());
+        			record.setTenantId(owner.getId());
+        			record.setData( items.toString());
+        			deviceMapper.updateByPrimaryKeySelective2(record);
+        			mongoJson.put("deviceId", exist.getId());
+        		}
+        		mongoJson.put("deviceMac", deviceName);
+        		mongoJson.put("time", json.getLong("gmtCreate"));
+        		mongoJson.put("tenantId", owner.getId());
+        		mongoJson.put("items", items);
+        		mongoTemplate.insert(mongoJson, CommonConstant.MONGO_COLLECTION_DEVICE_RECORD);
+        		
+        		if(mqttUtil != null) {
+        			log.info("mqtt publish2:"+  json.toString());
+        			mqttUtil.pub(CommonConstant.MQTT_PUBLISH_PREFIX+hospitalCode, json.toString());
+        		}
+        	}
+        } catch (Exception e) {
+        	log.error("processMessage occurs error ", e);
+        }
+    }
+
+    private static JmsConnectionListener jmsConnectionListener = new JmsConnectionListener() {
+        /**
+         * 连接成功建立。
+         */
+        @Override
+        public void onConnectionEstablished(URI remoteURI) {
+            log.info("onConnectionEstablished, remoteUri:{}", remoteURI);
+        }
+
+        /**
+         * 尝试过最大重试次数之后,最终连接失败。
+         */
+        @Override
+        public void onConnectionFailure(Throwable error) {
+            log.error("onConnectionFailure, {}", error.getMessage());
+        }
+
+        /**
+         * 连接中断。
+         */
+        @Override
+        public void onConnectionInterrupted(URI remoteURI) {
+            log.info("onConnectionInterrupted, remoteUri:{}", remoteURI);
+        }
+
+        /**
+         * 连接中断后又自动重连上。
+         */
+        @Override
+        public void onConnectionRestored(URI remoteURI) {
+            log.info("onConnectionRestored, 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);
+    }
+    
+    public static void repackJson(JSONObject json) {
+    	JSONObject items = json.getJSONObject("items");
+    	for(String key:items.keySet()) {
+    		JSONObject temp = items.getJSONObject(key);
+    		items.replace(key, temp.get("value"));
+    	}
+    	json.replace("items", items);
+    }
+}

+ 39 - 0
src/main/java/com/tuoren/forward/config/mqtt/MqttCallbackCustom.java

@@ -0,0 +1,39 @@
+package com.tuoren.forward.config.mqtt;
+
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@ConditionalOnBean(MqttConfig.class)
+public class MqttCallbackCustom implements MqttCallback{
+
+	
+	 /**
+     * MQTT 断开连接会执行此方法
+     */
+    @Override
+    public void connectionLost(Throwable throwable) {
+    	log.info("MQTT断开连接 :{}", throwable.getMessage());
+    }
+ 
+    /**
+     * publish发布成功后会执行到这里
+     */
+    @Override
+    public void deliveryComplete(IMqttDeliveryToken iMqttDeliveryToken) {
+    }
+
+
+	@Override
+	public void messageArrived(String topic, MqttMessage message) throws Exception {
+		// TODO Auto-generated method stub
+		
+	}
+
+}

+ 59 - 0
src/main/java/com/tuoren/forward/config/mqtt/MqttConfig.java

@@ -0,0 +1,59 @@
+package com.tuoren.forward.config.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+@Configuration
+public class MqttConfig{
+	    
+	@Value("${mqtt.hostUrl}")
+    private String hostUrl;
+	
+	@Value("${mqtt.clientId}")
+    private String clientId;
+	
+	@Value("${mqtt.username}")
+    private String username;
+	
+	@Value("${mqtt.password}")
+    private String password;
+	
+	@Value("${mqtt.timeout}")
+    private Integer timeout;
+	
+	@Value("${mqtt.keepalive}")
+    private Integer keepalive;
+	
+        
+ 
+    /**
+     * 客户端mqttClient
+     **/
+    @Bean
+    public MqttClient mqttClient(@Qualifier("connectOptions") MqttConnectOptions connectOptions) throws MqttException {
+    	 MqttClient mqttClient = new MqttClient(hostUrl, clientId, new MemoryPersistence());
+         mqttClient.connect(connectOptions);
+         return mqttClient;
+    }
+    
+    @Bean
+    public MqttConnectOptions connectOptions() {
+    	MqttConnectOptions options = new MqttConnectOptions();
+        options.setUserName(username);
+        options.setPassword(password.toCharArray());
+        options.setConnectionTimeout(timeout);///默认:30
+        options.setAutomaticReconnect(true);//默认:false
+        options.setCleanSession(false);//默认:true
+        options.setKeepAliveInterval(keepalive);//默认:60
+        return options;
+    }
+
+}
+
+

+ 92 - 0
src/main/java/com/tuoren/forward/config/mqtt/MqttUtil.java

@@ -0,0 +1,92 @@
+package com.tuoren.forward.config.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.eclipse.paho.client.mqttv3.MqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttException;
+import org.eclipse.paho.client.mqttv3.MqttMessage;
+import org.eclipse.paho.client.mqttv3.MqttTopic;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.stereotype.Component;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@ConditionalOnBean(MqttConfig.class)
+public class MqttUtil {
+	
+	
+	@Autowired
+	private MqttClient mqttClient;
+	
+	/**
+     * 向某个主题发布消息 默认qos:1
+     *
+     * @param topic:发布的主题
+     * @param msg:发布的消息
+     */
+    public void pub(String topic, String msg) {
+        MqttMessage mqttMessage = new MqttMessage();
+        mqttMessage.setPayload(msg.getBytes());
+        try {
+        	MqttTopic mqttTopic = mqttClient.getTopic(topic);
+            MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
+            token.waitForCompletion();
+        }catch (MqttException e) {
+			// TODO: handle exception
+        	log.error("发布mqtt消息异常 topic:"+topic+";payload:"+msg, e);
+		}
+    }
+    
+    /**
+     * 向某个主题发布消息
+     *
+     * @param topic: 发布的主题
+     * @param msg:   发布的消息
+     * @param qos:   消息质量    Qos:0、1、2
+     */
+    public void pub(String topic, String msg, int qos) {
+        MqttMessage mqttMessage = new MqttMessage();
+        mqttMessage.setQos(qos);
+        mqttMessage.setPayload(msg.getBytes());
+        try {
+        	MqttTopic mqttTopic = mqttClient.getTopic(topic);
+            MqttDeliveryToken token = mqttTopic.publish(mqttMessage);
+            token.waitForCompletion();
+        }catch (MqttException e) {
+			// TODO: handle exception
+        	log.error("发布mqtt消息异常 topic:"+topic+";payload:"+msg, e);
+		}
+    }
+    
+    /**
+     * 订阅某一个主题 ,此方法默认的的Qos等级为:1
+     *
+     * @param topic 主题
+     */
+    public void sub(String topic) {
+        try {
+			mqttClient.subscribe(topic);
+		} catch (MqttException e) {
+			// TODO Auto-generated catch block
+			log.error("订阅主题消息异常 topic:"+topic, e);
+		}
+    }
+ 
+    /**
+     * 订阅某一个主题,可携带Qos
+     *
+     * @param topic 所要订阅的主题
+     * @param qos   消息质量:0、1、2
+     */
+    public void sub(String topic, int qos) {
+        try {
+			mqttClient.subscribe(topic, qos);
+		} catch (MqttException e) {
+			// TODO Auto-generated catch block
+			log.error("订阅主题消息异常 topic:"+topic, e);
+		}
+    }
+
+}

+ 27 - 0
src/main/java/com/tuoren/forward/constant/CodeMsg.java

@@ -0,0 +1,27 @@
+package com.tuoren.forward.constant;
+
+public enum CodeMsg {
+	
+	SUCCESS(0,"操作成功"),
+	FAILURE(1,"操作失败"),
+	EXCEPTION(2,"系统繁忙"),
+	NOLOGIN(3,"请登录"),
+	RELOGIN(4,"登录超时,重新登录"),
+	NORIGHT(5,"权限不足");
+	
+	private Integer code;
+	private String msg;
+	
+	CodeMsg(Integer code,String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+	
+	public Integer getCode() {
+		return code;
+	}
+	
+	public String getMsg() {
+		return msg;
+	}
+}

+ 36 - 0
src/main/java/com/tuoren/forward/constant/CommonConstant.java

@@ -0,0 +1,36 @@
+package com.tuoren.forward.constant;
+
+public final class CommonConstant {
+	public static final Integer ZERO = 0;
+	public static final long LOGIN_EXPIRE = 30*60L; // 登陆有效时间
+	
+	public static final long VERIFYCODE_EXPIRE = 60L; // 验证码有效时间
+	
+	public static final String ROLE_MANAGER = "manager"; // 管理员角色
+	public static final String ROLE_USER = "user"; // 普通用户角色
+	
+	public static final String PERMISSION_TYPE_MAINMENU = "01"; //主菜单
+	public static final String PERMISSION_TYPE_SUBMENU = "02"; //子菜单
+	public static final String PERMISSION_TYPE_BUTTON = "03"; //按钮
+	
+	public static final Integer MQTT_QOS0 = 0;
+	public static final Integer MQTT_QOS1 = 1;
+	public static final Integer MQTT_QOS2 = 2;
+	public static final String MQTT_PUBLISH_PREFIX = "hospital/";
+
+	
+	public static final String TOKEN_NAME = "token";
+	
+	public static final String LACK_PARAM = "缺少必要参数";
+	
+	public static final String INI_PWD = "123456";
+	
+	public static final String MONGO_COLLECTION_DEVICE_RECORD = "device_record";
+	
+	public static final String CAPTCHA_REDIS_HASH = "captcha";
+	
+	public static final String REQUEST_LOG_ATTR= "logAttr";
+	
+	public static final String REQUEST_TIME_ATTR = "timeAttr";
+
+}

+ 18 - 0
src/main/java/com/tuoren/forward/constant/HandleLogChoice.java

@@ -0,0 +1,18 @@
+package com.tuoren.forward.constant;
+
+public enum HandleLogChoice {
+	
+	RECORD_ANY, //总是记录
+	
+	RECORD_SUC, //只有成功才记录
+	
+	RECORD_FAIL, //只有失败才记录
+	
+	RECORD_EXCEPTION,//只有异常才记录
+	
+	//日志类型
+	TYPE_COMMON, //普通操作
+	
+	TYPE_LOGIN,  //登录操作
+	
+}

+ 96 - 0
src/main/java/com/tuoren/forward/controller/DeviceController.java

@@ -0,0 +1,96 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.github.pagehelper.util.StringUtil;
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.req.DeviceAddReq;
+import com.tuoren.forward.entity.req.DeviceRecordSearchReq;
+import com.tuoren.forward.entity.req.DeviceSearchReq;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.resp.DeviceResp;
+import com.tuoren.forward.service.DeviceService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("device")
+@Tag(name="设备接口")
+public class DeviceController {
+	
+	@Autowired
+	DeviceService deviceService;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询设备")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<DeviceResp> search(@RequestBody DeviceSearchReq req){
+		log.info("search>>:{}",req);
+		return deviceService.search(req);
+	}
+	
+
+	@HandleLog
+	@PostMapping("add")
+    @ResponseBody
+    @Operation(summary = "添加设备")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result add(@RequestBody DeviceAddReq req){
+		log.info("add>>:{}",req);
+		if(StringUtil.isEmpty(req.getProductId()) || StringUtil.isEmpty(req.getMac())) {
+			return Result.fail(CommonConstant.LACK_PARAM);
+		}
+		return deviceService.add(req);
+	}
+	
+	@HandleLog
+	@PostMapping("edit")
+    @ResponseBody
+    @Operation(summary = "修改设备")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody DeviceAddReq req){
+		log.info("edit>>:{}",req);
+		if(StringUtil.isEmpty(req.getId())) {
+			return Result.fail(CommonConstant.LACK_PARAM);
+		}
+		return deviceService.edit(req);
+	}
+	
+	@HandleLog
+	@PostMapping("delete")
+    @ResponseBody
+    @Operation(summary = "删除设备")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IdReq req){
+		log.info("delete>>:{}",req);
+		if(StringUtil.isEmpty(req.getId())) {
+			return Result.fail(CommonConstant.LACK_PARAM);
+		}
+		return deviceService.delete(req.getId());
+	}
+	
+	@PostMapping("searchRecord")
+    @ResponseBody
+    @Operation(summary = "查询设备记录")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<JSONObject> searchRecord(@RequestBody DeviceRecordSearchReq req){
+		log.info("searchRecord>>:{}",req);
+		return deviceService.searchRecord(req);
+	}
+	
+}

+ 80 - 0
src/main/java/com/tuoren/forward/controller/HospitalController.java

@@ -0,0 +1,80 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.entity.Hospital;
+import com.tuoren.forward.entity.req.HospitalSearchReq;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.service.HospitalService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("hospital")
+@Tag(name="医院接口")
+public class HospitalController {
+	
+	@Autowired
+	HospitalService hospitalService;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询医院")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<Hospital> search(@RequestBody HospitalSearchReq req){
+		log.info("search>>:{}",req);
+		return hospitalService.search(req);
+	}
+	
+	@HandleLog
+	@PostMapping("add")
+    @ResponseBody
+    @Operation(summary = "添加医院")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result add(@RequestBody Hospital req){
+		log.info("add>>:{}",req);
+		return hospitalService.add(req);
+	}
+	
+	@HandleLog
+	@PostMapping("edit")
+    @ResponseBody
+    @Operation(summary = "修改医院")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody Hospital req){
+		log.info("editHospital>>:{}",req);
+		return hospitalService.edit(req);
+	}
+	
+	@HandleLog
+	@PostMapping("delete")
+    @ResponseBody
+    @Operation(summary = "删除医院")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IdReq req){
+		log.info("deleteHospital>>:{}",req);
+		return hospitalService.delete(req.getId());
+	}
+	
+	@PostMapping("localtion")
+    @ResponseBody
+    @Operation(summary = "定位")
+	public String location(){
+		log.info("deleteHospital>>");
+		return hospitalService.localtion();
+	}
+	
+}

+ 38 - 0
src/main/java/com/tuoren/forward/controller/LogController.java

@@ -0,0 +1,38 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.entity.Log;
+import com.tuoren.forward.entity.req.LogSearchReq;
+import com.tuoren.forward.service.LogService;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("log")
+@Tag(name="操作日志")
+public class LogController {
+
+	@Autowired
+	LogService logService;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询操作日志")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<Log> search(@RequestBody LogSearchReq req){
+		log.info("search>>:{}",req);
+		return logService.search(req);
+	}
+}

+ 67 - 0
src/main/java/com/tuoren/forward/controller/ModelController.java

@@ -0,0 +1,67 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.entity.Model;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.req.ModelSearchReq;
+import com.tuoren.forward.service.ModelService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("model")
+@Tag(name="设备接口")
+public class ModelController {
+
+	@Autowired
+	ModelService modelService;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询模型")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<Model> search(@RequestBody ModelSearchReq req){
+		log.info("search>>:{}",req);
+		return modelService.search(req);
+	}
+	
+	@PostMapping("add")
+    @ResponseBody
+    @Operation(summary = "添加模型")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result add(@RequestBody Model req){
+		log.info("add>>:{}",req);
+		return modelService.add(req);
+	}
+	
+	@PostMapping("edit")
+    @ResponseBody
+    @Operation(summary = "修改模型")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody Model req){
+		log.info("edit>>:{}",req);
+		return modelService.edit(req);
+	}
+	
+	@PostMapping("delete")
+    @ResponseBody
+    @Operation(summary = "删除模型")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IdReq req){
+		log.info("delete>>:{}",req);
+		return modelService.delete(req.getId());
+	}
+}

+ 108 - 0
src/main/java/com/tuoren/forward/controller/OpenController.java

@@ -0,0 +1,108 @@
+package com.tuoren.forward.controller;
+
+import java.util.concurrent.TimeUnit;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.redis.core.RedisTemplate;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Hospital;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.entity.req.HospitalAddOpenReq;
+import com.tuoren.forward.entity.req.UserAddOpenReq;
+import com.tuoren.forward.entity.resp.CaptchaResp;
+import com.tuoren.forward.service.HospitalService;
+import com.tuoren.forward.service.UserService;
+import com.tuoren.forward.util.ResultData;
+import com.tuoren.forward.util.UUIDUtil;
+
+import cn.hutool.captcha.CaptchaUtil;
+import cn.hutool.captcha.ShearCaptcha;
+import cn.hutool.captcha.generator.MathGenerator;
+import cn.hutool.crypto.digest.DigestUtil;
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("open")
+@Tag(name="开放接口")
+public class OpenController {
+	
+	@Autowired
+	RedisTemplate<String, Object> redisTemplate;
+	
+	@Autowired
+	HospitalService hospitalService;
+	
+	@Autowired
+	UserService userService;
+	
+	private final String SECRET = "yunzhineng";
+	
+//	@PostMapping("addHospital")
+//    @ResponseBody
+//    @Operation(summary = "添加医院")
+	public ResultData<Hospital> addHospital(@RequestBody HospitalAddOpenReq req){
+		log.info("addHospital>>:{}",req);
+		String content= new StringBuffer().append(req.getId()).append("&").append(req.getName())
+				.append("&").append(SECRET).toString();
+		String md5Hex1 = DigestUtil.md5Hex(content);
+		Hospital record = new Hospital();
+		if(!req.getMd5().equals(md5Hex1)) {
+			return ResultData.failNull();
+		}
+		
+		BeanUtils.copyProperties(req, record);
+		return hospitalService.addBack(record);
+	}
+	
+	@HandleLog
+	@PostMapping("addUser")
+    @ResponseBody
+    @Operation(summary = "添加用户")
+	public ResultData<User> addUser(@RequestBody UserAddOpenReq req){
+		log.info("addUser>>:{}",req);
+		String content= new StringBuffer(req.getUsername()).append("&").append(SECRET).toString();
+		String md5Hex1 = DigestUtil.md5Hex(content);
+		if(!req.getMd5().equals(md5Hex1)) {
+			return ResultData.failNull();
+		}
+		return userService.addBack(req);
+	}
+	
+	@PostMapping("getCaptcha")
+    @ResponseBody
+    @Operation(summary = "获取验证码")
+	public ResultData<CaptchaResp> getCaptcha(){
+		log.info("getCaptcha>>");
+		String captchaKey = UUIDUtil.get32UUID();
+		ShearCaptcha captcha = CaptchaUtil.createShearCaptcha(150, 40, 4, 0);
+		captcha.setGenerator(new MathGenerator(1));
+		captcha.createCode();
+		redisTemplate.opsForHash().put("captcha", captchaKey, captcha.getCode());
+		redisTemplate.expire(CommonConstant.CAPTCHA_REDIS_HASH, 2,TimeUnit.MINUTES); //2分钟过期
+		String base64String = "data:image/png;base64,"+captcha.getImageBase64();
+		CaptchaResp resp = new CaptchaResp();
+		resp.setCaptchaKey(captchaKey);
+		resp.setCaptchaImg(base64String);
+		return ResultData.success(resp);
+	}
+	
+	public static void main(String[] args) {
+		String content="test3&yunzhineng";
+		String md5Hex1 = DigestUtil.md5Hex(content);
+		MathGenerator ge = new MathGenerator();
+		boolean f = ge.verify("9+9","18");
+		System.out.println(md5Hex1+f);
+	}
+
+}

+ 91 - 0
src/main/java/com/tuoren/forward/controller/PermissionController.java

@@ -0,0 +1,91 @@
+package com.tuoren.forward.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.entity.Permission;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.req.IntIdReq;
+import com.tuoren.forward.service.PermissionService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("permission")
+@Tag(name= "资源接口")
+public class PermissionController {
+
+	@Autowired
+	PermissionService permissionService;
+	
+	@PostMapping("list")
+	@ResponseBody
+	@Operation(summary = "列出所有资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Permission>> list(){
+		log.info("list>>");
+		return permissionService.list();
+	}
+	
+	@PostMapping("listByRoleId")
+	@ResponseBody
+	@Operation(summary = "列出角色下的资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Permission>> listByRoleId(@RequestBody IdReq req){
+		log.info("listByRoleId>>:{}",req);
+		return permissionService.listByRoleId(req.getId());
+	}
+	
+	@PostMapping("listUserPermission")
+	@ResponseBody
+	@Operation(summary = "列出当前用户资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Permission>> listUserPermission(){
+		log.info("listUserPermission>>");
+		return permissionService.listUserPermission();
+	}
+	
+	@HandleLog
+	@PostMapping("add")
+	@ResponseBody
+	@Operation(summary = "添加资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result add(@RequestBody Permission req){
+		log.info("addPermission>>:{}",req);
+		return permissionService.add(req);
+	}
+	
+	@HandleLog
+	@PostMapping("edit")
+	@ResponseBody
+	@Operation(summary = "添加资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody Permission req){
+		log.info("edit>>:{}",req);
+		return permissionService.edit(req);
+	}
+	
+	@HandleLog
+	@PostMapping("delete")
+	@ResponseBody
+	@Operation(summary = "删除资源")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IntIdReq req){
+		log.info("delete>>:{}",req);
+		return permissionService.delete(req.getId());
+	}
+}

+ 84 - 0
src/main/java/com/tuoren/forward/controller/ProductController.java

@@ -0,0 +1,84 @@
+package com.tuoren.forward.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.entity.Product;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.req.ProductAddReq;
+import com.tuoren.forward.entity.req.ProductSearchReq;
+import com.tuoren.forward.service.ProductService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("product")
+@Tag(name="产品接口")
+public class ProductController {
+
+	@Autowired
+	ProductService productService;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询产品")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<Product> search(@RequestBody ProductSearchReq req){
+		log.info("search>>:{}",req);
+		return productService.search(req);
+	}
+	
+	@PostMapping("listAll")
+    @ResponseBody
+    @Operation(summary = "列出产品")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Product>> listAll(){
+		log.info("listAll>>");
+		return productService.listAll();
+	}
+	
+	@HandleLog
+	@PostMapping("add")
+    @ResponseBody
+    @Operation(summary = "添加产品")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result add(@RequestBody ProductAddReq req) {
+		log.info("add>>:{}",req);
+		return productService.add(req);
+	}
+	
+	@HandleLog
+	@PostMapping("edit")
+    @ResponseBody
+    @Operation(summary = "修改产品")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody ProductAddReq req) {
+		log.info("edit>>:{}",req);
+		return productService.edit(req);
+	}
+	
+	@HandleLog
+	@PostMapping("delete")
+    @ResponseBody
+    @Operation(summary = "删除产品")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IdReq req) {
+		log.info("delete>>:{}",req);
+		return productService.delete(req.getId());
+	}
+}

+ 31 - 0
src/main/java/com/tuoren/forward/controller/PublicController.java

@@ -0,0 +1,31 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+/**
+ * @date 2023-10-19
+ * @author wulianwei
+ */
+@Controller
+public class PublicController {
+
+	/**
+	 * @title 首页
+	 * @return
+	 */
+	@GetMapping("/")
+	public String sayHello() {
+		return "redirect:/index";
+	}
+
+	/**
+	 * @title 登录页面
+	 * @return
+	 */
+	@GetMapping("/login")
+	public String login() {
+		return "login";
+	}
+
+}

+ 49 - 0
src/main/java/com/tuoren/forward/controller/RegionController.java

@@ -0,0 +1,49 @@
+package com.tuoren.forward.controller;
+
+import java.util.List;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.entity.Region;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.service.RegionService;
+import com.tuoren.forward.util.ResultData;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("region")
+@Tag(name= "地区接口")
+public class RegionController {
+
+	@Autowired
+	RegionService regionService;
+	
+	@PostMapping("listByPCode")
+    @ResponseBody
+    @Operation(summary = "列出次级地区")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Region>> listByPCode(@RequestBody IdReq req){
+		log.info("listByPCode>>:{}",req);
+		return regionService.listByPCode(req.getId());
+	}
+	
+	@PostMapping("getByCode")
+    @ResponseBody
+    @Operation(summary = "根据编码查地区")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<Region> getByCode(@RequestBody IdReq req){
+		log.info("getByCode>>:{}",req);
+		return regionService.getByCode(req.getId());
+	}
+}

+ 99 - 0
src/main/java/com/tuoren/forward/controller/RoleController.java

@@ -0,0 +1,99 @@
+package com.tuoren.forward.controller;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Role;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.req.RoleAuthReq;
+import com.tuoren.forward.entity.req.RoleSearchReq;
+import com.tuoren.forward.service.RoleService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("role")
+@Tag(name="角色接口")
+public class RoleController {
+	
+	@Autowired
+	RoleService roleServcie;
+	
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询角色")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<Role> search(@RequestBody RoleSearchReq req){
+		log.info("search>>:{}",req);
+		return roleServcie.search(req);
+	} 
+	
+	@PostMapping("listAll")
+    @ResponseBody
+    @Operation(summary = "列出所有角色")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<List<Role>> listAll(){
+		log.info("listAll>>");
+		return roleServcie.listAll();
+	} 
+
+	@HandleLog
+	@PostMapping("add")
+	@ResponseBody
+	@Operation(summary = "添加角色")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result  add(@RequestBody Role req) {
+		log.info("add>>:{}"+req);
+		return roleServcie.add(req);
+	}
+	
+	@HandleLog
+	@PostMapping("edit")
+	@ResponseBody
+	@Operation(summary = "修改角色")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result edit(@RequestBody Role req) {
+		log.info("edit>>:{}",req);
+		return roleServcie.edit(req);
+	}
+	
+	@HandleLog
+	@PostMapping("delete")
+	@ResponseBody
+	@Operation(summary = "删除角色")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result delete(@RequestBody IdReq req) {
+		log.info("delete>>:{}",req);
+		return roleServcie.delete(req.getId());
+	}
+	
+	@HandleLog
+	@PostMapping("authPermission")
+	@ResponseBody
+	@Operation(summary = "角色赋权")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result authPermission(@RequestBody RoleAuthReq req) {
+		log.info("authorPermission>>:{}"+req);
+		if(StringUtils.isEmpty(req.getRoleId())) {
+			return Result.fail(CommonConstant.LACK_PARAM);
+		}
+		return roleServcie.authPermission(req);
+	} 
+}

+ 115 - 0
src/main/java/com/tuoren/forward/controller/UserController.java

@@ -0,0 +1,115 @@
+package com.tuoren.forward.controller;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+import com.tuoren.forward.annotation.HandleLog;
+import com.tuoren.forward.constant.HandleLogChoice;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.entity.req.IdReq;
+import com.tuoren.forward.entity.req.LoginReq;
+import com.tuoren.forward.entity.req.UserAddReq;
+import com.tuoren.forward.entity.req.UserEditSelfReq;
+import com.tuoren.forward.entity.req.UserSearchReq;
+import com.tuoren.forward.entity.resp.LoginResp;
+import com.tuoren.forward.entity.resp.UserResp;
+import com.tuoren.forward.service.UserService;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+import com.tuoren.forward.util.ResultPage;
+
+import io.swagger.v3.oas.annotations.Operation;
+import io.swagger.v3.oas.annotations.Parameter;
+import io.swagger.v3.oas.annotations.enums.ParameterIn;
+import io.swagger.v3.oas.annotations.tags.Tag;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Controller
+@RequestMapping("user")
+@Tag(name= "用户接口")
+public class UserController {
+	
+	@Autowired
+	UserService userService;
+	
+	@HandleLog(value=HandleLogChoice.RECORD_SUC, type = HandleLogChoice.TYPE_LOGIN)
+	@PostMapping("login")
+    @ResponseBody
+    @Operation(summary = "登录")
+	public ResultData<LoginResp> login(@RequestBody LoginReq req){
+		log.info("login>>:{}",req);
+		return userService.login(req);
+	}
+	
+	@PostMapping("logout")
+    @ResponseBody
+    @Operation(summary = "退出登录")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public Result logout(){
+		log.info("logout>>");
+		return userService.logout();
+	}
+
+	@PostMapping("search")
+    @ResponseBody
+    @Operation(summary = "查询用户")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultPage<User> search(@RequestBody UserSearchReq req){
+		log.info("search>>:{}",req);
+		return userService.search(req);
+	}
+	
+	@PostMapping("detail")
+    @ResponseBody
+    @Operation(summary = "用户详情")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+	public ResultData<UserResp> detail(@RequestBody IdReq req){
+		log.info("detail>>:{}",req);
+		return userService.detail(req.getId());
+	}
+	
+	@HandleLog
+	@PostMapping("add")
+    @ResponseBody
+    @Operation(summary = "添加用户")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+    public Result add(@RequestBody UserAddReq req){
+		log.info("add>>:{}",req);
+        return userService.add(req);
+    }
+	
+	@HandleLog
+	@PostMapping("edit")
+    @ResponseBody
+    @Operation(summary = "修改用户")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+    public Result edit(@RequestBody UserAddReq req){
+		log.info("edit>>:{}",req);
+        return userService.edit(req);
+    }
+	
+	@HandleLog
+	@PostMapping("editSelf")
+    @ResponseBody
+    @Operation(summary = "修改自身")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+    public Result editSelf(@RequestBody UserEditSelfReq req){
+		log.info("editSelf>>:{}",req);
+        return userService.editSelf(req);
+    }
+	
+	@HandleLog
+	@PostMapping("delete")
+    @ResponseBody
+    @Operation(summary = "删除用户")
+	@Parameter(name="token",description = "token",required = true,in = ParameterIn.HEADER)
+    public Result delete(@RequestBody IdReq req){
+    	log.info("delete>>:{}",req);
+		return userService.delete(req.getId());
+    }
+}

+ 39 - 0
src/main/java/com/tuoren/forward/entity/Device.java

@@ -0,0 +1,39 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Date;
+import lombok.Data;
+
+@Data
+@Schema(description = "设备")
+public class Device {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "MAC")
+    private String mac;
+
+    @Schema(description = "设备名称")
+    private String name;
+
+    @Schema(description = "是否删除:, '0':未删除.’'1' 删除")
+    private String isDelete;
+
+    @Schema(description = "产品ID")
+    private String productId;
+
+    @Schema(description = "描述")
+    private String description;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+
+    @Schema(description = "修改时间")
+    private Date modifytime;
+
+    @Schema(description = "租户ID")
+    private String tenantId;
+
+    @Schema(description = "当前数据")
+    private String data;
+}

+ 23 - 0
src/main/java/com/tuoren/forward/entity/Dictionary.java

@@ -0,0 +1,23 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "数据字典")
+public class Dictionary {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "父ID")
+    private String parentId;
+
+    @Schema(description = "选项名称")
+    private String name;
+
+    @Schema(description = "选项值")
+    private String value;
+
+    @Schema(description = "备注")
+    private String note;
+}

+ 33 - 0
src/main/java/com/tuoren/forward/entity/Hospital.java

@@ -0,0 +1,33 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Date;
+import lombok.Data;
+
+@Data
+@Schema(description = "医院")
+public class Hospital {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "编码")
+    private String code;
+
+    @Schema(description = "医院名称")
+    private String name;
+
+    @Schema(description = "地址编码")
+    private String regionCode;
+
+    @Schema(description = "医院地址")
+    private String address;
+    
+    @Schema(description = "备注")
+    private String remark;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+
+    @Schema(description = "修改时间")
+    private Date modifytime;
+}

+ 54 - 0
src/main/java/com/tuoren/forward/entity/Log.java

@@ -0,0 +1,54 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Date;
+import lombok.Data;
+
+@Data
+@Schema(description = "操作日志")
+public class Log {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "操作人IP")
+    private String ip;
+
+    @Schema(description = "操作人ID")
+    private String userid;
+
+    @Schema(description = "操作人名字")
+    private String username;
+
+    @Schema(description = "操作模块")
+    private String module;
+
+    @Schema(description = "操作功能")
+    private String operation;
+
+    @Schema(description = "调用方法")
+    private String method;
+
+    @Schema(description = "操作结果,0:成功,1:失败,2:异常")
+    private String status;
+
+    @Schema(description = "请求路径")
+    private String url;
+
+    @Schema(description = "请求方式")
+    private String style;
+
+    @Schema(description = "请求参数")
+    private String param;
+
+    @Schema(description = "请求负载")
+    private String body;
+
+    @Schema(description = "操作结果")
+    private String result;
+
+    @Schema(description = "耗时,单位:ms")
+    private String waste;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+}

+ 29 - 0
src/main/java/com/tuoren/forward/entity/Model.java

@@ -0,0 +1,29 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "产品模型")
+public class Model {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "产品ID")
+    private String productId;
+
+    @Schema(description = "字段名称")
+    private String name;
+
+    @Schema(description = "标识")
+    private String title;
+
+    @Schema(description = "数据类型, int,float,string")
+    private String type;
+
+    @Schema(description = "备注")
+    private String remark;
+    
+    @Schema(description = "租户ID")
+    private String tenantId;
+}

+ 32 - 0
src/main/java/com/tuoren/forward/entity/Permission.java

@@ -0,0 +1,32 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "资源")
+public class Permission {
+    @Schema(description = "ID")
+    private Integer id;
+
+    @Schema(description = "父ID")
+    private Integer pid;
+
+    @Schema(description = "标题")
+    private String title;
+
+    @Schema(description = "类型 '01'  目录,'02' 菜单 '03' 按钮 ")
+    private String type;
+
+    @Schema(description = "路径")
+    private String url;
+
+    @Schema(description = "描述")
+    private String description;
+
+    @Schema(description = "排序")
+    private Integer orders;
+
+    @Schema(description = "资源图标")
+    private String icon;
+}

+ 42 - 0
src/main/java/com/tuoren/forward/entity/Product.java

@@ -0,0 +1,42 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Date;
+import lombok.Data;
+
+@Data
+@Schema(description = "产品")
+public class Product {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "租户ID")
+    private String tenantId;
+
+    @Schema(description = "产品名称")
+    private String name;
+
+    @Schema(description = "产品编码")
+    private String code;
+
+    @Schema(description = "产品密钥")
+    private String secret;
+
+    @Schema(description = "描述")
+    private String description;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+
+    @Schema(description = "修改时间")
+    private Date modifytime;
+
+    @Schema(description = "创建人")
+    private String creator;
+
+    @Schema(description = "修改人")
+    private String modifier;
+
+    @Schema(description = "数据模型,JSON格式")
+    private String model;
+}

+ 23 - 0
src/main/java/com/tuoren/forward/entity/Region.java

@@ -0,0 +1,23 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "地区表")
+public class Region {
+    @Schema(description = "地区编码")
+    private String code;
+
+    @Schema(description = "上级地区编码")
+    private String pCode;
+
+    @Schema(description = "地区名称")
+    private String name;
+
+    @Schema(description = "地区级别,01:省级,02:市级,03:县级,04:乡级")
+    private String type;
+
+    @Schema(description = "是否开放该地区, 0:未开放,1:开放")
+    private String isOpen;
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/Role.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "角色")
+public class Role {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "名称")
+    private String name;
+
+    @Schema(description = "描述")
+    private String description;
+}

+ 14 - 0
src/main/java/com/tuoren/forward/entity/RolePermission.java

@@ -0,0 +1,14 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "角色资源关系")
+public class RolePermission {
+    @Schema(description = "角色ID")
+    private String roleId;
+
+    @Schema(description = "资源ID")
+    private Integer permissionId;
+}

+ 50 - 0
src/main/java/com/tuoren/forward/entity/User.java

@@ -0,0 +1,50 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import java.util.Date;
+import java.util.List;
+
+import lombok.Data;
+
+@Data
+@Schema(description = "用户")
+public class User {
+    @Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "用户名")
+    private String username;
+
+    @Schema(description = "密码")
+    private String password;
+
+    @Schema(description = "电话")
+    private String mobile;
+
+    @Schema(description = "邮箱")
+    private String email;
+
+    @Schema(description = "盐")
+    private String salt;
+
+    @Schema(description = "使能 '0' 无效 '1' 有效")
+    private String enabled;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+
+    @Schema(description = "最近登陆时间")
+    private Date lasttime;
+    
+    @Schema(description = "编码")
+    private String code;
+
+    @Schema(description = "地区编码")
+    private String regionCode;
+
+    @Schema(description = "详细地址")
+    private String address;
+    
+    @Schema(description="角色ID, 'roleId1,roleId2'")
+    private List<String> roleIds;
+}

+ 14 - 0
src/main/java/com/tuoren/forward/entity/UserRole.java

@@ -0,0 +1,14 @@
+package com.tuoren.forward.entity;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户角色关系")
+public class UserRole {
+    @Schema(description = "用户ID")
+    private String userId;
+
+    @Schema(description = "角色ID")
+    private String roleId;
+}

+ 20 - 0
src/main/java/com/tuoren/forward/entity/dto/DeviceDto.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.entity.dto;
+
+import com.tuoren.forward.entity.Device;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class DeviceDto extends Device{
+	
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+	
+	private String keyWord; //搜索内容
+
+}

+ 20 - 0
src/main/java/com/tuoren/forward/entity/dto/HospitalDto.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.entity.dto;
+
+import com.tuoren.forward.entity.Hospital;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class HospitalDto extends Hospital{
+	
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+	
+	private String keyWord; //搜索内容
+
+}

+ 25 - 0
src/main/java/com/tuoren/forward/entity/dto/LogDto.java

@@ -0,0 +1,25 @@
+package com.tuoren.forward.entity.dto;
+
+import java.util.Date;
+
+import com.tuoren.forward.entity.Log;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class LogDto extends Log{
+	
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+	
+	private String keyWord; //搜索内容
+	
+	private Date startTime; //开始时间
+	
+	private Date endTime; //结束时间
+}

+ 20 - 0
src/main/java/com/tuoren/forward/entity/dto/ModelDto.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.entity.dto;
+
+import com.tuoren.forward.entity.Model;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class ModelDto extends Model{
+
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+	
+	private String keyWord; //搜索内容
+		
+}

+ 20 - 0
src/main/java/com/tuoren/forward/entity/dto/ProductDto.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.entity.dto;
+
+import com.tuoren.forward.entity.Product;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class ProductDto extends Product{
+
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+	
+	private String keyWord; //搜索内容
+	
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/dto/UserDto.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity.dto;
+
+import com.tuoren.forward.entity.User;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class UserDto extends User{
+	
+	private String sort;  //排序字段
+	
+	private String order; //排序方式, 'asc':升序, 'desc':降序
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/req/CommonSearchReq.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="通用查询请求")
+public class CommonSearchReq extends PageReq{
+
+	@Schema(description = "搜索内容")
+    private String keyWord;
+	
+}

+ 24 - 0
src/main/java/com/tuoren/forward/entity/req/DeviceAddReq.java

@@ -0,0 +1,24 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "设备")
+public class DeviceAddReq {
+	
+		@Schema(description = "ID")
+	    private String id;
+	
+	 	@Schema(description = "MAC")
+	    private String mac;
+
+	    @Schema(description = "设备名称")
+	    private String name;
+
+	    @Schema(description = "产品ID")
+	    private String productId;
+	    
+	    @Schema(description = "描述")
+	    private String description;
+}

+ 22 - 0
src/main/java/com/tuoren/forward/entity/req/DeviceRecordSearchReq.java

@@ -0,0 +1,22 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="医院查询请求")
+public class DeviceRecordSearchReq extends PageReq{
+
+	@Schema(description = "搜索内容")
+    private String keyWord;
+	
+	@Schema(description = "设备ID")
+    private String deviceId;
+	
+	@Schema(description = "mac")
+    private String mac;
+}

+ 19 - 0
src/main/java/com/tuoren/forward/entity/req/DeviceSearchReq.java

@@ -0,0 +1,19 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="医院查询请求")
+public class DeviceSearchReq extends PageReq{
+	
+	@Schema(description = "搜索内容")
+    private String keyWord;
+	
+	@Schema(description = "产品ID")
+    private String productId;
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/req/HospitalAddOpenReq.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity.req;
+
+import com.tuoren.forward.entity.Hospital;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class HospitalAddOpenReq extends Hospital{
+	    
+	   @Schema(description = "校验码, 对 ${id}&${name}&${screte} md5加密")
+	    private String md5;
+}

+ 16 - 0
src/main/java/com/tuoren/forward/entity/req/HospitalSearchReq.java

@@ -0,0 +1,16 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="医院查询请求")
+public class HospitalSearchReq extends PageReq{
+	
+    @Schema(description = "搜索内容")
+    private String keyWord;
+}

+ 13 - 0
src/main/java/com/tuoren/forward/entity/req/IdReq.java

@@ -0,0 +1,13 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description="ID请求")
+public class IdReq {
+	
+	@Schema(description="ID, 'id1,id2'")
+	private String id;
+
+}

+ 13 - 0
src/main/java/com/tuoren/forward/entity/req/IntIdReq.java

@@ -0,0 +1,13 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description="整形ID请求")
+public class IntIdReq {
+	
+	@Schema(description="整形ID")
+	private Integer id;
+
+}

+ 30 - 0
src/main/java/com/tuoren/forward/entity/req/LogSearchReq.java

@@ -0,0 +1,30 @@
+package com.tuoren.forward.entity.req;
+
+import java.util.Date;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="模型查询请求")
+public class LogSearchReq extends PageReq{
+	
+	@Schema(description = "操作人")
+	private String username;
+	
+	@Schema(description = "操作功能")
+	private String operation;
+	
+	@Schema(description = "操作结果,0:成功,1:失败,2:异常")
+	private String status;
+	
+	@Schema(description = "开始时间")
+	private Date startTime;
+	
+	@Schema(description = "结束时间")
+	private Date endTime;
+}

+ 22 - 0
src/main/java/com/tuoren/forward/entity/req/LoginReq.java

@@ -0,0 +1,22 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description  = "用户登录请求")
+public class LoginReq {
+
+	@Schema(description = "用户名")
+    private String username;
+
+    @Schema(description = "密码")
+    private String password;
+    
+    @Schema(description = "验证码")
+    private String captchaCode;
+    
+    @Schema(description = "验证码键值")
+    private String captchaKey;
+    
+}

+ 20 - 0
src/main/java/com/tuoren/forward/entity/req/ModelSearchReq.java

@@ -0,0 +1,20 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="模型查询请求")
+public class ModelSearchReq extends PageReq{
+
+	@Schema(description = "搜索内容")
+    private String keyWord;
+	
+	@Schema(description = "产品ID")
+    private String productId;
+	
+}

+ 21 - 0
src/main/java/com/tuoren/forward/entity/req/PageReq.java

@@ -0,0 +1,21 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+public class PageReq {
+	
+	@Schema(description = "行数")
+	private Integer size;
+	
+	@Schema(description = "页数")
+	private Integer page;
+	
+	@Schema(description = "排序字段")
+	private String sort;  //排序字段
+	
+	@Schema(description = "排序方式, 'asc':升序, 'desc':降序")
+	private String order;  //排序,升/降
+
+}

+ 18 - 0
src/main/java/com/tuoren/forward/entity/req/ProductAddReq.java

@@ -0,0 +1,18 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "产品")
+public class ProductAddReq {
+
+	@Schema(description = "ID")
+    private String id;
+	
+	@Schema(description = "产品名称")
+    private String name;
+
+    @Schema(description = "描述")
+    private String description;
+}

+ 16 - 0
src/main/java/com/tuoren/forward/entity/req/ProductSearchReq.java

@@ -0,0 +1,16 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="医院查询请求")
+public class ProductSearchReq extends PageReq{
+	
+	@Schema(description = "搜索内容")
+    private String keyWord;
+}

+ 16 - 0
src/main/java/com/tuoren/forward/entity/req/RoleAuthReq.java

@@ -0,0 +1,16 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description="角色赋权请求")
+public class RoleAuthReq {
+	
+	@Schema(description="角色ID")
+	String roleId;
+	
+	@Schema(description="资源ID,数组")
+	private Integer[] permissionIds;
+
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/req/RoleSearchReq.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="角色查询请求")
+public class RoleSearchReq extends PageReq {
+	
+	@Schema(description = "名称")
+    private String name;
+	
+}

+ 31 - 0
src/main/java/com/tuoren/forward/entity/req/UserAddOpenReq.java

@@ -0,0 +1,31 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户")
+public class UserAddOpenReq {
+	
+	@Schema(description = "用户名")
+    private String username;
+
+    @Schema(description = "电话")
+    private String mobile;
+
+    @Schema(description = "邮箱")
+    private String email;
+
+    @Schema(description = "编码")
+    private String code;
+    
+    @Schema(description = "地区编码")
+    private String regionCode;
+
+    @Schema(description = "详细地址")
+    private String address;
+    
+	@Schema(description = "校验码, 对 ${name}&${screte} md5加密")
+    private String md5;
+
+}

+ 35 - 0
src/main/java/com/tuoren/forward/entity/req/UserAddReq.java

@@ -0,0 +1,35 @@
+package com.tuoren.forward.entity.req;
+
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户")
+public class UserAddReq {
+
+	@Schema(description = "ID")
+    private String id;
+	
+	@Schema(description = "用户名")
+    private String username;
+
+    @Schema(description = "电话")
+    private String mobile;
+
+    @Schema(description = "邮箱")
+    private String email;
+    
+    @Schema(description = "编码")
+    private String code;
+
+    @Schema(description = "地区编码")
+    private String regionCode;
+
+    @Schema(description = "详细地址")
+    private String address;
+    
+    @Schema(description="角色ID, 'roleId1,roleId2'")
+    private List<String> roleIds;
+}

+ 25 - 0
src/main/java/com/tuoren/forward/entity/req/UserEditSelfReq.java

@@ -0,0 +1,25 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "用户自己修改请求")
+public class UserEditSelfReq {
+
+    @Schema(description = "电话")
+    private String mobile;
+
+    @Schema(description = "邮箱")
+    private String email;
+
+    @Schema(description = "地区编码")
+    private String regionCode;
+
+    @Schema(description = "详细地址")
+    private String address;
+    
+    @Schema(description = "密码")
+    private String password;
+    
+}

+ 16 - 0
src/main/java/com/tuoren/forward/entity/req/UserSearchReq.java

@@ -0,0 +1,16 @@
+package com.tuoren.forward.entity.req;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+@Schema(description="用户查询请求")
+public class UserSearchReq extends PageReq{
+
+	@Schema(description = "用户名")
+    private String username;
+}

+ 15 - 0
src/main/java/com/tuoren/forward/entity/resp/CaptchaResp.java

@@ -0,0 +1,15 @@
+package com.tuoren.forward.entity.resp;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema(description = "验证码数据")
+public class CaptchaResp {
+	
+	@Schema(description = "验证码键值")
+	private String captchaKey;
+	
+	@Schema(description = "验证码数据")
+	private String captchaImg;
+}

+ 17 - 0
src/main/java/com/tuoren/forward/entity/resp/DeviceResp.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.entity.resp;
+
+import com.tuoren.forward.entity.Device;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class DeviceResp extends Device{
+	
+	@Schema(description = "产品名称")
+	private String productName;
+}

+ 45 - 0
src/main/java/com/tuoren/forward/entity/resp/LoginResp.java

@@ -0,0 +1,45 @@
+package com.tuoren.forward.entity.resp;
+
+import java.util.Date;
+import java.util.List;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+
+@Data
+@Schema
+public class LoginResp{
+	
+	@Schema(description = "ID")
+    private String id;
+
+    @Schema(description = "用户名")
+    private String username;
+
+    @Schema(description = "电话")
+    private String mobile;
+
+    @Schema(description = "邮箱")
+    private String email;
+
+    @Schema(description = "创建时间")
+    private Date createtime;
+
+    @Schema(description = "最近登陆时间")
+    private Date lasttime;
+    
+    @Schema(description = "编码")
+    private String code;
+
+    @Schema(description = "地区编码")
+    private String regionCode;
+
+    @Schema(description = "详细地址")
+    private String address;
+    
+    @Schema(description="角色ID, 'roleId1,roleId2'")
+    private List<String> roleIds;
+    
+	@Schema(description = "token值")
+	private String token;
+}

+ 19 - 0
src/main/java/com/tuoren/forward/entity/resp/UserResp.java

@@ -0,0 +1,19 @@
+package com.tuoren.forward.entity.resp;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.User;
+
+import io.swagger.v3.oas.annotations.media.Schema;
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+import lombok.ToString;
+
+@Data
+@ToString(callSuper = true)
+@EqualsAndHashCode(callSuper = true)
+public class UserResp extends User{
+
+	@Schema(description = "角色ID")
+	private List<String> roleIds;
+}

+ 38 - 0
src/main/java/com/tuoren/forward/init/AmqpInit.java

@@ -0,0 +1,38 @@
+package com.tuoren.forward.init;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Component;
+
+import com.tuoren.forward.config.amqp.AmqpClient1;
+import com.tuoren.forward.config.amqp.AmqpClient2;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class AmqpInit implements ApplicationRunner,Ordered{
+
+	@Autowired
+	AmqpClient1 amqpClient1; 
+	
+	@Autowired
+	AmqpClient2 amqpClient2; 
+	
+	@Override
+	public void run(ApplicationArguments args) throws Exception {
+		// TODO Auto-generated method stub
+		log.info("Amqp初始化>>>");
+		amqpClient1.connection();
+		amqpClient2.connection();
+	}
+
+	@Override
+	public int getOrder() {
+		// TODO Auto-generated method stub
+		return 1;
+	}
+
+}

+ 41 - 0
src/main/java/com/tuoren/forward/init/MqttInit.java

@@ -0,0 +1,41 @@
+package com.tuoren.forward.init;
+
+import org.eclipse.paho.client.mqttv3.MqttClient;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.boot.autoconfigure.condition.ConditionalOnBean;
+import org.springframework.core.Ordered;
+import org.springframework.stereotype.Component;
+
+import com.tuoren.forward.config.mqtt.MqttCallbackCustom;
+import com.tuoren.forward.config.mqtt.MqttConfig;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+@ConditionalOnBean(MqttConfig.class)
+public class MqttInit implements ApplicationRunner,Ordered{
+	
+
+	@Autowired
+	private MqttClient mqttClient;
+	
+	@Autowired
+	private MqttCallbackCustom callback;
+	
+	@Override
+	public int getOrder() {
+		// TODO Auto-generated method stub
+		return 2;
+	}
+
+	@Override
+	public void run(ApplicationArguments args) throws Exception {
+		// TODO Auto-generated method stub
+		log.info("mqtt初始化>>>>");
+		mqttClient.setCallback(callback);
+	}
+
+}

+ 30 - 0
src/main/java/com/tuoren/forward/init/MybatisInit.java

@@ -0,0 +1,30 @@
+package com.tuoren.forward.init;
+
+import org.apache.ibatis.session.SqlSessionFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.boot.ApplicationArguments;
+import org.springframework.boot.ApplicationRunner;
+import org.springframework.stereotype.Component;
+
+import com.tuoren.forward.interceptor.MybatisInterceptor;
+
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Component
+public class MybatisInit implements ApplicationRunner{
+	
+	@Autowired
+	@Qualifier("primarySqlSessionFactory")
+	SqlSessionFactory primarySqlSessionFactory;
+	
+	
+	@Override
+	public void run(ApplicationArguments args) throws Exception {
+		// TODO Auto-generated method stub
+		log.info("Mybatis 初始化, 保证MybatisInterceptor 优先执行>>>>");
+		primarySqlSessionFactory.getConfiguration().addInterceptor(new MybatisInterceptor());
+	}
+
+}

+ 176 - 0
src/main/java/com/tuoren/forward/interceptor/MybatisInterceptor.java

@@ -0,0 +1,176 @@
+package com.tuoren.forward.interceptor;
+
+import java.lang.reflect.Method;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.ibatis.cache.CacheKey;
+import org.apache.ibatis.executor.Executor;
+import org.apache.ibatis.mapping.BoundSql;
+import org.apache.ibatis.mapping.MappedStatement;
+import org.apache.ibatis.mapping.SqlCommandType;
+import org.apache.ibatis.mapping.SqlSource;
+import org.apache.ibatis.plugin.Interceptor;
+import org.apache.ibatis.plugin.Intercepts;
+import org.apache.ibatis.plugin.Invocation;
+import org.apache.ibatis.plugin.Plugin;
+import org.apache.ibatis.plugin.Signature;
+import org.apache.ibatis.session.ResultHandler;
+import org.apache.ibatis.session.RowBounds;
+
+import com.tuoren.forward.annotation.SqlLimit;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.util.AccessTokenUtil;
+
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
+@Intercepts({
+    @Signature(
+            type = Executor.class,
+            method = "query",
+            args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class}
+    ),
+    @Signature(
+            method = "query",
+            type = Executor.class,
+            args = {MappedStatement.class, Object.class, RowBounds.class, ResultHandler.class, CacheKey.class, BoundSql.class}
+    ),
+    @Signature(
+            type = Executor.class,
+            method = "update",
+            args = {MappedStatement.class, Object.class}
+    )
+})
+public class MybatisInterceptor implements Interceptor {
+
+    @Override
+    public Object intercept(Invocation invocation) throws Throwable {
+    	
+        MappedStatement statement = (MappedStatement) invocation.getArgs()[0];
+        Object parameter = invocation.getArgs()[1];
+        BoundSql boundSql = statement.getBoundSql(parameter);
+        String originalSql = boundSql.getSql();
+        Object parameterObject = boundSql.getParameterObject();
+        
+        SqlCommandType sqlCommandType = statement.getSqlCommandType();
+
+        if (SqlCommandType.INSERT.equals(sqlCommandType) || SqlCommandType.FLUSH.equals(sqlCommandType)) {
+            return invocation.proceed();
+        }
+        
+        SqlLimit sqlLimit = isLimit(statement);
+        if (sqlLimit == null || sqlLimit.isWork() == false) {
+            return invocation.proceed();
+        }
+        
+        User user = AccessTokenUtil.getUser();
+ 	    if(user == null) {
+ 	    	return invocation.proceed();
+ 	    }
+ 	    if(user.getRoleIds() != null && user.getRoleIds().contains(CommonConstant.ROLE_MANAGER)) {
+ 	    	return invocation.proceed();
+ 	    }
+        
+        String limitValue = user.getId();
+        String sql = addTenantCondition(originalSql, limitValue, sqlLimit.alis(),sqlLimit.columnName());
+        log.info("原SQL:{}, 数据权限替换后的SQL:{}", originalSql, sql);
+        BoundSql newBoundSql = new BoundSql(statement.getConfiguration(), sql, boundSql.getParameterMappings(), parameterObject);
+        MappedStatement newStatement = copyFromMappedStatement(statement, new BoundSqlSqlSource(newBoundSql));
+        invocation.getArgs()[0] = newStatement;
+        return invocation.proceed();
+    }
+
+    @Override
+    public Object plugin(Object target) {
+        if (target instanceof Executor) {
+            return Plugin.wrap(target, this);
+        } else {
+            return target;
+        }
+    }
+
+	
+    /**
+     * 重新拼接SQL
+     */
+    private String addTenantCondition(String originalSql, String limitValue, String alias,String column) {
+        String field = "tenant_id";
+        if(StringUtils.isNoneBlank(column)){
+            field = column;
+        }
+        if(StringUtils.isNoneBlank(alias)){
+            field = alias + "." + field;
+        }
+
+        StringBuilder sb = new StringBuilder(originalSql);
+        limitValue = "'"+limitValue+"'";
+        int index = StringUtils.indexOfAny(sb, "where","WHERE");
+        if (index < 0) {
+        	int orderIndex = sb.indexOf("order");
+        	if(orderIndex < 0) {
+        		sb.append(" where ") .append(field).append(" = ").append(limitValue);
+        	}else {
+        		 sb.insert(orderIndex - 1, " where " + field +" = " + limitValue);
+        	}
+        } else {
+            sb.insert(index + 5, " " + field +" = " + limitValue + " and ");
+        }
+        return sb.toString();
+    }
+
+    private MappedStatement copyFromMappedStatement(MappedStatement ms, SqlSource newSqlSource) {
+        MappedStatement.Builder builder = new MappedStatement.Builder(ms.getConfiguration(), ms.getId(), newSqlSource, ms.getSqlCommandType());
+        builder.resource(ms.getResource());
+        builder.fetchSize(ms.getFetchSize());
+        builder.statementType(ms.getStatementType());
+        builder.keyGenerator(ms.getKeyGenerator());
+        builder.timeout(ms.getTimeout());
+        builder.parameterMap(ms.getParameterMap());
+        builder.resultMaps(ms.getResultMaps());
+        builder.cache(ms.getCache());
+        builder.useCache(ms.isUseCache());
+        return builder.build();
+    }
+
+
+    /**
+     * 通过注解判断是否需要限制数据
+     * @return
+     */
+    private SqlLimit isLimit(MappedStatement mappedStatement) {
+        SqlLimit sqlLimit = null;
+        try {
+            String id = mappedStatement.getId();
+            String className = id.substring(0, id.lastIndexOf("."));
+            String methodName = id.substring(id.lastIndexOf(".") + 1, id.length());
+            final Class<?> cls = Class.forName(className);
+            if(cls.isAnnotationPresent(SqlLimit.class)) {
+            	sqlLimit = cls.getAnnotation(SqlLimit.class);
+            }
+            final Method[] method = cls.getMethods();
+            for (Method me : method) {
+                if (me.getName().equals(methodName) && me.isAnnotationPresent(SqlLimit.class)) {
+                    sqlLimit = me.getAnnotation(SqlLimit.class);
+                }
+            }
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        return sqlLimit;
+    }
+
+
+    public static class BoundSqlSqlSource implements SqlSource {
+
+        private final BoundSql boundSql;
+
+        public BoundSqlSqlSource(BoundSql boundSql) {
+            this.boundSql = boundSql;
+        }
+
+        @Override
+        public BoundSql getBoundSql(Object parameterObject) {
+            return boundSql;
+        }
+    }
+}

+ 41 - 0
src/main/java/com/tuoren/forward/mapper/DeviceMapper.java

@@ -0,0 +1,41 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.annotation.SqlLimit;
+import com.tuoren.forward.entity.Device;
+import com.tuoren.forward.entity.dto.DeviceDto;
+import com.tuoren.forward.entity.resp.DeviceResp;
+
+@SqlLimit
+public interface DeviceMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Device row);
+
+    int insertSelective(Device row);
+
+    
+    Device selectByPrimaryKey(String id);
+    
+    @SqlLimit(isWork = false)
+    Device selectByMac(String mac);
+    
+    @SqlLimit(isWork = false)
+    Device selectByMacOwner(String mac,String owner);
+    
+    @SqlLimit(isWork = false)
+    Integer existByMacOwner(String mac,String owner);
+    
+    @SqlLimit(alis = "d")
+    List<DeviceResp> select(DeviceDto row);
+
+    int updateByPrimaryKeySelective(Device row);
+    
+    @SqlLimit(isWork = false)
+    int updateByPrimaryKeySelective2(Device row);
+
+    int updateByPrimaryKeyWithBLOBs(Device row);
+
+    int updateByPrimaryKey(Device row);
+}

+ 17 - 0
src/main/java/com/tuoren/forward/mapper/DictionaryMapper.java

@@ -0,0 +1,17 @@
+package com.tuoren.forward.mapper;
+
+import com.tuoren.forward.entity.Dictionary;
+
+public interface DictionaryMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Dictionary row);
+
+    int insertSelective(Dictionary row);
+
+    Dictionary selectByPrimaryKey(String id);
+
+    int updateByPrimaryKeySelective(Dictionary row);
+
+    int updateByPrimaryKey(Dictionary row);
+}

+ 24 - 0
src/main/java/com/tuoren/forward/mapper/HospitalMapper.java

@@ -0,0 +1,24 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.Hospital;
+import com.tuoren.forward.entity.dto.HospitalDto;
+
+public interface HospitalMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Hospital row);
+
+    int insertSelective(Hospital row);
+
+    Hospital selectByPrimaryKey(String id);
+    
+    Hospital selectByCode(String code);
+    
+    List<Hospital> select(HospitalDto row);
+
+    int updateByPrimaryKeySelective(Hospital row);
+
+    int updateByPrimaryKey(Hospital row);
+}

+ 22 - 0
src/main/java/com/tuoren/forward/mapper/LogMapper.java

@@ -0,0 +1,22 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.Log;
+import com.tuoren.forward.entity.dto.LogDto;
+
+public interface LogMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Log row);
+
+    int insertSelective(Log row);
+
+    Log selectByPrimaryKey(String id);
+
+    List<Log> select(LogDto row);
+    
+    int updateByPrimaryKeySelective(Log row);
+
+    int updateByPrimaryKey(Log row);
+}

+ 26 - 0
src/main/java/com/tuoren/forward/mapper/ModelMapper.java

@@ -0,0 +1,26 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.annotation.SqlLimit;
+import com.tuoren.forward.entity.Model;
+import com.tuoren.forward.entity.dto.ModelDto;
+
+@SqlLimit
+public interface ModelMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Model row);
+
+    int insertSelective(Model row);
+
+    Model selectByPrimaryKey(String id);
+    
+    Model selectByTitle(String title);
+    
+    List<Model> select(ModelDto row);
+
+    int updateByPrimaryKeySelective(Model row);
+
+    int updateByPrimaryKey(Model row);
+}

+ 37 - 0
src/main/java/com/tuoren/forward/mapper/PermissionMapper.java

@@ -0,0 +1,37 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.Permission;
+
+public interface PermissionMapper {
+    int deleteByPrimaryKey(Integer id);
+
+    int insert(Permission row);
+
+    int insertSelective(Permission row);
+
+    Permission selectByPrimaryKey(Integer id);
+    
+    Permission selectByUrl(String url);
+    
+    Permission selectByTitle(String title);
+    
+    Permission selectOne(Permission row);
+    
+    List<String> selectUrlByUserId(String userId);
+    
+    List<Permission> select(Permission row);
+    
+    List<String> selectAllUrl();
+    
+    List<Permission> selectAll();
+    
+    List<Permission> selectByRoleId(String roleId);
+    
+    List<Permission> selectByUserId(String userId);
+
+    int updateByPrimaryKeySelective(Permission row);
+
+    int updateByPrimaryKey(Permission row);
+}

+ 35 - 0
src/main/java/com/tuoren/forward/mapper/ProductMapper.java

@@ -0,0 +1,35 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.annotation.SqlLimit;
+import com.tuoren.forward.entity.Product;
+import com.tuoren.forward.entity.dto.ProductDto;
+
+@SqlLimit
+public interface ProductMapper {
+	
+    int deleteByPrimaryKey(String id);
+
+    int insert(Product row);
+
+    int insertSelective(Product row);
+
+    
+    Product selectByPrimaryKey(String id);
+    
+    
+    List<Product> selectAll();
+    
+    
+    List<Product> select(ProductDto row);
+
+    
+    int updateByPrimaryKeySelective(Product row);
+
+    
+    int updateByPrimaryKeyWithBLOBs(Product row);
+
+    
+    int updateByPrimaryKey(Product row);
+}

+ 21 - 0
src/main/java/com/tuoren/forward/mapper/RegionMapper.java

@@ -0,0 +1,21 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.Region;
+
+public interface RegionMapper {
+    int deleteByPrimaryKey(String code);
+
+    int insert(Region row);
+
+    int insertSelective(Region row);
+
+    Region selectByPrimaryKey(String code);
+    
+    List<Region> selectByPCode(String pCode);
+
+    int updateByPrimaryKeySelective(Region row);
+
+    int updateByPrimaryKey(Region row);
+}

+ 25 - 0
src/main/java/com/tuoren/forward/mapper/RoleMapper.java

@@ -0,0 +1,25 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.Role;
+
+public interface RoleMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(Role row);
+
+    int insertSelective(Role row);
+
+    Role selectByPrimaryKey(String id);
+    
+    List<String> selectIdByUserId(String userId);
+    
+    List<Role> selectAll();
+    
+    List<Role> select(Role row);
+
+    int updateByPrimaryKeySelective(Role row);
+
+    int updateByPrimaryKey(Role row);
+}

+ 12 - 0
src/main/java/com/tuoren/forward/mapper/RolePermissionMapper.java

@@ -0,0 +1,12 @@
+package com.tuoren.forward.mapper;
+
+
+import com.tuoren.forward.entity.RolePermission;
+
+public interface RolePermissionMapper {
+    int insert(RolePermission row);
+
+    int insertSelective(RolePermission row);
+    
+    int deleteByRoleId(String roleId);
+}

+ 26 - 0
src/main/java/com/tuoren/forward/mapper/UserMapper.java

@@ -0,0 +1,26 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.entity.dto.UserDto;
+
+public interface UserMapper {
+    int deleteByPrimaryKey(String id);
+
+    int insert(User row);
+
+    int insertSelective(User row);
+
+    User selectByPrimaryKey(String id);
+    
+    User selectByUsername(String username);
+    
+    User selectByCode(String code);
+    
+    List<User> select(UserDto row);
+
+    int updateByPrimaryKeySelective(User row);
+
+    int updateByPrimaryKey(User row);
+}

+ 15 - 0
src/main/java/com/tuoren/forward/mapper/UserRoleMapper.java

@@ -0,0 +1,15 @@
+package com.tuoren.forward.mapper;
+
+import java.util.List;
+
+import com.tuoren.forward.entity.UserRole;
+
+public interface UserRoleMapper {
+	List<String> selectRoleIdByUserId(String userId);
+	
+    int insert(UserRole row);
+
+    int insertSelective(UserRole row);
+    
+    int deleteByUserId(String userId);
+}

+ 130 - 0
src/main/java/com/tuoren/forward/service/DeviceService.java

@@ -0,0 +1,130 @@
+package com.tuoren.forward.service;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.data.domain.Sort;
+import org.springframework.data.mongodb.core.MongoTemplate;
+import org.springframework.data.mongodb.core.query.Criteria;
+import org.springframework.data.mongodb.core.query.Query;
+import org.springframework.stereotype.Service;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Device;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.entity.dto.DeviceDto;
+import com.tuoren.forward.entity.req.DeviceAddReq;
+import com.tuoren.forward.entity.req.DeviceRecordSearchReq;
+import com.tuoren.forward.entity.req.DeviceSearchReq;
+import com.tuoren.forward.entity.resp.DeviceResp;
+import com.tuoren.forward.mapper.DeviceMapper;
+import com.tuoren.forward.util.AccessTokenUtil;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultPage;
+import com.tuoren.forward.util.UUIDUtil;
+
+@Service
+public class DeviceService {
+
+	@Autowired
+	DeviceMapper deviceMapper;
+	
+	@Autowired
+    MongoTemplate mongoTemplate;
+	
+	/**
+	 * @title 查询设备
+	 * @param req
+	 * @return ResultPage<Device>
+	 */
+	public ResultPage<DeviceResp> search(DeviceSearchReq req){
+		Page<Object> page = PageHelper.startPage(req.getPage(), req.getSize());
+		DeviceDto dto = new DeviceDto();
+		BeanUtils.copyProperties(req, dto);
+		List<DeviceResp> devices = deviceMapper.select(dto);
+		return ResultPage.success(devices,page.getTotal());
+	}
+	
+	/**
+	 * @title 添加设备
+	 * @param req
+	 * @return Result
+	 */
+	public Result add(DeviceAddReq req) {
+		String userId = AccessTokenUtil.getUserId();
+		Date date = new Date();
+		Device exist = deviceMapper.selectByMac(req.getMac());
+		if(exist != null) {
+			return Result.fail("设备已存在");
+		}
+		Device device = new Device();
+		BeanUtils.copyProperties(req, device);
+		device.setId(UUIDUtil.get32UUID());
+		device.setTenantId(userId);
+		device.setCreatetime(date);
+		deviceMapper.insertSelective(device);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 修改设备
+	 * @param req
+	 * @return Result
+	 */
+	public Result edit(DeviceAddReq req) {
+		Date date = new Date();
+		Device device = new Device();
+		BeanUtils.copyProperties(req, device);
+		device.setModifytime(date);
+		device.setMac(null);
+		deviceMapper.updateByPrimaryKeySelective(device);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 删除设备
+	 * @param req
+	 * @return Result
+	 */
+	public Result delete(String id) {
+		deviceMapper.deleteByPrimaryKey(id);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 查询设备记录
+	 * @param req
+	 * @return ResultPage<JSONObject>
+	 */
+	public ResultPage<JSONObject> searchRecord(DeviceRecordSearchReq req){
+		User user = AccessTokenUtil.getUser();
+		Query query = new Query();
+		if(user.getRoleIds()==null || !user.getRoleIds().contains(CommonConstant.ROLE_MANAGER)) {
+			query.addCriteria(Criteria.where("tenantId").is(user.getId()));
+		}
+		if(!StringUtils.isEmpty(req.getDeviceId())) {
+			query.addCriteria(Criteria.where("deviceId").is(req.getDeviceId()));
+		}
+		if(!StringUtils.isEmpty(req.getMac())) {
+			query.addCriteria(Criteria.where("deviceMac").is(req.getMac()));
+		}
+		if(!StringUtils.isEmpty(req.getKeyWord())) {
+			query.addCriteria(new Criteria().orOperator(
+					Criteria.where("deviceId").regex(req.getKeyWord())
+				));
+		}
+		long totol = mongoTemplate.count(query, "device_record");
+		query.with(Sort.by(Sort.Direction.DESC, "time"));
+		int skip = (req.getPage()-1)*req.getSize();
+		query.skip(skip);
+		query.limit(req.getSize());
+		List<JSONObject> results = mongoTemplate.find(query, JSONObject.class, "device_record");
+		return ResultPage.success(results, totol);
+	}
+}

+ 186 - 0
src/main/java/com/tuoren/forward/service/HospitalService.java

@@ -0,0 +1,186 @@
+package com.tuoren.forward.service;
+
+import java.util.Date;
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.stereotype.Service;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import com.alibaba.fastjson2.JSONObject;
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.tuoren.forward.constant.CommonConstant;
+import com.tuoren.forward.entity.Dictionary;
+import com.tuoren.forward.entity.Hospital;
+import com.tuoren.forward.entity.dto.HospitalDto;
+import com.tuoren.forward.entity.req.HospitalSearchReq;
+import com.tuoren.forward.mapper.DictionaryMapper;
+import com.tuoren.forward.mapper.HospitalMapper;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+import com.tuoren.forward.util.ResultPage;
+import com.tuoren.forward.util.UUIDUtil;
+
+@Service
+public class HospitalService {
+	
+	@Autowired
+	HospitalMapper hospitalMapper;
+	
+	@Autowired
+	RestTemplate restTemplate;
+	
+	@Autowired
+	DictionaryMapper dictionaryMapper;
+	
+	@Autowired
+	UserService userService;
+	
+	/**
+	 * @title 查询医院
+	 * @param req
+	 * @return
+	 */
+	public ResultPage<Hospital> search(HospitalSearchReq req) {
+		Page<Object> page = PageHelper.startPage(req.getPage(), req.getSize());
+		HospitalDto dto = new HospitalDto();
+		BeanUtils.copyProperties(req, dto);
+		List<Hospital> hospitals = hospitalMapper.select(dto);
+		return ResultPage.success(hospitals, page.getTotal());
+	}
+	
+	/**
+	 * @title 添加医院
+	 * @param req
+	 * @return
+	 */
+	@Transactional
+	public Result add(Hospital req) {
+		Date date = new Date();
+		Dictionary dic = dictionaryMapper.selectByPrimaryKey("hospitalCode");
+		String maxCode = dic.getValue();
+		int code = Integer.parseInt(maxCode);
+		code++;
+		if(code>9999) {
+			return Result.fail("医院编码超出范围");
+		}
+		String curCode = String.format("%04d", code);
+		Hospital record = hospitalMapper.selectByCode(curCode);
+		if(record != null) {
+			return Result.fail("医院编码已存在");
+		}
+		req.setId(UUIDUtil.get32UUID());
+		req.setCode(curCode);
+		req.setCreatetime(date);
+		hospitalMapper.insertSelective(req);
+		
+		dic.setValue(curCode);
+		dictionaryMapper.updateByPrimaryKey(dic);
+//		UserAddReq userReq = new UserAddReq();
+//		userReq.setUsername(curCode);
+//		List<String> roleIds = new ArrayList<String>();
+//		roleIds.add(CommonConstant.ROLE_USER); //添加用户角色
+//		userReq.setRoleIds(roleIds);
+//		Result result = userService.add(userReq);
+//		return result;
+		return Result.success();
+	}
+	
+	/**
+	 * @title 添加医院
+	 * @param req
+	 * @return ResultData<Hospital>
+	 */
+	@Transactional
+	public ResultData<Hospital> addBack(Hospital req) {
+		Date date = new Date();
+		Dictionary dic = dictionaryMapper.selectByPrimaryKey("hospitalCode");
+		String maxCode = dic.getValue();
+		int code = Integer.parseInt(maxCode);
+		code++;
+		if(code>9999) {
+			return ResultData.fail(null,"医院编码超出范围");
+		}
+		String curCode = String.format("%04d", code);
+		Hospital record = hospitalMapper.selectByCode(curCode);
+		if(record != null) {
+			return ResultData.fail(null,"医院编码已存在");
+		}
+		Hospital hos = hospitalMapper.selectByPrimaryKey(req.getId());
+		if(hos!=null) {
+			return ResultData.failNull("医院已存在");
+		}
+//		req.setId(UUIDUtil.get32UUID());
+		req.setCode(curCode);
+		req.setCreatetime(date);
+		hospitalMapper.insertSelective(req);
+		
+		dic.setValue(curCode);
+		dictionaryMapper.updateByPrimaryKey(dic);
+//		UserAddReq userReq = new UserAddReq();
+//		userReq.setUsername(curCode);
+//		List<String> roleIds = new ArrayList<String>();
+//		roleIds.add(CommonConstant.ROLE_USER); //添加用户角色
+//		userReq.setRoleIds(roleIds);
+//		userService.add(userReq);
+		return ResultData.success(req);
+	}
+	
+	/**
+	 * @title 修改医院
+	 * @param req
+	 * @return
+	 */
+	public Result edit(Hospital req) {
+		Date date = new Date();
+		if(StringUtils.isEmpty(req.getId())) {
+			return Result.fail(CommonConstant.LACK_PARAM);
+		}
+		req.setCode(null); //编码不可修改
+		req.setModifytime(date);
+		hospitalMapper.updateByPrimaryKeySelective(req);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 删除医院
+	 * @param id
+	 * @return
+	 */
+	public Result delete(String id) {
+		hospitalMapper.deleteByPrimaryKey(id);
+		return Result.success();
+	}
+	
+	public String localtion() {
+		HttpHeaders headers = new HttpHeaders();
+	    headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+	    
+	    MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
+	    map.add("mcc", "460");
+	    map.add("mnc", "0");
+	    map.add("lac","21133");
+	    map.add("ci","52365");
+	    map.add("hex","10");
+	    
+	    HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(map, headers);
+	    
+		String result = restTemplate.postForObject("http://bs.openluat.com/get_gps", request, String.class);
+		System.out.println("result========="+result);
+		JSONObject json = JSONObject.parseObject(result);
+		if(json.containsKey("result")) {
+			return json.getString("result");
+		}
+		return "";
+	}
+
+}

+ 35 - 0
src/main/java/com/tuoren/forward/service/LogService.java

@@ -0,0 +1,35 @@
+package com.tuoren.forward.service;
+
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.tuoren.forward.entity.Log;
+import com.tuoren.forward.entity.dto.LogDto;
+import com.tuoren.forward.entity.req.LogSearchReq;
+import com.tuoren.forward.mapper.LogMapper;
+import com.tuoren.forward.util.ResultPage;
+
+@Service
+public class LogService {
+
+	@Autowired
+	LogMapper logMapper;
+	
+	/**
+	 * @title 查询日志
+	 * @param req
+	 * @return ResultPage<Log>
+	 */
+	public ResultPage<Log> search(LogSearchReq req){
+		Page<Object> page = PageHelper.startPage(req.getPage(), req.getSize());
+		LogDto dto = new LogDto();
+		BeanUtils.copyProperties(req, dto);
+		List<Log> logs = logMapper.select(dto);
+		return ResultPage.success(logs, page.getTotal());
+	}
+}

+ 81 - 0
src/main/java/com/tuoren/forward/service/ModelService.java

@@ -0,0 +1,81 @@
+package com.tuoren.forward.service;
+
+import java.util.List;
+
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.github.pagehelper.Page;
+import com.github.pagehelper.PageHelper;
+import com.tuoren.forward.entity.Model;
+import com.tuoren.forward.entity.dto.ModelDto;
+import com.tuoren.forward.entity.req.ModelSearchReq;
+import com.tuoren.forward.mapper.ModelMapper;
+import com.tuoren.forward.util.AccessTokenUtil;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultPage;
+import com.tuoren.forward.util.UUIDUtil;
+
+@Service
+public class ModelService {
+
+	@Autowired
+	ModelMapper modelMapper;
+	
+	/**
+	 * @title 查询产品模型数据
+	 * @param req
+	 * @return ResultPage<Model>
+	 */
+	public ResultPage<Model> search(ModelSearchReq req){
+		Page<Object> page = PageHelper.startPage(req.getPage(), req.getSize());
+		ModelDto dto = new ModelDto();
+		BeanUtils.copyProperties(req, dto);
+		List<Model> models = modelMapper.select(dto);
+		return ResultPage.success(models,page.getTotal());
+	}
+	
+	/**
+	 * @title 添加模型
+	 * @param req
+	 * @return Result
+	 */
+	public Result add(Model req) {
+		String userId = AccessTokenUtil.getUserId();
+		Model exist = modelMapper.selectByTitle(req.getTitle());
+		if(exist != null) {
+			return Result.fail("模型数据存在");
+		}
+		req.setId(UUIDUtil.get32UUID());
+		req.setTenantId(userId);
+		modelMapper.insertSelective(req);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 修改模型
+	 * @param req
+	 * @return Result
+	 */
+	public Result edit(Model req) {
+		Model exist = modelMapper.selectByTitle(req.getTitle());
+		if(exist != null && !exist.getId().equals(req.getId())) {
+			return Result.fail("模型数据存在");
+		}
+		req.setProductId(null);
+		req.setTenantId(null);
+		modelMapper.updateByPrimaryKeySelective(req);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 删除模型
+	 * @param req
+	 * @return Result
+	 */
+	public Result delete(String id) {
+		modelMapper.deleteByPrimaryKey(id);
+		return Result.success();
+	}
+}

+ 126 - 0
src/main/java/com/tuoren/forward/service/PermissionService.java

@@ -0,0 +1,126 @@
+package com.tuoren.forward.service;
+
+import java.util.List;
+
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import com.tuoren.forward.entity.Permission;
+import com.tuoren.forward.entity.User;
+import com.tuoren.forward.mapper.PermissionMapper;
+import com.tuoren.forward.util.AccessTokenUtil;
+import com.tuoren.forward.util.Result;
+import com.tuoren.forward.util.ResultData;
+
+@Service
+public class PermissionService {
+
+	public static final String PERMISSON_TYPE_MAINMENU = "01";
+	public static final String PERMISSON_TYPE_SUBMENU = "02";
+	public static final String PERMISSON_TYPE_BUTTON = "03";
+	
+	public static final String PERMISSION_EXIST = "资源已存在";
+	public static final String CHILDREN_PERMISSION_EXIST = "存在子功能";
+	
+	public static final Integer MAINMENU_PID = 0;
+	
+	@Autowired
+	PermissionMapper permissionMapper;
+	
+	/**
+	 * @title 列出所有资源 
+	 * @return
+	 */
+	public ResultData<List<Permission>> list(){
+		List<Permission> pers = permissionMapper.selectAll();
+		return ResultData.success(pers);
+	}
+	
+	/**
+	 * @title 列出角色下资源
+	 * @param roleId
+	 * @return ResultData
+	 */
+	public ResultData<List<Permission>> listByRoleId(String roleId){
+		List<Permission> persmissions = permissionMapper.selectByRoleId(roleId);
+		return ResultData.success(persmissions);
+	}
+	
+	/**
+	 * @title 列出当前用户资源
+	 * @param roleId
+	 * @return ResultData
+	 */
+	public ResultData<List<Permission>> listUserPermission(){
+		User user = AccessTokenUtil.getUser();
+		List<Permission> persmissions = permissionMapper.selectByUserId(user.getId());
+		return ResultData.success(persmissions);
+	}
+	
+	/**
+	 * @title 添加资源 
+	 * @param req
+	 * @return
+	 */
+	public Result add(Permission req) {
+		// TODO Auto-generated method stub
+		if(PERMISSON_TYPE_MAINMENU.equals(req.getType())) {
+			req.setPid(MAINMENU_PID);
+		}else {
+			Permission existP = permissionMapper.selectByUrl(req.getUrl());
+			if(existP != null) {
+				return  Result.fail(PERMISSION_EXIST);
+			}
+		}
+		
+		if(!StringUtils.isEmpty(req.getTitle())) {
+			Permission exist = permissionMapper.selectByTitle(req.getTitle());
+			if(exist != null &&!exist.getId().equals(req.getId()) ) {
+				return  Result.fail(PERMISSION_EXIST);
+			}
+		}
+		permissionMapper.insertSelective(req);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 修改资源
+	 * @param req
+	 * @return Result
+	 */
+	public Result edit(Permission req) {
+		// TODO Auto-generated method stub
+		if(!StringUtils.isEmpty(req.getUrl())) {
+			Permission exist = permissionMapper.selectByUrl(req.getUrl());
+			if(exist != null &&!exist.getId().equals(req.getId()) ) {
+				return  Result.fail(PERMISSION_EXIST);
+			}
+		}
+		if(!StringUtils.isEmpty(req.getTitle())) {
+			Permission exist = permissionMapper.selectByTitle(req.getTitle());
+			if(exist != null &&!exist.getId().equals(req.getId()) ) {
+				return  Result.fail(PERMISSION_EXIST);
+			}
+		}
+		permissionMapper.updateByPrimaryKeySelective(req);
+		return Result.success();
+	}
+	
+	/**
+	 * @title 删除资源 
+	 * @param id
+	 * @return Result
+	 */
+	public Result delete(Integer id) {
+		// TODO Auto-generated method stub
+		Permission req = new Permission();
+		req.setPid(id);
+		List<Permission> children = permissionMapper.select(req);
+		if(children != null && children.size() > 0) {
+			return Result.fail(CHILDREN_PERMISSION_EXIST);
+		}
+		permissionMapper.deleteByPrimaryKey(id);
+		return Result.success();
+	}
+}

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