chenyi406 преди 3 години
ревизия
4c15c013ff
променени са 100 файла, в които са добавени 5069 реда и са изтрити 0 реда
  1. 32 0
      .gitignore
  2. 129 0
      pom.xml
  3. 13 0
      src/main/java/com/zy/omp/OMPApplication.java
  4. 63 0
      src/main/java/com/zy/omp/common/Constant.java
  5. 50 0
      src/main/java/com/zy/omp/common/ServerResponse.java
  6. 35 0
      src/main/java/com/zy/omp/common/controller/BaseController.java
  7. 21 0
      src/main/java/com/zy/omp/common/controller/CommonController.java
  8. 34 0
      src/main/java/com/zy/omp/common/controller/ExceptionController.java
  9. 18 0
      src/main/java/com/zy/omp/common/enums/ResponseCode.java
  10. 23 0
      src/main/java/com/zy/omp/common/exception/ApiRuntimeException.java
  11. 43 0
      src/main/java/com/zy/omp/common/redis/DeviceLatestLocationManager.java
  12. 59 0
      src/main/java/com/zy/omp/common/redis/SessionManager.java
  13. 52 0
      src/main/java/com/zy/omp/config/BeanConfig.java
  14. 51 0
      src/main/java/com/zy/omp/config/InterceptorConfig.java
  15. 28 0
      src/main/java/com/zy/omp/config/WebMvcConfig.java
  16. 31 0
      src/main/java/com/zy/omp/config/interceptor/AuthInterceptor.java
  17. 29 0
      src/main/java/com/zy/omp/config/interceptor/VerifyInterceptor.java
  18. 229 0
      src/main/java/com/zy/omp/config/mqtt/MqttCallbackHandler.java
  19. 56 0
      src/main/java/com/zy/omp/config/mqtt/MqttConfig.java
  20. 80 0
      src/main/java/com/zy/omp/config/mqtt/MqttConsumerCfg.java
  21. 21 0
      src/main/java/com/zy/omp/config/mqtt/MqttGateway.java
  22. 48 0
      src/main/java/com/zy/omp/config/mqtt/MqttProducerCfg.java
  23. 58 0
      src/main/java/com/zy/omp/controller/pc/AdminController.java
  24. 41 0
      src/main/java/com/zy/omp/controller/pc/PcDeviceController.java
  25. 31 0
      src/main/java/com/zy/omp/controller/pc/PcLocationController.java
  26. 60 0
      src/main/java/com/zy/omp/controller/pc/PcMqttLogController.java
  27. 92 0
      src/main/java/com/zy/omp/controller/pc/PcSetController.java
  28. 32 0
      src/main/java/com/zy/omp/controller/pc/PcUserController.java
  29. 95 0
      src/main/java/com/zy/omp/controller/wx/DeviceController.java
  30. 19 0
      src/main/java/com/zy/omp/controller/wx/DeviceLpController.java
  31. 54 0
      src/main/java/com/zy/omp/controller/wx/IdiomsController.java
  32. 41 0
      src/main/java/com/zy/omp/controller/wx/LocationController.java
  33. 94 0
      src/main/java/com/zy/omp/controller/wx/SetController.java
  34. 80 0
      src/main/java/com/zy/omp/controller/wx/SetInfoController.java
  35. 41 0
      src/main/java/com/zy/omp/controller/wx/UserController.java
  36. 18 0
      src/main/java/com/zy/omp/mapper/AdminMapper.java
  37. 27 0
      src/main/java/com/zy/omp/mapper/CallRecordsMapper.java
  38. 33 0
      src/main/java/com/zy/omp/mapper/DeviceDynamicMapper.java
  39. 20 0
      src/main/java/com/zy/omp/mapper/DeviceLpMapper.java
  40. 35 0
      src/main/java/com/zy/omp/mapper/DeviceMapper.java
  41. 18 0
      src/main/java/com/zy/omp/mapper/IdiomsMapper.java
  42. 25 0
      src/main/java/com/zy/omp/mapper/LatestLocationMapper.java
  43. 17 0
      src/main/java/com/zy/omp/mapper/LocationMapper.java
  44. 28 0
      src/main/java/com/zy/omp/mapper/MqttLogMapper.java
  45. 27 0
      src/main/java/com/zy/omp/mapper/NewsMapper.java
  46. 18 0
      src/main/java/com/zy/omp/mapper/SetBaseMapper.java
  47. 27 0
      src/main/java/com/zy/omp/mapper/UserMapper.java
  48. 41 0
      src/main/java/com/zy/omp/model/Admin.java
  49. 48 0
      src/main/java/com/zy/omp/model/CallRecords.java
  50. 52 0
      src/main/java/com/zy/omp/model/Device.java
  51. 52 0
      src/main/java/com/zy/omp/model/DeviceDynamic.java
  52. 126 0
      src/main/java/com/zy/omp/model/DeviceLp.java
  53. 84 0
      src/main/java/com/zy/omp/model/LatestLocation.java
  54. 83 0
      src/main/java/com/zy/omp/model/Location.java
  55. 50 0
      src/main/java/com/zy/omp/model/MqttLog.java
  56. 49 0
      src/main/java/com/zy/omp/model/News.java
  57. 83 0
      src/main/java/com/zy/omp/model/SetBase.java
  58. 69 0
      src/main/java/com/zy/omp/model/User.java
  59. 29 0
      src/main/java/com/zy/omp/model/UserIdioms.java
  60. 120 0
      src/main/java/com/zy/omp/pojo/dto/MqttMsgDto.java
  61. 26 0
      src/main/java/com/zy/omp/pojo/io/CallRecordsIO.java
  62. 26 0
      src/main/java/com/zy/omp/pojo/io/NewsIO.java
  63. 36 0
      src/main/java/com/zy/omp/pojo/io/PageIO.java
  64. 22 0
      src/main/java/com/zy/omp/pojo/io/pc/DeviceIO.java
  65. 29 0
      src/main/java/com/zy/omp/pojo/io/pc/MqttLogsIO.java
  66. 23 0
      src/main/java/com/zy/omp/pojo/io/pc/UserIO.java
  67. 26 0
      src/main/java/com/zy/omp/pojo/io/wechat/DeviceHistoryIO.java
  68. 104 0
      src/main/java/com/zy/omp/pojo/io/wechat/SetIO.java
  69. 47 0
      src/main/java/com/zy/omp/pojo/vo/AdminListVo.java
  70. 88 0
      src/main/java/com/zy/omp/pojo/vo/DeviceFullDataVo.java
  71. 49 0
      src/main/java/com/zy/omp/schedule/DeviceStatusSchedule.java
  72. 35 0
      src/main/java/com/zy/omp/service/AdminService.java
  73. 29 0
      src/main/java/com/zy/omp/service/CallRecordsService.java
  74. 61 0
      src/main/java/com/zy/omp/service/DeviceDynamicService.java
  75. 38 0
      src/main/java/com/zy/omp/service/DeviceLpService.java
  76. 62 0
      src/main/java/com/zy/omp/service/DeviceService.java
  77. 68 0
      src/main/java/com/zy/omp/service/IdiomsService.java
  78. 26 0
      src/main/java/com/zy/omp/service/LatestLocationService.java
  79. 65 0
      src/main/java/com/zy/omp/service/LocationService.java
  80. 54 0
      src/main/java/com/zy/omp/service/MqttLogService.java
  81. 26 0
      src/main/java/com/zy/omp/service/NewsService.java
  82. 122 0
      src/main/java/com/zy/omp/service/RabbitMQApi.java
  83. 73 0
      src/main/java/com/zy/omp/service/SetBaseService.java
  84. 174 0
      src/main/java/com/zy/omp/service/SetService.java
  85. 61 0
      src/main/java/com/zy/omp/service/UserService.java
  86. 74 0
      src/main/java/com/zy/omp/utils/AesUtils.java
  87. 22 0
      src/main/java/com/zy/omp/utils/BeanUtil.java
  88. 41 0
      src/main/java/com/zy/omp/utils/CodeGenerator.java
  89. 153 0
      src/main/java/com/zy/omp/utils/CoordTransformUtil.java
  90. 24 0
      src/main/java/com/zy/omp/utils/DateTimeUtil.java
  91. 33 0
      src/main/java/com/zy/omp/utils/GaoDeApiUtil.java
  92. 72 0
      src/main/java/com/zy/omp/utils/HttpUtil.java
  93. 35 0
      src/main/java/com/zy/omp/utils/MD5Util.java
  94. 76 0
      src/main/java/com/zy/omp/websocket/WebSocketServer.java
  95. 32 0
      src/main/resources/application-dev.yml
  96. 33 0
      src/main/resources/application-prod.yml
  97. 3 0
      src/main/resources/application.yml
  98. 22 0
      src/main/resources/mapper/CallRecordsMapping.xml
  99. 12 0
      src/main/resources/mapper/DeviceDynamicMapping.xml
  100. 5 0
      src/main/resources/mapper/DeviceLpMapper.xml

+ 32 - 0
.gitignore

@@ -0,0 +1,32 @@
+HELP.md
+target/
+!.mvn/wrapper/maven-wrapper.jar
+!**/src/main/**
+!**/src/test/**
+
+### STS ###
+.apt_generated
+.classpath
+.factorypath
+.project
+.settings
+.springBeans
+.sts4-cache
+
+### IntelliJ IDEA ###
+.idea
+*.iws
+*.iml
+*.ipr
+
+### NetBeans ###
+/nbproject/private/
+/nbbuild/
+/dist/
+/nbdist/
+/.nb-gradle/
+build/
+
+### VS Code ###
+.vscode/
+/web/node_modules/

+ 129 - 0
pom.xml

@@ -0,0 +1,129 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.springframework.boot</groupId>
+        <artifactId>spring-boot-starter-parent</artifactId>
+        <version>2.1.0.RELEASE</version>
+        <relativePath/> <!-- lookup parent from repository -->
+    </parent>
+    <groupId>com.zhiyun.mqtt</groupId>
+    <artifactId>bms</artifactId>
+    <version>0.0.1-SNAPSHOT</version>
+    <name>omp-java</name>
+    <description>老人机定位项目</description>
+
+    <properties>
+        <java.version>1.8</java.version>
+    </properties>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-aop</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.projectlombok</groupId>
+            <artifactId>lombok</artifactId>
+            <optional>true</optional>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-test</artifactId>
+            <scope>test</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-data-redis</artifactId>
+        </dependency>
+
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-web</artifactId>
+        </dependency>
+
+        <!-- websocket -->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-websocket</artifactId>
+        </dependency>
+
+        <!--MQTT-->
+        <dependency>
+            <groupId>org.springframework.boot</groupId>
+            <artifactId>spring-boot-starter-integration</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.integration</groupId>
+            <artifactId>spring-integration-stream</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.springframework.integration</groupId>
+            <artifactId>spring-integration-mqtt</artifactId>
+        </dependency>
+
+        <!--mybatis-plus-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-boot-starter</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+
+        <!-- Mybatis-plus 代码生成器-->
+        <dependency>
+            <groupId>com.baomidou</groupId>
+            <artifactId>mybatis-plus-generator</artifactId>
+            <version>3.4.0</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.freemarker</groupId>
+            <artifactId>freemarker</artifactId>
+            <version>2.3.30</version>
+        </dependency>
+
+        <dependency>
+            <groupId>mysql</groupId>
+            <artifactId>mysql-connector-java</artifactId>
+            <version>8.0.19</version>
+            <scope>runtime</scope>
+        </dependency>
+
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>fastjson</artifactId>
+            <version>1.2.28</version>
+        </dependency>
+
+        <!--阿里druid数据库连接池-->
+        <dependency>
+            <groupId>com.alibaba</groupId>
+            <artifactId>druid</artifactId>
+            <version>1.1.21</version>
+        </dependency>
+
+        <dependency>
+            <groupId>com.github.dozermapper</groupId>
+            <artifactId>dozer-core</artifactId>
+            <version>6.5.0</version>
+        </dependency>
+
+    </dependencies>
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.springframework.boot</groupId>
+                <artifactId>spring-boot-maven-plugin</artifactId>
+            </plugin>
+        </plugins>
+    </build>
+</project>

+ 13 - 0
src/main/java/com/zy/omp/OMPApplication.java

@@ -0,0 +1,13 @@
+package com.zy.omp;
+
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+
+@SpringBootApplication
+public class OMPApplication {
+
+    public static void main(String[] args) {
+        SpringApplication.run(OMPApplication.class, args);
+    }
+
+}

+ 63 - 0
src/main/java/com/zy/omp/common/Constant.java

@@ -0,0 +1,63 @@
+package com.zy.omp.common;
+
+/**
+ * 常量
+ *
+ * @author yang xiao kun
+ * create on 2021/2/2
+ */
+public class Constant {
+
+
+    public static final String OLD_PHONE_DEVICE_ID_PREFIX = "omp_";//老人机项目设备注册MQTT用户名前缀
+    public static final String LP_DEVICE_ID_PREFIX = "IMEI";//路牌项目设备注册MQTT用户名前缀
+
+    /**
+     * redis key前缀
+     */
+    public static final String REDIS_LOCATION = "omp:device:location";//数据上传位置信息前缀
+    public static final String REDIS_TOKEN_PREFIX = "omp:user:token:";//PC管理员登录token 前缀
+
+    /**
+     * MQTT 协议报文 中 M值
+     */
+    public static final String M_CODE_REGISTER = "10";//注册
+    public static final String M_CODE_RETURN_CODE = "11";//返回授权码
+    public static final String M_CODE_UPLOAD_LOCATION = "20";//设备上传位置信息
+    public static final String M_CODE_GPS_RATE = "31";//定位频率
+    public static final String M_CODE_SOS = "33";//紧急呼救
+    public static final String M_CODE_VOLUME = "34";//音量
+    public static final String M_CODE_AUTO_ANSWER = "36";//自动接听
+    public static final String M_CODE_NEWS = "39";//语音播报
+    public static final String M_CODE_UPLOAD_CALL_RECORD = "40";//设备上传通话记录
+    public static final String M_CODE_CONTINUE_GPS = "41";//设备连续定位设置
+
+    public static final String M_CODE_UPLOAD_INFO_LP = "70";//路牌设备上传信息
+    public static final String M_CODE_UPDATE_DEVICE_INFO_LP = "71";//同步更新路牌设备信息
+
+
+    /**
+     * 主题前缀
+     * SERVER为服务器订阅主题  用来接收设备发来消息
+     * CLIENT为设备订阅主题    用来发送消息给设备
+     */
+    public static final String TOPIC_REGISTER_SERVER = "$regdtx";
+    public static final String TOPIC_REGISTER_CLIENT = "$regdrx";
+    public static final String TOPIC_DEVICE_SERVER = "$dtx/";
+    public static final String TOPIC_DEVICE_CLIENT = "$drx/";
+
+    /**
+     * 路牌
+     */
+    public static final String TOPIC_REGISTER_SERVER_LP = "$regdtx2";
+    public static final String TOPIC_REGISTER_CLIENT_LP = "$regdrx2";
+    public static final String TOPIC_DEVICE_SERVER_LP = "$dtxlp/";
+    public static final String TOPIC_DEVICE_CLIENT_LP = "$drxlp/IMEI";
+
+    /**
+     * 微信小程序登录相关配置
+     */
+    public static final String wxAppId = "wxe90699b45e28a0b6";// 小程序唯一标识
+    public static final String wxSecret = "66690a1ffcfe7f1d85a6dcfa38791f25";//小程序的 app secret
+    public static final String grant_type = "authorization_code"; // 授权(必填)
+}

+ 50 - 0
src/main/java/com/zy/omp/common/ServerResponse.java

@@ -0,0 +1,50 @@
+package com.zy.omp.common;
+
+import com.fasterxml.jackson.databind.annotation.JsonSerialize;
+import com.zy.omp.common.enums.ResponseCode;
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 接口数据返回定义类
+ */
+@Data
+@JsonSerialize
+public class ServerResponse implements Serializable {
+    //接口返回状态
+    private Integer status;
+    //返回提示信息
+    private String msg;
+    //返回的数据
+    private Object data;
+
+    /**
+     * 根据成功与否及是否需要返回data提供的各种静态构造方法
+     */
+    public static ServerResponse createBySuccess() {
+        return new ServerResponse(ResponseCode.SUCCESS.code, null, ResponseCode.SUCCESS.msg);
+    }
+
+    public static ServerResponse createBySuccess(Object data) {
+        return new ServerResponse(ResponseCode.SUCCESS.code, data, ResponseCode.SUCCESS.msg);
+    }
+
+    public static ServerResponse createByError() {
+        return new ServerResponse(ResponseCode.ERROR.code, null, ResponseCode.ERROR.msg);
+    }
+
+    public static ServerResponse createByWarning(String msg) {
+        return new ServerResponse(ResponseCode.WARNING.code, null, msg);
+    }
+
+    public static ServerResponse createByAuthor() {
+        return new ServerResponse(ResponseCode.AUTHOR.code, null, ResponseCode.AUTHOR.msg);
+    }
+
+    private ServerResponse(int status, Object data, String msg) {
+        this.status = status;
+        this.msg = msg;
+        this.data = data;
+    }
+}

+ 35 - 0
src/main/java/com/zy/omp/common/controller/BaseController.java

@@ -0,0 +1,35 @@
+package com.zy.omp.common.controller;
+
+import com.zy.omp.common.exception.ApiRuntimeException;
+import com.zy.omp.utils.AesUtils;
+import org.springframework.stereotype.Component;
+import org.springframework.web.bind.annotation.ModelAttribute;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * controller公共类提出
+ *
+ * @author chenyi
+ * date: create on 2019/6/8
+ */
+@Component
+public class BaseController {
+    private HttpServletRequest request;
+
+    //获取登录信息
+    @ModelAttribute
+    public void setModelAttribute(HttpServletRequest request) {
+        this.request = request;
+    }
+
+    /**
+     * 微信小程序
+     * 获取用户ID
+     */
+    public String getUserId() {
+        String userId = AesUtils.decrypt(request.getHeader("user"));
+        if (userId == null) throw new ApiRuntimeException("未登录");
+        return userId;
+    }
+}

+ 21 - 0
src/main/java/com/zy/omp/common/controller/CommonController.java

@@ -0,0 +1,21 @@
+package com.zy.omp.common.controller;
+
+import com.zy.omp.common.ServerResponse;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * 通用 Controller
+ *
+ * @author yang xiao kun
+ * create on 2021/4/7
+ */
+@RestController
+@RequestMapping("common")
+public class CommonController {
+
+    @RequestMapping("author.do")
+    public ServerResponse author() {
+        return ServerResponse.createByAuthor();
+    }
+}

+ 34 - 0
src/main/java/com/zy/omp/common/controller/ExceptionController.java

@@ -0,0 +1,34 @@
+package com.zy.omp.common.controller;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.exception.ApiRuntimeException;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.RestControllerAdvice;
+import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
+
+
+/**
+ * 全局异常拦截
+ *
+ * @author chenyi
+ * Create on 2019/10/21
+ */
+@RestControllerAdvice
+public class ExceptionController {
+
+    /**
+     * 对参数类型不匹配异常做统一拦截处理
+     */
+    @ExceptionHandler(value = MethodArgumentTypeMismatchException.class)
+    public ServerResponse MethodArgumentTypeMismatchExceptionHandler() {
+        return ServerResponse.createByError();
+    }
+
+    /**
+     * 对运行时异常拦截
+     */
+    @ExceptionHandler(value = ApiRuntimeException.class)
+    public ServerResponse ApiRuntimeExceptionHandler() {
+        return ServerResponse.createByError();
+    }
+}

+ 18 - 0
src/main/java/com/zy/omp/common/enums/ResponseCode.java

@@ -0,0 +1,18 @@
+package com.zy.omp.common.enums;
+
+/**
+ * 接口返回常量
+ */
+public enum ResponseCode {
+    SUCCESS(200, "Success"),//成功
+    WARNING(300, "Warning"),//警告,不进入成功回调函数,直接alert
+    AUTHOR(401, "Forbidden"),//没有权限,跳转登录
+    ERROR(500, "Error");//服务器异常
+    public final int code;
+    public final String msg;
+
+    ResponseCode(int code, String msg) {
+        this.code = code;
+        this.msg = msg;
+    }
+}

+ 23 - 0
src/main/java/com/zy/omp/common/exception/ApiRuntimeException.java

@@ -0,0 +1,23 @@
+package com.zy.omp.common.exception;
+
+/**
+ * 运行时异常
+ *
+ * @author yang xiao kun
+ * create on 2021/1/5
+ */
+public class ApiRuntimeException extends RuntimeException {
+    /**
+     * 错误信息
+     */
+    private String msg;
+
+    public ApiRuntimeException(String msg) {
+        this.msg = msg;
+    }
+
+    @Override
+    public String getMessage() {
+        return msg;
+    }
+}

+ 43 - 0
src/main/java/com/zy/omp/common/redis/DeviceLatestLocationManager.java

@@ -0,0 +1,43 @@
+package com.zy.omp.common.redis;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.omp.common.Constant;
+import com.zy.omp.model.Location;
+import org.springframework.data.redis.core.RedisTemplate;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备最新的位置信息,存储在Redis缓存中
+ * 弃用
+ *
+ * @author yang xiao kun
+ * create on 2021/2/8
+ */
+//@Component
+@Deprecated
+public class DeviceLatestLocationManager {
+
+    @Resource
+    private RedisTemplate<String, String> redisTemplate;
+
+    /**
+     * 将最新位置信息保存至redis中
+     *
+     * @param entity 位置信息
+     */
+    public void saveLocation(Location entity) {
+        redisTemplate.boundHashOps(Constant.REDIS_LOCATION).put(entity.getDeviceId(), JSON.toJSONString(entity));
+    }
+
+    /**
+     * 获取设备最新位置信息
+     *
+     * @param deviceId 设备ID
+     */
+    public Location getLocation(String deviceId) {
+        Object json = redisTemplate.boundHashOps(Constant.REDIS_LOCATION).get(deviceId);
+        if (json == null) return null;
+        return JSON.parseObject(json.toString(), Location.class);
+    }
+}

+ 59 - 0
src/main/java/com/zy/omp/common/redis/SessionManager.java

@@ -0,0 +1,59 @@
+package com.zy.omp.common.redis;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.omp.common.Constant;
+import com.zy.omp.model.Admin;
+import com.zy.omp.utils.CodeGenerator;
+import org.springframework.data.redis.core.StringRedisTemplate;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.concurrent.TimeUnit;
+
+/**
+ * 用户登录Session
+ *
+ * @author chenyi
+ * Create on 2020/4/3
+ */
+@Component
+public class SessionManager {
+
+    @Resource
+    private StringRedisTemplate stringRedisTemplate;
+
+    /**
+     * 生成token
+     */
+    public String generateToken(Admin admin) {
+        String token = CodeGenerator.generateUUID();
+        stringRedisTemplate.opsForValue()
+                .set(Constant.REDIS_TOKEN_PREFIX + token, JSON.toJSONString(admin), 30, TimeUnit.MINUTES);
+        return token;
+    }
+
+    /**
+     * 删除Token
+     */
+    public void removeToken(String token) {
+        if (token == null) return;
+        stringRedisTemplate.delete(Constant.REDIS_TOKEN_PREFIX + token);
+    }
+
+    /**
+     * 获取登录的用户信息
+     */
+    public Admin getUser(String token) {
+        if (token == null) return null;
+        return JSON.parseObject(stringRedisTemplate.opsForValue().get(Constant.REDIS_TOKEN_PREFIX + token), Admin.class);
+    }
+
+    /**
+     * 验证token有效
+     */
+    public boolean valid(String token) {
+        if (token == null || getUser(token) == null) return false;
+        stringRedisTemplate.expire(Constant.REDIS_TOKEN_PREFIX + token, 30, TimeUnit.MINUTES);
+        return true;
+    }
+}

+ 52 - 0
src/main/java/com/zy/omp/config/BeanConfig.java

@@ -0,0 +1,52 @@
+package com.zy.omp.config;
+
+import com.baomidou.mybatisplus.annotation.DbType;
+import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor;
+import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor;
+import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
+import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.web.socket.server.standard.ServerEndpointExporter;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * @author yang xiao kun
+ * create on 2021/2/4
+ */
+@Configuration
+public class BeanConfig {
+    /**
+     * mybatis-plus分页插件
+     */
+    @Bean
+    public MybatisPlusInterceptor mybatisPlusInterceptor() {
+        MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+        //向Mybatis过滤器链中添加分页拦截器
+        interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL));
+        //还可以添加i他的拦截器
+        return interceptor;
+    }
+
+    /**
+     * LocalDateTime 全局格式化配置
+     */
+    @Bean
+    public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() {
+        return builder -> builder.serializerByType(LocalDateTime.class,
+                new LocalDateTimeSerializer(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss")));
+    }
+
+    /**
+     * WebSocket
+     * <p>
+     * ServerEndpointExporter 作用
+     * 这个Bean会自动注册使用@ServerEndpoint注解声明的websocket endpoint
+     */
+    @Bean
+    public ServerEndpointExporter serverEndpointExporter() {
+        return new ServerEndpointExporter();
+    }
+}

+ 51 - 0
src/main/java/com/zy/omp/config/InterceptorConfig.java

@@ -0,0 +1,51 @@
+package com.zy.omp.config;
+
+import com.zy.omp.config.interceptor.AuthInterceptor;
+import com.zy.omp.config.interceptor.VerifyInterceptor;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import javax.annotation.Resource;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 配置拦截器
+ *
+ * @author chenyi
+ * Create on 2019/10/10
+ */
+@Profile("prod")
+@Configuration
+public class InterceptorConfig implements WebMvcConfigurer {
+    /**
+     * 身份验证拦截器
+     */
+    @Resource
+    private VerifyInterceptor verifyInterceptor;
+    @Resource
+    private AuthInterceptor authInterceptor;
+
+    private static List<String> whiteList = new ArrayList<>();
+
+    static {
+        whiteList.add("omp/api/pc/admin/login.do");
+        whiteList.add("/common/**");
+    }
+
+    /**
+     * 添加自定义拦截器
+     */
+    @Override
+    public void addInterceptors(InterceptorRegistry registry) {
+        registry.addInterceptor(verifyInterceptor)
+                .addPathPatterns("omp/api/pc/**")
+                .excludePathPatterns("/common/**");
+
+        registry.addInterceptor(authInterceptor)
+                .addPathPatterns("omp/api/pc/**")
+                .excludePathPatterns(whiteList);
+    }
+}

+ 28 - 0
src/main/java/com/zy/omp/config/WebMvcConfig.java

@@ -0,0 +1,28 @@
+package com.zy.omp.config;
+
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import org.springframework.web.servlet.config.annotation.CorsRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+/**
+ * 解决测试时的跨域,开发环境关掉
+ */
+@Profile("dev")
+@Configuration
+public class WebMvcConfig implements WebMvcConfigurer {
+
+    @Override
+    public void addCorsMappings(CorsRegistry registry) {
+        //设置允许跨域的路径
+        registry.addMapping("/**")
+                //设置允许跨域请求的域名
+                .allowedOrigins("*")
+                //是否允许证书 不再默认开启
+                .allowCredentials(true)
+                //设置允许的方法
+                .allowedMethods("*")
+                //跨域允许时间
+                .maxAge(3600);
+    }
+}

+ 31 - 0
src/main/java/com/zy/omp/config/interceptor/AuthInterceptor.java

@@ -0,0 +1,31 @@
+package com.zy.omp.config.interceptor;
+
+import com.zy.omp.common.redis.SessionManager;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.annotation.Resource;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 登录权限验证拦截器
+ *
+ * @author chenyi
+ * Create on 2019/10/10
+ */
+@Component
+public class AuthInterceptor extends HandlerInterceptorAdapter {
+
+    @Resource
+    private SessionManager sessionManager;
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (!sessionManager.valid(request.getHeader("token"))) {
+            request.getRequestDispatcher("/common/author.do").forward(request, response);
+            return false;
+        }
+        return true;
+    }
+}

+ 29 - 0
src/main/java/com/zy/omp/config/interceptor/VerifyInterceptor.java

@@ -0,0 +1,29 @@
+package com.zy.omp.config.interceptor;
+
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+/**
+ * 身份验证拦截器
+ * 防止第三方请求服务器
+ *
+ * @author chenyi
+ * Create on 2019/10/10
+ */
+@Component
+public class VerifyInterceptor extends HandlerInterceptorAdapter {
+
+    @Override
+    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
+        if (request.getMethod().equals("OPTIONS")) {
+            response.setStatus(HttpServletResponse.SC_OK);
+            return true;
+        }
+        if (request.getHeader("verify") != null && request.getHeader("verify").equals("omp")) return true;
+        request.getRequestDispatcher("/common/author.do").forward(request, response);
+        return false;
+    }
+}

+ 229 - 0
src/main/java/com/zy/omp/config/mqtt/MqttCallbackHandler.java

@@ -0,0 +1,229 @@
+package com.zy.omp.config.mqtt;
+
+import com.zy.omp.common.Constant;
+import com.zy.omp.pojo.dto.MqttMsgDto;
+import com.zy.omp.common.exception.ApiRuntimeException;
+import com.zy.omp.model.*;
+import com.zy.omp.service.*;
+import com.zy.omp.utils.*;
+import com.zy.omp.utils.CoordTransformUtil;
+import com.zy.omp.utils.GaoDeApiUtil;
+import com.zy.omp.websocket.WebSocketServer;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.time.LocalDateTime;
+
+/**
+ * MQTT 消息返回处理类
+ *
+ * @author yang xiao kun
+ * create on 2021/1/19
+ */
+@Component
+public class MqttCallbackHandler {
+
+    @Resource
+    private DeviceService deviceService;
+    @Resource
+    private DeviceLpService deviceLpService;
+    @Resource
+    private SetBaseService setBaseService;
+    @Resource
+    private SetService setService;
+    @Resource
+    private LocationService deviceLocationService;
+    @Resource
+    private WebSocketServer webSocketServer;
+    @Resource
+    private CallRecordsService callRecordsService;
+    @Resource
+    private MqttLogService mqttLogService;
+    @Resource
+    private RabbitMQApi rabbitMQApi;
+
+    /**
+     * 处理消息
+     *
+     * @param topic   主题
+     * @param payload 消息内容
+     */
+    void handle(String topic, String payload) {
+        System.out.println(topic + " -- " + payload);
+        //存储日志-接收
+        mqttLogService.saveLog(topic, payload, 0);
+        //消息返回JSON转Object
+        MqttMsgDto msgDto = MqttMsgDto.parse(payload);
+        //路牌项目
+        if (topic.startsWith("$regdtx2") || topic.startsWith("$dtxlp")) {
+            switch (msgDto.getM()) {
+                //设备端注册报文
+                case Constant.M_CODE_REGISTER: {
+                    registerHandler_LP(msgDto);
+                    break;
+                }
+                // 设备上传信息
+                case Constant.M_CODE_UPLOAD_INFO_LP: {
+                    uploadDeviceInfoLPHandler(topic, msgDto);
+                    break;
+                }
+            }
+        }
+        //老人机项目
+        else {
+            switch (msgDto.getM()) {
+                //设备端注册报文
+                case Constant.M_CODE_REGISTER: {
+                    registerHandler_OMP(msgDto);
+                    break;
+                }
+                // 设备位置信息上报
+                case Constant.M_CODE_UPLOAD_LOCATION: {
+                    uploadLocationHandler(msgDto);
+                    break;
+                }
+                //设备上传通话记录
+                case Constant.M_CODE_UPLOAD_CALL_RECORD: {
+                    uploadCallRecordsHandler(msgDto);
+                    break;
+                }
+            }
+            //转发消息至网页,忽略注册的报文
+            if (!topic.equals(Constant.TOPIC_REGISTER_SERVER)) {
+                webSocketServer.massMessage(msgDto.getDeviceId(), payload);
+            }
+        }
+    }
+
+    /**
+     * 注册设备
+     * 老人机
+     */
+    private void registerHandler_OMP(MqttMsgDto obj) {
+        String num = obj.getString("regnum");
+        //查询数据库中是否有此设备
+        Device device = deviceService.getByNum(num);
+        //没有该设备,保存至数据库
+        if (device == null) {
+            device = new Device();
+            device.setNum(num);
+            device.setClientId(Constant.OLD_PHONE_DEVICE_ID_PREFIX + num);
+            device.setPassword(MD5Util.MD5Encode(num));
+            deviceService.save(device);
+            SetBase setBase = new SetBase();
+            setBase.setDeviceId(device.getClientId());
+            setBaseService.save(setBase);
+        }
+        //mqtt服务器注册用户
+        rabbitMQApi.registerMqtt(device.getClientId(), device.getPassword());
+        //发送消息
+        setService.returnCode_OMP(device);
+    }
+
+    /**
+     * 注册设备
+     * 路牌
+     */
+    private void registerHandler_LP(MqttMsgDto obj) {
+        String num = obj.getString("regnum");
+        //查询数据库中是否有此设备
+        DeviceLp deviceLp = deviceLpService.getByNum(num);
+        //没有该设备,保存至数据库
+        if (deviceLp == null) {
+            deviceLp = new DeviceLp();
+            deviceLp.setNum(num);
+            deviceLp.setClientId(Constant.LP_DEVICE_ID_PREFIX + num);
+            deviceLp.setPassword(MD5Util.MD5Encode(num));
+            deviceLp.setGroup(obj.getString("group"));
+            deviceLpService.save(deviceLp);
+        }
+        //mqtt服务器注册用户
+        rabbitMQApi.registerMqtt(deviceLp.getClientId(), deviceLp.getPassword());
+        //发送消息
+        setService.returnCode_LP(deviceLp);
+    }
+
+    /**
+     * 处理上传位置
+     * 老人机
+     */
+    private void uploadLocationHandler(MqttMsgDto msg) {
+        try {
+            Location location = new Location();
+            location.setDeviceId(msg.getDeviceId());
+            location.setBatteryNum(msg.getInt("batterynum"));
+            location.setSignalNum(msg.getInt("signalnum"));
+            location.setMode(msg.getInt("mode"));
+            location.setLon(msg.getString("lon"));
+            location.setLat(msg.getString("lat"));
+            location.setSpeed(msg.getString("speed"));
+            location.setNum(msg.getInt("num"));
+            location.setUploadTime(msg.getDate("createtime"));
+            //转换后的坐标
+            String[] gcj = CoordTransformUtil.wgs84toGcj02(location.getLon(), location.getLat());
+            location.setLonGcj(gcj[0]);
+            location.setLatGcj(gcj[1]);
+            // 逆地理位置解析
+            location.setSite(GaoDeApiUtil.regeo(location.getLonGcj(), location.getLatGcj()));
+            // 保存位置信息
+            deviceLocationService.saveLocation(location);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ApiRuntimeException("处理设备上传位置定位信息出错");
+        }
+    }
+
+    /**
+     * 处理设备信息上传
+     * 路牌
+     */
+    private void uploadDeviceInfoLPHandler(String topic, MqttMsgDto msg) {
+        try {
+            String num = topic.split("IMEI")[1];
+            //如果远程设备的信息与数据库的信息不一致,则发送消息更新远程信息
+            DeviceLp dbDevice = deviceLpService.getByNum(num);
+            if (!dbDevice.getWakeInt().equals(msg.getInt("wakeint"))
+                    || !dbDevice.getThresh().equals(msg.getDouble("thresh"))) {
+                setService.updateDevice_LP(num, dbDevice.getWakeInt(), dbDevice.getThresh());
+            }
+            DeviceLp deviceLp = new DeviceLp();
+            deviceLp.setBattery(msg.getString("batterynum"));
+            deviceLp.setS4g(msg.getString("s4g"));
+            deviceLp.setX(msg.getString("x"));
+            deviceLp.setY(msg.getString("y"));
+            deviceLp.setZ(msg.getString("z"));
+            deviceLp.setAnglex(msg.getString("anglex"));
+            deviceLp.setAngley(msg.getString("angley"));
+            deviceLp.setAnglez(msg.getString("anglez"));
+            deviceLp.setTemp(msg.getString("temp"));
+            deviceLp.setLng(msg.getString("lng"));
+            deviceLp.setLat(msg.getString("lat"));
+            deviceLp.setUpdateTime(LocalDateTime.now());
+            //转换后的坐标
+            String[] gcj = CoordTransformUtil.wgs84toGcj02(deviceLp.getLng(), deviceLp.getLat());
+            deviceLp.setLngGcj(gcj[0]);
+            deviceLp.setLatGcj(gcj[1]);
+            // 逆地理位置解析
+            deviceLp.setSite(GaoDeApiUtil.regeo(deviceLp.getLngGcj(), deviceLp.getLatGcj()));
+            // 保存位置信息
+            deviceLpService.updateByNum(deviceLp, num);
+        } catch (Exception e) {
+            e.printStackTrace();
+            throw new ApiRuntimeException("处理设备上传位置定位信息出错");
+        }
+    }
+
+    /**
+     * 设备上传通话记录
+     */
+    private void uploadCallRecordsHandler(MqttMsgDto obj) {
+        CallRecords callRecords = new CallRecords();
+        callRecords.setDeviceId(obj.getDeviceId());
+        callRecords.setCallType(obj.getInt("type"));
+        callRecords.setKeyNum(obj.getString("key"));
+        callRecords.setPhoneNum(obj.getString("phnoenum"));
+        callRecords.setTalkTime(obj.getInt("talktime"));
+        callRecords.setEndTime(obj.getString("endtime"));
+        callRecordsService.save(callRecords);
+    }
+}

+ 56 - 0
src/main/java/com/zy/omp/config/mqtt/MqttConfig.java

@@ -0,0 +1,56 @@
+package com.zy.omp.config.mqtt;
+
+import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.mqtt.core.DefaultMqttPahoClientFactory;
+import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
+
+/**
+ * MQTT 配置
+ *
+ * @author yang xiao kun
+ * create on 2021/1/14
+ */
+@Configuration
+public class MqttConfig {
+
+    private static final String username = "lq2019";
+    private static final String password = "LiQuanRabbit";
+    private static final String address = "tcp://view.ailishi.org:1883";
+
+    /**
+     * MQTT连接器配置选项
+     */
+    @Bean
+    public MqttConnectOptions getMqttConnectOptions() {
+        MqttConnectOptions options = new MqttConnectOptions();
+        // 设置是否清空session,这里如果设置为false表示服务器会保留客户端的连接记录,这里设置为true表示每次连接到服务器都以新的身份连接
+        options.setCleanSession(true);
+        // 设置连接的用户名
+        options.setUserName(username);
+        // 设置连接的密码
+        options.setPassword(password.toCharArray());
+        // 连接地址
+        options.setServerURIs(new String[]{address});
+        // 设置超时时间 单位为秒
+        options.setConnectionTimeout(10);
+        // 设置会话心跳时间 单位为秒 服务器会每隔1.5*20秒的时间向客户端发送心跳判断客户端是否在线,但这个方法并没有重连的机制
+        options.setKeepAliveInterval(20);
+        // 设置“遗嘱”消息的话题,若客户端与服务器之间的连接意外中断,服务器将发布客户端的“遗嘱”消息。
+        // options.setWill("willTopic", WILL_DATA, 2, false);
+        // 配置最大不确定接收消息数量,默认值10,qos!=0 时生效
+        // mqttConnectOptions.setMaxInflight(10);
+        return options;
+    }
+
+    /**
+     * MQTT客户端
+     */
+    @Bean
+    public MqttPahoClientFactory mqttClientFactory() {
+        DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory();
+        factory.setConnectionOptions(getMqttConnectOptions());
+        return factory;
+    }
+}

+ 80 - 0
src/main/java/com/zy/omp/config/mqtt/MqttConsumerCfg.java

@@ -0,0 +1,80 @@
+package com.zy.omp.config.mqtt;
+
+import com.zy.omp.utils.CodeGenerator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.core.MessageProducer;
+import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
+import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter;
+import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHandler;
+
+import java.util.Objects;
+
+/**
+ * MQTT 服务 消费者配置
+ *
+ * @author yang xiao kun
+ * create on 2021/1/19
+ */
+@Configuration
+public class MqttConsumerCfg {
+
+    @Autowired
+    private MqttCallbackHandler mqttCallbackHandler;
+
+    @Autowired
+    private MqttPahoClientFactory mqttClientFactory;
+
+    //默认监听主题
+    private final String[] defaultTopic = new String[]{"$regdtx", "$dtx/#","$regdtx2","$dtxlp/#"};
+
+    /**
+     * MQTT 消息订阅绑定(消费者)
+     * 可以同时消费(订阅)多个Topic
+     */
+    @Bean
+    public MessageProducer inbound() {
+        // 初始化入站通道适配器,使用的是Eclipse Paho MQTT客户端库
+        MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter(CodeGenerator.generateUUID(), mqttClientFactory, defaultTopic);
+        // 设置连接超时时长 毫秒
+        adapter.setCompletionTimeout(5000);
+        // 配置默认Paho消息转换器(qos=0, retain=false, charset=UTF-8)
+        adapter.setConverter(new DefaultPahoMessageConverter());
+        /*
+            设置服务质量
+            0 最多一次,数据可能丢失;
+            1 至少一次,数据可能重复;
+            2 只有一次,有且只有一次;最耗性能;
+         */
+        adapter.setQos(0);
+        // 设置订阅通道
+        adapter.setOutputChannel(mqttInboundChannel());
+        return adapter;
+    }
+
+    /**
+     * MQTT信息通道(消费者)
+     */
+    @Bean(name = "mqttInboundChannel")
+    public MessageChannel mqttInboundChannel() {
+        return new DirectChannel();
+    }
+
+    /**
+     * MQTT消息处理器(消费者)
+     */
+    @Bean
+    @ServiceActivator(inputChannel = "mqttInboundChannel")
+    public MessageHandler handler() {
+        return message -> {
+            String topic = Objects.requireNonNull(message.getHeaders().get("mqtt_receivedTopic")).toString();
+            String payload = message.getPayload().toString();
+            mqttCallbackHandler.handle(topic, payload);
+        };
+    }
+}

+ 21 - 0
src/main/java/com/zy/omp/config/mqtt/MqttGateway.java

@@ -0,0 +1,21 @@
+package com.zy.omp.config.mqtt;
+
+import org.springframework.integration.annotation.MessagingGateway;
+import org.springframework.integration.mqtt.support.MqttHeaders;
+import org.springframework.messaging.handler.annotation.Header;
+import org.springframework.stereotype.Service;
+
+/**
+ * 消息推送接口
+ */
+@Service
+@MessagingGateway(defaultRequestChannel = "mqttOutboundChannel")
+public interface MqttGateway {
+    /**
+     * 向指定主题推送消息
+     *
+     * @param data  消息
+     * @param topic 主题
+     */
+    void sendMsgToMqtt(String data, @Header(MqttHeaders.TOPIC) String topic);
+}

+ 48 - 0
src/main/java/com/zy/omp/config/mqtt/MqttProducerCfg.java

@@ -0,0 +1,48 @@
+package com.zy.omp.config.mqtt;
+
+import com.zy.omp.utils.CodeGenerator;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.integration.annotation.ServiceActivator;
+import org.springframework.integration.channel.DirectChannel;
+import org.springframework.integration.mqtt.core.MqttPahoClientFactory;
+import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler;
+import org.springframework.messaging.MessageChannel;
+import org.springframework.messaging.MessageHandler;
+
+/**
+ * MQTT 生产者配置
+ *
+ * @author yang xiao kun
+ * create on 2021/1/19
+ */
+@Configuration
+public class MqttProducerCfg {
+
+    @Autowired
+    private MqttPahoClientFactory mqttClientFactory;
+
+    /**
+     * MQTT信息通道(生产者)
+     */
+    @Bean(name = "mqttOutboundChannel")
+    public MessageChannel mqttOutboundChannel() {
+        return new DirectChannel();
+    }
+
+    /**
+     * MQTT消息处理器(生产者)
+     */
+    @Bean
+    @ServiceActivator(inputChannel = "mqttOutboundChannel")
+    public MessageHandler mqttOutbound() {
+        MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler(CodeGenerator.generateUUID(), mqttClientFactory);
+        // 设置异步发送,默认是false(发送时阻塞)
+        messageHandler.setAsync(true);
+        // 设置默认的服务质量
+        messageHandler.setDefaultQos(0);
+        messageHandler.setDefaultRetained(false);
+        return messageHandler;
+    }
+}

+ 58 - 0
src/main/java/com/zy/omp/controller/pc/AdminController.java

@@ -0,0 +1,58 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.controller.BaseController;
+import com.zy.omp.model.Admin;
+import com.zy.omp.common.redis.SessionManager;
+import com.zy.omp.service.AdminService;
+import com.zy.omp.utils.MD5Util;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 管理员Controller
+ *
+ * @author yang xiao kun
+ * create on 2021/2/24
+ */
+@RestController
+@RequestMapping("omp/api/pc/admin")
+public class AdminController extends BaseController {
+
+    @Resource
+    private AdminService adminService;
+
+    @Resource
+    private SessionManager sessionManager;
+
+    /**
+     * 登录
+     */
+    @PostMapping("login.do")
+    public ServerResponse login(String username, String password) {
+        Admin admin = adminService.getByUsername(username);
+        if (admin == null) return ServerResponse.createByWarning("用户不存在");
+        //MD5密码
+        password = MD5Util.MD5Encode(password);
+        if (!admin.getPassword().equals(password)) return ServerResponse.createByWarning("密码错误");
+        // 返回 token 和 昵称
+        Map<String, String> result = new HashMap<>();
+        result.put("token", sessionManager.generateToken(admin));
+        result.put("nickname", admin.getNickname());
+        return ServerResponse.createBySuccess(result);
+    }
+
+    /**
+     * token 验证
+     */
+    @GetMapping("verify.do")
+    public ServerResponse verify() {
+        return ServerResponse.createBySuccess();
+    }
+}

+ 41 - 0
src/main/java/com/zy/omp/controller/pc/PcDeviceController.java

@@ -0,0 +1,41 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.pojo.io.pc.DeviceIO;
+import com.zy.omp.service.DeviceService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备相关
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/pc/device")
+public class PcDeviceController {
+
+    @Resource
+    private DeviceService deviceService;
+
+    /**
+     * 分页查询设备集合
+     */
+    @PostMapping("listPage.do")
+    public ServerResponse getListPage(DeviceIO io) {
+        return ServerResponse.createBySuccess(deviceService.listPage(io));
+    }
+
+    /**
+     * 通过ClientId 查询设备信息
+     */
+    @GetMapping("getDetailByClientId.do")
+    public ServerResponse getByClientId(String clientId) {
+        return ServerResponse.createBySuccess(deviceService.getByClientId(clientId));
+    }
+}

+ 31 - 0
src/main/java/com/zy/omp/controller/pc/PcLocationController.java

@@ -0,0 +1,31 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.service.LatestLocationService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备定位相关
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/pc/location")
+public class PcLocationController {
+
+    @Resource
+    private LatestLocationService latestLocationService;
+
+    /**
+     * 获取所有设备的最新定位信息
+     */
+    @GetMapping("getLatestLocation.do")
+    public ServerResponse getLatestLocation() {
+        return ServerResponse.createBySuccess(latestLocationService.getLatestLocation());
+    }
+}

+ 60 - 0
src/main/java/com/zy/omp/controller/pc/PcMqttLogController.java

@@ -0,0 +1,60 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.Constant;
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.pojo.io.pc.MqttLogsIO;
+import com.zy.omp.service.MqttLogService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+
+/**
+ * mqtt收发日志
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/pc/logs")
+public class PcMqttLogController {
+
+    @Resource
+    private MqttLogService mqttLogService;
+    private static HashMap<String, String> instruction = new HashMap<>();
+
+    /*
+     * 所有指令暂时写死内存中
+     */
+    static {
+        instruction.put(Constant.M_CODE_REGISTER, "注册");
+        instruction.put(Constant.M_CODE_RETURN_CODE, "返回授权码");
+        instruction.put(Constant.M_CODE_UPLOAD_LOCATION, "上传位置信息");
+        instruction.put(Constant.M_CODE_GPS_RATE, "设置定位频率");
+        instruction.put(Constant.M_CODE_SOS, "设置联系人");
+        instruction.put(Constant.M_CODE_VOLUME, "设置音量");
+        instruction.put(Constant.M_CODE_AUTO_ANSWER, "设置自动接听");
+        instruction.put(Constant.M_CODE_NEWS, "设置语音播报");
+        instruction.put(Constant.M_CODE_UPLOAD_CALL_RECORD, "上传通话记录");
+        instruction.put(Constant.M_CODE_CONTINUE_GPS, "设置连续定位");
+    }
+
+    /**
+     * 分页查询日志
+     */
+    @PostMapping("listPage.do")
+    public ServerResponse getListPage(MqttLogsIO io) {
+        return ServerResponse.createBySuccess(mqttLogService.getListPage(io));
+    }
+
+    /**
+     * 查询所有的指令
+     */
+    @GetMapping("getInstruction.do")
+    public ServerResponse getInstruction() {
+        return ServerResponse.createBySuccess(instruction);
+    }
+}

+ 92 - 0
src/main/java/com/zy/omp/controller/pc/PcSetController.java

@@ -0,0 +1,92 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.Constant;
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.pojo.io.wechat.SetIO;
+import com.zy.omp.service.SetBaseService;
+import com.zy.omp.service.SetService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备设置相关
+ *
+ * @author yang xiao kun
+ * create on 2021/3/3
+ */
+@RestController
+@RequestMapping("omp/api/pc/set")
+public class PcSetController {
+
+    @Resource
+    private SetBaseService setBaseService;
+    @Resource
+    private SetService setService;
+
+    /**
+     * 其他设置
+     *
+     * @param deviceId 设备ID
+     */
+    @GetMapping("baseSet.do")
+    public ServerResponse getBaseSet(String deviceId) {
+        return ServerResponse.createBySuccess(setBaseService.getByDeviceId(deviceId));
+    }
+
+    /**
+     * 设置音量
+     */
+    @PostMapping("volume.do")
+    public ServerResponse setVolume(SetIO io) {
+        setService.set(Constant.M_CODE_VOLUME, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置定位频率
+     */
+    @PostMapping("gpsRate.do")
+    public ServerResponse setGpsRate(SetIO io) {
+        setService.set(Constant.M_CODE_GPS_RATE, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 自动接听
+     *
+     * @param io 设置参数
+     */
+    @PostMapping("autoAnswer.do")
+    public ServerResponse setAutoAnswer(SetIO io) {
+        setService.set(Constant.M_CODE_AUTO_ANSWER, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置语音播报
+     */
+    @PostMapping("news.do")
+    public ServerResponse setNews(SetIO io) {
+        setService.set(Constant.M_CODE_NEWS, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置SOS紧急呼叫
+     */
+    @PostMapping("sos.do")
+    public ServerResponse setSOS(SetIO io) {
+        setService.set(Constant.M_CODE_SOS, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置持续定位
+     */
+    @PostMapping("continue.do")
+    public ServerResponse setContinue(SetIO io) {
+        setService.set(Constant.M_CODE_CONTINUE_GPS, io);
+        return ServerResponse.createBySuccess();
+    }
+}

+ 32 - 0
src/main/java/com/zy/omp/controller/pc/PcUserController.java

@@ -0,0 +1,32 @@
+package com.zy.omp.controller.pc;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.pojo.io.pc.UserIO;
+import com.zy.omp.service.UserService;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 用户管理
+ *
+ * @author chen_yi
+ * Create on 2020/8/1
+ */
+@RestController
+@RequestMapping("omp/api/pc/user")
+public class PcUserController {
+
+    @Resource
+    private UserService userService;
+
+    /**
+     * 分页查询用户集合
+     */
+    @PostMapping("listPage.do")
+    public ServerResponse listPage(UserIO io) {
+        return ServerResponse.createBySuccess(userService.listPage(io));
+    }
+}

+ 95 - 0
src/main/java/com/zy/omp/controller/wx/DeviceController.java

@@ -0,0 +1,95 @@
+package com.zy.omp.controller.wx;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.toolkit.Wrappers;
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.controller.BaseController;
+import com.zy.omp.model.DeviceDynamic;
+import com.zy.omp.service.DeviceService;
+import com.zy.omp.service.DeviceDynamicService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 用户设备绑定关系
+ *
+ * @author chen_yi
+ * Create on 2020/8/1
+ */
+@RestController
+@RequestMapping("omp/api/wx/device")
+public class DeviceController extends BaseController {
+
+    @Resource
+    private DeviceDynamicService deviceDynamicService;
+
+    @Resource
+    private DeviceService deviceService;
+
+    /**
+     * 更新设备名称
+     *
+     * @param num  设备随机 num
+     * @param name 设备名称
+     */
+    @PostMapping("updateName.do")
+    public ServerResponse updateName(String num, String name) {
+        deviceDynamicService.updateName(getUserId(), num, name);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 添加绑定关系
+     */
+    @PostMapping("bind.do")
+    public ServerResponse bind(DeviceDynamic entity) {
+        if (deviceService.getByNum(entity.getDeviceNum()) == null)
+            return ServerResponse.createByWarning("无效设备码!");
+        if (deviceDynamicService.checkBind(entity.getDeviceNum()))
+            return ServerResponse.createByWarning("该设备已经有用户绑定!");
+        entity.setUserId(getUserId());
+        deviceDynamicService.save(entity);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 解除绑定关系
+     */
+    @PostMapping("unbind.do")
+    public ServerResponse unbind(String deviceNum) {
+        deviceDynamicService.unbind(deviceNum, getUserId());
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 查询用户的所有设备
+     */
+    @GetMapping("getListByUserId.do")
+    public ServerResponse getListByUserId() {
+        QueryWrapper<DeviceDynamic> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("userId", getUserId());
+        queryWrapper.orderByDesc("isDefault");
+        return ServerResponse.createBySuccess(deviceDynamicService.list(queryWrapper));
+    }
+
+    /**
+     * 修改默认设备
+     * 即登陆以后使用那个设备
+     *
+     * @param deviceNum 设备码
+     */
+    @PostMapping("changeDefault.do")
+    public ServerResponse changeDefault(String deviceNum) {
+        //删除上一个默认设备
+        deviceDynamicService.update(Wrappers.<DeviceDynamic>lambdaUpdate().eq(DeviceDynamic::getIsDefault, 1)
+                .eq(DeviceDynamic::getUserId, getUserId()).set(DeviceDynamic::getIsDefault, 0));
+        //添加新的默认设备
+        deviceDynamicService.update(Wrappers.<DeviceDynamic>lambdaUpdate().eq(DeviceDynamic::getDeviceNum, deviceNum)
+                .set(DeviceDynamic::getIsDefault, 1));
+        return ServerResponse.createBySuccess();
+    }
+}

+ 19 - 0
src/main/java/com/zy/omp/controller/wx/DeviceLpController.java

@@ -0,0 +1,19 @@
+package com.zy.omp.controller.wx;
+
+
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+/**
+ * <p>
+ * 设备-路牌 前端控制器
+ * </p>
+ *
+ * @author chenyi
+ * @since 2021-06-12
+ */
+@RestController
+@RequestMapping("/builder/device-lp")
+public class DeviceLpController {
+
+}

+ 54 - 0
src/main/java/com/zy/omp/controller/wx/IdiomsController.java

@@ -0,0 +1,54 @@
+package com.zy.omp.controller.wx;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.controller.BaseController;
+import com.zy.omp.service.IdiomsService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 用户常用语
+ *
+ * @author yang xiao kun
+ * create on 2021/1/22
+ */
+@RestController
+@RequestMapping("omp/api/wx/idioms")
+public class IdiomsController extends BaseController {
+
+    @Resource
+    IdiomsService userIdiomsService;
+
+    /**
+     * 通过用户ID 查询用户常用语
+     */
+    @GetMapping("getList.do")
+    public ServerResponse getList() {
+        return ServerResponse.createBySuccess(userIdiomsService.getListByUserId(getUserId()));
+    }
+
+    /**
+     * 添加常用语
+     */
+    @PostMapping("save.do")
+    public ServerResponse save(String content) {
+        String userId = getUserId();
+        if (userIdiomsService.countByUserId(getUserId()) > 10) {
+            return ServerResponse.createByWarning("最多添加十条常用语");
+        }
+        userIdiomsService.saveEntity(userId, content);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 通过ID删除常用语
+     */
+    @PostMapping("delById.do")
+    public ServerResponse delById(Integer id) {
+        return ServerResponse.createBySuccess(userIdiomsService.delById(id, getUserId()));
+    }
+}

+ 41 - 0
src/main/java/com/zy/omp/controller/wx/LocationController.java

@@ -0,0 +1,41 @@
+package com.zy.omp.controller.wx;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.pojo.io.wechat.DeviceHistoryIO;
+import com.zy.omp.service.LocationService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备定位相关
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/wx/location")
+public class LocationController {
+
+    @Resource
+    private LocationService locationService;
+
+    /**
+     * 通过设备ID获取最新的定位信息
+     */
+    @GetMapping("getLocation.do")
+    public ServerResponse getLatestLocation(String deviceId) {
+        return ServerResponse.createBySuccess(locationService.getLatestLocation(deviceId));
+    }
+
+    /**
+     * 查看设备历史轨迹
+     */
+    @PostMapping("getHistory.do")
+    public ServerResponse getHistory(DeviceHistoryIO io) {
+        return ServerResponse.createBySuccess(locationService.getHistory(io));
+    }
+}

+ 94 - 0
src/main/java/com/zy/omp/controller/wx/SetController.java

@@ -0,0 +1,94 @@
+package com.zy.omp.controller.wx;
+
+import com.zy.omp.common.Constant;
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.controller.BaseController;
+import com.zy.omp.pojo.io.wechat.SetIO;
+import com.zy.omp.service.DeviceDynamicService;
+import com.zy.omp.service.SetService;
+import org.springframework.web.bind.annotation.*;
+
+import javax.annotation.Resource;
+
+/**
+ * 设备设置相关
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/wx/set")
+public class SetController extends BaseController {
+
+    @Resource
+    private SetService setService;
+    @Resource
+    private DeviceDynamicService relationService;
+
+    /**
+     * 校验设备是否是该用户的设备
+     */
+    private boolean verify(SetIO io) {
+        boolean flag = relationService.checkBelong(getUserId(), io.getDeviceId());
+        if (!flag) {
+            System.out.println("非法请求----" + getUserId() + "-----" + io.getDeviceId());
+        }
+        return flag;
+    }
+
+    /**
+     * 设置音量
+     */
+    @PostMapping("volume.do")
+    public ServerResponse setVolume(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_VOLUME, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置定位频率
+     */
+    @PostMapping("gpsRate.do")
+    public ServerResponse gpsRate(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_GPS_RATE, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 自动接听
+     *
+     * @param io 设置参数
+     */
+    @PostMapping("autoAnswer.do")
+    public ServerResponse setAutoAnswer(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_AUTO_ANSWER, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置语音播报
+     */
+    @PostMapping("news.do")
+    public ServerResponse setNews(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_NEWS, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置SOS紧急呼叫
+     */
+    @PostMapping("sos.do")
+    public ServerResponse setSOS(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_SOS, io);
+        return ServerResponse.createBySuccess();
+    }
+
+    /**
+     * 设置持续定位
+     */
+    @PostMapping("continue.do")
+    public ServerResponse setContinue(SetIO io) {
+        if (verify(io)) setService.set(Constant.M_CODE_CONTINUE_GPS, io);
+        return ServerResponse.createBySuccess();
+    }
+}

+ 80 - 0
src/main/java/com/zy/omp/controller/wx/SetInfoController.java

@@ -0,0 +1,80 @@
+package com.zy.omp.controller.wx;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.common.controller.BaseController;
+import com.zy.omp.pojo.io.CallRecordsIO;
+import com.zy.omp.pojo.io.NewsIO;
+import com.zy.omp.service.CallRecordsService;
+import com.zy.omp.service.SetBaseService;
+import com.zy.omp.service.NewsService;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 获取设备设置相关接口
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@RestController
+@RequestMapping("omp/api/wx/setInfo")
+public class SetInfoController extends BaseController {
+
+    @Resource
+    private SetBaseService setBaseService;
+    @Resource
+    private CallRecordsService callRecordsService;
+    @Resource
+    private NewsService setNewsService;
+
+    /**
+     * 查询设备的音量设置
+     * 系统音量,通话音量,铃声音量
+     *
+     * @param deviceId 设备ID
+     */
+    @GetMapping("volume.do")
+    public ServerResponse volume(String deviceId) {
+        return ServerResponse.createBySuccess(setBaseService.getVolumeSet(deviceId));
+    }
+
+    /**
+     * 查询设备的其他设置
+     * 自动接听,定位频率,连续定位设置
+     *
+     * @param deviceId 设备ID
+     */
+    @GetMapping("other.do")
+    public ServerResponse other(String deviceId) {
+        return ServerResponse.createBySuccess(setBaseService.getOtherSet(deviceId));
+    }
+
+    /**
+     * 获取SOS按键设置
+     *
+     * @param deviceId 设备ID
+     */
+    @GetMapping("sos.do")
+    public ServerResponse sos(String deviceId) {
+        return ServerResponse.createBySuccess(setBaseService.getSosSet(deviceId));
+    }
+
+    /**
+     * 获取通话记录
+     */
+    @GetMapping("callRecords.do")
+    public ServerResponse callRecords(CallRecordsIO io) {
+        return ServerResponse.createBySuccess(callRecordsService.getListPage(io));
+    }
+
+    /**
+     * 获取播报记录
+     */
+    @GetMapping("news.do")
+    public ServerResponse news(NewsIO io) {
+        return ServerResponse.createBySuccess(setNewsService.getListPage(io));
+    }
+}

+ 41 - 0
src/main/java/com/zy/omp/controller/wx/UserController.java

@@ -0,0 +1,41 @@
+package com.zy.omp.controller.wx;
+
+import com.zy.omp.common.ServerResponse;
+import com.zy.omp.model.User;
+import com.zy.omp.service.UserService;
+import com.zy.omp.utils.AesUtils;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javax.annotation.Resource;
+
+/**
+ * 用户信息相关
+ *
+ * @author chen_yi
+ * Create on 2020/8/1
+ */
+@RestController
+@RequestMapping("omp/api/wx/user")
+public class UserController {
+    @Resource
+    private UserService userService;
+
+    /**
+     * 微信登录
+     *
+     * @param code 微信登录凭证
+     * @return 用户openId
+     */
+    @PostMapping("login.do")
+    public ServerResponse login(String code) {
+        String openId = userService.getWxAppId(code);
+        if (openId == null) return ServerResponse.createByError();
+        //保存新用户
+        if (userService.getByOpenId(openId) == null) {
+            userService.save(new User(openId));
+        }
+        return ServerResponse.createBySuccess(AesUtils.encrypt(openId));
+    }
+}

+ 18 - 0
src/main/java/com/zy/omp/mapper/AdminMapper.java

@@ -0,0 +1,18 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.model.Admin;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 管理员 Mapper
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface AdminMapper extends BaseMapper<Admin> {
+
+}

+ 27 - 0
src/main/java/com/zy/omp/mapper/CallRecordsMapper.java

@@ -0,0 +1,27 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zy.omp.pojo.io.CallRecordsIO;
+import com.zy.omp.model.CallRecords;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 通话记录 Mapper
+ * <p>
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface CallRecordsMapper extends BaseMapper<CallRecords> {
+
+    /**
+     * 分页查询通话记录
+     *
+     * @param io 查询参数
+     */
+    IPage<CallRecords> getListPage(Page<CallRecords> page, @Param("io") CallRecordsIO io);
+}

+ 33 - 0
src/main/java/com/zy/omp/mapper/DeviceDynamicMapper.java

@@ -0,0 +1,33 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.model.DeviceDynamic;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 用户设备绑定关系表
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface DeviceDynamicMapper extends BaseMapper<DeviceDynamic> {
+
+    /**
+     * 查询设备是否有绑定用户
+     *
+     * @param deviceNum 设备号
+     */
+    int checkBind(@Param("deviceNum") String deviceNum);
+
+    /**
+     * 查询设备是否属于某用户
+     *
+     * @param userId   用户ID
+     * @param deviceId 设备ID
+     */
+    int checkBelong(@Param("userId") String userId, @Param("deviceId") String deviceId);
+}

+ 20 - 0
src/main/java/com/zy/omp/mapper/DeviceLpMapper.java

@@ -0,0 +1,20 @@
+package com.zy.omp.mapper;
+
+import com.zy.omp.model.DeviceLp;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * <p>
+ * 设备-路牌 Mapper 接口
+ * </p>
+ *
+ * @author chenyi
+ * @since 2021-06-12
+ */
+@Mapper
+@Repository
+public interface DeviceLpMapper extends BaseMapper<DeviceLp> {
+
+}

+ 35 - 0
src/main/java/com/zy/omp/mapper/DeviceMapper.java

@@ -0,0 +1,35 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zy.omp.pojo.io.pc.DeviceIO;
+import com.zy.omp.pojo.vo.DeviceFullDataVo;
+import com.zy.omp.model.Device;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface DeviceMapper extends BaseMapper<Device> {
+
+    /**
+     * 后台
+     * 分页查询设备列表
+     *
+     * @param page 分页条件
+     * @param io   查询条件
+     */
+    IPage<DeviceFullDataVo> listPage(IPage<DeviceFullDataVo> page, @Param("io") DeviceIO io);
+
+    /**
+     * 批量更新设备在线状态
+     */
+    void updateDeviceStatus(@Param("devices") List<Device> devices);
+}

+ 18 - 0
src/main/java/com/zy/omp/mapper/IdiomsMapper.java

@@ -0,0 +1,18 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.model.UserIdioms;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 常用语 Mapper
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface IdiomsMapper extends BaseMapper<UserIdioms> {
+
+}

+ 25 - 0
src/main/java/com/zy/omp/mapper/LatestLocationMapper.java

@@ -0,0 +1,25 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.pojo.vo.DeviceFullDataVo;
+import com.zy.omp.model.LatestLocation;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+import java.util.List;
+
+/**
+ * 设备最新位置信息
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface LatestLocationMapper extends BaseMapper<LatestLocation> {
+
+    /**
+     * 获取所有设备最新的位置信息
+     */
+    List<DeviceFullDataVo> getLatestLocation();
+}

+ 17 - 0
src/main/java/com/zy/omp/mapper/LocationMapper.java

@@ -0,0 +1,17 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.model.Location;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 设备位置信息
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface LocationMapper extends BaseMapper<Location> {
+}

+ 28 - 0
src/main/java/com/zy/omp/mapper/MqttLogMapper.java

@@ -0,0 +1,28 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zy.omp.pojo.io.pc.MqttLogsIO;
+import com.zy.omp.model.MqttLog;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * MQTT 收发日志 Mapper
+ * <p>
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface MqttLogMapper extends BaseMapper<MqttLog> {
+
+    /**
+     * 分页查询日志
+     *
+     * @param page 分页参数
+     * @param io   查询条件
+     */
+    IPage<MqttLog> getListPage(Page<MqttLog> page, @Param("io") MqttLogsIO io);
+}

+ 27 - 0
src/main/java/com/zy/omp/mapper/NewsMapper.java

@@ -0,0 +1,27 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.zy.omp.pojo.io.NewsIO;
+import com.zy.omp.model.News;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 语音播报 Mapper
+ *
+ * @author konglilia
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface NewsMapper extends BaseMapper<News> {
+    /**
+     * 分页查询播报记录
+     *
+     * @param io 查询参数
+     */
+    IPage<News> getListPage(Page<News> page, @Param("io") NewsIO io);
+}

+ 18 - 0
src/main/java/com/zy/omp/mapper/SetBaseMapper.java

@@ -0,0 +1,18 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.zy.omp.model.SetBase;
+import org.apache.ibatis.annotations.Mapper;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 设备基本其他设置
+ *
+ * @author konglilia
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface SetBaseMapper extends BaseMapper<SetBase> {
+
+}

+ 27 - 0
src/main/java/com/zy/omp/mapper/UserMapper.java

@@ -0,0 +1,27 @@
+package com.zy.omp.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.zy.omp.pojo.io.pc.UserIO;
+import com.zy.omp.model.User;
+import org.apache.ibatis.annotations.Mapper;
+import org.apache.ibatis.annotations.Param;
+import org.springframework.stereotype.Repository;
+
+/**
+ * 微信用户Mapper
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Mapper
+@Repository
+public interface UserMapper extends BaseMapper<User> {
+    /**
+     * 分页查询用户列表
+     *
+     * @param page 分页条件
+     * @param io   查询条件
+     */
+    IPage<User> listPage(IPage<User> page, @Param("io") UserIO io);
+}

+ 41 - 0
src/main/java/com/zy/omp/model/Admin.java

@@ -0,0 +1,41 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * PC 管理员
+ *
+ * @author chen_yi
+ * Create on 2020/7/31
+ */
+@Data
+@TableName("admin")
+public class Admin {
+
+    @TableId
+    private Integer id;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 密码
+     */
+    private String password;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 48 - 0
src/main/java/com/zy/omp/model/CallRecords.java

@@ -0,0 +1,48 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 通话记录
+ *
+ * @author yang xiao kun
+ * create on 2021/4/1
+ */
+@Data
+@TableName("call_records")
+public class CallRecords {
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 1:播出 2:接听
+     */
+    private Integer callType;
+
+    /**
+     * key1,key1,service
+     */
+    private String keyNum;
+
+    /**
+     * 通话号码
+     */
+    private String phoneNum;
+
+    /**
+     * 通话时长
+     */
+    private Integer talkTime;
+
+    /**
+     * 通话结束时间
+     */
+    private String endTime;
+}

+ 52 - 0
src/main/java/com/zy/omp/model/Device.java

@@ -0,0 +1,52 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备信息
+ */
+@Data
+@TableName("device")
+public class Device {
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备随机码
+     */
+    private String num;
+
+    /**
+     * MQTT clientId
+     */
+    private String clientId;
+
+    /**
+     * MQTT 密码
+     */
+    private String password;
+
+    /**
+     * 设备组
+     */
+    private String group;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 最后一次在线时间
+     */
+    private LocalDateTime lastOnlineTime;
+
+    /**
+     * 1:在线 0:离线
+     */
+    private Integer status;
+}

+ 52 - 0
src/main/java/com/zy/omp/model/DeviceDynamic.java

@@ -0,0 +1,52 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备扩展信息表
+ *
+ * @author chen_yi
+ * Create on 2020/8/1
+ */
+@Data
+@TableName("device_dynamic")
+public class DeviceDynamic {
+
+    @TableId
+    private Integer id;
+
+    /**
+     * 用户ID
+     */
+    private String userId;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 设备随机码
+     */
+    private String deviceNum;
+
+    /**
+     * 是否是默认设备
+     * 0:否 1:是
+     */
+    private Integer isDefault;
+
+    /**
+     * 设备名
+     */
+    private String name;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 126 - 0
src/main/java/com/zy/omp/model/DeviceLp.java

@@ -0,0 +1,126 @@
+package com.zy.omp.model;
+
+import java.io.Serializable;
+import java.time.LocalDateTime;
+
+import com.baomidou.mybatisplus.annotation.TableField;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+
+/**
+ * <p>
+ * 设备-路牌
+ * </p>
+ *
+ * @author chenyi
+ * @since 2021-06-12
+ */
+@Data
+@TableName("device_lp")
+public class DeviceLp implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    @TableId(value = "id", type = IdType.AUTO)
+    private Integer id;
+
+    /**
+     * 设备IMEI
+     */
+    private String num;
+
+    /**
+     * 登录MQTT 用户名
+     */
+    private String clientId;
+
+    /**
+     * 登录MQTT 密码
+     */
+    private String password;
+
+    /**
+     * 状态
+     */
+    private Integer status;
+
+    /**
+     * 设备组
+     */
+    @TableField("`group`")
+    private String group;
+
+    /**
+     * SN码
+     */
+    private String sn;
+
+    /**
+     * 定时唤醒时间
+     */
+    private Integer wakeInt;
+
+    /**
+     * 阈值
+     */
+    private Double thresh;
+
+    /**
+     * 电量
+     */
+    private String battery;
+
+    /**
+     * 信号
+     */
+    private String s4g;
+
+    private String x;
+
+    private String y;
+
+    private String z;
+
+    private String anglex;
+
+    private String angley;
+
+    private String anglez;
+
+    /**
+     * 温度
+     */
+    private String temp;
+
+    /**
+     * 经度
+     */
+    private String lng;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 经度(gcj)
+     */
+    private String lngGcj;
+
+    /**
+     * 纬度(gcj)
+     */
+    private String latGcj;
+
+    /**
+     * 格式化的地理位置
+     */
+    private String site;
+
+    /**
+     * 数据更新时间
+     */
+    private LocalDateTime updateTime;
+}

+ 84 - 0
src/main/java/com/zy/omp/model/LatestLocation.java

@@ -0,0 +1,84 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备最新的定位
+ */
+@Data
+@TableName("latest_location")
+public class LatestLocation {
+
+
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 电量
+     */
+    private Integer batteryNum;
+
+    /**
+     * 信号强度
+     */
+    private Integer signalNum;
+
+    /**
+     * 0:无法定位,1:北斗定位,2:基站定位,3:GPS定位
+     */
+    private Integer mode;
+
+    /**
+     * 经度
+     */
+    private String lon;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 经度(gcj)
+     */
+    private String lonGcj;
+
+    /**
+     * 纬度(gcj)
+     */
+    private String latGcj;
+
+    /**
+     * 格式化的地理位置
+     */
+    private String site;
+
+    /**
+     * 速度
+     */
+    private String speed;
+
+    /**
+     * 收星颗数
+     */
+    private Integer num;
+
+    /**
+     * 数据上传时间
+     */
+    private LocalDateTime uploadTime;
+
+    /**
+     * 最新的修改时间
+     */
+    private LocalDateTime modifyTime;
+}

+ 83 - 0
src/main/java/com/zy/omp/model/Location.java

@@ -0,0 +1,83 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备定位信息表
+ */
+@Data
+@TableName("location")
+public class Location {
+
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 电量
+     */
+    private Integer batteryNum;
+
+    /**
+     * 信号强度
+     */
+    private Integer signalNum;
+
+    /**
+     * 0:无法定位,1:北斗定位,2:基站定位,3:GPS定位
+     */
+    private Integer mode;
+
+    /**
+     * 经度
+     */
+    private String lon;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 经度(gcj)
+     */
+    private String lonGcj;
+
+    /**
+     * 纬度(gcj)
+     */
+    private String latGcj;
+
+    /**
+     * 格式化的地理位置
+     */
+    private String site;
+
+    /**
+     * 速度
+     */
+    private String speed;
+
+    /**
+     * 收星颗数
+     */
+    private Integer num;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 数据上传时间
+     */
+    private LocalDateTime uploadTime;
+}

+ 50 - 0
src/main/java/com/zy/omp/model/MqttLog.java

@@ -0,0 +1,50 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * mqtt消息收发记录
+ *
+ * @author yang xiao kun
+ * create on 2021/4/14
+ */
+@Data
+@TableName("mqtt_log")
+public class MqttLog {
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 类型
+     */
+    private Integer tag;
+
+    /**
+     * 发送内容
+     */
+    private String content;
+
+    /**
+     * 主题
+     */
+    private String topic;
+
+    /**
+     * 指令
+     */
+    private String instruction;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 49 - 0
src/main/java/com/zy/omp/model/News.java

@@ -0,0 +1,49 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 语音播报记录
+ */
+@Data
+@TableName("news")
+public class News {
+    @TableId
+    private Integer id;
+    /**
+     * 用户ID
+     */
+    private String userId;
+
+    /**
+     * 设备Id
+     */
+    private String deviceId;
+
+    /**
+     * 星期几的几点几分播报
+     * 星期之间逗号间隔
+     * 星期与时间空格间隔 1,2,3,4,5 13:23
+     */
+    private String newsTime;
+
+    /**
+     * 播报类型
+     * 1:实时播报,0:固定时间播报
+     */
+    private Integer newsType;
+
+    /**
+     * 服务器下发文字
+     */
+    private String news;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 83 - 0
src/main/java/com/zy/omp/model/SetBase.java

@@ -0,0 +1,83 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+/**
+ * 其他设置
+ */
+@Data
+@TableName("set_base")
+public class SetBase {
+
+    @TableId
+    private Integer id;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 系统音量
+     */
+    private Integer msgVol;
+
+    /**
+     * 通话音量
+     */
+    private Integer phoneVol;
+
+    /**
+     * 铃声音量
+     */
+    private Integer ringVol;
+
+    /**
+     * 自动接听
+     */
+    private Integer autoAnswer;
+
+    /**
+     * 设备连续定位设置  1:开启 0:关闭
+     */
+    private Integer highFreq;
+
+    /**
+     * 定位频率 单位小时
+     */
+    private Integer gpsRate;
+
+    /**
+     * SOS按键 拨号姓名
+     */
+    private String key0Name;
+    /**
+     * SOS按键 拨号号码
+     */
+    private String key0Phone;
+
+    /**
+     * key1按键 拨号姓名
+     */
+    private String key1Name;
+    /**
+     * key1按键 拨号号码
+     */
+    private String key1Phone;
+
+    /**
+     * key2按键 拨号姓名
+     */
+    private String key2Name;
+    /**
+     * key2按键 拨号号码
+     */
+    private String key2Phone;
+
+    //服务器地址
+    private String serverHost;
+    //服务器端口
+    private Integer serverPort;
+}

+ 69 - 0
src/main/java/com/zy/omp/model/User.java

@@ -0,0 +1,69 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+import lombok.ToString;
+
+import java.time.LocalDateTime;
+
+/**
+ * 微信-用户表
+ *
+ * @author chen_yi
+ * Create on 2020/7/31
+ */
+@Data
+@ToString
+@TableName("user")
+@NoArgsConstructor
+public class User {
+    @TableId
+    private Integer id;
+
+    /**
+     * 微信
+     */
+    private String openId;
+
+    /**
+     * 头像
+     */
+    private String avatar;
+
+    /**
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 性别
+     */
+    private Integer gender;
+
+    /**
+     * 国家
+     */
+    private String country;
+
+    /**
+     * 省份
+     */
+    private String province;
+
+    /**
+     * 城市
+     */
+    private String city;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+
+    public User(String openId) {
+        this.openId = openId;
+    }
+}

+ 29 - 0
src/main/java/com/zy/omp/model/UserIdioms.java

@@ -0,0 +1,29 @@
+package com.zy.omp.model;
+
+import com.baomidou.mybatisplus.annotation.TableId;
+import com.baomidou.mybatisplus.annotation.TableName;
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 常用语
+ */
+@Data
+@TableName("user_idioms")
+public class UserIdioms {
+    @TableId
+    private Integer id;
+    /**
+     * 用户ID
+     */
+    private String userId;
+    /**
+     * 内容
+     */
+    private String content;
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 120 - 0
src/main/java/com/zy/omp/pojo/dto/MqttMsgDto.java

@@ -0,0 +1,120 @@
+package com.zy.omp.pojo.dto;
+
+import com.alibaba.fastjson.JSON;
+import com.zy.omp.common.Constant;
+import com.zy.omp.utils.DateTimeUtil;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.time.LocalDateTime;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * MQTT 消息模板类
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@Data
+@NoArgsConstructor
+public class MqttMsgDto {
+    private String m;
+    private String t;
+    private String r;
+    /**
+     * 数据项
+     */
+    private Map<String, Object> data;
+
+    /**
+     * 通用构造器
+     *
+     * @param m        MQTT协议设置代码
+     * @param deviceId 设备ID
+     */
+    public MqttMsgDto(String m, String deviceId) {
+        this.m = m;
+        this.t = Constant.TOPIC_DEVICE_CLIENT + deviceId;
+        this.r = Constant.TOPIC_DEVICE_SERVER + deviceId;
+        this.data = new HashMap<>();
+    }
+
+    /**
+     * 由 JSON 字符串 转 MqttMsgDto 对象
+     */
+    public static MqttMsgDto parse(String jsonStr) {
+        return JSON.parseObject(jsonStr, MqttMsgDto.class);
+    }
+
+    /**
+     * 往data中添加数据 支持链式
+     *
+     * @param key   键
+     * @param value 值
+     */
+    public MqttMsgDto set(String key, Object value) {
+        data.put(key, value);
+        return this;
+    }
+
+    /**
+     * 获取json 对象
+     */
+    public String toJson() {
+        return JSON.toJSONString(this);
+    }
+
+    /**
+     * 获取 Object 数据
+     */
+    public Object getObject(String key) {
+        return data.get(key);
+    }
+
+    /**
+     * 获取String 数据
+     */
+    public String getString(String key) {
+        return data.containsKey(key) ? data.get(key).toString() : null;
+    }
+
+    /**
+     * 获取 Integer 数据
+     */
+    public Integer getInt(String key) {
+        if (!data.containsKey(key) || data.get(key).toString().equals("")) {
+            return null;
+        }
+        return Integer.parseInt(data.get(key).toString());
+    }
+
+    /**
+     * 获取 Double 数据
+     */
+    public Double getDouble(String key) {
+        if (!data.containsKey(key) || data.get(key).toString().equals("")) {
+            return null;
+        }
+        return Double.parseDouble(data.get(key).toString());
+    }
+
+    /**
+     * 获取 日期数据 数据
+     */
+    public LocalDateTime getDate(String key) {
+        if (!data.containsKey(key) || data.get(key).toString().equals("")) {
+            return null;
+        }
+        return DateTimeUtil.strToTime(data.get(key).toString());
+    }
+
+    /**
+     * 获取设备ID
+     */
+    public String getDeviceId() {
+        if (r == null) return null;
+        String[] res = r.split("/");
+        return res.length > 1 ? res[1] : null;
+    }
+}

+ 26 - 0
src/main/java/com/zy/omp/pojo/io/CallRecordsIO.java

@@ -0,0 +1,26 @@
+package com.zy.omp.pojo.io;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 通话记录IO
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class CallRecordsIO extends PageIO {
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 1:播出 2:接听
+     */
+    private Integer type;
+
+}

+ 26 - 0
src/main/java/com/zy/omp/pojo/io/NewsIO.java

@@ -0,0 +1,26 @@
+package com.zy.omp.pojo.io;
+
+import lombok.Data;
+import lombok.EqualsAndHashCode;
+
+/**
+ * 查询语音播报 IO
+ *
+ * @author yang xiao kun
+ * create on 2021/1/21
+ */
+@Data
+@EqualsAndHashCode(callSuper = true)
+public class NewsIO extends PageIO {
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 播报类型,1:实时播报,0:固定时间播报
+     */
+    private Integer newsType;
+
+}

+ 36 - 0
src/main/java/com/zy/omp/pojo/io/PageIO.java

@@ -0,0 +1,36 @@
+package com.zy.omp.pojo.io;
+
+import lombok.Data;
+
+/**
+ * 分页参数封装类,其他入参类继承此类
+ * 默认第一页,每页20条
+ *
+ * @author yang xiao kun
+ * create on 2021/2/18
+ */
+@Data
+public class PageIO {
+    /**
+     * 每页大小
+     */
+    Integer size;
+    /**
+     * 当前页码
+     */
+    Integer current;
+    /**
+     * 排序字段
+     */
+    String orderBy;
+    /**
+     * 排序规则
+     */
+    String order;
+
+    public PageIO() {
+        this.current = 1;
+        this.size = 20;
+        this.order = "DESC";
+    }
+}

+ 22 - 0
src/main/java/com/zy/omp/pojo/io/pc/DeviceIO.java

@@ -0,0 +1,22 @@
+package com.zy.omp.pojo.io.pc;
+
+import com.zy.omp.pojo.io.PageIO;
+import lombok.Data;
+
+/**
+ * 设备查询入参
+ *
+ * @author yang xiao kun
+ * create on 2021/2/18
+ */
+@Data
+public class DeviceIO extends PageIO {
+    /**
+     * 设备码
+     */
+    private String num;
+    /**
+     * 设备状态
+     */
+    private Integer status;
+}

+ 29 - 0
src/main/java/com/zy/omp/pojo/io/pc/MqttLogsIO.java

@@ -0,0 +1,29 @@
+package com.zy.omp.pojo.io.pc;
+
+import com.zy.omp.pojo.io.PageIO;
+import lombok.Data;
+
+/**
+ * mqtt 收发日志查询入参
+ *
+ * @author yang xiao kun
+ * create on 2021/4/23
+ */
+@Data
+public class MqttLogsIO extends PageIO {
+
+    /**
+     * 0:接收 1:发送
+     */
+    private Integer tag;
+
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * 指令
+     */
+    private String instruction;
+}

+ 23 - 0
src/main/java/com/zy/omp/pojo/io/pc/UserIO.java

@@ -0,0 +1,23 @@
+package com.zy.omp.pojo.io.pc;
+
+import com.zy.omp.pojo.io.PageIO;
+import lombok.Data;
+
+/**
+ * 用户查询入参
+ *
+ * @author yang xiao kun
+ * create on 2021/2/18
+ */
+@Data
+public class UserIO extends PageIO {
+    /**
+     * 昵称/用户名
+     */
+    private String key;
+
+    /**
+     * 性别 1:男 2:女
+     */
+    private Integer gender;
+}

+ 26 - 0
src/main/java/com/zy/omp/pojo/io/wechat/DeviceHistoryIO.java

@@ -0,0 +1,26 @@
+package com.zy.omp.pojo.io.wechat;
+
+import lombok.Data;
+
+/**
+ * 设备历史轨迹入参
+ *
+ * @author yang xiao kun
+ * create on 2021/2/8
+ */
+@Data
+public class DeviceHistoryIO {
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+    /**
+     * 开始时间
+     */
+    private String startTime;
+
+    /**
+     * 结束时间
+     */
+    private String endTime;
+}

+ 104 - 0
src/main/java/com/zy/omp/pojo/io/wechat/SetIO.java

@@ -0,0 +1,104 @@
+package com.zy.omp.pojo.io.wechat;
+
+import com.zy.omp.common.Constant;
+import lombok.Data;
+
+/**
+ * 设置入参
+ *
+ * @author chen_yi
+ * Create on 2021/5/27
+ */
+@Data
+public class SetIO {
+    /**
+     * 设备名
+     */
+    private String deviceId;
+
+    /**
+     * 用户ID
+     */
+    private String userId;
+
+    /**
+     * 1:代表打开连续定位 0:代表关闭连续定位
+     * 设备在做后一次收到开启连续定位起计时5分钟后自动关闭连续定位。
+     * 如果希望持续开启连续定位,需要间隔小于5分钟重复发送开 启。收到关闭连续定位后设备会马上关闭连续定位
+     */
+    private Integer highFreq;
+
+    /**
+     * 自动接听
+     * 0关闭,1打开
+     */
+    private Integer autoAnswer;
+
+    /**
+     * 定位频率
+     * 单位 小时
+     */
+    private Integer gpsRate;
+
+    /**
+     * 铃声音量
+     */
+    private Integer ringVol;
+
+    /**
+     * 系统音量
+     */
+    private Integer msgVol;
+
+    /**
+     * 通话音量
+     */
+    private Integer phoneVol;
+
+    /**
+     * 姓名
+     */
+    private String key0Name;
+    /**
+     * 电话号码
+     */
+    private String key0Phone;
+
+    /**
+     * 姓名
+     */
+    private String key1Name;
+    /**
+     * 电话号码
+     */
+    private String key1Phone;
+
+    /**
+     * 姓名
+     */
+    private String key2Name;
+    /**
+     * 电话号码
+     */
+    private String key2Phone;
+
+    /**
+     * 星期几的几点几分播报,星期之间逗号间隔,星期与时间空格间隔
+     * 1,2,3,4,5 13:13
+     */
+    private String newsTime;
+
+    /**
+     * 播报类型,1:实时播报,0:固定时间播报
+     */
+    private Integer newsType;
+
+    /**
+     * 服务器下发文字
+     */
+    private String news;
+
+    public String getTopic() {
+        return Constant.TOPIC_DEVICE_CLIENT + deviceId;
+    }
+}

+ 47 - 0
src/main/java/com/zy/omp/pojo/vo/AdminListVo.java

@@ -0,0 +1,47 @@
+package com.zy.omp.pojo.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * PC用户列表查询 视图
+ *
+ * @author yang xiao kun
+ * create on 2021/5/19
+ */
+@Data
+public class AdminListVo {
+
+    private Integer id;
+
+    /**
+     * 用户名
+     */
+    private String username;
+
+    /**
+     * 昵称
+     */
+    private String nickname;
+
+    /**
+     * 手机号
+     */
+    private String phone;
+
+    /**
+     * 角色
+     */
+    private String role;
+
+    /**
+     * 状态 0停用 1启用
+     */
+    private Integer status;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+}

+ 88 - 0
src/main/java/com/zy/omp/pojo/vo/DeviceFullDataVo.java

@@ -0,0 +1,88 @@
+package com.zy.omp.pojo.vo;
+
+import lombok.Data;
+
+import java.time.LocalDateTime;
+
+/**
+ * 设备信息Vo 包含设备信息,位置信息
+ *
+ * @author yang xiao kun
+ * create on 2021/5/12
+ */
+@Data
+public class DeviceFullDataVo {
+    /**
+     * 设备随机码
+     */
+    private String deviceNum;
+    /**
+     * 设备ID
+     */
+    private String deviceId;
+
+    /**
+     * MQTT 密码
+     */
+    private String password;
+
+    /**
+     * 创建时间
+     */
+    private LocalDateTime createTime;
+
+    /**
+     * 最后一次在线时间
+     */
+    private LocalDateTime lastOnlineTime;
+
+    /**
+     * 1在线,0离线
+     */
+    private Integer status;
+
+    /**
+     * 电量
+     */
+    private Integer batteryNum;
+
+    /**
+     * 信号强度
+     */
+    private Integer signalNum;
+
+    /**
+     * 0:无法定位,1:北斗定位,2:基站定位,3:GPS定位
+     */
+    private Integer mode;
+
+    /**
+     * 经度
+     */
+    private String lon;
+
+    /**
+     * 纬度
+     */
+    private String lat;
+
+    /**
+     * 格式化的地理位置
+     */
+    private String site;
+
+    /**
+     * 速度
+     */
+    private String speed;
+
+    /**
+     * 收星颗数
+     */
+    private Integer num;
+
+    /**
+     * 数据上传时间
+     */
+    private LocalDateTime uploadTime;
+}

+ 49 - 0
src/main/java/com/zy/omp/schedule/DeviceStatusSchedule.java

@@ -0,0 +1,49 @@
+package com.zy.omp.schedule;
+
+import com.zy.omp.model.Device;
+import com.zy.omp.service.DeviceService;
+import com.zy.omp.service.RabbitMQApi;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Async;
+import org.springframework.scheduling.annotation.Scheduled;
+
+import java.time.LocalDateTime;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * 定时更新设备在线状态
+ *
+ * @author yang xiao kun
+ * create on 2021/5/14
+ */
+//@EnableAsync
+//@Configuration
+//@EnableScheduling
+public class DeviceStatusSchedule {
+
+    @Autowired
+    private RabbitMQApi rabbitMQApi;
+    @Autowired
+    private DeviceService deviceService;
+
+    /**
+     * 更新频率 5分钟
+     * 定时更新设备在线状态
+     */
+    @Async
+    @Scheduled(cron = "0 0/5 * * * ?")
+    public void updateDeviceStatus() {
+        //全部的设备
+        List<Device> devices = deviceService.list();
+        Set<String> online = rabbitMQApi.getOnlineDevice();
+        for (Device item : devices) {
+            int status = online.contains(item.getClientId()) ? 1 : 0;
+            item.setStatus(status);
+            if (status == 1) {
+                item.setLastOnlineTime(LocalDateTime.now());
+            }
+        }
+        deviceService.updateDeviceStatus(devices);
+    }
+}

+ 35 - 0
src/main/java/com/zy/omp/service/AdminService.java

@@ -0,0 +1,35 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.mapper.AdminMapper;
+import com.zy.omp.model.Admin;
+import org.springframework.stereotype.Service;
+
+/**
+ * 管理员 Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class AdminService extends ServiceImpl<AdminMapper, Admin> {
+
+    /**
+     * 查询用户信息
+     *
+     * @param content 用户名 或 密码
+     */
+    public Admin getByUsername(String content) {
+        QueryWrapper<Admin> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("username", content);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    public void up(Admin admin) {
+        UpdateWrapper<Admin> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.eq("username", admin.getUsername());
+        baseMapper.update(admin, updateWrapper);
+    }
+}

+ 29 - 0
src/main/java/com/zy/omp/service/CallRecordsService.java

@@ -0,0 +1,29 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.pojo.io.CallRecordsIO;
+import com.zy.omp.mapper.CallRecordsMapper;
+import com.zy.omp.model.CallRecords;
+import org.springframework.stereotype.Service;
+
+/**
+ * 通话记录 Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class CallRecordsService extends ServiceImpl<CallRecordsMapper, CallRecords> {
+
+    /**
+     * 分页查询通话记录
+     *
+     * @param io 查询参数
+     */
+    public IPage<CallRecords> getListPage(CallRecordsIO io) {
+        Page<CallRecords> page = new Page<>(io.getCurrent(), io.getSize());
+        return baseMapper.getListPage(page, io);
+    }
+}

+ 61 - 0
src/main/java/com/zy/omp/service/DeviceDynamicService.java

@@ -0,0 +1,61 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.mapper.DeviceDynamicMapper;
+import com.zy.omp.model.DeviceDynamic;
+import org.springframework.stereotype.Service;
+
+/**
+ * 用户设备绑定关系Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class DeviceDynamicService extends ServiceImpl<DeviceDynamicMapper, DeviceDynamic> {
+
+    /**
+     * 通过设备号删除绑定关系
+     *
+     * @param deviceNum 设备号
+     */
+    public void unbind(String deviceNum, String userId) {
+        QueryWrapper<DeviceDynamic> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("deviceNum", deviceNum);
+        queryWrapper.eq("userId", userId);
+        baseMapper.delete(queryWrapper);
+    }
+
+    /**
+     * 查询设备是否有绑定关系
+     *
+     * @param deviceNum 设备号
+     */
+    public boolean checkBind(String deviceNum) {
+        return baseMapper.checkBind(deviceNum) > 0;
+    }
+
+    /**
+     * 查询设备是否属于该用户
+     *
+     * @param userId    用户ID
+     * @param deviceNum 设备码
+     */
+    public void updateName(String userId, String deviceNum, String newName) {
+        UpdateWrapper<DeviceDynamic> updateWrapper = new UpdateWrapper<>();
+        updateWrapper.set("name", newName).eq("userId", userId).eq("deviceNum", deviceNum);
+        update(updateWrapper);
+    }
+
+    /**
+     * 查询设备是否属于该用户
+     *
+     * @param userId   用户ID
+     * @param deviceId 设备ID
+     */
+    public boolean checkBelong(String userId, String deviceId) {
+        return baseMapper.checkBelong(userId, deviceId) > 0;
+    }
+}

+ 38 - 0
src/main/java/com/zy/omp/service/DeviceLpService.java

@@ -0,0 +1,38 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
+import com.zy.omp.model.DeviceLp;
+import com.zy.omp.mapper.DeviceLpMapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.springframework.stereotype.Service;
+
+/**
+ * <p>
+ * 设备-路牌 服务实现类
+ * </p>
+ *
+ * @author chenyi
+ * @since 2021-06-12
+ */
+@Service
+public class DeviceLpService extends ServiceImpl<DeviceLpMapper, DeviceLp> {
+
+    /**
+     * 通过设备 num 获取设备信息
+     *
+     * @param num 设备号
+     */
+    public DeviceLp getByNum(String num) {
+        QueryWrapper<DeviceLp> queryWrapper = new QueryWrapper<DeviceLp>().eq("num", num);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 更新设备信息
+     */
+    public void updateByNum(DeviceLp entity, String num) {
+        UpdateWrapper<DeviceLp> updateWrapper = new UpdateWrapper<DeviceLp>().eq("num", num);
+        baseMapper.update(entity, updateWrapper);
+    }
+}

+ 62 - 0
src/main/java/com/zy/omp/service/DeviceService.java

@@ -0,0 +1,62 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.pojo.io.pc.DeviceIO;
+import com.zy.omp.pojo.vo.DeviceFullDataVo;
+import com.zy.omp.mapper.DeviceMapper;
+import com.zy.omp.model.Device;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+
+/**
+ * 设备信息相关
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class DeviceService extends ServiceImpl<DeviceMapper, Device> {
+
+    /**
+     * 后台
+     * 分页查询设备列表
+     *
+     * @param io 查询条件
+     */
+    public IPage<DeviceFullDataVo> listPage(DeviceIO io) {
+        Page<DeviceFullDataVo> page = new Page<>(io.getCurrent(), io.getSize());
+        return baseMapper.listPage(page, io);
+    }
+
+    /**
+     * 批量更新设备在线状态
+     */
+    public void updateDeviceStatus(List<Device> devices) {
+        baseMapper.updateDeviceStatus(devices);
+    }
+
+    /**
+     * 通过设备 num 获取设备信息
+     *
+     * @param num 设备号
+     */
+    public Device getByNum(String num) {
+        QueryWrapper<Device> queryWrapper = new QueryWrapper<Device>().eq("num", num);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 通过设备 clientId 获取设备信息
+     *
+     * @param clientId 设备 MQTT 登录账号
+     */
+    public Device getByClientId(String clientId) {
+        QueryWrapper<Device> queryWrapper = new QueryWrapper<Device>().eq("clientId", clientId);
+        return baseMapper.selectOne(queryWrapper);
+    }
+}

+ 68 - 0
src/main/java/com/zy/omp/service/IdiomsService.java

@@ -0,0 +1,68 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.mapper.IdiomsMapper;
+import com.zy.omp.model.UserIdioms;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 常用语 Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class IdiomsService extends ServiceImpl<IdiomsMapper, UserIdioms> {
+
+    /**
+     * 添加常用语
+     *
+     * @param userId  用户Id
+     * @param content 常用语内容
+     */
+    public void saveEntity(String userId, String content) {
+        UserIdioms entity = new UserIdioms();
+        entity.setUserId(userId);
+        entity.setContent(content);
+        baseMapper.insert(entity);
+    }
+
+    /**
+     * 通过用户ID 查询用户常用语
+     *
+     * @param userId 用户ID
+     */
+    public List<UserIdioms> getListByUserId(String userId) {
+        QueryWrapper<UserIdioms> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("userId", userId);
+        queryWrapper.orderByDesc("createTime");
+        return baseMapper.selectList(queryWrapper);
+    }
+
+    /**
+     * 查询用户常用语数量
+     *
+     * @param userId 用户ID
+     */
+    public int countByUserId(String userId) {
+        QueryWrapper<UserIdioms> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("userId", userId);
+        return baseMapper.selectCount(queryWrapper);
+    }
+
+    /**
+     * 删除常用语
+     *
+     * @param id     常用语主键ID
+     * @param userId 用户ID
+     */
+    public int delById(Integer id, String userId) {
+        QueryWrapper<UserIdioms> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("id", id);
+        queryWrapper.eq("userId", userId);
+        return baseMapper.delete(queryWrapper);
+    }
+}

+ 26 - 0
src/main/java/com/zy/omp/service/LatestLocationService.java

@@ -0,0 +1,26 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.pojo.vo.DeviceFullDataVo;
+import com.zy.omp.mapper.LatestLocationMapper;
+import com.zy.omp.model.LatestLocation;
+import org.springframework.stereotype.Service;
+
+import java.util.List;
+
+/**
+ * 设备位置信息相关
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class LatestLocationService extends ServiceImpl<LatestLocationMapper, LatestLocation> {
+
+    /**
+     * 获取所有设备最新的位置信息
+     */
+    public List<DeviceFullDataVo> getLatestLocation() {
+        return baseMapper.getLatestLocation();
+    }
+}

+ 65 - 0
src/main/java/com/zy/omp/service/LocationService.java

@@ -0,0 +1,65 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.pojo.io.wechat.DeviceHistoryIO;
+import com.zy.omp.mapper.LocationMapper;
+import com.zy.omp.model.Location;
+import com.zy.omp.model.LatestLocation;
+import com.zy.omp.utils.BeanUtil;
+import org.springframework.stereotype.Service;
+
+import javax.annotation.Resource;
+import java.util.List;
+
+/**
+ * 设备位置信息相关
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class LocationService extends ServiceImpl<LocationMapper, Location> {
+
+    @Resource
+    private LatestLocationService latestLocationService;
+
+    /**
+     * 保存位置信息
+     */
+    public void saveLocation(Location entity) {
+        save(entity);
+        //更新最新的位置信息
+        QueryWrapper<LatestLocation> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("deviceId", entity.getDeviceId());
+        LatestLocation latestLocation = BeanUtil.cast(entity, LatestLocation.class);
+        latestLocationService.saveOrUpdate(latestLocation, queryWrapper);
+    }
+
+    /**
+     * 获取设备的最新位置信息
+     *
+     * @param deviceId 设备ID
+     */
+    public LatestLocation getLatestLocation(String deviceId) {
+        QueryWrapper<LatestLocation> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("deviceId", deviceId);
+        return latestLocationService.getOne(queryWrapper);
+    }
+
+    /**
+     * 查看设备历史轨迹
+     *
+     * @param io 查询入参
+     */
+    public List<Location> getHistory(DeviceHistoryIO io) {
+        QueryWrapper<Location> queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("lonGcj", "latGcj", "uploadTime")
+                .eq("deviceId", io.getDeviceId())
+                .ge("uploadTime", io.getStartTime())
+                .le("uploadTime", io.getEndTime())
+                .orderByDesc("uploadTime");
+        return baseMapper.selectList(queryWrapper);
+    }
+
+}

+ 54 - 0
src/main/java/com/zy/omp/service/MqttLogService.java

@@ -0,0 +1,54 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.common.Constant;
+import com.zy.omp.pojo.io.pc.MqttLogsIO;
+import com.zy.omp.mapper.MqttLogMapper;
+import com.zy.omp.model.MqttLog;
+import com.zy.omp.pojo.dto.MqttMsgDto;
+import org.springframework.stereotype.Service;
+
+/**
+ * MQTT 收发日志 Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class MqttLogService extends ServiceImpl<MqttLogMapper, MqttLog> {
+
+    /**
+     * 保存 日志
+     *
+     * @param topic   主题
+     * @param payload 消息内容
+     * @param tag     0收 1发
+     */
+    public void saveLog(String topic, String payload, Integer tag) {
+        MqttLog entity = new MqttLog();
+        entity.setTopic(topic);
+        //mqtt 日志类型
+        entity.setTag(tag);
+        //获取消息解析对象
+        MqttMsgDto mqttMsgDto = MqttMsgDto.parse(payload);
+        String regTopic = tag == 0 ? Constant.TOPIC_REGISTER_SERVER : Constant.TOPIC_REGISTER_CLIENT;
+        //区分注册报文和普通报文,注册报文取设备随机码
+        entity.setDeviceId(topic.contains(regTopic) ? mqttMsgDto.getString("regnum") : mqttMsgDto.getDeviceId());
+        //mqtt 指令
+        entity.setInstruction(mqttMsgDto.getM());
+        entity.setContent(payload);
+        baseMapper.insert(entity);
+    }
+
+    /**
+     * 分页查询日志
+     *
+     * @param io 查询条件
+     */
+    public IPage<MqttLog> getListPage(MqttLogsIO io) {
+        Page<MqttLog> page = new Page<>(io.getCurrent(), io.getSize());
+        return baseMapper.getListPage(page, io);
+    }
+}

+ 26 - 0
src/main/java/com/zy/omp/service/NewsService.java

@@ -0,0 +1,26 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.pojo.io.NewsIO;
+import com.zy.omp.mapper.NewsMapper;
+import com.zy.omp.model.News;
+import org.springframework.stereotype.Service;
+
+/**
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class NewsService extends ServiceImpl<NewsMapper, News> {
+    /**
+     * 分页查询播报记录
+     *
+     * @param io 查询参数
+     */
+    public IPage<News> getListPage(NewsIO io) {
+        Page<News> page = new Page<>(io.getCurrent(), io.getSize());
+        return baseMapper.getListPage(page, io);
+    }
+}

+ 122 - 0
src/main/java/com/zy/omp/service/RabbitMQApi.java

@@ -0,0 +1,122 @@
+package com.zy.omp.service;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONArray;
+import com.alibaba.fastjson.JSONObject;
+import com.zy.omp.utils.HttpUtil;
+import org.springframework.http.HttpHeaders;
+import org.springframework.stereotype.Component;
+
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * RabbitMQ HTTP API接口请求
+ *
+ * @author yang xiao kun
+ * create on 2021/5/14
+ */
+@Component
+public class RabbitMQApi {
+
+    /**
+     * 获取在线的设备
+     */
+    public Set<String> getOnlineDevice() {
+        String url = "http://view.ailishi.org:15672/api/connections?page=1&page_size=500";
+        //请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("authorization", "Basic bHEyMDE5OkxpUXVhblJhYmJpdA==");
+        String httpRes = HttpUtil.getForEntity(url, headers);
+        Set<String> result = new HashSet<>();
+        if (httpRes != null) {
+            JSONObject jsonObject = JSON.parseObject(httpRes);
+            JSONArray jsonArray = jsonObject.getJSONArray("items");
+            for (int i = 0; i < jsonArray.size(); i++) {
+                result.add(jsonArray.getJSONObject(i).getString("user"));
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 向 MQTT 服务器申请用户,供设备进行登录
+     * <p>
+     * 因为存在先后问题,需要先注册用户,在开通虚拟机权限,
+     * 所以逻辑为
+     * 发送注册用户请求
+     * 尝试申请权限
+     * 如果失败,则间隔一秒再次请求
+     * 如果申请次数超过3次,则尝试重新注册
+     * 重新注册后再次尝试申请
+     * 如果申请五次都失败,则结束方法,记录日志
+     *
+     * @param clientId 设备登录ID
+     * @param password 设备登录密码
+     */
+    public void registerMqtt(String clientId, String password) {
+        addRabbitMqUser(clientId, password);
+        int count = 0;
+        while (!setPermission(clientId)) {
+            try {
+                Thread.sleep(1000);
+                if (count == 2) {
+                    addRabbitMqUser(clientId, password);
+                }
+                if (count > 4) {
+                    break;
+                }
+                count++;
+            } catch (InterruptedException e) {
+                e.printStackTrace();
+                break;
+            }
+        }
+    }
+
+    /**
+     * 注册 RabbitMQ 用户
+     *
+     * @param clientId 用户名
+     * @param password 用户密码
+     */
+    private void addRabbitMqUser(String clientId, String password) {
+        String url = "http://view.ailishi.org:15672/api/users/" + clientId;
+        //请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("authorization", "Basic bHEyMDE5OkxpUXVhblJhYmJpdA==");
+        //请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("username", clientId);
+        params.put("password", password);
+        params.put("tags", "");
+        HttpUtil.putForJSONEntity(url, headers, JSON.toJSONString(params));
+    }
+
+    /**
+     * 申请虚拟机权限
+     *
+     * @param clientId 用户ID
+     */
+    private boolean setPermission(String clientId) {
+        String url = "http://view.ailishi.org:15672/api/permissions/%2F/" + clientId;
+        //请求头
+        HttpHeaders headers = new HttpHeaders();
+        headers.add("authorization", "Basic bHEyMDE5OkxpUXVhblJhYmJpdA==");
+        //请求参数
+        Map<String, String> params = new HashMap<>();
+        params.put("username", clientId);
+        params.put("vhost", "/");
+        params.put("configure", ".*");
+        params.put("write", ".*");
+        params.put("read", ".*");
+        try {
+            HttpUtil.putForJSONEntity(url, headers, JSON.toJSONString(params));
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+}

+ 73 - 0
src/main/java/com/zy/omp/service/SetBaseService.java

@@ -0,0 +1,73 @@
+package com.zy.omp.service;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.common.exception.ApiRuntimeException;
+import com.zy.omp.mapper.SetBaseMapper;
+import com.zy.omp.model.SetBase;
+import org.springframework.stereotype.Service;
+
+/**
+ * 其他设置相关
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class SetBaseService extends ServiceImpl<SetBaseMapper, SetBase> {
+
+    /**
+     * 后台
+     * 获取全部的设置信息
+     *
+     * @param deviceId 设备ID
+     */
+    public SetBase getByDeviceId(String deviceId) {
+        QueryWrapper<SetBase> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("deviceId", deviceId);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 获取音量设置信息
+     */
+    public SetBase getVolumeSet(String deviceId) {
+        QueryWrapper<SetBase> queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("deviceId", "msgVol", "phoneVol", "ringVol");
+        queryWrapper.eq("deviceId", deviceId);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 获取SOS设置信息
+     */
+    public SetBase getSosSet(String deviceId) {
+        QueryWrapper<SetBase> queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("deviceId", "key0Name", "key0Phone", "key1Name", "key1Phone", "key2Name", "key2Phone");
+        queryWrapper.eq("deviceId", deviceId);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 获取其他设置设置信息
+     */
+    public SetBase getOtherSet(String deviceId) {
+        QueryWrapper<SetBase> queryWrapper = new QueryWrapper<>();
+        queryWrapper.select("deviceId", "autoAnswer", "gpsRate", "highFreq");
+        queryWrapper.eq("deviceId", deviceId);
+        return baseMapper.selectOne(queryWrapper);
+    }
+
+    /**
+     * 通过设备ID 更新设备信息
+     *
+     * @param entity 设备实体类
+     */
+    public void updateByDeviceId(SetBase entity) {
+        QueryWrapper<SetBase> queryWrapper = new QueryWrapper<>();
+        queryWrapper.eq("deviceId", entity.getDeviceId());
+        if (baseMapper.update(entity, queryWrapper) < 1) {
+            throw new ApiRuntimeException("更新设备设置信息失败");
+        }
+    }
+}

+ 174 - 0
src/main/java/com/zy/omp/service/SetService.java

@@ -0,0 +1,174 @@
+package com.zy.omp.service;
+
+import com.zy.omp.common.Constant;
+import com.zy.omp.model.DeviceLp;
+import com.zy.omp.pojo.dto.MqttMsgDto;
+import com.zy.omp.config.mqtt.MqttGateway;
+import com.zy.omp.model.Device;
+import com.zy.omp.model.SetBase;
+import com.zy.omp.model.News;
+import com.zy.omp.pojo.io.wechat.SetIO;
+import com.zy.omp.utils.BeanUtil;
+import com.zy.omp.websocket.WebSocketServer;
+import org.springframework.stereotype.Component;
+
+import javax.annotation.Resource;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * 设备设置 Service
+ *
+ * @author chen_yi
+ * Create on 2021/3/27
+ */
+@Component
+public class SetService {
+
+    @Resource
+    private SetBaseService setBaseService;
+    @Resource
+    private NewsService setNewsService;
+    @Resource
+    private MqttGateway mqttGateway;
+    @Resource
+    private MqttLogService mqttLogService;
+    @Resource
+    private WebSocketServer webSocketServer;
+
+    /**
+     * 设置设备
+     *
+     * @param code 设置指令
+     * @param io   设置信息
+     */
+    public void set(String code, SetIO io) {
+        MqttMsgDto msgDto = getMqttMsgDtoByCode(code, io);
+        // 1. 向设备发送设置指令
+        mqttGateway.sendMsgToMqtt(msgDto.toJson(), io.getTopic());
+        // 2. 设置信息保存至数据库
+        saveToDataBase(code, io);
+        // 3. 存储消息日志
+        mqttLogService.saveLog(io.getTopic(), msgDto.toJson(), 1);
+        // 4. 消息转发前端webSocket
+        String deviceId = io.getTopic().split("/")[1];
+        webSocketServer.massMessage(deviceId, msgDto.toJson());
+    }
+
+    /**
+     * 服务器返回授权码
+     * 老人机
+     */
+    public void returnCode_OMP(Device device) {
+        //发送模板消息给设备
+        MqttMsgDto msgDto = new MqttMsgDto();
+        msgDto.setM(Constant.M_CODE_RETURN_CODE);
+        msgDto.setR(Constant.TOPIC_REGISTER_CLIENT);
+        msgDto.setT(Constant.TOPIC_REGISTER_SERVER);
+        Map<String, Object> data = new HashMap<>();
+        data.put("regnum", device.getNum());
+        data.put("deviceid", device.getClientId());
+        data.put("password", device.getPassword());
+        msgDto.setData(data);
+        mqttGateway.sendMsgToMqtt(msgDto.toJson(), Constant.TOPIC_REGISTER_CLIENT);
+        // 3. 存储消息日志
+        mqttLogService.saveLog(Constant.TOPIC_REGISTER_CLIENT, msgDto.toJson(), 1);
+    }
+
+    /**
+     * 存储至数据库
+     */
+    private void saveToDataBase(String code, SetIO io) {
+        //发送语音播报单独处理
+        if (code.equals(Constant.M_CODE_NEWS)) {
+            News entity = BeanUtil.cast(io, News.class);
+            setNewsService.save(entity);
+        } else {
+            SetBase entity = BeanUtil.cast(io, SetBase.class);
+            setBaseService.updateByDeviceId(entity);
+        }
+    }
+
+    /**
+     * 组装需要发送的模板消息
+     *
+     * @param code 协议中 M 值
+     * @param io   设置信息
+     * @return 模板消息对象
+     */
+    private MqttMsgDto getMqttMsgDtoByCode(String code, SetIO io) {
+        MqttMsgDto result = new MqttMsgDto(code, io.getDeviceId());
+        switch (code) {
+            //自动接听
+            case Constant.M_CODE_AUTO_ANSWER: {
+                result.set("autoanswer", io.getAutoAnswer());
+                break;
+            }
+            //音量
+            case Constant.M_CODE_VOLUME: {
+                result.set("msgvol", io.getMsgVol()).set("phonevol", io.getPhoneVol()).set("msgtype", 1);
+                break;
+            }
+            //定位频率
+            case Constant.M_CODE_GPS_RATE: {
+                result.set("GPS_rate", io.getGpsRate());
+                break;
+            }
+            //语音播报
+            case Constant.M_CODE_NEWS: {
+                result.set("newstype", io.getNewsType()).set("newstime", io.getNewsTime()).set("news", io.getNews());
+                break;
+            }
+            //SOS紧急呼叫
+            case Constant.M_CODE_SOS: {
+                result.set("key0_name", io.getKey0Name()).set("key0_phone", io.getKey0Phone())
+                        .set("key1_name", io.getKey1Name()).set("key1_phone", io.getKey1Phone())
+                        .set("key2_name", io.getKey2Name()).set("key2_phone", io.getKey2Phone());
+                break;
+            }
+            //持续定位
+            case Constant.M_CODE_CONTINUE_GPS: {
+                result.set("highfreq", io.getHighFreq());
+                break;
+            }
+        }
+        return result;
+    }
+
+    /**
+     * 服务器返回授权码
+     * 路牌
+     */
+    public void returnCode_LP(DeviceLp device) {
+        //发送模板消息给设备
+        MqttMsgDto msgDto = new MqttMsgDto();
+        msgDto.setM(Constant.M_CODE_RETURN_CODE);
+        Map<String, Object> data = new HashMap<>();
+        data.put("regnum", device.getNum());
+        data.put("sn", "SN" + device.getNum());
+        data.put("password", "123456");
+        data.put("group", device.getGroup());
+        msgDto.setData(data);
+        mqttGateway.sendMsgToMqtt(msgDto.toJson(), Constant.TOPIC_REGISTER_CLIENT_LP);
+        // 3. 存储消息日志
+        mqttLogService.saveLog(Constant.TOPIC_REGISTER_CLIENT_LP, msgDto.toJson(), 1);
+    }
+
+    /**
+     * 服务器返回授权码
+     * 路牌
+     */
+    public void updateDevice_LP(String num, Integer wakeInt, Double thresh) {
+        //发送模板消息给设备
+        MqttMsgDto msgDto = new MqttMsgDto();
+        msgDto.setM(Constant.M_CODE_UPDATE_DEVICE_INFO_LP);
+        Map<String, Object> data = new HashMap<>();
+        data.put("setf", "true");
+        data.put("wakeint", wakeInt);
+        data.put("thresh", thresh);
+        msgDto.setData(data);
+        mqttGateway.sendMsgToMqtt(msgDto.toJson(), Constant.TOPIC_DEVICE_CLIENT_LP + num);
+        // 3. 存储消息日志
+        mqttLogService.saveLog(Constant.M_CODE_UPDATE_DEVICE_INFO_LP, msgDto.toJson(), 1);
+    }
+}

+ 61 - 0
src/main/java/com/zy/omp/service/UserService.java

@@ -0,0 +1,61 @@
+package com.zy.omp.service;
+
+import com.alibaba.fastjson.JSONObject;
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.core.metadata.IPage;
+import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import com.zy.omp.common.Constant;
+import com.zy.omp.pojo.io.pc.UserIO;
+import com.zy.omp.mapper.UserMapper;
+import com.zy.omp.model.User;
+import com.zy.omp.utils.HttpUtil;
+import org.springframework.stereotype.Service;
+import org.springframework.util.LinkedMultiValueMap;
+import org.springframework.util.MultiValueMap;
+
+/**
+ * 用户Service
+ *
+ * @author chenyi
+ * Create on 2020/4/10
+ */
+@Service
+public class UserService extends ServiceImpl<UserMapper, User> {
+
+    /**
+     * 后台
+     * 分页查询用户列表
+     *
+     * @param io 查询条件
+     */
+    public IPage<User> listPage(UserIO io) {
+        Page<User> page = new Page<>(io.getCurrent(), io.getSize());
+        return baseMapper.listPage(page, io);
+    }
+
+    /**
+     * 通过 openId 查询用户
+     */
+    public User getByOpenId(String openId) {
+        return baseMapper.selectOne(new QueryWrapper<User>().eq("openId", openId));
+    }
+
+    /**
+     * 通过微信传来的code 换取 appid
+     */
+    public String getWxAppId(String code) {
+        try {
+            // 请求参数
+            MultiValueMap<String, String> paramsMap = new LinkedMultiValueMap<>();
+            paramsMap.add("appid", Constant.wxAppId);
+            paramsMap.add("secret", Constant.wxSecret);
+            paramsMap.add("js_code", code);
+            paramsMap.add("grant_type", Constant.grant_type);
+            String message = HttpUtil.post("https://api.weixin.qq.com/sns/jscode2session", null, paramsMap);
+            return JSONObject.parseObject(message).getString("openid");
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 74 - 0
src/main/java/com/zy/omp/utils/AesUtils.java

@@ -0,0 +1,74 @@
+package com.zy.omp.utils;
+
+import javax.crypto.Cipher;
+import javax.crypto.KeyGenerator;
+import javax.crypto.SecretKey;
+import javax.crypto.spec.SecretKeySpec;
+import java.security.Key;
+import java.security.SecureRandom;
+import java.util.Base64;
+
+/**
+ * AES对称加密工具类
+ *
+ * @author yangxiaokun
+ */
+public class AesUtils {
+
+    private static final String KEY_ALGORITHM = "AES";
+    private static final String CIPHER_ALGORITHM = "AES/ECB/PKCS5Padding";
+    //进行了Base64编码的秘钥(由keyGenerate()方法生成的)
+    private static final String KEY_NUM = "6RAwrG9BcU1D1bObGGskqw==";
+
+    /**
+     * AES对称-加密操作
+     *
+     * @param data 需要进行加密的原文
+     * @return 数据密文,加密后的数据,进行了Base64的编码
+     */
+    public static String encrypt(String data) {
+        try {
+            // 转换密钥
+            Key key = new SecretKeySpec(Base64.getDecoder().decode(KEY_NUM), KEY_ALGORITHM);
+            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+            // 加密
+            cipher.init(Cipher.ENCRYPT_MODE, key);
+            byte[] result = cipher.doFinal(data.getBytes());
+            return Base64.getEncoder().encodeToString(result);
+        } catch (Exception e) {
+            return "AES";
+        }
+    }
+
+    /**
+     * @param data 需要解密的数据(数据必须是通过AES进行加密后,对加密数据Base64编码的数据)
+     * @return String 返回解密后的原文
+     */
+    public static String decrypt(String data) {
+        try {
+            // 转换密钥
+            Key key = new SecretKeySpec(Base64.getDecoder().decode(KEY_NUM), KEY_ALGORITHM);
+            Cipher cipher = Cipher.getInstance(CIPHER_ALGORITHM);
+            // 解密
+            cipher.init(Cipher.DECRYPT_MODE, key);
+            byte[] result = cipher.doFinal(Base64.getDecoder().decode(data));
+            return new String(result);
+        } catch (Exception e) {
+            return null;
+        }
+    }
+
+    /**
+     * 生成AES的秘钥,秘钥进行了Base64编码的字符串
+     *
+     * @return 对生成的秘钥进行了Base64编码的字符串
+     */
+    public static String keyGenerate() throws Exception {
+        // 生成密钥
+        KeyGenerator keyGenerator = KeyGenerator.getInstance(KEY_ALGORITHM);
+        keyGenerator.init(new SecureRandom());
+        SecretKey secretKey = keyGenerator.generateKey();
+        byte[] keyBytes = secretKey.getEncoded();
+        return Base64.getEncoder().encodeToString(keyBytes);
+    }
+}

+ 22 - 0
src/main/java/com/zy/omp/utils/BeanUtil.java

@@ -0,0 +1,22 @@
+package com.zy.omp.utils;
+
+import com.github.dozermapper.core.DozerBeanMapperBuilder;
+import com.github.dozermapper.core.Mapper;
+
+/**
+ * @author yangxiaokun
+ * Create on 2021/1/5
+ */
+public class BeanUtil {
+    private static Mapper mapper = DozerBeanMapperBuilder.buildDefault();
+
+    /**
+     * 强转 类型
+     *
+     * @param source      源对象
+     * @param targetClass 目标class
+     */
+    public static <T> T cast(Object source, Class<T> targetClass) {
+        return mapper.map(source, targetClass);
+    }
+}

+ 41 - 0
src/main/java/com/zy/omp/utils/CodeGenerator.java

@@ -0,0 +1,41 @@
+package com.zy.omp.utils;
+
+import java.util.UUID;
+
+/**
+ * 生成随机码
+ *
+ * @author yang xiao kun
+ * create on 2021/1/15
+ */
+public class CodeGenerator {
+
+    private static final String[] codeChars = {
+            "0", "1", "2", "3", "4", "5", "6", "7", "8", "9",
+            "a", "b", "c", "d", "e", "f", "g", "h", "i", "j",
+            "k", "l", "m", "n", "o", "p", "q", "r", "s", "t",
+            "u", "v", "w", "x", "y", "z", "A", "B", "C", "D",
+            "E", "F", "G", "H", "I", "J", "K", "L", "M", "N",
+            "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X",
+            "Y", "Z"};
+
+    /**
+     * 生成短八位UUID随机码
+     */
+    public static String shortUuid() {
+        StringBuilder stringBuilder = new StringBuilder();
+        String uuid = UUID.randomUUID().toString().replace("-", "");
+        for (int i = 0; i < 8; i++) {
+            stringBuilder.append(codeChars[Integer.parseInt(uuid.substring(i * 4, i * 4 + 4), 16) % 0x3E]);
+        }
+        return stringBuilder.toString();
+    }
+
+    /**
+     * 随机生成UUID
+     * 小写,去掉 '-'
+     */
+    public static String generateUUID() {
+        return UUID.randomUUID().toString().replace("-", "");
+    }
+}

+ 153 - 0
src/main/java/com/zy/omp/utils/CoordTransformUtil.java

@@ -0,0 +1,153 @@
+package com.zy.omp.utils;
+
+import java.text.DecimalFormat;
+
+/**
+ * 坐标转换工具类
+ * 同芯片厂家提供一致
+ *
+ * @author yang xiao kun
+ * create on 2021/2/3
+ */
+public class CoordTransformUtil {
+
+    //定义一些常量
+    private static final double x_PI = 52.359877559829887;//3.14159265358979324 * 3000.0 / 180.0
+    private static final double PI = 3.1415926535897932384626;
+    private static final double a = 6378245.0;
+    private static final double ee = 0.00669342162296594323;
+    private static final DecimalFormat decimalFormat = new DecimalFormat("#.000000");//保留七位
+
+    /**
+     * WGS84转GCj02
+     *
+     * @param lngStr 经度 dd.dddd
+     * @param latStr 纬度 dd.dddd
+     */
+    public static String[] wgs84toGcj02(String lngStr, String latStr) {
+        double lat = Double.parseDouble(latStr);
+        double lng = Double.parseDouble(lngStr);
+
+        double dLat = transformLat(lng - 105.0, lat - 35.0);
+        double dLng = transformLng(lng - 105.0, lat - 35.0);
+        double radLat = lat / 180.0 * PI;
+        double magic = Math.sin(radLat);
+        magic = 1 - ee * magic * magic;
+        double sqrtMagic = Math.sqrt(magic);
+        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
+        dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
+        double mgLat = lat + dLat;
+        double mgLng = lng + dLng;
+        return new String[]{decimalFormat.format(mgLng), decimalFormat.format(mgLat)};
+    }
+
+    /**
+     * GCJ02 转换为 WGS84
+     *
+     * @param lngStr 经度 dd.dddd
+     * @param latStr 纬度 dd.dddd
+     */
+    public static String[] gcj02toWgs84(String lngStr, String latStr) {
+        double lat = Double.parseDouble(latStr);
+        double lng = Double.parseDouble(lngStr);
+        double dLat = transformLat(lng - 105.0, lat - 35.0);
+        double dLng = transformLng(lng - 105.0, lat - 35.0);
+        double radLat = lat / 180.0 * PI;
+        double magic = Math.sin(radLat);
+        magic = 1 - ee * magic * magic;
+        double sqrtMagic = Math.sqrt(magic);
+        dLat = (dLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * PI);
+        dLng = (dLng * 180.0) / (a / sqrtMagic * Math.cos(radLat) * PI);
+        double mgLat = lat + dLat;
+        double mgLng = lng + dLng;
+        return new String[]{decimalFormat.format(lng * 2 - mgLng), decimalFormat.format(lat * 2 - mgLat)};
+    }
+
+    /**
+     * 坐标格式转换
+     * ddmm.mmmm -> dd.dddd
+     *
+     * @param val 经纬度
+     */
+    public static String dm2dd(String val) {
+        String[] varArr = String.valueOf(Double.parseDouble(val) / 100).split("\\.");
+        double num1 = Double.parseDouble(varArr[0]);
+        double num2 = Double.parseDouble("0." + varArr[1]) * 100 / 60;
+        return String.valueOf(num1 + num2);
+    }
+
+    /**
+     * 坐标格式转换
+     * dd.dddd -> ddmm.mmmm
+     *
+     * @param val 经纬度
+     */
+    public static String dd2dm(String val) {
+        String[] varArr = val.split("\\.");
+        double num1 = Double.parseDouble("0." + varArr[1]) * 60;
+        double num2 = Double.parseDouble(varArr[0]) * 100 + num1;
+        return String.valueOf(num2);
+    }
+
+    /**
+     * 百度坐标系 (BD-09) 与 火星坐标系 (GCJ-02)的转换
+     * 即 百度 转 谷歌、高德
+     *
+     * @param bd_lon 百度坐标系 经度
+     * @param bd_lat 百度坐标系 纬度
+     */
+    public static String[] bd09ToGcj02(String bd_lon, String bd_lat) {
+        double x = Double.parseDouble(bd_lon) - 0.0065;
+        double y = Double.parseDouble(bd_lat) - 0.006;
+        double z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * x_PI);
+        double theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * x_PI);
+        double gg_lng = z * Math.cos(theta);
+        double gg_lat = z * Math.sin(theta);
+        return new String[]{decimalFormat.format(gg_lng), decimalFormat.format(gg_lat)};
+    }
+
+    /**
+     * 火星坐标系 (GCJ-02) 与百度坐标系 (BD-09) 的转换
+     * 即谷歌、高德 转 百度
+     *
+     * @param lngStr 经度
+     * @param latStr 纬度
+     */
+    public static String[] gcj02toBd09(String lngStr, String latStr) {
+        double lat = Double.parseDouble(latStr);
+        double lng = Double.parseDouble(lngStr);
+        double z = Math.sqrt(lng * lng + lat * lat) + 0.00002 * Math.sin(lat * x_PI);
+        double theta = Math.atan2(lat, lng) + 0.000003 * Math.cos(lng * x_PI);
+        double bd_lng = z * Math.cos(theta) + 0.0065;
+        double bd_lat = z * Math.sin(theta) + 0.006;
+        return new String[]{decimalFormat.format(bd_lng), decimalFormat.format(bd_lat)};
+    }
+
+    /**
+     * 转换纬度
+     *
+     * @param lng 经度
+     * @param lat 纬度
+     */
+    private static double transformLat(double lng, double lat) {
+        double ret = -100.0 + 2.0 * lng + 3.0 * lat + 0.2 * lat * lat + 0.1 * lng * lat + 0.2 * Math.sqrt(Math.abs(lng));
+        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(lat * PI) + 40.0 * Math.sin(lat / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (160.0 * Math.sin(lat / 12.0 * PI) + 320 * Math.sin(lat * PI / 30.0)) * 2.0 / 3.0;
+        return ret;
+    }
+
+    /**
+     * 转换经度
+     *
+     * @param lng 经度
+     * @param lat 纬度
+     */
+    private static double transformLng(double lng, double lat) {
+        double ret = 300.0 + lng + 2.0 * lat + 0.1 * lng * lng + 0.1 * lng * lat + 0.1 * Math.sqrt(Math.abs(lng));
+        ret += (20.0 * Math.sin(6.0 * lng * PI) + 20.0 * Math.sin(2.0 * lng * PI)) * 2.0 / 3.0;
+        ret += (20.0 * Math.sin(lng * PI) + 40.0 * Math.sin(lng / 3.0 * PI)) * 2.0 / 3.0;
+        ret += (150.0 * Math.sin(lng / 12.0 * PI) + 300.0 * Math.sin(lng / 30.0 * PI)) * 2.0 / 3.0;
+        return ret;
+    }
+}

+ 24 - 0
src/main/java/com/zy/omp/utils/DateTimeUtil.java

@@ -0,0 +1,24 @@
+package com.zy.omp.utils;
+
+import java.time.LocalDateTime;
+import java.time.format.DateTimeFormatter;
+
+/**
+ * 时间格式化工具类
+ *
+ * @author yang xiao kun
+ * create on 2021/3/31
+ */
+public class DateTimeUtil {
+
+    public static final String Pattern_YDMHMS = "yyyy-MM-dd HH:mm:ss";
+
+    /**
+     * 字符串转时间
+     *
+     * @param str 字符串
+     */
+    public static LocalDateTime strToTime(String str) {
+        return LocalDateTime.parse(str, DateTimeFormatter.ofPattern(DateTimeUtil.Pattern_YDMHMS));
+    }
+}

+ 33 - 0
src/main/java/com/zy/omp/utils/GaoDeApiUtil.java

@@ -0,0 +1,33 @@
+package com.zy.omp.utils;
+
+import com.alibaba.fastjson.JSON;
+import com.alibaba.fastjson.JSONObject;
+
+/**
+ * 高德API 服务类
+ *
+ * @author yang xiao kun
+ * create on 2021/2/4
+ */
+public class GaoDeApiUtil {
+
+    private static final String url = "https://restapi.amap.com/v3/geocode/regeo?key=10ab24979b475f6ea5eba052c0c2016f&location={1}";
+
+    /**
+     * 逆地址解析,获取位置的详细描述信息
+     *
+     * @param lng 经度
+     * @param lat 纬度
+     */
+    public static String regeo(String lng, String lat) {
+        if (lng == null || lat == null) return null;
+        try {
+            String result = HttpUtil.getForEntity(url, lng + "," + lat);
+            JSONObject jsonMap = JSON.parseObject(result);
+            JSONObject regeoCode = jsonMap.getJSONObject("regeocode");
+            return regeoCode.getString("formatted_address");
+        } catch (Exception e) {
+            return null;
+        }
+    }
+}

+ 72 - 0
src/main/java/com/zy/omp/utils/HttpUtil.java

@@ -0,0 +1,72 @@
+package com.zy.omp.utils;
+
+import org.springframework.http.*;
+import org.springframework.util.MultiValueMap;
+import org.springframework.web.client.RestTemplate;
+
+import java.net.URI;
+import java.util.Map;
+
+/**
+ * Http 工具类
+ *
+ * @author chenyi
+ * date create on 2019/4/21
+ */
+public class HttpUtil {
+
+    private static final RestTemplate restTemplate = new RestTemplate();
+
+    /**
+     * 发送 PUT 请求
+     *
+     * @param url 请求地址
+     */
+    public static String putForJSONEntity(String url, HttpHeaders header, String json) {
+        header.setContentType(MediaType.APPLICATION_JSON_UTF8);
+        HttpEntity<String> httpEntity = new HttpEntity<>(json, header);
+        return restTemplate.exchange(URI.create(url), HttpMethod.PUT, httpEntity, String.class).getBody();
+    }
+
+    /**
+     * 发送 Get 请求
+     *
+     * @param url 请求地址
+     */
+    public static String getForEntity(String url, HttpHeaders header, Object... uriVariables) {
+        HttpEntity<String> httpEntity = new HttpEntity<>(header);
+        ResponseEntity<String> result = restTemplate.exchange(url, HttpMethod.GET, httpEntity, String.class, uriVariables);
+        return result.getBody();
+    }
+
+    /**
+     * 发送 Get 请求
+     *
+     * @param url          请求地址
+     * @param uriVariables 请求参数
+     */
+    public static String getForEntity(String url, Object... uriVariables) {
+        ResponseEntity<String> result = restTemplate.getForEntity(url, String.class, uriVariables);
+        return result.getBody();
+    }
+
+    /**
+     * 发送 POST 请求
+     * JSON 格式请求信息
+     *
+     * @param url    地址
+     * @param params 参数
+     */
+    public static String post(String url, Map<String, String> header, MultiValueMap<String, String> params) {
+        HttpHeaders headers = new HttpHeaders();
+        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
+        //设置请求头信息
+        if (header != null && !header.isEmpty()) {
+            for (Map.Entry<String, String> entry : header.entrySet()) {
+                headers.add(entry.getKey(), entry.getValue());
+            }
+        }
+        HttpEntity<MultiValueMap<String, String>> request = new HttpEntity<>(params, headers);
+        return restTemplate.postForEntity(url, request, String.class).getBody();
+    }
+}

+ 35 - 0
src/main/java/com/zy/omp/utils/MD5Util.java

@@ -0,0 +1,35 @@
+package com.zy.omp.utils;
+
+import java.security.MessageDigest;
+
+/**
+ * MD5 字符串加密
+ *
+ * @author chen_yi
+ * Create on 2020/10/17
+ */
+public class MD5Util {
+    /**
+     * MD5 字符串加密
+     *
+     * @param plainText 加密字符串
+     */
+    public static String MD5Encode(String plainText) {
+        try {
+            StringBuilder stringBuilder = new StringBuilder();
+            MessageDigest messageDigest = MessageDigest.getInstance("MD5");
+            messageDigest.update(plainText.getBytes());
+            byte[] bytes = messageDigest.digest();
+            int i;
+            for (byte value : bytes) {
+                i = value;
+                if (i < 0) i += 256;
+                if (i < 16) stringBuilder.append("0");
+                stringBuilder.append(Integer.toHexString(i));
+            }
+            return stringBuilder.toString();
+        } catch (Exception e) {
+            return "MD5";
+        }
+    }
+}

+ 76 - 0
src/main/java/com/zy/omp/websocket/WebSocketServer.java

@@ -0,0 +1,76 @@
+package com.zy.omp.websocket;
+
+import org.springframework.stereotype.Component;
+
+import javax.websocket.*;
+import javax.websocket.server.PathParam;
+import javax.websocket.server.ServerEndpoint;
+import java.io.IOException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+/**
+ * webSocket 监听器
+ */
+@Component
+@ServerEndpoint("/webSocket/{deviceId}")
+public class WebSocketServer {
+
+    /**
+     * 存放每个客户端对应的MyWebSocket对象。
+     * key : 设备ID
+     * value : 实时接收该设备的web端session
+     */
+    private static ConcurrentHashMap<String, Set<Session>> webSocketMap = new ConcurrentHashMap<>();
+
+    /**
+     * 连接成功
+     */
+    @OnOpen
+    public void onOpen(Session session, @PathParam("deviceId") String deviceId) {
+        //如果该设备没有web端查看,则初始化
+        if (!webSocketMap.containsKey(deviceId)) webSocketMap.put(deviceId, new HashSet<>());
+        //添加到集合中
+        webSocketMap.get(deviceId).add(session);
+    }
+
+    /**
+     * 连接关闭
+     */
+    @OnClose
+    public void onClose(Session session, @PathParam("deviceId") String deviceId) {
+        webSocketMap.get(deviceId).remove(session);
+    }
+
+    /**
+     * 连接错误
+     */
+    @OnError
+    public void onError(Session session, Throwable error, @PathParam("deviceId") String deviceId) {
+        webSocketMap.get(deviceId).remove(session);
+    }
+
+    /**
+     * 群发消息
+     */
+    public void massMessage(String deviceId, String message) {
+        Set<Session> sessions = webSocketMap.get(deviceId);
+        if (sessions == null || sessions.isEmpty()) return;
+        // 遍历客户端 发送消息
+        for (Session session : sessions) {
+            sendMessage(session, message);
+        }
+    }
+
+    /**
+     * 实现服务器主动推送
+     */
+    private void sendMessage(Session session, String message) {
+        try {
+            session.getBasicRemote().sendText(message);
+        } catch (IOException e) {
+            e.printStackTrace();
+        }
+    }
+}

+ 32 - 0
src/main/resources/application-dev.yml

@@ -0,0 +1,32 @@
+server:
+  port: 8081
+spring:
+  redis:
+    host: 59.110.141.39
+    port: 6379
+    timeout: 9000
+    password: CHENyi_406
+  jackson:
+    default-property-inclusion: non_null
+  # MySQL
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://59.110.141.39:3306/zy_mobile?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=true
+    username: useryxk
+    password: CHENyi406@
+    dbcp2:
+      min-idle: 10
+      initial-size: 15
+      max-total: 20
+      max-wait-millis: 2000
+  # mybatis-plus
+mybatis-plus:
+  type-aliases-package: com.zy.bms.model
+  mapper-locations: classpath:mapper/*.xml
+  configuration:
+#    log-impl: org.apache.ibatis.logging.stdout.StdOutImpl
+    map-underscore-to-camel-case: false  # close "user_id"  use userId
+  global-config:
+    db-config:
+      id-type: auto

+ 33 - 0
src/main/resources/application-prod.yml

@@ -0,0 +1,33 @@
+server:
+  port: 9001 # Key product method
+spring:
+  redis:
+    host: localhost
+    port: 6379
+    timeout: 9000
+    password: CHENyi_406
+  jackson:
+    default-property-inclusion: non_null
+    date-format: yyyy-MM-dd HH:mm:ss
+    time-zone: GMT+8
+  # MySQL
+  datasource:
+    type: com.alibaba.druid.pool.DruidDataSource
+    driver-class-name: com.mysql.cj.jdbc.Driver
+    url: jdbc:mysql://localhost:3306/zy_mobile?serverTimezone=Asia/Shanghai&characterEncoding=utf8&useSSL=true
+    username: root
+    password: kun95736489+
+    dbcp2:
+      min-idle: 10
+      initial-size: 15
+      max-total: 20
+      max-wait-millis: 2000
+# mybatis-plus
+mybatis-plus:
+  type-aliases-package: com.zy.bms.model
+  mapper-locations: classpath:mapper/*.xml
+  configuration:
+    map-underscore-to-camel-case: false  # close "user_id"  use userId
+  global-config:
+    db-config:
+      id-type: auto

+ 3 - 0
src/main/resources/application.yml

@@ -0,0 +1,3 @@
+spring:
+  profiles:
+    active: dev

+ 22 - 0
src/main/resources/mapper/CallRecordsMapping.xml

@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.omp.mapper.CallRecordsMapper">
+
+    <select id="getListPage" resultType="com.zy.omp.model.CallRecords">
+        SELECT
+            deviceId,
+            `type`,
+            `key`,
+            phoneNum,
+            talkTime,
+            endTime
+        FROM
+            call_records
+        <where>
+            <if test="io.type != null and io.type > -1">
+                AND `type` = #{io.type}
+            </if>
+        </where>
+            ORDER BY createTime DESC
+    </select>
+</mapper>

+ 12 - 0
src/main/resources/mapper/DeviceDynamicMapping.xml

@@ -0,0 +1,12 @@
+<?xml version="1.0" encoding="UTF-8" ?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.omp.mapper.DeviceDynamicMapper">
+
+    <select id="checkBind" resultType="java.lang.Integer">
+        SELECT IFNULL( (SELECT 1 FROM device_dynamic WHERE deviceNum = #{deviceNum} LIMIT 1) ,0)
+    </select>
+
+    <select id="checkBelong" resultType="java.lang.Integer">
+        SELECT IFNULL( (SELECT 1 FROM device_dynamic WHERE deviceId = #{deviceId} AND userId = #{userId} LIMIT 1), 0)
+    </select>
+</mapper>

+ 5 - 0
src/main/resources/mapper/DeviceLpMapper.xml

@@ -0,0 +1,5 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
+<mapper namespace="com.zy.omp.mapper.DeviceLpMapper">
+
+</mapper>

Някои файлове не бяха показани, защото твърде много файлове са промени