sean.zhou
3 years ago
205 changed files with 10748 additions and 0 deletions
@ -0,0 +1,38 @@ |
|||||||
|
HELP.md |
||||||
|
target/ |
||||||
|
!.mvn/wrapper/maven-wrapper.jar |
||||||
|
!**/src/main/**/target/ |
||||||
|
!**/src/test/**/target/ |
||||||
|
|
||||||
|
### 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/ |
||||||
|
!**/src/main/**/build/ |
||||||
|
!**/src/test/**/build/ |
||||||
|
|
||||||
|
### VS Code ### |
||||||
|
.vscode/ |
||||||
|
/.mvn/ |
||||||
|
/mvnw |
||||||
|
/mvnw.cmd |
||||||
|
/logs/ |
||||||
|
/src/test/ |
@ -0,0 +1,148 @@ |
|||||||
|
<?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.4.11</version> |
||||||
|
<relativePath/> <!-- lookup parent from repository --> |
||||||
|
</parent> |
||||||
|
|
||||||
|
<groupId>com.dji</groupId> |
||||||
|
<artifactId>cloud-api-sample</artifactId> |
||||||
|
<version>1.0.0</version> |
||||||
|
<name>cloud-api-sample</name> |
||||||
|
|
||||||
|
<properties> |
||||||
|
<java.version>11</java.version> |
||||||
|
<mybatis-plus.version>3.4.2</mybatis-plus.version> |
||||||
|
<druid.version>1.2.6</druid.version> |
||||||
|
<jwt.version>3.12.1</jwt.version> |
||||||
|
<mqtt.version>5.5.5</mqtt.version> |
||||||
|
<minio.version>8.3.7</minio.version> |
||||||
|
<okhttp3.version>4.9.1</okhttp3.version> |
||||||
|
<aliyun-sdk-sts.version>3.1.0</aliyun-sdk-sts.version> |
||||||
|
<aliyun-oss.version>3.12.0</aliyun-oss.version> |
||||||
|
<javax-activation.version>1.1.1</javax-activation.version> |
||||||
|
<glassfish-jaxb.version>2.3.3</glassfish-jaxb.version> |
||||||
|
<log4j2.version>2.15.0</log4j2.version> |
||||||
|
<javax-jaxb.version>2.3.0</javax-jaxb.version> |
||||||
|
</properties> |
||||||
|
|
||||||
|
<dependencies> |
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-web</artifactId> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>mysql</groupId> |
||||||
|
<artifactId>mysql-connector-java</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>com.baomidou</groupId> |
||||||
|
<artifactId>mybatis-plus-boot-starter</artifactId> |
||||||
|
<version>${mybatis-plus.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.alibaba</groupId> |
||||||
|
<artifactId>druid-spring-boot-starter</artifactId> |
||||||
|
<version>${druid.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.auth0</groupId> |
||||||
|
<artifactId>java-jwt</artifactId> |
||||||
|
<version>${jwt.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.integration</groupId> |
||||||
|
<artifactId>spring-integration-mqtt</artifactId> |
||||||
|
<version>${mqtt.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-starter-websocket</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>org.jetbrains</groupId> |
||||||
|
<artifactId>annotations</artifactId> |
||||||
|
<version>RELEASE</version> |
||||||
|
<scope>compile</scope> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>io.minio</groupId> |
||||||
|
<artifactId>minio</artifactId> |
||||||
|
<version>${minio.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.squareup.okhttp3</groupId> |
||||||
|
<artifactId>okhttp</artifactId> |
||||||
|
<version>${okhttp3.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.aliyun</groupId> |
||||||
|
<artifactId>aliyun-java-sdk-sts</artifactId> |
||||||
|
<version>${aliyun-sdk-sts.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>com.aliyun.oss</groupId> |
||||||
|
<artifactId>aliyun-sdk-oss</artifactId> |
||||||
|
<version>${aliyun-oss.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
<dependency> |
||||||
|
<groupId>javax.xml.bind</groupId> |
||||||
|
<artifactId>jaxb-api</artifactId> |
||||||
|
</dependency> |
||||||
|
<dependency> |
||||||
|
<groupId>javax.activation</groupId> |
||||||
|
<artifactId>activation</artifactId> |
||||||
|
<version>${javax-activation.version}</version> |
||||||
|
</dependency> |
||||||
|
<!-- no more than 2.3.3--> |
||||||
|
<dependency> |
||||||
|
<groupId>org.glassfish.jaxb</groupId> |
||||||
|
<artifactId>jaxb-runtime</artifactId> |
||||||
|
<version>${glassfish-jaxb.version}</version> |
||||||
|
</dependency> |
||||||
|
|
||||||
|
</dependencies> |
||||||
|
|
||||||
|
<build> |
||||||
|
<plugins> |
||||||
|
<plugin> |
||||||
|
<groupId>org.springframework.boot</groupId> |
||||||
|
<artifactId>spring-boot-maven-plugin</artifactId> |
||||||
|
<configuration> |
||||||
|
<excludes> |
||||||
|
<exclude> |
||||||
|
<groupId>org.projectlombok</groupId> |
||||||
|
<artifactId>lombok</artifactId> |
||||||
|
</exclude> |
||||||
|
</excludes> |
||||||
|
</configuration> |
||||||
|
</plugin> |
||||||
|
</plugins> |
||||||
|
</build> |
||||||
|
</project> |
@ -0,0 +1,324 @@ |
|||||||
|
CREATE DATABASE IF NOT EXISTS `cloud_sample` /*!40100 DEFAULT CHARACTER SET utf8 */; |
||||||
|
USE `cloud_sample`; |
||||||
|
|
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_CLIENT=@@CHARACTER_SET_CLIENT */; |
||||||
|
/*!40101 SET @OLD_CHARACTER_SET_RESULTS=@@CHARACTER_SET_RESULTS */; |
||||||
|
/*!40101 SET @OLD_COLLATION_CONNECTION=@@COLLATION_CONNECTION */; |
||||||
|
SET NAMES utf8mb4; |
||||||
|
/*!40014 SET @OLD_FOREIGN_KEY_CHECKS=@@FOREIGN_KEY_CHECKS, FOREIGN_KEY_CHECKS=0 */; |
||||||
|
/*!40101 SET @OLD_SQL_MODE='NO_AUTO_VALUE_ON_ZERO', SQL_MODE='NO_AUTO_VALUE_ON_ZERO' */; |
||||||
|
/*!40111 SET @OLD_SQL_NOTES=@@SQL_NOTES, SQL_NOTES=0 */; |
||||||
|
|
||||||
|
|
||||||
|
# manage_camera_video |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_camera_video`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_camera_video` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`camera_id` int NOT NULL, |
||||||
|
`video_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`video_type` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# manage_capacity_camera |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_capacity_camera`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_capacity_camera` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
||||||
|
`description` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`camera_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`coexist_video_number_max` int NOT NULL, |
||||||
|
`available_video_number` int NOT NULL, |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# manage_device |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_device`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_device` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`device_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
||||||
|
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`device_type` smallint NOT NULL, |
||||||
|
`sub_type` smallint NOT NULL, |
||||||
|
`domain` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`version` smallint NOT NULL, |
||||||
|
`device_index` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`child_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
`device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`url_normal` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`url_select` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `product_sn_UNIQUE` (`device_sn`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# manage_device_dictionary |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_device_dictionary`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_device_dictionary` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`domain` int NOT NULL, |
||||||
|
`device_type` int NOT NULL, |
||||||
|
`sub_type` int NOT NULL, |
||||||
|
`device_name` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`device_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
LOCK TABLES `manage_device_dictionary` WRITE; |
||||||
|
/*!40000 ALTER TABLE `manage_device_dictionary` DISABLE KEYS */; |
||||||
|
|
||||||
|
INSERT INTO `manage_device_dictionary` (`id`, `domain`, `device_type`, `sub_type`, `device_name`, `device_desc`) |
||||||
|
VALUES |
||||||
|
(1,0,60,0,'Matrice 300 RTK',NULL), |
||||||
|
(16,2,56,0,'DJI Smart Controller','Remote control for M300'), |
||||||
|
(17,1,20,0,'Z30',NULL), |
||||||
|
(18,1,26,0,'XT2',NULL), |
||||||
|
(19,1,39,0,'FPV',NULL), |
||||||
|
(20,1,41,0,'XTS',NULL), |
||||||
|
(21,1,42,0,'H20',NULL), |
||||||
|
(22,1,43,0,'H20T',NULL), |
||||||
|
(24,1,90742,0,'L1',NULL), |
||||||
|
(27,1,50,0,'P1 24mm lens',NULL), |
||||||
|
(28,1,50,1,'P1 35mm lens',NULL), |
||||||
|
(29,1,50,2,'P1 50mm lens',NULL), |
||||||
|
(30,0,67,0,'Matrice 30',NULL), |
||||||
|
(31,0,67,1,'Matrice 30T',NULL), |
||||||
|
(32,2,119,0,'DJI RC Plus','Remote control for M30'), |
||||||
|
(33,1,52,0,'M30',NULL), |
||||||
|
(34,1,53,1,'M30T',NULL); |
||||||
|
|
||||||
|
/*!40000 ALTER TABLE `manage_device_dictionary` ENABLE KEYS */; |
||||||
|
UNLOCK TABLES; |
||||||
|
|
||||||
|
|
||||||
|
# manage_device_payload |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_device_payload`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_device_payload` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`payload_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`payload_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
||||||
|
`payload_type` smallint NOT NULL, |
||||||
|
`sub_type` smallint NOT NULL, |
||||||
|
`version` smallint DEFAULT NULL, |
||||||
|
`payload_index` smallint NOT NULL, |
||||||
|
`device_sn` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`payload_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `payload_sn_UNIQUE` (`payload_sn`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# manage_user |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_user`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_user` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`user_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`workspace_id` int NOT NULL, |
||||||
|
`user_type` smallint NOT NULL, |
||||||
|
`mqtt_username` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`mqtt_password` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `user_id_UNIQUE` (`user_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
LOCK TABLES `manage_user` WRITE; |
||||||
|
/*!40000 ALTER TABLE `manage_user` DISABLE KEYS */; |
||||||
|
|
||||||
|
INSERT INTO `manage_user` (`id`, `user_id`, `username`, `password`, `workspace_id`, `user_type`, `mqtt_username`, `mqtt_password`, `create_time`, `update_time`) |
||||||
|
VALUES |
||||||
|
(1,'a1559e7c-8dd8-4780-b952-100cc4797da2','adminPC','adminPC',1,1,'admin','admin',1634898410751,1634898410751), |
||||||
|
(2,'be7c6c3d-afe9-4be4-b9eb-c55066c0914e','pilot','pilot123',1,2,'pilot','pilot123',1634898410751,1634898410751); |
||||||
|
|
||||||
|
/*!40000 ALTER TABLE `manage_user` ENABLE KEYS */; |
||||||
|
UNLOCK TABLES; |
||||||
|
|
||||||
|
|
||||||
|
# manage_workspace |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `manage_workspace`; |
||||||
|
|
||||||
|
CREATE TABLE `manage_workspace` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`workspace_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`workspace_desc` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`platform_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `workspace_id_UNIQUE` (`workspace_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
LOCK TABLES `manage_workspace` WRITE; |
||||||
|
/*!40000 ALTER TABLE `manage_workspace` DISABLE KEYS */; |
||||||
|
|
||||||
|
INSERT INTO `manage_workspace` (`id`, `workspace_id`, `workspace_name`, `workspace_desc`, `platform_name`, `create_time`, `update_time`) |
||||||
|
VALUES |
||||||
|
(1,'e3dea0f5-37f2-4d79-ae58-490af3228069','Test Group One','Cloud Sample Test Platform','Cloud Api Platform',1634898410751,1634898410751); |
||||||
|
|
||||||
|
/*!40000 ALTER TABLE `manage_workspace` ENABLE KEYS */; |
||||||
|
UNLOCK TABLES; |
||||||
|
|
||||||
|
|
||||||
|
# map_element_coordinate |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `map_element_coordinate`; |
||||||
|
|
||||||
|
CREATE TABLE `map_element_coordinate` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`element_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`longitude` decimal(18,14) NOT NULL, |
||||||
|
`latitude` decimal(17,14) NOT NULL, |
||||||
|
`altitude` decimal(17,14) DEFAULT NULL, |
||||||
|
PRIMARY KEY (`id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# map_group |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `map_group`; |
||||||
|
|
||||||
|
CREATE TABLE `map_group` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`group_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`group_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`group_type` int NOT NULL, |
||||||
|
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`is_distributed` tinyint(1) NOT NULL DEFAULT '1', |
||||||
|
`is_lock` tinyint(1) NOT NULL DEFAULT '0', |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `group_id_UNIQUE` (`group_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; |
||||||
|
|
||||||
|
LOCK TABLES `map_group` WRITE; |
||||||
|
/*!40000 ALTER TABLE `map_group` DISABLE KEYS */; |
||||||
|
|
||||||
|
INSERT INTO `map_group` (`id`, `group_id`, `group_name`, `group_type`, `workspace_id`, `is_distributed`, `is_lock`, `create_time`, `update_time`) |
||||||
|
VALUES |
||||||
|
(1,'e3dea0f5-37f2-4d79-ae58-490af3228060','Pilot Share Layer',2,'e3dea0f5-37f2-4d79-ae58-490af3228069',1,0,1638330077356,1638330077356), |
||||||
|
(2,'e3dea0f5-37f2-4d79-ae58-490af3228011','Default Layer',1,'e3dea0f5-37f2-4d79-ae58-490af3228069',1,0,1638330077356,1638330077356); |
||||||
|
|
||||||
|
/*!40000 ALTER TABLE `map_group` ENABLE KEYS */; |
||||||
|
UNLOCK TABLES; |
||||||
|
|
||||||
|
|
||||||
|
# map_group_element |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `map_group_element`; |
||||||
|
|
||||||
|
CREATE TABLE `map_group_element` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`element_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`element_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`display` smallint NOT NULL DEFAULT '1', |
||||||
|
`group_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`element_type` smallint NOT NULL, |
||||||
|
`username` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`color` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`clamp_to_ground` tinyint(1) NOT NULL DEFAULT '0', |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `element_id_UNIQUE` (`element_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3 COLLATE=utf8_bin; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# media_file |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `media_file`; |
||||||
|
|
||||||
|
CREATE TABLE `media_file` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`file_name` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`file_path` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`fingerprint` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`tinny_fingerprint` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`object_key` varchar(100) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`sub_file_type` int NOT NULL, |
||||||
|
`is_original` tinyint(1) NOT NULL, |
||||||
|
`drone` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
||||||
|
`payload` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT 'undefined', |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL, |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `fingerprint_UNIQUE` (`fingerprint`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# wayline_file |
||||||
|
# ------------------------------------------------------------ |
||||||
|
|
||||||
|
DROP TABLE IF EXISTS `wayline_file`; |
||||||
|
|
||||||
|
CREATE TABLE `wayline_file` ( |
||||||
|
`id` int unsigned NOT NULL AUTO_INCREMENT, |
||||||
|
`name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`wayline_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`drone_model_key` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`payload_model_keys` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci DEFAULT NULL, |
||||||
|
`workspace_id` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`favorited` tinyint(1) NOT NULL DEFAULT '0', |
||||||
|
`template_types` varchar(32) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`object_key` varchar(200) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL DEFAULT '', |
||||||
|
`user_name` varchar(64) CHARACTER SET utf8 COLLATE utf8_general_ci NOT NULL, |
||||||
|
`create_time` bigint NOT NULL, |
||||||
|
`update_time` bigint NOT NULL COMMENT 'required, can not modify.', |
||||||
|
PRIMARY KEY (`id`), |
||||||
|
UNIQUE KEY `wayline_id_UNIQUE` (`wayline_id`) |
||||||
|
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb3; |
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/*!40111 SET SQL_NOTES=@OLD_SQL_NOTES */; |
||||||
|
/*!40101 SET SQL_MODE=@OLD_SQL_MODE */; |
||||||
|
/*!40014 SET FOREIGN_KEY_CHECKS=@OLD_FOREIGN_KEY_CHECKS */; |
||||||
|
/*!40101 SET CHARACTER_SET_CLIENT=@OLD_CHARACTER_SET_CLIENT */; |
||||||
|
/*!40101 SET CHARACTER_SET_RESULTS=@OLD_CHARACTER_SET_RESULTS */; |
||||||
|
/*!40101 SET COLLATION_CONNECTION=@OLD_COLLATION_CONNECTION */; |
||||||
|
|
@ -0,0 +1,17 @@ |
|||||||
|
package com.dji.sample; |
||||||
|
|
||||||
|
import org.mybatis.spring.annotation.MapperScan; |
||||||
|
import org.springframework.boot.SpringApplication; |
||||||
|
import org.springframework.boot.autoconfigure.SpringBootApplication; |
||||||
|
import org.springframework.scheduling.annotation.EnableScheduling; |
||||||
|
|
||||||
|
@MapperScan("com.dji.sample.*.dao") |
||||||
|
@SpringBootApplication |
||||||
|
@EnableScheduling |
||||||
|
public class CloudApiSampleApplication { |
||||||
|
|
||||||
|
public static void main(String[] args) { |
||||||
|
SpringApplication.run(CloudApiSampleApplication.class, args); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.dji.sample.common.error; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/25 |
||||||
|
*/ |
||||||
|
public enum CommonErrorEnum implements IErrorInfo { |
||||||
|
|
||||||
|
SYSTEM_ERROR(600500, "system error"), |
||||||
|
|
||||||
|
SECRET_INVALID(600100, "secret invalid"), |
||||||
|
|
||||||
|
NO_TOKEN(600101, "accss_token is null"), |
||||||
|
|
||||||
|
TOKEN_EXPIRED(600102, "token is expired"), |
||||||
|
|
||||||
|
TOKEN_INVALID(600103, "token invalid"), |
||||||
|
|
||||||
|
SIGN_INVALID(600104, "sign invalid"); |
||||||
|
|
||||||
|
private String msg; |
||||||
|
|
||||||
|
private int code; |
||||||
|
|
||||||
|
CommonErrorEnum(int code, String msg) { |
||||||
|
this.code = code; |
||||||
|
this.msg = msg; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getErrorMsg() { |
||||||
|
return this.msg; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Integer getErrorCode() { |
||||||
|
return this.code; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package com.dji.sample.common.error; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/25 |
||||||
|
*/ |
||||||
|
public interface IErrorInfo { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get error message. |
||||||
|
* @return error message |
||||||
|
*/ |
||||||
|
String getErrorMsg(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Get error code. |
||||||
|
* @return error code |
||||||
|
*/ |
||||||
|
Integer getErrorCode(); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,78 @@ |
|||||||
|
package com.dji.sample.common.error; |
||||||
|
|
||||||
|
/** |
||||||
|
* Live streaming related error codes. When on-demand via mqtt, |
||||||
|
* it can be matched with the error code information replied by the pilot. |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/25 |
||||||
|
*/ |
||||||
|
public enum LiveErrorEnum implements IErrorInfo { |
||||||
|
|
||||||
|
NO_AIRCRAFT(613001, "No aircraft."), |
||||||
|
|
||||||
|
NO_CAMERA(613002, "No camera."), |
||||||
|
|
||||||
|
LIVE_STREAM_ALREADY_STARTED(613003, "The camera has started live streaming."), |
||||||
|
|
||||||
|
FUNCTION_NOT_SUPPORT(613004, "The function is not supported."), |
||||||
|
|
||||||
|
STRATEGY_NOT_SUPPORT(613005, "The strategy is not supported."), |
||||||
|
|
||||||
|
NOT_IN_CAMERA_INTERFACE(613006, "The current app is not in the camera interface."), |
||||||
|
|
||||||
|
NO_FLIGHT_CONTROL(613007, "The remote control has no flight control rights and cannot respond to control commands"), |
||||||
|
|
||||||
|
NO_STREAM_DATA(613008, "The current app has no stream data."), |
||||||
|
|
||||||
|
TOO_FREQUENT(613009, "The operation is too frequent."), |
||||||
|
|
||||||
|
ENABLE_FAILED(613010, "Please check whether the live stream service is normal."), |
||||||
|
|
||||||
|
NO_LIVE_STREAM(613011, "There are no live stream currently."), |
||||||
|
|
||||||
|
SWITCH_NOT_SUPPORT(613012, "There is already another camera in the live stream. It's not support to switch the stream directly."), |
||||||
|
|
||||||
|
URL_TYPE_NOT_SUPPORTED(613013, "This url type is not supported."), |
||||||
|
|
||||||
|
ERROR_PARAMETERS(613014, "The live stream parameters are abnormal or incomplete."), |
||||||
|
|
||||||
|
NO_REPLY(613098, "No live reply received."), |
||||||
|
|
||||||
|
UNKNOWN(613099, "UNKNOWN"); |
||||||
|
|
||||||
|
|
||||||
|
private String msg; |
||||||
|
|
||||||
|
private int code; |
||||||
|
|
||||||
|
LiveErrorEnum(int code, String msg) { |
||||||
|
this.code = code; |
||||||
|
this.msg = msg; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public String getErrorMsg() { |
||||||
|
return this.msg; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public Integer getErrorCode() { |
||||||
|
return this.code; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the corresponding enumeration object based on the error code. |
||||||
|
* @param code error code |
||||||
|
* @return enumeration object |
||||||
|
*/ |
||||||
|
public static LiveErrorEnum find(int code) { |
||||||
|
|
||||||
|
for (LiveErrorEnum errorEnum : LiveErrorEnum.class.getEnumConstants()) { |
||||||
|
if (errorEnum.code == code) { |
||||||
|
return errorEnum; |
||||||
|
} |
||||||
|
} |
||||||
|
return UNKNOWN; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,88 @@ |
|||||||
|
package com.dji.sample.common.model; |
||||||
|
|
||||||
|
import com.auth0.jwt.interfaces.Claim; |
||||||
|
import com.fasterxml.jackson.annotation.JsonAlias; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.lang.reflect.Field; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* A custom claim for storing custom information in the token. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Data |
||||||
|
@Slf4j |
||||||
|
public class CustomClaim { |
||||||
|
|
||||||
|
/** |
||||||
|
* The id of the account. |
||||||
|
*/ |
||||||
|
private String id; |
||||||
|
|
||||||
|
private String username; |
||||||
|
|
||||||
|
@JsonAlias("user_type") |
||||||
|
private Integer userType; |
||||||
|
|
||||||
|
@JsonAlias("workspace_id") |
||||||
|
private String workspaceId; |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert the custom claim data type to the Map type. |
||||||
|
* @return map |
||||||
|
*/ |
||||||
|
public ConcurrentHashMap<String, String> convertToMap() { |
||||||
|
ConcurrentHashMap<String, String> map = new ConcurrentHashMap<>(4); |
||||||
|
try { |
||||||
|
Field[] declaredFields = this.getClass().getDeclaredFields(); |
||||||
|
for (Field field : declaredFields) { |
||||||
|
JsonAlias annotation = field.getAnnotation(JsonAlias.class); |
||||||
|
field.setAccessible(true); |
||||||
|
// The value of key is named underscore.
|
||||||
|
map.put(annotation != null ? annotation.value()[0] : field.getName(), |
||||||
|
field.get(this).toString()); |
||||||
|
} |
||||||
|
} catch (IllegalAccessException e) { |
||||||
|
log.info("CustomClaim converts failed. {}", this.toString()); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return map; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Convert the data in Map into a custom claim object. |
||||||
|
* @param claimMap |
||||||
|
*/ |
||||||
|
public CustomClaim (Map<String, Claim> claimMap) { |
||||||
|
Field[] declaredFields = this.getClass().getDeclaredFields(); |
||||||
|
for (Field field : declaredFields) { |
||||||
|
field.setAccessible(true); |
||||||
|
JsonAlias annotation = field.getAnnotation(JsonAlias.class); |
||||||
|
|
||||||
|
Claim value = claimMap.get(annotation == null ? field.getName() : annotation.value()[0]); |
||||||
|
try { |
||||||
|
Class<?> type = field.getType(); |
||||||
|
if (Integer.class.equals(type)) { |
||||||
|
field.set(this, Integer.valueOf(value.asString())); |
||||||
|
continue; |
||||||
|
} |
||||||
|
if (String.class.equals(type)) { |
||||||
|
field.set(this, value.asString()); |
||||||
|
continue; |
||||||
|
} |
||||||
|
} catch (IllegalAccessException e) { |
||||||
|
log.info("Claim parses failed. {}", claimMap.toString()); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,36 @@ |
|||||||
|
package com.dji.sample.common.model; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.extension.plugins.pagination.Page; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* Used for paging display in the wayline. These field names cannot be changed. |
||||||
|
* Because they need to be the same as the pilot. |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/22 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class Pagination { |
||||||
|
|
||||||
|
/** |
||||||
|
* The current page number. |
||||||
|
*/ |
||||||
|
private long page; |
||||||
|
|
||||||
|
/** |
||||||
|
* The amount of data displayed per page. |
||||||
|
*/ |
||||||
|
private long pageSize; |
||||||
|
|
||||||
|
/** |
||||||
|
* The total amount of all data. |
||||||
|
*/ |
||||||
|
private long total; |
||||||
|
|
||||||
|
public Pagination(Page page) { |
||||||
|
this.page = page.getCurrent(); |
||||||
|
this.pageSize = page.getSize(); |
||||||
|
this.total = page.getTotal(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.dji.sample.common.model; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* The format of the data response when a paginated display is required. |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/22 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class PaginationData<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* The collection in which the data list is stored. |
||||||
|
*/ |
||||||
|
private List<T> list; |
||||||
|
|
||||||
|
private Pagination pagination; |
||||||
|
|
||||||
|
public PaginationData(List<T> list, Pagination pagination) { |
||||||
|
this.list = list; |
||||||
|
this.pagination = pagination; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package com.dji.sample.common.model; |
||||||
|
|
||||||
|
import com.dji.sample.common.error.IErrorInfo; |
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
|
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
@JsonInclude |
||||||
|
public class ResponseResult<T> { |
||||||
|
|
||||||
|
public static final int CODE_SUCCESS = 0; |
||||||
|
public static final String MESSAGE_SUCCESS = "success"; |
||||||
|
|
||||||
|
private int code; |
||||||
|
|
||||||
|
private String message; |
||||||
|
|
||||||
|
private T data; |
||||||
|
|
||||||
|
public static <T> ResponseResult<T> success(T data) { |
||||||
|
return ResponseResult.<T>builder() |
||||||
|
.code(CODE_SUCCESS) |
||||||
|
.message(MESSAGE_SUCCESS) |
||||||
|
.data(data) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResponseResult success() { |
||||||
|
return ResponseResult.builder() |
||||||
|
.code(0) |
||||||
|
.message(MESSAGE_SUCCESS) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResponseResult error() { |
||||||
|
return ResponseResult.builder() |
||||||
|
.code(HttpStatus.INTERNAL_SERVER_ERROR.value()) |
||||||
|
.message(HttpStatus.INTERNAL_SERVER_ERROR.getReasonPhrase()) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResponseResult error(String message) { |
||||||
|
return ResponseResult.builder() |
||||||
|
.code(HttpStatus.INTERNAL_SERVER_ERROR.value()) |
||||||
|
.message(message) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResponseResult error(int code, String message) { |
||||||
|
return ResponseResult.builder() |
||||||
|
.code(code) |
||||||
|
.message(message) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
|
||||||
|
public static ResponseResult error(IErrorInfo errorInfo) { |
||||||
|
return ResponseResult.builder() |
||||||
|
.code(errorInfo.getErrorCode()) |
||||||
|
.message(errorInfo.getErrorMsg()) |
||||||
|
.build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,103 @@ |
|||||||
|
package com.dji.sample.common.util; |
||||||
|
|
||||||
|
import com.auth0.jwt.JWT; |
||||||
|
import com.auth0.jwt.JWTCreator; |
||||||
|
import com.auth0.jwt.JWTVerifier; |
||||||
|
import com.auth0.jwt.algorithms.Algorithm; |
||||||
|
import com.auth0.jwt.exceptions.TokenExpiredException; |
||||||
|
import com.auth0.jwt.interfaces.DecodedJWT; |
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.util.Date; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Component |
||||||
|
public class JwtUtil { |
||||||
|
|
||||||
|
private static String issuer; |
||||||
|
|
||||||
|
private static String subject; |
||||||
|
|
||||||
|
private static long age; |
||||||
|
|
||||||
|
private static String secret; |
||||||
|
|
||||||
|
private static Algorithm algorithm; |
||||||
|
|
||||||
|
@Value("${jwt.issuer: DJI}") |
||||||
|
private void setIssuer(String issuer) { |
||||||
|
JwtUtil.issuer = issuer; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${jwt.subject: CloudApiSample}") |
||||||
|
private void setSubject(String subject) { |
||||||
|
JwtUtil.subject = subject; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${jwt.age: 86400}") |
||||||
|
private void setAge(long age) { |
||||||
|
JwtUtil.age = age * 1000; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${jwt.secret: CloudApiSample}") |
||||||
|
private void setSecret(String secret) { |
||||||
|
JwtUtil.secret = secret; |
||||||
|
setAlgorithm(); |
||||||
|
} |
||||||
|
|
||||||
|
private void setAlgorithm() { |
||||||
|
JwtUtil.algorithm = Algorithm.HMAC256(secret); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Create a token based on custom information. |
||||||
|
* @param claims custom information |
||||||
|
* @return token |
||||||
|
*/ |
||||||
|
public static String createToken(Map<String, String> claims) { |
||||||
|
Date now = new Date(); |
||||||
|
JWTCreator.Builder builder = JWT.create(); |
||||||
|
// Add custom information to the token's payload segment.
|
||||||
|
claims.forEach(builder::withClaim); |
||||||
|
String token = builder.withIssuer(issuer) |
||||||
|
.withSubject(subject) |
||||||
|
.withIssuedAt(now) |
||||||
|
.withExpiresAt(new Date(now.getTime() + age)) |
||||||
|
.withNotBefore(now) |
||||||
|
.sign(algorithm); |
||||||
|
log.debug("token created. " + token); |
||||||
|
return token; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Verify that the token is valid. |
||||||
|
* @param token |
||||||
|
* @return |
||||||
|
* @throws TokenExpiredException |
||||||
|
*/ |
||||||
|
public static DecodedJWT verifyToken(String token) { |
||||||
|
try { |
||||||
|
JWTVerifier verifier = JWT.require(algorithm).build(); |
||||||
|
return verifier.verify(token); |
||||||
|
} catch (Exception e) { |
||||||
|
log.error(e.getMessage()); |
||||||
|
e.printStackTrace(); |
||||||
|
return null; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Parses the custom information in the token into a CustomClaim object. |
||||||
|
* @param token |
||||||
|
* @return custom claim |
||||||
|
*/ |
||||||
|
public static Optional<CustomClaim> parseToken(String token) { |
||||||
|
DecodedJWT jwt = verifyToken(token); |
||||||
|
return jwt == null ? Optional.empty() : Optional.of(new CustomClaim(jwt.getClaims())); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.dji.sample.component; |
||||||
|
|
||||||
|
import com.dji.sample.manage.model.DeviceStatusManager; |
||||||
|
import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
||||||
|
import com.dji.sample.manage.model.param.DeviceQueryParam; |
||||||
|
import com.dji.sample.manage.service.IDeviceService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.boot.CommandLineRunner; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.time.LocalDateTime; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/24 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
public class ApplicationBootInitial implements CommandLineRunner { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IDeviceService deviceService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe to the devices that exist in the database when the program starts, |
||||||
|
* to prevent the data from being different from the pilot side due to program interruptions. |
||||||
|
* @param args |
||||||
|
* @throws Exception |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void run(String... args) throws Exception { |
||||||
|
deviceService.getDevicesByParams(DeviceQueryParam.builder().build()) |
||||||
|
.forEach(device -> { |
||||||
|
deviceService.subscribeTopicOnline(device.getDeviceSn()); |
||||||
|
DeviceStatusManager.STATUS_MANAGER.put( |
||||||
|
DeviceDomainEnum.getVal(device.getDomain()) + "/" |
||||||
|
+ device.getDeviceSn(), LocalDateTime.now()); |
||||||
|
}); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
package com.dji.sample.component; |
||||||
|
|
||||||
|
import com.dji.sample.common.error.CommonErrorEnum; |
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.util.JwtUtil; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.http.HttpMethod; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
import org.springframework.web.servlet.HandlerInterceptor; |
||||||
|
import org.springframework.web.servlet.ModelAndView; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
@Slf4j |
||||||
|
@Component |
||||||
|
public class AuthInterceptor implements HandlerInterceptor { |
||||||
|
|
||||||
|
public static final String PARAM_TOKEN = "x-auth-token"; |
||||||
|
|
||||||
|
public static final String TOKEN_CLAIM = "customClaim"; |
||||||
|
|
||||||
|
@Override |
||||||
|
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { |
||||||
|
String uri = request.getRequestURI(); |
||||||
|
log.debug("request uri: {}", uri); |
||||||
|
// The options method is passed directly.
|
||||||
|
if (HttpMethod.OPTIONS.matches(request.getMethod())) { |
||||||
|
response.setStatus(HttpStatus.OK.value()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
String token = request.getHeader(PARAM_TOKEN); |
||||||
|
// Check if the token exists.
|
||||||
|
if (!StringUtils.hasText(token)) { |
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
||||||
|
log.error(CommonErrorEnum.NO_TOKEN.getErrorMsg()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Check if the current token is valid.
|
||||||
|
Optional<CustomClaim> customClaimOpt = JwtUtil.parseToken(token); |
||||||
|
if (customClaimOpt.isEmpty()) { |
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
// Put the custom data from the token into the request.
|
||||||
|
request.setAttribute(TOKEN_CLAIM, customClaimOpt.get()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { |
||||||
|
// Delete the custom data in the request after the request ends.
|
||||||
|
request.removeAttribute(TOKEN_CLAIM); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package com.dji.sample.component; |
||||||
|
|
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import javax.servlet.*; |
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.io.IOException; |
||||||
|
|
||||||
|
import static com.dji.sample.component.AuthInterceptor.PARAM_TOKEN; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/22 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
public class CorsFilter implements Filter { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void doFilter(ServletRequest request, ServletResponse response, FilterChain filterChain) throws IOException, ServletException { |
||||||
|
HttpServletResponse res = (HttpServletResponse) response; |
||||||
|
res.addHeader("Access-Control-Allow-Credentials", "true"); |
||||||
|
res.addHeader("Access-Control-Allow-Origin", "*"); |
||||||
|
res.addHeader("Access-Control-Allow-Methods", "GET, POST, DELETE, PUT"); |
||||||
|
res.addHeader("Access-Control-Allow-Headers", "Access-Control-Allow-Headers," + |
||||||
|
"Authorization, Content-Length, X-CSRF-Token, Token,session,X_Requested_With,Accept, "+ |
||||||
|
"Origin, Host, Connection, Accept-Encoding, Accept-Language,DNT, X-CustomHeader, Keep-Alive," + |
||||||
|
" User-Agent, X-Requested-With, If-Modified-Since, Cache-Control, Content-Type, Pragma," + PARAM_TOKEN); |
||||||
|
if (((HttpServletRequest) request).getMethod().equals("OPTIONS")) { |
||||||
|
return; |
||||||
|
} |
||||||
|
filterChain.doFilter(request, response); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.dji.sample.component; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import org.springframework.web.bind.annotation.ControllerAdvice; |
||||||
|
import org.springframework.web.bind.annotation.ExceptionHandler; |
||||||
|
import org.springframework.web.bind.annotation.ResponseBody; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/1 |
||||||
|
*/ |
||||||
|
@ControllerAdvice |
||||||
|
@ResponseBody |
||||||
|
public class GlobalExceptionHandler { |
||||||
|
|
||||||
|
/** |
||||||
|
* Please do not return directly like this, there is a risk. |
||||||
|
* @param e |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@ExceptionHandler(Exception.class) |
||||||
|
public ResponseResult exceptionHandler(Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
return ResponseResult.error(e.getLocalizedMessage()); |
||||||
|
} |
||||||
|
|
||||||
|
@ExceptionHandler(NullPointerException.class) |
||||||
|
public ResponseResult nullPointerExceptionHandler(NullPointerException e) { |
||||||
|
e.printStackTrace(); |
||||||
|
return ResponseResult.error("A null object appeared."); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,58 @@ |
|||||||
|
package com.dji.sample.component; |
||||||
|
|
||||||
|
import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
||||||
|
import com.dji.sample.manage.service.IDeviceService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.scheduling.annotation.Scheduled; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.time.LocalDateTime; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.TimeUnit; |
||||||
|
|
||||||
|
import static com.dji.sample.manage.model.DeviceStatusManager.DEFAULT_ALIVE_SECOND; |
||||||
|
import static com.dji.sample.manage.model.DeviceStatusManager.STATUS_MANAGER; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/24 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@Slf4j |
||||||
|
public class GlobalScheduleService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IDeviceService deviceService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Check the status of the devices every 30 seconds. It is recommended to use cache. |
||||||
|
*/ |
||||||
|
@Scheduled(fixedRate = 30, timeUnit = TimeUnit.SECONDS) |
||||||
|
private void deviceStatusListen() { |
||||||
|
for (Map.Entry<String, LocalDateTime> entry : STATUS_MANAGER.entrySet()) { |
||||||
|
if (entry.getValue().isAfter( |
||||||
|
LocalDateTime.now().minusSeconds(DEFAULT_ALIVE_SECOND))) { |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
String device = entry.getKey(); |
||||||
|
int index = device.indexOf("/"); |
||||||
|
|
||||||
|
STATUS_MANAGER.remove(device); |
||||||
|
|
||||||
|
int type = Integer.parseInt(device.substring(0, index)); |
||||||
|
String sn = device.substring(index + 1); |
||||||
|
// Determine whether it is a gateway device.
|
||||||
|
if (DeviceDomainEnum.GATEWAY.getVal() == type) { |
||||||
|
deviceService.deviceOffline(sn); |
||||||
|
deviceService.unsubscribeTopicOffline(sn); |
||||||
|
continue; |
||||||
|
} |
||||||
|
|
||||||
|
deviceService.subDeviceOffline(sn); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,95 @@ |
|||||||
|
package com.dji.sample.component.mqtt.config; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.integration.annotation.Router; |
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.integration.router.AbstractMessageRouter; |
||||||
|
import org.springframework.messaging.Message; |
||||||
|
import org.springframework.messaging.MessageChannel; |
||||||
|
import org.springframework.messaging.MessageHeaders; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
import java.util.Collection; |
||||||
|
import java.util.Collections; |
||||||
|
import java.util.regex.Pattern; |
||||||
|
|
||||||
|
import static com.dji.sample.component.mqtt.model.TopicConst.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@Slf4j |
||||||
|
public class InboundMessageRouter extends AbstractMessageRouter { |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND) |
||||||
|
private MessageChannel inboundChannel; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND_STATUS) |
||||||
|
private MessageChannel statusChannel; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND_STATE) |
||||||
|
private MessageChannel stateChannel; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.DEFAULT) |
||||||
|
private MessageChannel defaultChannel; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND_SERVICE_REPLY) |
||||||
|
private MessageChannel serviceReplyChannel; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND_OSD) |
||||||
|
private MessageChannel osdChannel; |
||||||
|
|
||||||
|
private static final Pattern PATTERN_TOPIC_STATUS = |
||||||
|
Pattern.compile("^" + BASIC_PRE + PRODUCT + REGEX_SN + STATUS_SUF + "$"); |
||||||
|
|
||||||
|
private static final Pattern PATTERN_TOPIC_STATE = |
||||||
|
Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + STATE_SUF + "$"); |
||||||
|
|
||||||
|
private static final Pattern PATTERN_TOPIC_SERVICE_REPLY = |
||||||
|
Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + SERVICES_SUF + _REPLY_SUF + "$"); |
||||||
|
|
||||||
|
private static final Pattern PATTERN_TOPIC_OSD = |
||||||
|
Pattern.compile("^" + THING_MODEL_PRE + PRODUCT + REGEX_SN + OSD_SUF); |
||||||
|
|
||||||
|
/** |
||||||
|
* All mqtt broker messages will arrive here before distributing them to different channels. |
||||||
|
* @param message message from mqtt broker |
||||||
|
* @return channel |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
@Router(inputChannel = ChannelName.INBOUND) |
||||||
|
protected Collection<MessageChannel> determineTargetChannels(Message<?> message) { |
||||||
|
MessageHeaders headers = message.getHeaders(); |
||||||
|
String topic = headers.get(MqttHeaders.RECEIVED_TOPIC).toString(); |
||||||
|
byte[] payload = (byte[])message.getPayload(); |
||||||
|
|
||||||
|
// osd
|
||||||
|
if (PATTERN_TOPIC_OSD.matcher(topic).matches()) { |
||||||
|
return Collections.singleton(osdChannel); |
||||||
|
} |
||||||
|
|
||||||
|
log.debug("received topic :{} \t payload :{}", topic, new String(payload)); |
||||||
|
|
||||||
|
// status
|
||||||
|
if (PATTERN_TOPIC_STATUS.matcher(topic).matches()) { |
||||||
|
return Collections.singleton(statusChannel); |
||||||
|
} |
||||||
|
|
||||||
|
// state
|
||||||
|
if (PATTERN_TOPIC_STATE.matcher(topic).matches()) { |
||||||
|
return Collections.singleton(stateChannel); |
||||||
|
} |
||||||
|
|
||||||
|
// services_reply
|
||||||
|
if (PATTERN_TOPIC_SERVICE_REPLY.matcher(topic).matches()) { |
||||||
|
return Collections.singleton(serviceReplyChannel); |
||||||
|
} |
||||||
|
return Collections.singleton(defaultChannel); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,63 @@ |
|||||||
|
package com.dji.sample.component.mqtt.config; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
import org.eclipse.paho.client.mqttv3.MqttConnectOptions; |
||||||
|
import org.springframework.boot.context.properties.ConfigurationProperties; |
||||||
|
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; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
@Data |
||||||
|
@ConfigurationProperties(prefix = "mqtt") |
||||||
|
public class MqttConfiguration { |
||||||
|
|
||||||
|
private String protocol; |
||||||
|
|
||||||
|
private String host; |
||||||
|
|
||||||
|
private Integer port; |
||||||
|
|
||||||
|
private String username; |
||||||
|
|
||||||
|
private String password; |
||||||
|
|
||||||
|
private String clientId; |
||||||
|
|
||||||
|
/** |
||||||
|
* The topic to subscribe to immediately when client connects. |
||||||
|
*/ |
||||||
|
private String inboundTopic; |
||||||
|
|
||||||
|
@Bean |
||||||
|
public MqttConnectOptions mqttConnectOptions() { |
||||||
|
MqttConnectOptions mqttConnectOptions = new MqttConnectOptions(); |
||||||
|
mqttConnectOptions.setServerURIs(new String[]{ |
||||||
|
new StringBuilder() |
||||||
|
.append(protocol.trim()) |
||||||
|
.append("://") |
||||||
|
.append(host.trim()) |
||||||
|
.append(":") |
||||||
|
.append(port) |
||||||
|
.toString()}); |
||||||
|
mqttConnectOptions.setUserName(username); |
||||||
|
mqttConnectOptions.setPassword(password.toCharArray()); |
||||||
|
mqttConnectOptions.setAutomaticReconnect(true); |
||||||
|
mqttConnectOptions.setKeepAliveInterval(10); |
||||||
|
return mqttConnectOptions; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
public MqttPahoClientFactory mqttClientFactory() { |
||||||
|
DefaultMqttPahoClientFactory factory = new DefaultMqttPahoClientFactory(); |
||||||
|
factory.setConnectionOptions(mqttConnectOptions()); |
||||||
|
return factory; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package com.dji.sample.component.mqtt.config; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.integration.annotation.IntegrationComponentScan; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.integration.endpoint.MessageProducerSupport; |
||||||
|
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 javax.annotation.Resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* Client configuration for inbound messages. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
@Configuration |
||||||
|
@IntegrationComponentScan |
||||||
|
public class MqttInboundConfiguration { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MqttConfiguration mqttConfiguration; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MqttPahoClientFactory mqttClientFactory; |
||||||
|
|
||||||
|
@Resource(name = ChannelName.INBOUND) |
||||||
|
private MessageChannel inboundChannel; |
||||||
|
|
||||||
|
/** |
||||||
|
* Clients of inbound message channels. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Bean(name = "adapter") |
||||||
|
public MessageProducerSupport mqttInbound() { |
||||||
|
MqttPahoMessageDrivenChannelAdapter adapter = new MqttPahoMessageDrivenChannelAdapter( |
||||||
|
mqttConfiguration.getClientId() + "_consumer_" + System.currentTimeMillis(), |
||||||
|
mqttClientFactory, mqttConfiguration.getInboundTopic().split(",")); |
||||||
|
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter(); |
||||||
|
// use byte types uniformly
|
||||||
|
converter.setPayloadAsBytes(true); |
||||||
|
adapter.setConverter(converter); |
||||||
|
adapter.setQos(1); |
||||||
|
adapter.setOutputChannel(inboundChannel); |
||||||
|
return adapter; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Define a default channel to handle messages that have no effect. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
@ServiceActivator(inputChannel = ChannelName.DEFAULT) |
||||||
|
public MessageHandler defaultInboundHandler() { |
||||||
|
return message -> { |
||||||
|
log.info("The default channel does not handle messages."); |
||||||
|
}; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,90 @@ |
|||||||
|
package com.dji.sample.component.mqtt.config; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.integration.channel.DirectChannel; |
||||||
|
import org.springframework.integration.channel.ExecutorChannel; |
||||||
|
import org.springframework.messaging.MessageChannel; |
||||||
|
|
||||||
|
import java.util.concurrent.Executor; |
||||||
|
|
||||||
|
/** |
||||||
|
* Definition classes for all channels |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class MqttMessageChannel { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private Executor threadPool; |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND) |
||||||
|
public MessageChannel inboundChannel() { |
||||||
|
return new ExecutorChannel(threadPool); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATUS) |
||||||
|
public MessageChannel statusChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATUS_ONLINE) |
||||||
|
public MessageChannel statusOnlineChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATUS_OFFLINE) |
||||||
|
public MessageChannel statusOffChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATE) |
||||||
|
public MessageChannel stateChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATE_BASIC) |
||||||
|
public MessageChannel stateBasicChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATE_PAYLOAD) |
||||||
|
public MessageChannel statePayloadChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_SERVICE_REPLY) |
||||||
|
public MessageChannel serviceReplyChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATE_CAPACITY) |
||||||
|
public MessageChannel stateCapacityChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
||||||
|
public MessageChannel statePayloadUpdateChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.INBOUND_OSD) |
||||||
|
public MessageChannel osdChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.DEFAULT) |
||||||
|
public MessageChannel defaultChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
@Bean(name = ChannelName.OUTBOUND) |
||||||
|
public MessageChannel outboundChannel() { |
||||||
|
return new DirectChannel(); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.dji.sample.component.mqtt.config; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
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.mqtt.core.MqttPahoClientFactory; |
||||||
|
import org.springframework.integration.mqtt.outbound.MqttPahoMessageHandler; |
||||||
|
import org.springframework.integration.mqtt.support.DefaultPahoMessageConverter; |
||||||
|
import org.springframework.messaging.MessageHandler; |
||||||
|
|
||||||
|
/** |
||||||
|
* Client configuration for outbound messages. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class MqttOutboundConfiguration { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MqttConfiguration mqttConfiguration; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MqttPahoClientFactory mqttClientFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* Clients of outbound message channels. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
@ServiceActivator(inputChannel = ChannelName.OUTBOUND) |
||||||
|
public MessageHandler mqttOutbound() { |
||||||
|
MqttPahoMessageHandler messageHandler = new MqttPahoMessageHandler( |
||||||
|
mqttConfiguration.getClientId() + "_producer_" + System.currentTimeMillis(), |
||||||
|
mqttClientFactory); |
||||||
|
DefaultPahoMessageConverter converter = new DefaultPahoMessageConverter(); |
||||||
|
// use byte types uniformly
|
||||||
|
converter.setPayloadAsBytes(true); |
||||||
|
|
||||||
|
messageHandler.setAsync(true); |
||||||
|
messageHandler.setDefaultQos(0); |
||||||
|
messageHandler.setConverter(converter); |
||||||
|
return messageHandler; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package com.dji.sample.component.mqtt.model; |
||||||
|
|
||||||
|
/** |
||||||
|
* The name of all channels. |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public class ChannelName { |
||||||
|
|
||||||
|
public static final String INBOUND = "inbound"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATUS = "inboundStatus"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATUS_ROUTER = "inboundStatusRouter"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATUS_ONLINE = "inboundStatusOnline"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATUS_OFFLINE = "inboundStatusOffline"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE = "inboundState"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_SPLITTER = "inboundStateSplitter"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_ROUTER = "inboundStateRouter"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_BASIC = "inboundStateBasic"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_PAYLOAD = "inboundStatePayload"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_PAYLOAD_UPDATE = "inboundStatePayloadUpdate"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_CAPACITY = "inboundStateCapacity"; |
||||||
|
|
||||||
|
public static final String INBOUND_STATE_LIST = "inboundStateList"; |
||||||
|
|
||||||
|
public static final String INBOUND_SERVICE_REPLY = "inboundStateServiceReply"; |
||||||
|
|
||||||
|
public static final String INBOUND_OSD = "inboundOsd"; |
||||||
|
|
||||||
|
public static final String DEFAULT = "default"; |
||||||
|
|
||||||
|
public static final String OUTBOUND = "outbound"; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.dji.sample.component.mqtt.model; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unified topic receiving format. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||||
|
public class CommonTopicReceiver<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* The command is sent and the response is matched by the tid and bid fields in the message, |
||||||
|
* and the reply should keep the tid and bid the same. |
||||||
|
*/ |
||||||
|
private String tid; |
||||||
|
|
||||||
|
private String bid; |
||||||
|
|
||||||
|
private String method; |
||||||
|
|
||||||
|
private Long timestamp; |
||||||
|
|
||||||
|
private T data; |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.dji.sample.component.mqtt.model; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* Unified Topic response format |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/15 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||||
|
public class CommonTopicResponse<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* The command is sent and the response is matched by the tid and bid fields in the message, |
||||||
|
* and the reply should keep the tid and bid the same. |
||||||
|
*/ |
||||||
|
private String tid; |
||||||
|
|
||||||
|
private String bid; |
||||||
|
|
||||||
|
private String method; |
||||||
|
|
||||||
|
private T data; |
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.dji.sample.component.mqtt.model; |
||||||
|
|
||||||
|
/** |
||||||
|
* All the topics that need to be used in the project. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public class TopicConst { |
||||||
|
|
||||||
|
public static final String BASIC_PRE = "sys/"; |
||||||
|
|
||||||
|
public static final String THING_MODEL_PRE = "thing/"; |
||||||
|
|
||||||
|
public static final String PRODUCT = "product/"; |
||||||
|
|
||||||
|
public static final String STATUS_SUF = "/status"; |
||||||
|
|
||||||
|
public static final String _REPLY_SUF = "_reply"; |
||||||
|
|
||||||
|
public static final String STATE_SUF = "/state"; |
||||||
|
|
||||||
|
public static final String SERVICES_SUF = "/services"; |
||||||
|
|
||||||
|
public static final String OSD_SUF = "/osd"; |
||||||
|
|
||||||
|
public static final String REGEX_SN = "[A-Za-z0-9]+"; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.dji.sample.component.mqtt.model; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonIgnoreProperties; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* The data format of the state topic. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/17 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@JsonIgnoreProperties(ignoreUnknown = true) |
||||||
|
public class TopicStateReceiver<T> { |
||||||
|
|
||||||
|
private String tid; |
||||||
|
|
||||||
|
private String bid; |
||||||
|
|
||||||
|
private Long timestamp; |
||||||
|
|
||||||
|
/** |
||||||
|
* The sn of the gateway device. |
||||||
|
*/ |
||||||
|
private String gateway; |
||||||
|
|
||||||
|
private T data; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.dji.sample.component.mqtt.service; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/25 |
||||||
|
*/ |
||||||
|
public interface IMessageSenderService { |
||||||
|
|
||||||
|
/** |
||||||
|
* Publish a message to a specific topic. |
||||||
|
* @param topic target |
||||||
|
* @param response message |
||||||
|
*/ |
||||||
|
void publish(String topic, CommonTopicResponse response); |
||||||
|
|
||||||
|
/** |
||||||
|
* Use a specific qos to push messages to a specific topic. |
||||||
|
* @param topic target |
||||||
|
* @param qos qos |
||||||
|
* @param response message |
||||||
|
*/ |
||||||
|
void publish(String topic, int qos, CommonTopicResponse response); |
||||||
|
|
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.dji.sample.component.mqtt.service; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import org.springframework.integration.annotation.MessagingGateway; |
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.messaging.handler.annotation.Header; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@MessagingGateway(defaultRequestChannel = ChannelName.OUTBOUND) |
||||||
|
public interface IMqttMessageGateway { |
||||||
|
|
||||||
|
/** |
||||||
|
* Publish a message to a specific topic. |
||||||
|
* @param topic target |
||||||
|
* @param payload message |
||||||
|
*/ |
||||||
|
void publish(@Header(MqttHeaders.TOPIC) String topic, byte[] payload); |
||||||
|
|
||||||
|
/** |
||||||
|
* Use a specific qos to push messages to a specific topic. |
||||||
|
* @param topic target |
||||||
|
* @param payload message |
||||||
|
* @param qos qos |
||||||
|
*/ |
||||||
|
void publish(@Header(MqttHeaders.TOPIC) String topic, byte[] payload, @Header(MqttHeaders.QOS) int qos); |
||||||
|
} |
@ -0,0 +1,38 @@ |
|||||||
|
package com.dji.sample.component.mqtt.service; |
||||||
|
|
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.messaging.handler.annotation.Header; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface IMqttTopicService { |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe to a specific topic. |
||||||
|
* @param topic target |
||||||
|
*/ |
||||||
|
void subscribe(@Header(MqttHeaders.TOPIC) String topic); |
||||||
|
|
||||||
|
/** |
||||||
|
* Subscribe to a specific topic using a specific qos. |
||||||
|
* @param topic target |
||||||
|
* @param qos qos |
||||||
|
*/ |
||||||
|
void subscribe(@Header(MqttHeaders.TOPIC) String topic, int qos); |
||||||
|
|
||||||
|
/** |
||||||
|
* Unsubscribe from a specific topic. |
||||||
|
* @param topic target |
||||||
|
*/ |
||||||
|
void unsubscribe(@Header(MqttHeaders.TOPIC) String topic); |
||||||
|
|
||||||
|
/** |
||||||
|
* Get all the subscribed topics. |
||||||
|
* @return topics |
||||||
|
*/ |
||||||
|
String[] getSubscribedTopic(); |
||||||
|
} |
@ -0,0 +1,50 @@ |
|||||||
|
package com.dji.sample.component.mqtt.service.impl; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
||||||
|
import com.dji.sample.component.mqtt.service.IMessageSenderService; |
||||||
|
import com.dji.sample.component.mqtt.service.IMqttMessageGateway; |
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
@Slf4j |
||||||
|
public class MessageSenderServiceImpl implements IMessageSenderService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IMqttMessageGateway messageGateway; |
||||||
|
|
||||||
|
public void publish(String topic, CommonTopicResponse response) { |
||||||
|
try { |
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
// Only parameters whose value is not null will be serialised.
|
||||||
|
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
||||||
|
|
||||||
|
messageGateway.publish(topic, mapper.writeValueAsBytes(response)); |
||||||
|
} catch (JsonProcessingException e) { |
||||||
|
log.info("Failed to publish the message. {}", response.toString()); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
public void publish(String topic, int qos, CommonTopicResponse response) { |
||||||
|
try { |
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
// Only parameters whose value is not null will be serialised.
|
||||||
|
mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); |
||||||
|
|
||||||
|
messageGateway.publish(topic, mapper.writeValueAsBytes(response), qos); |
||||||
|
} catch (JsonProcessingException e) { |
||||||
|
log.info("Failed to publish the message. {}", response.toString()); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,44 @@ |
|||||||
|
package com.dji.sample.component.mqtt.service.impl; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.service.IMqttTopicService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.integration.mqtt.inbound.MqttPahoMessageDrivenChannelAdapter; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
@Slf4j |
||||||
|
public class MqttTopicServiceImpl implements IMqttTopicService { |
||||||
|
|
||||||
|
@Resource |
||||||
|
private MqttPahoMessageDrivenChannelAdapter adapter; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void subscribe(String topic) { |
||||||
|
log.debug("subscribe topic: {}", topic); |
||||||
|
adapter.addTopic(topic); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void subscribe(String topic, int qos) { |
||||||
|
log.debug("subscribe topic: {}", topic); |
||||||
|
adapter.addTopic(topic, qos); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void unsubscribe(String topic) { |
||||||
|
log.debug("unsubscribe topic: {}", topic); |
||||||
|
adapter.removeTopic(topic); |
||||||
|
} |
||||||
|
|
||||||
|
public String[] getSubscribedTopic() { |
||||||
|
return adapter.getTopic(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package com.dji.sample.component.mybatis; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.DbType; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.MybatisPlusInterceptor; |
||||||
|
import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerInterceptor; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/22 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class MybatisPlusConfiguration { |
||||||
|
|
||||||
|
@Bean |
||||||
|
public MybatisPlusInterceptor mybatisPlusInterceptor() { |
||||||
|
MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor(); |
||||||
|
// select database
|
||||||
|
interceptor.addInnerInterceptor(new PaginationInnerInterceptor(DbType.MYSQL)); |
||||||
|
return interceptor; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.dji.sample.component.mybatis; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.handlers.MetaObjectHandler; |
||||||
|
import org.apache.ibatis.reflection.MetaObject; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
|
||||||
|
import java.time.LocalDateTime; |
||||||
|
import java.time.ZoneOffset; |
||||||
|
|
||||||
|
/** |
||||||
|
* Automatic filling for set values |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
public class MybatisPlusMetaObjectHandler implements MetaObjectHandler { |
||||||
|
|
||||||
|
/** |
||||||
|
* Automatic filling when inserting into the database. |
||||||
|
* @param metaObject |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void insertFill(MetaObject metaObject) { |
||||||
|
this.strictInsertFill(metaObject, "createTime", Long.class, |
||||||
|
LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
||||||
|
this.strictInsertFill(metaObject, "updateTime", Long.class, |
||||||
|
LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Automatic filling when updating the data. |
||||||
|
* @param metaObject |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
public void updateFill(MetaObject metaObject) { |
||||||
|
this.strictUpdateFill(metaObject, "updateTime", Long.class, |
||||||
|
LocalDateTime.now().toInstant(ZoneOffset.ofHours(8)).toEpochMilli()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,104 @@ |
|||||||
|
package com.dji.sample.component.oss.model; |
||||||
|
|
||||||
|
import com.aliyun.oss.OSS; |
||||||
|
import com.aliyun.oss.OSSClientBuilder; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.context.annotation.Lazy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/9 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class AliyunOSSConfiguration { |
||||||
|
|
||||||
|
/** |
||||||
|
* default |
||||||
|
*/ |
||||||
|
public static final String PROVIDER = "ali"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether to use the current storage service. |
||||||
|
*/ |
||||||
|
public static boolean enable; |
||||||
|
|
||||||
|
/** |
||||||
|
* The protocol needs to be included at the beginning of the address. |
||||||
|
*/ |
||||||
|
public static String endpoint; |
||||||
|
|
||||||
|
public static String accessKey; |
||||||
|
|
||||||
|
public static String secretKey; |
||||||
|
|
||||||
|
public static String region; |
||||||
|
|
||||||
|
public static Long expire; |
||||||
|
|
||||||
|
public static String roleSessionName; |
||||||
|
|
||||||
|
public static String roleArn; |
||||||
|
|
||||||
|
public static String bucket; |
||||||
|
|
||||||
|
public static String objectDirPrefix; |
||||||
|
|
||||||
|
@Value("${aliyun.oss.endpoint}") |
||||||
|
private void setEndpoint(String endpoint) { |
||||||
|
AliyunOSSConfiguration.endpoint = endpoint; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.access-key}") |
||||||
|
private void setAccessKey(String accessKey) { |
||||||
|
AliyunOSSConfiguration.accessKey = accessKey; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.secret-key}") |
||||||
|
private void setSecretKey(String secretKey) { |
||||||
|
AliyunOSSConfiguration.secretKey = secretKey; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.region}") |
||||||
|
private void setRegion(String region) { |
||||||
|
AliyunOSSConfiguration.region = region; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.expire: 3600}") |
||||||
|
private void setExpire(Long expire) { |
||||||
|
AliyunOSSConfiguration.expire = expire; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.enable: false}") |
||||||
|
private void setEnable(boolean enable) { |
||||||
|
AliyunOSSConfiguration.enable = enable; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.role-session-name}") |
||||||
|
private void setRoleSessionName(String roleSessionName) { |
||||||
|
AliyunOSSConfiguration.roleSessionName = roleSessionName; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.role-arn}") |
||||||
|
private void setRoleArn(String roleArn) { |
||||||
|
AliyunOSSConfiguration.roleArn = roleArn; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.bucket}") |
||||||
|
private void setBucket(String bucket) { |
||||||
|
AliyunOSSConfiguration.bucket = bucket; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${aliyun.oss.object-dir-prefix: wayline}") |
||||||
|
private void setObjectDir(String objectDirPrefix) { |
||||||
|
AliyunOSSConfiguration.objectDirPrefix = objectDirPrefix; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
@Lazy |
||||||
|
public OSS ossClient() { |
||||||
|
return new OSSClientBuilder().build(endpoint, accessKey, secretKey); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,93 @@ |
|||||||
|
package com.dji.sample.component.oss.model; |
||||||
|
|
||||||
|
import io.minio.MinioClient; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.context.annotation.Lazy; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/7 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class MinIOConfiguration { |
||||||
|
|
||||||
|
/** |
||||||
|
* default |
||||||
|
*/ |
||||||
|
public static final String PROVIDER = "aws"; |
||||||
|
|
||||||
|
/** |
||||||
|
* Whether to use the current storage service. |
||||||
|
*/ |
||||||
|
public static boolean enable; |
||||||
|
|
||||||
|
public static String endpoint; |
||||||
|
|
||||||
|
public static String accessKey; |
||||||
|
|
||||||
|
public static String secretKey; |
||||||
|
|
||||||
|
public static String region; |
||||||
|
|
||||||
|
public static String bucket; |
||||||
|
|
||||||
|
public static Integer expire; |
||||||
|
|
||||||
|
public static String objectDirPrefix; |
||||||
|
|
||||||
|
@Value("${minio.endpoint: http://localhost:9000/}") |
||||||
|
private void setEndpoint(String endpoint) { |
||||||
|
MinIOConfiguration.endpoint = endpoint; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.access-key: minioadmin}") |
||||||
|
private void setAccessKey(String accessKey) { |
||||||
|
MinIOConfiguration.accessKey = accessKey; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.secret-key: minioadmin}") |
||||||
|
private void setSecretKey(String secretKey) { |
||||||
|
MinIOConfiguration.secretKey = secretKey; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.region: }") |
||||||
|
private void setRegion(String region) { |
||||||
|
MinIOConfiguration.region = region; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.bucket: test}") |
||||||
|
private void setBucket(String bucket) { |
||||||
|
MinIOConfiguration.bucket = bucket; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.expire: 3600}") |
||||||
|
private void setExpire(Integer expire) { |
||||||
|
MinIOConfiguration.expire = expire; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.enable: false}") |
||||||
|
private void setEnable(boolean enable) { |
||||||
|
MinIOConfiguration.enable = enable; |
||||||
|
} |
||||||
|
|
||||||
|
@Value("${minio.object-dir-prefix: wayline}") |
||||||
|
private void setObjectDir(String objectDirPrefix) { |
||||||
|
MinIOConfiguration.objectDirPrefix = objectDirPrefix; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
@Lazy |
||||||
|
public MinioClient minioClient() { |
||||||
|
MinioClient.Builder builder = MinioClient.builder() |
||||||
|
.endpoint(endpoint) |
||||||
|
.credentials(accessKey, secretKey); |
||||||
|
if (StringUtils.hasText(region)) { |
||||||
|
builder.region(MinIOConfiguration.region); |
||||||
|
} |
||||||
|
return builder.build(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.dji.sample.component.oss.service; |
||||||
|
|
||||||
|
import com.dji.sample.media.model.CredentialsDTO; |
||||||
|
|
||||||
|
import java.net.URL; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/23 |
||||||
|
*/ |
||||||
|
public interface IOssService { |
||||||
|
|
||||||
|
/** |
||||||
|
* Get temporary credentials. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
CredentialsDTO getCredentials(); |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the address of the object based on the bucket name and the object name. |
||||||
|
* @param bucket bucket name |
||||||
|
* @param objectKey object name |
||||||
|
* @return download link |
||||||
|
*/ |
||||||
|
URL getObjectUrl(String bucket, String objectKey); |
||||||
|
} |
@ -0,0 +1,68 @@ |
|||||||
|
package com.dji.sample.component.oss.service.impl; |
||||||
|
|
||||||
|
import com.aliyun.oss.OSS; |
||||||
|
import com.aliyuncs.DefaultAcsClient; |
||||||
|
import com.aliyuncs.IAcsClient; |
||||||
|
import com.aliyuncs.exceptions.ClientException; |
||||||
|
import com.aliyuncs.profile.DefaultProfile; |
||||||
|
import com.aliyuncs.sts.model.v20150401.AssumeRoleRequest; |
||||||
|
import com.aliyuncs.sts.model.v20150401.AssumeRoleResponse; |
||||||
|
import com.dji.sample.component.oss.model.AliyunOSSConfiguration; |
||||||
|
import com.dji.sample.component.oss.service.IOssService; |
||||||
|
import com.dji.sample.media.model.CredentialsDTO; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
|
||||||
|
import java.net.URL; |
||||||
|
import java.util.Date; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/23 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
@Slf4j |
||||||
|
public class AliyunOssServiceImpl implements IOssService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private OSS ossClient; |
||||||
|
|
||||||
|
@Override |
||||||
|
public CredentialsDTO getCredentials() { |
||||||
|
|
||||||
|
try { |
||||||
|
DefaultProfile profile = DefaultProfile.getProfile( |
||||||
|
AliyunOSSConfiguration.region, AliyunOSSConfiguration.accessKey, AliyunOSSConfiguration.secretKey); |
||||||
|
IAcsClient client = new DefaultAcsClient(profile); |
||||||
|
|
||||||
|
AssumeRoleRequest request = new AssumeRoleRequest(); |
||||||
|
request.setDurationSeconds(AliyunOSSConfiguration.expire); |
||||||
|
request.setRoleArn(AliyunOSSConfiguration.roleArn); |
||||||
|
request.setRoleSessionName(AliyunOSSConfiguration.roleSessionName); |
||||||
|
|
||||||
|
AssumeRoleResponse response = client.getAcsResponse(request); |
||||||
|
return new CredentialsDTO(response.getCredentials(), AliyunOSSConfiguration.expire); |
||||||
|
|
||||||
|
} catch (ClientException e) { |
||||||
|
log.debug("Failed to obtain sts."); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public URL getObjectUrl(String bucket, String objectKey) { |
||||||
|
if (!StringUtils.hasText(bucket) || !StringUtils.hasText(objectKey)) { |
||||||
|
return null; |
||||||
|
} |
||||||
|
// First check if the object can be fetched.
|
||||||
|
ossClient.getObject(bucket, objectKey); |
||||||
|
|
||||||
|
return ossClient.generatePresignedUrl(bucket, objectKey, |
||||||
|
new Date(System.currentTimeMillis() + AliyunOSSConfiguration.expire * 1000)); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.dji.sample.component.oss.service.impl; |
||||||
|
|
||||||
|
import com.dji.sample.component.oss.model.MinIOConfiguration; |
||||||
|
import com.dji.sample.component.oss.service.IOssService; |
||||||
|
import com.dji.sample.media.model.CredentialsDTO; |
||||||
|
import io.minio.GetPresignedObjectUrlArgs; |
||||||
|
import io.minio.MinioClient; |
||||||
|
import io.minio.credentials.AssumeRoleProvider; |
||||||
|
import io.minio.errors.*; |
||||||
|
import io.minio.http.Method; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.net.URL; |
||||||
|
import java.security.InvalidKeyException; |
||||||
|
import java.security.NoSuchAlgorithmException; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2021/12/23 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
@Slf4j |
||||||
|
public class MinIOServiceImpl implements IOssService { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private MinioClient client; |
||||||
|
|
||||||
|
@Override |
||||||
|
public CredentialsDTO getCredentials() { |
||||||
|
try { |
||||||
|
AssumeRoleProvider provider = new AssumeRoleProvider(MinIOConfiguration.endpoint, MinIOConfiguration.accessKey, |
||||||
|
MinIOConfiguration.secretKey, MinIOConfiguration.expire, |
||||||
|
null, null, null, null, null, null); |
||||||
|
return new CredentialsDTO(provider.fetch(), MinIOConfiguration.expire); |
||||||
|
} catch (NoSuchAlgorithmException e) { |
||||||
|
log.debug("Failed to obtain sts."); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public URL getObjectUrl(String bucket, String objectKey) { |
||||||
|
try { |
||||||
|
return new URL( |
||||||
|
client.getPresignedObjectUrl( |
||||||
|
GetPresignedObjectUrlArgs.builder() |
||||||
|
.method(Method.GET) |
||||||
|
.bucket(bucket) |
||||||
|
.object(objectKey) |
||||||
|
.expiry(MinIOConfiguration.expire) |
||||||
|
.build())); |
||||||
|
} catch (ErrorResponseException | InsufficientDataException | InternalException | |
||||||
|
InvalidKeyException | InvalidResponseException | IOException | |
||||||
|
NoSuchAlgorithmException | XmlParserException | ServerException e) { |
||||||
|
log.error("The file does not exist on the oss."); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return null; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
package com.dji.sample.component.websocket.config; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.util.JwtUtil; |
||||||
|
import com.dji.sample.component.AuthInterceptor; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.http.server.ServerHttpRequest; |
||||||
|
import org.springframework.http.server.ServletServerHttpRequest; |
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
import org.springframework.web.socket.WebSocketHandler; |
||||||
|
import org.springframework.web.socket.server.support.DefaultHandshakeHandler; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import java.security.Principal; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
@Component |
||||||
|
public class AuthPrincipalHandler extends DefaultHandshakeHandler { |
||||||
|
|
||||||
|
@Override |
||||||
|
protected boolean isValidOrigin(ServerHttpRequest request) { |
||||||
|
|
||||||
|
if (request instanceof ServletServerHttpRequest) { |
||||||
|
HttpServletRequest servletRequest = ((ServletServerHttpRequest) request).getServletRequest(); |
||||||
|
String token = servletRequest.getParameter(AuthInterceptor.PARAM_TOKEN); |
||||||
|
|
||||||
|
if (!StringUtils.hasText(token)) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
Optional<CustomClaim> customClaim = JwtUtil.parseToken(token); |
||||||
|
if (customClaim.isEmpty()) { |
||||||
|
return false; |
||||||
|
} |
||||||
|
|
||||||
|
servletRequest.setAttribute(AuthInterceptor.TOKEN_CLAIM, customClaim.get()); |
||||||
|
return true; |
||||||
|
} |
||||||
|
return false; |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* The principal's name: {workspaceId}/{userType}/{userId} |
||||||
|
* @param request |
||||||
|
* @param wsHandler |
||||||
|
* @param attributes |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Override |
||||||
|
protected Principal determineUser(ServerHttpRequest request, WebSocketHandler wsHandler, Map<String, Object> attributes) { |
||||||
|
if (request instanceof ServletServerHttpRequest) { |
||||||
|
|
||||||
|
// get the custom claim
|
||||||
|
CustomClaim claim = (CustomClaim) ((ServletServerHttpRequest) request).getServletRequest() |
||||||
|
.getAttribute(AuthInterceptor.TOKEN_CLAIM); |
||||||
|
|
||||||
|
return () -> claim.getWorkspaceId() + "/" + claim.getUserType() + "/" + claim.getId(); |
||||||
|
} |
||||||
|
return () -> null; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package com.dji.sample.component.websocket.config; |
||||||
|
|
||||||
|
import org.springframework.web.socket.WebSocketSession; |
||||||
|
import org.springframework.web.socket.handler.ConcurrentWebSocketSessionDecorator; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/24 |
||||||
|
*/ |
||||||
|
public class ConcurrentWebSocketSession extends ConcurrentWebSocketSessionDecorator { |
||||||
|
|
||||||
|
private static final int SEND_BUFFER_SIZE_LIMIT = 1024 * 1024; |
||||||
|
|
||||||
|
private static final int SEND_TIME_LIMIT = 1000; |
||||||
|
|
||||||
|
private ConcurrentWebSocketSession(WebSocketSession delegate, int sendTimeLimit, int bufferSizeLimit) { |
||||||
|
super(delegate, sendTimeLimit, bufferSizeLimit); |
||||||
|
} |
||||||
|
|
||||||
|
ConcurrentWebSocketSession(WebSocketSession delegate) { |
||||||
|
this(delegate, SEND_TIME_LIMIT, SEND_BUFFER_SIZE_LIMIT); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.dji.sample.component.websocket.config; |
||||||
|
|
||||||
|
import org.springframework.stereotype.Component; |
||||||
|
import org.springframework.web.socket.WebSocketHandler; |
||||||
|
import org.springframework.web.socket.handler.WebSocketHandlerDecoratorFactory; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Component |
||||||
|
public class WebSocketDefaultFactory implements WebSocketHandlerDecoratorFactory { |
||||||
|
|
||||||
|
@Override |
||||||
|
public WebSocketHandler decorate(WebSocketHandler handler) { |
||||||
|
return new WebSocketDefaultHandler(handler); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,60 @@ |
|||||||
|
package com.dji.sample.component.websocket.config; |
||||||
|
|
||||||
|
import com.dji.sample.component.websocket.model.WebSocketManager; |
||||||
|
import com.dji.sample.component.websocket.service.ISendMessageService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.util.StringUtils; |
||||||
|
import org.springframework.web.socket.CloseStatus; |
||||||
|
import org.springframework.web.socket.WebSocketHandler; |
||||||
|
import org.springframework.web.socket.WebSocketMessage; |
||||||
|
import org.springframework.web.socket.WebSocketSession; |
||||||
|
import org.springframework.web.socket.handler.WebSocketHandlerDecorator; |
||||||
|
|
||||||
|
import java.security.Principal; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class WebSocketDefaultHandler extends WebSocketHandlerDecorator { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ISendMessageService sendMessageService; |
||||||
|
|
||||||
|
WebSocketDefaultHandler(WebSocketHandler delegate) { |
||||||
|
super(delegate); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void afterConnectionEstablished(WebSocketSession session) throws Exception { |
||||||
|
Principal principal = session.getPrincipal(); |
||||||
|
if (StringUtils.hasText(principal.getName())) { |
||||||
|
WebSocketManager.put(principal.getName(), new ConcurrentWebSocketSession(session)); |
||||||
|
log.debug("{} is connected. ID: {}. WebSocketSession[current count: {}]", |
||||||
|
principal.getName(), session.getId(), WebSocketManager.getConnectedCount()); |
||||||
|
return; |
||||||
|
} |
||||||
|
session.close(); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void afterConnectionClosed(WebSocketSession session, CloseStatus closeStatus) throws Exception { |
||||||
|
Principal principal = session.getPrincipal(); |
||||||
|
if (StringUtils.hasText(principal.getName())) { |
||||||
|
WebSocketManager.remove(principal.getName(), session.getId()); |
||||||
|
log.debug("{} is disconnected. ID: {}. WebSocketSession[current count: {}]", |
||||||
|
principal.getName(), session.getId(), WebSocketManager.getConnectedCount()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void handleMessage(WebSocketSession session, WebSocketMessage<?> message) throws Exception { |
||||||
|
log.debug("received message: {}", message.getPayload()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
package com.dji.sample.component.websocket.config; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.web.socket.config.annotation.EnableWebSocketMessageBroker; |
||||||
|
import org.springframework.web.socket.config.annotation.StompEndpointRegistry; |
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketMessageBrokerConfigurer; |
||||||
|
import org.springframework.web.socket.config.annotation.WebSocketTransportRegistration; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/17 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@EnableWebSocketMessageBroker |
||||||
|
@Configuration |
||||||
|
public class WebSocketMessageConfiguration implements WebSocketMessageBrokerConfigurer { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private AuthPrincipalHandler authPrincipalHandler; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private WebSocketDefaultFactory webSocketDefaultFactory; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void registerStompEndpoints(StompEndpointRegistry registry) { |
||||||
|
// Set the WebSocket connection address
|
||||||
|
registry.addEndpoint("/api/v1/ws").setAllowedOriginPatterns("*") |
||||||
|
.setHandshakeHandler(authPrincipalHandler); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void configureWebSocketTransport(WebSocketTransportRegistration registry) { |
||||||
|
registry.addDecoratorFactory(webSocketDefaultFactory); |
||||||
|
registry.setTimeToFirstMessage(60000 * 60 * 24 * 10); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.dji.sample.component.websocket.model; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/26 |
||||||
|
*/ |
||||||
|
public enum BizCodeEnum { |
||||||
|
|
||||||
|
DEVICE_ONLINE("device_online"), |
||||||
|
|
||||||
|
DEVICE_OFFLINE("device_offline"), |
||||||
|
|
||||||
|
DEVICE_UPDATE_TOPO("device_update_topo"), |
||||||
|
|
||||||
|
DEVICE_OSD("device_osd"), |
||||||
|
|
||||||
|
GATEWAY_OSD("gateway_osd"), |
||||||
|
|
||||||
|
MAP_ELEMENT_CREATE("map_element_create"), |
||||||
|
|
||||||
|
MAP_ELEMENT_UPDATE("map_element_update"), |
||||||
|
|
||||||
|
MAP_ELEMENT_DELETE("map_element_delete"), |
||||||
|
|
||||||
|
MAP_GROUP_REFRESH("map_group_refresh"); |
||||||
|
|
||||||
|
private String code; |
||||||
|
|
||||||
|
BizCodeEnum(String code) { |
||||||
|
this.code = code; |
||||||
|
} |
||||||
|
|
||||||
|
public String getCode() { |
||||||
|
return code; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,30 @@ |
|||||||
|
package com.dji.sample.component.websocket.model; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* The format of WebSocket messages that the pilot can receive. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/17 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
public class CustomWebSocketMessage<T> { |
||||||
|
|
||||||
|
/** |
||||||
|
* @see BizCodeEnum |
||||||
|
* specific value |
||||||
|
*/ |
||||||
|
@JsonProperty("biz_code") |
||||||
|
private String bizCode; |
||||||
|
|
||||||
|
@Builder.Default |
||||||
|
private String version = "1.0"; |
||||||
|
|
||||||
|
private Long timestamp; |
||||||
|
|
||||||
|
private T data; |
||||||
|
} |
@ -0,0 +1,112 @@ |
|||||||
|
package com.dji.sample.component.websocket.model; |
||||||
|
|
||||||
|
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
||||||
|
import com.dji.sample.manage.model.enums.UserTypeEnum; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
import java.util.HashSet; |
||||||
|
import java.util.Set; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* Manage all WebSocket connection objects. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/16 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Slf4j |
||||||
|
public class WebSocketManager { |
||||||
|
|
||||||
|
private static final ConcurrentHashMap<String, |
||||||
|
ConcurrentHashMap<String, |
||||||
|
ConcurrentHashMap<String, ConcurrentWebSocketSession>>> MANAGER = new ConcurrentHashMap<>(16); |
||||||
|
|
||||||
|
/** |
||||||
|
* WebSocket connection from the pilot. |
||||||
|
*/ |
||||||
|
private static final Set<ConcurrentWebSocketSession> PILOT_SESSION = ConcurrentHashMap.newKeySet(16); |
||||||
|
|
||||||
|
/** |
||||||
|
* WebSocket connection from the web. |
||||||
|
*/ |
||||||
|
private static final Set<ConcurrentWebSocketSession> WEB_SESSION = ConcurrentHashMap.newKeySet(16); |
||||||
|
|
||||||
|
public static void put(String key, ConcurrentWebSocketSession val) { |
||||||
|
|
||||||
|
String[] name = key.split("/"); |
||||||
|
if (name.length != 3) { |
||||||
|
log.debug("The key is out of format. [{workspaceId}/{userType}/{userId}]"); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
ConcurrentHashMap<String, ConcurrentHashMap<String, ConcurrentWebSocketSession>> workspaceSessions = |
||||||
|
MANAGER.getOrDefault(name[0], new ConcurrentHashMap<>(16)); |
||||||
|
|
||||||
|
ConcurrentHashMap<String, ConcurrentWebSocketSession> userSessions = workspaceSessions.getOrDefault( |
||||||
|
name[2], new ConcurrentHashMap<>(16)); |
||||||
|
userSessions.put(val.getId(), val); |
||||||
|
workspaceSessions.put(name[2], userSessions); |
||||||
|
MANAGER.put(name[0], workspaceSessions); |
||||||
|
|
||||||
|
getSetByUserType(Integer.valueOf(name[1])).add(val); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static void remove(String key, String sessionId) { |
||||||
|
String[] name = key.split("/"); |
||||||
|
if (name.length != 3) { |
||||||
|
log.debug("The key is out of format. [{workspaceId}/{userType}/{userId}]"); |
||||||
|
return; |
||||||
|
} |
||||||
|
ConcurrentHashMap<String, ConcurrentWebSocketSession> userSession = MANAGER.get(name[0]).get(name[2]); |
||||||
|
|
||||||
|
Set<ConcurrentWebSocketSession> typeSession = getSetByUserType(Integer.valueOf(name[1])); |
||||||
|
|
||||||
|
ConcurrentWebSocketSession session = userSession.get(sessionId); |
||||||
|
typeSession.remove(session); |
||||||
|
userSession.remove(sessionId); |
||||||
|
} |
||||||
|
|
||||||
|
public static int getConnectedCount() { |
||||||
|
return PILOT_SESSION.size() + WEB_SESSION.size(); |
||||||
|
} |
||||||
|
|
||||||
|
public static Collection<ConcurrentWebSocketSession> getValueWithWorkspace(String workspaceId) { |
||||||
|
Set<ConcurrentWebSocketSession> sessions = ConcurrentHashMap.newKeySet(); |
||||||
|
|
||||||
|
MANAGER.get(workspaceId) |
||||||
|
.forEach((userId, userSessions) -> { |
||||||
|
sessions.addAll(userSessions.values()); |
||||||
|
}); |
||||||
|
return sessions; |
||||||
|
} |
||||||
|
|
||||||
|
public static Collection<ConcurrentWebSocketSession> getValueWithWorkspaceAndUserType(String workspaceId, Integer userType) { |
||||||
|
Set<ConcurrentWebSocketSession> sessions = ConcurrentHashMap.newKeySet(); |
||||||
|
Set<ConcurrentWebSocketSession> typeSessions = getSetByUserType(userType); |
||||||
|
|
||||||
|
MANAGER.getOrDefault(workspaceId, new ConcurrentHashMap<>()) |
||||||
|
.forEach((userId, userSessions) -> { |
||||||
|
Collection<ConcurrentWebSocketSession> sessionList = userSessions.values(); |
||||||
|
if (!sessionList.isEmpty()) { |
||||||
|
ConcurrentWebSocketSession session = sessionList.iterator().next(); |
||||||
|
if (typeSessions.contains(session)) { |
||||||
|
sessions.addAll(sessionList); |
||||||
|
} |
||||||
|
} |
||||||
|
}); |
||||||
|
return sessions; |
||||||
|
} |
||||||
|
|
||||||
|
private static Set<ConcurrentWebSocketSession> getSetByUserType(Integer userType) { |
||||||
|
if (UserTypeEnum.PILOT.getVal() == userType) { |
||||||
|
return PILOT_SESSION; |
||||||
|
} |
||||||
|
|
||||||
|
if (UserTypeEnum.WEB.getVal() == userType) { |
||||||
|
return WEB_SESSION; |
||||||
|
} |
||||||
|
return new HashSet<>(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
package com.dji.sample.component.websocket.service; |
||||||
|
|
||||||
|
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
||||||
|
import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
||||||
|
|
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/24 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface ISendMessageService { |
||||||
|
|
||||||
|
/** |
||||||
|
* Send a message to the specific connection. |
||||||
|
* @param session A WebSocket connection object |
||||||
|
* @param message message |
||||||
|
*/ |
||||||
|
void sendMessage(ConcurrentWebSocketSession session, CustomWebSocketMessage message); |
||||||
|
|
||||||
|
/** |
||||||
|
* Send the same message to specific connection. |
||||||
|
* @param sessions A collection of WebSocket connection objects. |
||||||
|
* @param message message |
||||||
|
*/ |
||||||
|
void sendBatch(Collection<ConcurrentWebSocketSession> sessions, CustomWebSocketMessage message); |
||||||
|
} |
@ -0,0 +1,72 @@ |
|||||||
|
package com.dji.sample.component.websocket.service.impl; |
||||||
|
|
||||||
|
import com.dji.sample.component.websocket.config.ConcurrentWebSocketSession; |
||||||
|
import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
||||||
|
import com.dji.sample.component.websocket.service.ISendMessageService; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
import org.springframework.web.socket.TextMessage; |
||||||
|
|
||||||
|
import java.io.IOException; |
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/24 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
@Slf4j |
||||||
|
public class SendMessageServiceImpl implements ISendMessageService { |
||||||
|
|
||||||
|
@Override |
||||||
|
public void sendMessage(ConcurrentWebSocketSession session, CustomWebSocketMessage message) { |
||||||
|
if (session == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
if (!session.isOpen()) { |
||||||
|
session.close(); |
||||||
|
log.debug("This session is closed."); |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
|
||||||
|
session.sendMessage(new TextMessage(mapper.writeValueAsBytes(message))); |
||||||
|
} catch (IOException e) { |
||||||
|
log.info("Failed to publish the message. {}", message.toString()); |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public void sendBatch(Collection<ConcurrentWebSocketSession> sessions, CustomWebSocketMessage message) { |
||||||
|
if (sessions.isEmpty()) { |
||||||
|
return; |
||||||
|
} |
||||||
|
|
||||||
|
try { |
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
TextMessage data = new TextMessage(mapper.writeValueAsBytes(message)); |
||||||
|
|
||||||
|
for (ConcurrentWebSocketSession session : sessions) { |
||||||
|
if (!session.isOpen()) { |
||||||
|
session.close(); |
||||||
|
log.debug("This session is closed."); |
||||||
|
return; |
||||||
|
} |
||||||
|
session.sendMessage(data); |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
} catch (IOException e) { |
||||||
|
log.info("Failed to publish the message. {}", message.toString()); |
||||||
|
|
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package com.dji.sample.configuration; |
||||||
|
|
||||||
|
import com.dji.sample.component.AuthInterceptor; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.web.servlet.config.annotation.InterceptorRegistry; |
||||||
|
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
@Configuration |
||||||
|
public class GlobalMVCConfigurer implements WebMvcConfigurer { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private AuthInterceptor authInterceptor; |
||||||
|
|
||||||
|
private static List<String> excludePaths = new ArrayList<>(); |
||||||
|
|
||||||
|
@Value("${url.manage.prefix}") |
||||||
|
private String managePrefix; |
||||||
|
|
||||||
|
@Value("${url.manage.version}") |
||||||
|
private String manageVersion; |
||||||
|
|
||||||
|
@Override |
||||||
|
public void addInterceptors(InterceptorRegistry registry) { |
||||||
|
// Exclude the login interface.
|
||||||
|
excludePaths.add(managePrefix + manageVersion + "/login"); |
||||||
|
excludePaths.add(managePrefix + manageVersion + "/token/refresh"); |
||||||
|
// Intercept for all request interfaces.
|
||||||
|
registry.addInterceptor(authInterceptor).addPathPatterns("/**").excludePathPatterns(excludePaths); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,42 @@ |
|||||||
|
package com.dji.sample.configuration; |
||||||
|
|
||||||
|
import org.springframework.beans.factory.annotation.Value; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
|
||||||
|
import java.util.concurrent.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Configuration |
||||||
|
public class GlobalThreadPoolConfiguration { |
||||||
|
|
||||||
|
@Value("${thread.pool.core-pool-size: 10}") |
||||||
|
private int corePoolSize; |
||||||
|
|
||||||
|
@Value("${thread.pool.maximum-pool-size: 20}") |
||||||
|
private int maximumPoolSize; |
||||||
|
|
||||||
|
@Value("${thread.pool.keep-alive-time: 60}") |
||||||
|
private long keepAliveTime; |
||||||
|
|
||||||
|
@Value("${thread.pool.queue.capacity: 1000}") |
||||||
|
private int capacity; |
||||||
|
|
||||||
|
/** |
||||||
|
* A custom thread pool. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
public Executor threadPool() { |
||||||
|
return new ThreadPoolExecutor(corePoolSize, |
||||||
|
maximumPoolSize, keepAliveTime, |
||||||
|
TimeUnit.SECONDS, new LinkedBlockingQueue<>(capacity), |
||||||
|
Executors.defaultThreadFactory(), new ThreadPoolExecutor.DiscardOldestPolicy()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,138 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.component.AuthInterceptor; |
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicResponse; |
||||||
|
import com.dji.sample.component.websocket.model.BizCodeEnum; |
||||||
|
import com.dji.sample.component.websocket.model.CustomWebSocketMessage; |
||||||
|
import com.dji.sample.component.websocket.model.WebSocketManager; |
||||||
|
import com.dji.sample.component.websocket.service.ISendMessageService; |
||||||
|
import com.dji.sample.manage.model.dto.DeviceDTO; |
||||||
|
import com.dji.sample.manage.model.dto.WorkspaceDTO; |
||||||
|
import com.dji.sample.manage.model.enums.UserTypeEnum; |
||||||
|
import com.dji.sample.manage.model.param.DeviceQueryParam; |
||||||
|
import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
||||||
|
import com.dji.sample.manage.service.IDeviceService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.messaging.Message; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/15 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@Slf4j |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}/devices") |
||||||
|
public class DeviceController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IDeviceService deviceService; |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ISendMessageService sendMessageService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the message that the drone goes online. |
||||||
|
* @param receiver The drone information is not empty. |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATUS_ONLINE, outputChannel = ChannelName.OUTBOUND) |
||||||
|
public void deviceOnline(CommonTopicReceiver<StatusGatewayReceiver> receiver) { |
||||||
|
boolean online = deviceService.deviceOnline(receiver.getData()); |
||||||
|
if (online) { |
||||||
|
// Notify pilot that the drone is online successfully.
|
||||||
|
deviceService.publishStatusReply(receiver.getData().getSn(), |
||||||
|
CommonTopicResponse.builder() |
||||||
|
.tid(receiver.getTid()) |
||||||
|
.bid(receiver.getBid()) |
||||||
|
.build()); |
||||||
|
|
||||||
|
// Publish the latest device topology information in the current workspace to the pilot.
|
||||||
|
deviceService.pushDeviceOnlineTopo(WorkspaceDTO.DEFAULT_WORKSPACE_ID, |
||||||
|
receiver.getData().getSn(), receiver.getData().getSubDevices().get(0).getSn()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the message that the drone goes offline. |
||||||
|
* @param receiver The drone information is empty. |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATUS_OFFLINE, outputChannel = ChannelName.OUTBOUND) |
||||||
|
public void deviceOffline(CommonTopicReceiver<StatusGatewayReceiver> receiver) { |
||||||
|
|
||||||
|
boolean offline = deviceService.deviceOffline(receiver.getData().getSn()); |
||||||
|
if (offline) { |
||||||
|
// Notify pilot that the device is offline successfully.
|
||||||
|
deviceService.publishStatusReply(receiver.getData().getSn(), |
||||||
|
CommonTopicResponse.builder() |
||||||
|
.tid(receiver.getTid()) |
||||||
|
.bid(receiver.getBid()) |
||||||
|
.build()); |
||||||
|
|
||||||
|
// Publish the latest device topology information in the current workspace to the pilot.
|
||||||
|
deviceService.pushDeviceOfflineTopo(WorkspaceDTO.DEFAULT_WORKSPACE_ID, receiver.getData().getSn()); |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the topology list of all devices in the current user workspace. |
||||||
|
* @param request |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@GetMapping("/devices") |
||||||
|
public ResponseResult<List<DeviceDTO>> getDevices(HttpServletRequest request) { |
||||||
|
// Get information about the current user.
|
||||||
|
CustomClaim claim = (CustomClaim)request.getAttribute(AuthInterceptor.TOKEN_CLAIM); |
||||||
|
String workspaceId = claim.getWorkspaceId(); |
||||||
|
// Get information about the devices in the current user's workspace.
|
||||||
|
List<DeviceDTO> devicesList = deviceService.getDevicesTopoForWeb(workspaceId); |
||||||
|
|
||||||
|
return ResponseResult.success(devicesList); |
||||||
|
} |
||||||
|
|
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_OSD) |
||||||
|
public void osdRealTime(Message<?> message) { |
||||||
|
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); |
||||||
|
byte[] payload = (byte[])message.getPayload(); |
||||||
|
deviceService.handleOSD(topic, payload); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the payloads data of the drone. |
||||||
|
* @param deviceSn drone's sn |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
||||||
|
public void pushWebSocketDevices(String deviceSn) { |
||||||
|
List<DeviceDTO> devicesList = deviceService.getDevicesByParams( |
||||||
|
DeviceQueryParam.builder() |
||||||
|
.deviceSn(deviceSn) |
||||||
|
.build()); |
||||||
|
// Get drone information based on the sn of the drone. The sn of the drone is unique.
|
||||||
|
DeviceDTO device = devicesList.get(0); |
||||||
|
// Set the remote controller and payloads information of the drone.
|
||||||
|
deviceService.spliceDeviceTopo(device); |
||||||
|
|
||||||
|
CustomWebSocketMessage wsMessage = CustomWebSocketMessage.builder() |
||||||
|
.timestamp(System.currentTimeMillis()) |
||||||
|
.bizCode(BizCodeEnum.DEVICE_UPDATE_TOPO.getCode()) |
||||||
|
.data(device) |
||||||
|
.build(); |
||||||
|
// Update the topology of the drone via WebSocket notifications to the web side.
|
||||||
|
sendMessageService.sendBatch(WebSocketManager |
||||||
|
.getValueWithWorkspaceAndUserType( |
||||||
|
device.getWorkspaceId(), UserTypeEnum.WEB.getVal()), |
||||||
|
wsMessage); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,66 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
||||||
|
import com.dji.sample.manage.service.IDevicePayloadService; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@Slf4j |
||||||
|
public class DevicePayloadController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IDevicePayloadService devicePayloadService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the data for the payload messages in the state topic. |
||||||
|
* @param payloadsList List of payload information. |
||||||
|
* @return drone's sn |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_PAYLOAD, |
||||||
|
outputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
||||||
|
public String statePayload(List<DevicePayloadReceiver> payloadsList) { |
||||||
|
// Delete all payload information for the drone based on the drone's sn.
|
||||||
|
devicePayloadService.deletePayloadsByDeviceSn(List.of(payloadsList.get(0).getDeviceSn())); |
||||||
|
|
||||||
|
// Save the new payload information.
|
||||||
|
devicePayloadService.savePayloadDTOs(payloadsList); |
||||||
|
|
||||||
|
log.debug("The result of saving the payload is successful."); |
||||||
|
|
||||||
|
return payloadsList.get(0).getDeviceSn(); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles messages in the state topic about basic drone data. |
||||||
|
* |
||||||
|
* Note: Only the data of the drone payload is handled here. You can handle other data from the drone |
||||||
|
* according to your business needs. |
||||||
|
* @param deviceBasic basic drone data |
||||||
|
* @return drone's sn |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_BASIC, |
||||||
|
outputChannel = ChannelName.INBOUND_STATE_PAYLOAD_UPDATE) |
||||||
|
public String stateBasic(DeviceBasicReceiver deviceBasic) { |
||||||
|
// Delete all payload information for the drone based on the drone's sn.
|
||||||
|
devicePayloadService.deletePayloadsByDeviceSn(List.of(deviceBasic.getDeviceSn())); |
||||||
|
|
||||||
|
// Save the new payload information.
|
||||||
|
boolean isSave = devicePayloadService.savePayloadDTOs(deviceBasic.getPayloads()); |
||||||
|
|
||||||
|
log.debug("The result of saving the payloads is {}.", isSave); |
||||||
|
|
||||||
|
return deviceBasic.getDeviceSn(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,113 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
||||||
|
import com.dji.sample.manage.model.Chan; |
||||||
|
import com.dji.sample.manage.model.dto.CapacityDeviceDTO; |
||||||
|
import com.dji.sample.manage.model.dto.LiveTypeDTO; |
||||||
|
import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.ServiceReplyReceiver; |
||||||
|
import com.dji.sample.manage.service.ILiveStreamService; |
||||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.messaging.Message; |
||||||
|
import org.springframework.web.bind.annotation.*; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/19 |
||||||
|
*/ |
||||||
|
|
||||||
|
@RestController |
||||||
|
@Slf4j |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}/live") |
||||||
|
public class LiveStreamController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ILiveStreamService liveStreamService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Analyze the live streaming capabilities of drones. |
||||||
|
* This data is necessary if drones are required for live streaming. |
||||||
|
* @param device the capacity of drone |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE_CAPACITY) |
||||||
|
public void stateCapacity(CapacityDeviceReceiver device) { |
||||||
|
boolean parseCapacity = liveStreamService.saveLiveCapacity(device); |
||||||
|
log.debug("The result of parsing the live capacity is {}.", parseCapacity); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Get live capability data of all drones in the current user's workspace from the database. |
||||||
|
* @param request |
||||||
|
* @return live capability |
||||||
|
*/ |
||||||
|
@GetMapping("/capacity") |
||||||
|
public ResponseResult<List<CapacityDeviceDTO>> getLiveCapacity(HttpServletRequest request) { |
||||||
|
// Get information about the current user.
|
||||||
|
CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
||||||
|
|
||||||
|
List<CapacityDeviceDTO> liveCapacity = liveStreamService.getLiveCapacity(customClaim.getWorkspaceId()); |
||||||
|
|
||||||
|
return ResponseResult.success(liveCapacity); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Live streaming according to the parameters passed in from the web side. |
||||||
|
* @param liveParam Live streaming parameters. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@PostMapping("/streams/start") |
||||||
|
public ResponseResult liveStart(@RequestBody LiveTypeDTO liveParam) { |
||||||
|
return liveStreamService.liveStart(liveParam); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Stop live streaming according to the parameters passed in from the web side. |
||||||
|
* @param liveParam Live streaming parameters. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@PostMapping("/streams/stop") |
||||||
|
public ResponseResult liveStop(@RequestBody LiveTypeDTO liveParam) { |
||||||
|
return liveStreamService.liveStop(liveParam.getVideoId()); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Set the quality of the live streaming according to the parameters passed in from the web side. |
||||||
|
* @param liveParam Live streaming parameters. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@PostMapping("/streams/update") |
||||||
|
public ResponseResult liveSetQuality(@RequestBody LiveTypeDTO liveParam) { |
||||||
|
return liveStreamService.liveSetQuality(liveParam); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handle the reply message from the pilot side to the on-demand video. |
||||||
|
* @param message reply message |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_SERVICE_REPLY) |
||||||
|
public void serviceReply(Message<?> message) throws IOException { |
||||||
|
byte[] payload = (byte[])message.getPayload(); |
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
CommonTopicReceiver<ServiceReplyReceiver> receiver = mapper.readValue(payload, |
||||||
|
new TypeReference<CommonTopicReceiver<ServiceReplyReceiver>>() { |
||||||
|
}); |
||||||
|
Chan<CommonTopicReceiver> chan = Chan.getInstance(); |
||||||
|
// Put the message to the chan object.
|
||||||
|
chan.put(receiver); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.error.CommonErrorEnum; |
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.manage.model.dto.UserDTO; |
||||||
|
import com.dji.sample.manage.model.dto.UserLoginDTO; |
||||||
|
import com.dji.sample.manage.service.IUserService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.http.HttpStatus; |
||||||
|
import org.springframework.web.bind.annotation.PostMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestBody; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import javax.servlet.http.HttpServletResponse; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import static com.dji.sample.component.AuthInterceptor.PARAM_TOKEN; |
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}") |
||||||
|
public class LoginController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IUserService userService; |
||||||
|
|
||||||
|
@PostMapping("/login") |
||||||
|
public ResponseResult login(@RequestBody UserLoginDTO loginDTO) { |
||||||
|
String username = loginDTO.getUsername(); |
||||||
|
String password = loginDTO.getPassword(); |
||||||
|
return userService.userLogin(username, password); |
||||||
|
} |
||||||
|
|
||||||
|
@PostMapping("/token/refresh") |
||||||
|
public ResponseResult refreshToken(HttpServletRequest request, HttpServletResponse response) { |
||||||
|
String token = request.getHeader(PARAM_TOKEN); |
||||||
|
Optional<UserDTO> user = userService.refreshToken(token); |
||||||
|
|
||||||
|
if (user.isEmpty()) { |
||||||
|
response.setStatus(HttpStatus.UNAUTHORIZED.value()); |
||||||
|
return ResponseResult.error(CommonErrorEnum.NO_TOKEN.getErrorMsg()); |
||||||
|
} |
||||||
|
|
||||||
|
return ResponseResult.success(user); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,40 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.manage.model.dto.TopologyDTO; |
||||||
|
import com.dji.sample.manage.service.ITopologyService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.PathVariable; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}/workspaces") |
||||||
|
public class TopologyController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private ITopologyService topologyService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Get the topology list of all devices in the current user workspace for pilot display. |
||||||
|
* @param workspaceId |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@GetMapping("/{workspace_id}/devices/topologies") |
||||||
|
public ResponseResult<Map<String, List<TopologyDTO>>> getDevicesTopologiesForPilot( |
||||||
|
@PathVariable(name = "workspace_id") String workspaceId) { |
||||||
|
List<TopologyDTO> topologyList = topologyService.getDeviceTopology(workspaceId); |
||||||
|
return ResponseResult.success(new ConcurrentHashMap<>(Map.of("list", topologyList))); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.manage.service.IUserService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
|
||||||
|
import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
||||||
|
|
||||||
|
|
||||||
|
@RestController |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}/users") |
||||||
|
public class UserController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IUserService userService; |
||||||
|
|
||||||
|
@GetMapping("/current") |
||||||
|
public ResponseResult getCurrentUserInfo(HttpServletRequest request) { |
||||||
|
CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
||||||
|
return userService.getUserByUsername(customClaim.getUsername(), customClaim.getWorkspaceId()); |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,41 @@ |
|||||||
|
package com.dji.sample.manage.controller; |
||||||
|
|
||||||
|
import com.dji.sample.common.model.CustomClaim; |
||||||
|
import com.dji.sample.common.model.ResponseResult; |
||||||
|
import com.dji.sample.manage.model.dto.WorkspaceDTO; |
||||||
|
import com.dji.sample.manage.service.IWorkspaceService; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.web.bind.annotation.GetMapping; |
||||||
|
import org.springframework.web.bind.annotation.RequestMapping; |
||||||
|
import org.springframework.web.bind.annotation.RestController; |
||||||
|
|
||||||
|
import javax.servlet.http.HttpServletRequest; |
||||||
|
import java.util.Optional; |
||||||
|
|
||||||
|
import static com.dji.sample.component.AuthInterceptor.TOKEN_CLAIM; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/23 |
||||||
|
*/ |
||||||
|
@RestController |
||||||
|
@RequestMapping("${url.manage.prefix}${url.manage.version}/workspaces") |
||||||
|
public class WorkspaceController { |
||||||
|
|
||||||
|
@Autowired |
||||||
|
private IWorkspaceService workspaceService; |
||||||
|
|
||||||
|
/** |
||||||
|
* Gets information about the workspace that the current user is in. |
||||||
|
* @param request |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@GetMapping("/current") |
||||||
|
public ResponseResult getCurrentWorkspace(HttpServletRequest request) { |
||||||
|
CustomClaim customClaim = (CustomClaim)request.getAttribute(TOKEN_CLAIM); |
||||||
|
Optional<WorkspaceDTO> workspaceOpt = workspaceService.getWorkspaceByWorkspaceId(customClaim.getWorkspaceId()); |
||||||
|
|
||||||
|
return workspaceOpt.isEmpty() ? ResponseResult.error() : ResponseResult.success(workspaceOpt.get()); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.CameraVideoEntity; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/19 |
||||||
|
*/ |
||||||
|
public interface ICameraVideoMapper extends BaseMapper<CameraVideoEntity> { |
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.CapacityCameraEntity; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface ICapacityCameraMapper extends BaseMapper<CapacityCameraEntity> { |
||||||
|
} |
@ -0,0 +1,13 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.DeviceDictionaryEntity; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/15 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface IDeviceDictionaryMapper extends BaseMapper<DeviceDictionaryEntity> { |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.DeviceEntity; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/10 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface IDeviceMapper extends BaseMapper<DeviceEntity> { |
||||||
|
|
||||||
|
} |
@ -0,0 +1,12 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.DevicePayloadEntity; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public interface IDevicePayloadMapper extends BaseMapper<DevicePayloadEntity> { |
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.UserEntity; |
||||||
|
|
||||||
|
public interface IUserMapper extends BaseMapper<UserEntity> { |
||||||
|
|
||||||
|
} |
@ -0,0 +1,8 @@ |
|||||||
|
package com.dji.sample.manage.dao; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.core.mapper.BaseMapper; |
||||||
|
import com.dji.sample.manage.model.entity.WorkspaceEntity; |
||||||
|
|
||||||
|
public interface IWorkspaceMapper extends BaseMapper<WorkspaceEntity> { |
||||||
|
|
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/2/21 |
||||||
|
*/ |
||||||
|
public abstract class AbstractStateTopicHandler { |
||||||
|
|
||||||
|
protected AbstractStateTopicHandler handler; |
||||||
|
protected static ObjectMapper mapper = new ObjectMapper();; |
||||||
|
|
||||||
|
protected AbstractStateTopicHandler(AbstractStateTopicHandler handler){ |
||||||
|
this.handler = handler; |
||||||
|
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
||||||
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Passing dataNode data, using different processing methods depending on the data selection. |
||||||
|
* @param dataNode |
||||||
|
* @param stateReceiver |
||||||
|
* @param sn |
||||||
|
* @return |
||||||
|
* @throws JsonProcessingException |
||||||
|
*/ |
||||||
|
public abstract TopicStateReceiver handleState(JsonNode dataNode, TopicStateReceiver stateReceiver, String sn) throws JsonProcessingException; |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/3/21 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class StateDefaultHandler extends AbstractStateTopicHandler { |
||||||
|
|
||||||
|
protected StateDefaultHandler() { |
||||||
|
super(null); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public TopicStateReceiver handleState(JsonNode dataNode, TopicStateReceiver stateReceiver, String sn) throws JsonProcessingException { |
||||||
|
// If no suitable handler is found for the data, it is not processed.
|
||||||
|
return stateReceiver; |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/2/21 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class StateDeviceBasicHandler extends AbstractStateTopicHandler { |
||||||
|
|
||||||
|
public StateDeviceBasicHandler(@Autowired @Qualifier("statePayloadHandler") AbstractStateTopicHandler handler) { |
||||||
|
super(handler); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public TopicStateReceiver handleState(JsonNode dataNode, TopicStateReceiver stateReceiver, String sn) throws JsonProcessingException { |
||||||
|
// handle device basic data
|
||||||
|
if (dataNode.size() != 1) { |
||||||
|
DeviceBasicReceiver data = mapper.treeToValue(dataNode, DeviceBasicReceiver.class); |
||||||
|
data.setDeviceSn(sn); |
||||||
|
stateReceiver.setData(data); |
||||||
|
return stateReceiver; |
||||||
|
} |
||||||
|
return handler.handleState(dataNode, stateReceiver, sn); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,39 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.dji.sample.manage.model.enums.StateDataEnum; |
||||||
|
import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/2/21 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class StateLiveCapacityHandler extends AbstractStateTopicHandler { |
||||||
|
|
||||||
|
private static final String DEVICE_LIST = "device_list"; |
||||||
|
|
||||||
|
protected StateLiveCapacityHandler(@Autowired @Qualifier("stateDefaultHandler") AbstractStateTopicHandler handler) { |
||||||
|
super(handler); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public TopicStateReceiver handleState(JsonNode dataNode, TopicStateReceiver stateReceiver, String sn) throws JsonProcessingException { |
||||||
|
String name = dataNode.fieldNames().next(); |
||||||
|
JsonNode childNode = dataNode.findPath(name); |
||||||
|
// Determine if it is live capacity data based on name.
|
||||||
|
if (name.equals(StateDataEnum.LIVE_CAPACITY.getDesc())) { |
||||||
|
JsonNode deviceNode = childNode.findPath(DEVICE_LIST); |
||||||
|
stateReceiver.setData( |
||||||
|
mapper.treeToValue(deviceNode.get(0), CapacityDeviceReceiver.class)); |
||||||
|
return stateReceiver; |
||||||
|
} |
||||||
|
return handler.handleState(dataNode, stateReceiver, sn); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,55 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.dji.sample.manage.model.enums.StateDataEnum; |
||||||
|
import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
||||||
|
import com.fasterxml.jackson.core.JsonProcessingException; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import org.springframework.beans.factory.annotation.Autowired; |
||||||
|
import org.springframework.beans.factory.annotation.Qualifier; |
||||||
|
import org.springframework.stereotype.Service; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Iterator; |
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/2/21 |
||||||
|
*/ |
||||||
|
@Service |
||||||
|
public class StatePayloadHandler extends AbstractStateTopicHandler { |
||||||
|
|
||||||
|
protected StatePayloadHandler(@Autowired @Qualifier("stateLiveCapacityHandler") AbstractStateTopicHandler handler) { |
||||||
|
super(handler); |
||||||
|
} |
||||||
|
|
||||||
|
@Override |
||||||
|
public TopicStateReceiver handleState(JsonNode dataNode, TopicStateReceiver stateReceiver, String sn) throws JsonProcessingException { |
||||||
|
String name = dataNode.fieldNames().next(); |
||||||
|
JsonNode childNode = dataNode.findPath(name); |
||||||
|
// Determine if it is payload data based on name.
|
||||||
|
if (name.equals(StateDataEnum.PAYLOADS.getDesc())) { |
||||||
|
List<DevicePayloadReceiver> payloadsList = new ArrayList<>(); |
||||||
|
|
||||||
|
Iterator<JsonNode> payloadsNode = childNode.elements(); |
||||||
|
while (payloadsNode.hasNext()) { |
||||||
|
DevicePayloadReceiver payloadReceiver = mapper.treeToValue( |
||||||
|
payloadsNode.next(), DevicePayloadReceiver.class); |
||||||
|
payloadReceiver.setDeviceSn(sn); |
||||||
|
payloadsList.add(payloadReceiver); |
||||||
|
} |
||||||
|
|
||||||
|
if (payloadsList.isEmpty()) { |
||||||
|
DevicePayloadReceiver payloadReceiver = new DevicePayloadReceiver(); |
||||||
|
payloadReceiver.setDeviceSn(sn); |
||||||
|
payloadsList.add(payloadReceiver); |
||||||
|
} |
||||||
|
|
||||||
|
stateReceiver.setData(payloadsList); |
||||||
|
return stateReceiver; |
||||||
|
} |
||||||
|
return handler.handleState(dataNode, stateReceiver, sn); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,92 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.CapacityDeviceReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.DeviceBasicReceiver; |
||||||
|
import com.fasterxml.jackson.databind.DeserializationFeature; |
||||||
|
import com.fasterxml.jackson.databind.JsonNode; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
import com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException; |
||||||
|
import lombok.extern.slf4j.Slf4j; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.integration.annotation.MessageEndpoint; |
||||||
|
import org.springframework.integration.annotation.Router; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.integration.router.MessageRouter; |
||||||
|
import org.springframework.integration.router.PayloadTypeRouter; |
||||||
|
import org.springframework.messaging.Message; |
||||||
|
|
||||||
|
import javax.annotation.Resource; |
||||||
|
import java.io.IOException; |
||||||
|
import java.util.List; |
||||||
|
import java.util.Map; |
||||||
|
|
||||||
|
import static com.dji.sample.component.mqtt.model.TopicConst.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/17 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@MessageEndpoint |
||||||
|
@Slf4j |
||||||
|
@Configuration |
||||||
|
public class StateRouter { |
||||||
|
|
||||||
|
@Resource(name = "stateDeviceBasicHandler") |
||||||
|
private AbstractStateTopicHandler handler; |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the routing of state topic messages. Depending on the data, it is assigned to different channels for handling. |
||||||
|
* @param message |
||||||
|
* @return |
||||||
|
* @throws IOException |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATE, outputChannel = ChannelName.INBOUND_STATE_SPLITTER) |
||||||
|
public TopicStateReceiver<?> resolveStateData(Message<?> message) throws IOException { |
||||||
|
byte[] payload = (byte[])message.getPayload(); |
||||||
|
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); |
||||||
|
|
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
||||||
|
mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); |
||||||
|
|
||||||
|
TopicStateReceiver stateReceiver = mapper.readValue(payload, TopicStateReceiver.class); |
||||||
|
// Get the sn of the topic source.
|
||||||
|
String from = topic.substring((THING_MODEL_PRE + PRODUCT).length(), |
||||||
|
topic.indexOf(STATE_SUF)); |
||||||
|
|
||||||
|
try { |
||||||
|
JsonNode dataNode = mapper.readTree(payload).findPath("data"); |
||||||
|
return handler.handleState(dataNode, stateReceiver, from); |
||||||
|
|
||||||
|
} catch (UnrecognizedPropertyException e) { |
||||||
|
log.info("The {} data is not processed.", e.getPropertyName()); |
||||||
|
} |
||||||
|
return stateReceiver; |
||||||
|
} |
||||||
|
|
||||||
|
@Bean |
||||||
|
@Router(inputChannel = ChannelName.INBOUND_STATE_ROUTER) |
||||||
|
public MessageRouter resolveStateRouter() { |
||||||
|
PayloadTypeRouter router = new PayloadTypeRouter(); |
||||||
|
// // Channel mapping for basic data.
|
||||||
|
router.setChannelMapping(DeviceBasicReceiver.class.getName(), |
||||||
|
ChannelName.INBOUND_STATE_BASIC); |
||||||
|
// Channel mapping for live streaming capabilities.
|
||||||
|
router.setChannelMapping(CapacityDeviceReceiver.class.getName(), |
||||||
|
ChannelName.INBOUND_STATE_CAPACITY); |
||||||
|
// Channel mapping for payload data.
|
||||||
|
router.setChannelMapping(List.class.getName(), |
||||||
|
ChannelName.INBOUND_STATE_PAYLOAD); |
||||||
|
router.setChannelMapping(Map.class.getName(), |
||||||
|
ChannelName.DEFAULT); |
||||||
|
return router; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,59 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.component.mqtt.model.TopicStateReceiver; |
||||||
|
import com.dji.sample.manage.model.receiver.DevicePayloadReceiver; |
||||||
|
import org.springframework.context.annotation.Bean; |
||||||
|
import org.springframework.context.annotation.Configuration; |
||||||
|
import org.springframework.integration.annotation.MessageEndpoint; |
||||||
|
import org.springframework.integration.annotation.Splitter; |
||||||
|
import org.springframework.integration.dsl.IntegrationFlow; |
||||||
|
import org.springframework.integration.dsl.IntegrationFlows; |
||||||
|
|
||||||
|
import java.util.ArrayList; |
||||||
|
import java.util.Collection; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/17 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@MessageEndpoint |
||||||
|
@Configuration |
||||||
|
public class StateSplitter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Split the state message data to different channels for handling according to their different types. |
||||||
|
* @param receiver state message |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Splitter(inputChannel = ChannelName.INBOUND_STATE_SPLITTER, outputChannel = ChannelName.INBOUND_STATE_ROUTER) |
||||||
|
public Collection<Object> splitState(TopicStateReceiver receiver) { |
||||||
|
ArrayList<Object> type = new ArrayList<>(); |
||||||
|
type.add(receiver.getData()); |
||||||
|
return type; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Split according to the different types in the list. |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Bean |
||||||
|
public IntegrationFlow splitList() { |
||||||
|
return IntegrationFlows |
||||||
|
.from(ChannelName.INBOUND_STATE_LIST) |
||||||
|
.split() |
||||||
|
.<Object, String> route(dataType -> { |
||||||
|
Class<?> clazz = dataType.getClass(); |
||||||
|
if (DevicePayloadReceiver.class.isAssignableFrom(clazz)) { |
||||||
|
return ChannelName.INBOUND_STATE_PAYLOAD; |
||||||
|
} |
||||||
|
return null; |
||||||
|
}, mapping -> { |
||||||
|
mapping.channelMapping(ChannelName.INBOUND_STATE_PAYLOAD, |
||||||
|
ChannelName.INBOUND_STATE_PAYLOAD); |
||||||
|
}) |
||||||
|
.get(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,70 @@ |
|||||||
|
package com.dji.sample.manage.handler; |
||||||
|
|
||||||
|
import com.dji.sample.component.mqtt.model.ChannelName; |
||||||
|
import com.dji.sample.component.mqtt.model.CommonTopicReceiver; |
||||||
|
import com.dji.sample.manage.model.enums.DeviceDomainEnum; |
||||||
|
import com.dji.sample.manage.model.receiver.StatusGatewayReceiver; |
||||||
|
import com.fasterxml.jackson.core.type.TypeReference; |
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper; |
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
import org.springframework.integration.annotation.MessageEndpoint; |
||||||
|
import org.springframework.integration.annotation.Router; |
||||||
|
import org.springframework.integration.annotation.ServiceActivator; |
||||||
|
import org.springframework.integration.mqtt.support.MqttHeaders; |
||||||
|
import org.springframework.messaging.Message; |
||||||
|
import org.springframework.util.CollectionUtils; |
||||||
|
|
||||||
|
import static com.dji.sample.component.mqtt.model.TopicConst.*; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/12 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@MessageEndpoint |
||||||
|
public class StatusRouter { |
||||||
|
|
||||||
|
/** |
||||||
|
* Converts the status data sent by the gateway device into an object. |
||||||
|
* @param message |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@ServiceActivator(inputChannel = ChannelName.INBOUND_STATUS, outputChannel = ChannelName.INBOUND_STATUS_ROUTER) |
||||||
|
public CommonTopicReceiver<StatusGatewayReceiver> resolveStatus(Message<?> message) { |
||||||
|
|
||||||
|
CommonTopicReceiver<StatusGatewayReceiver> statusReceiver = new CommonTopicReceiver<>(); |
||||||
|
ObjectMapper mapper = new ObjectMapper(); |
||||||
|
mapper.setPropertyNamingStrategy(PropertyNamingStrategy.SNAKE_CASE); |
||||||
|
try { |
||||||
|
statusReceiver = mapper.readValue( |
||||||
|
(byte[])message.getPayload(), |
||||||
|
new TypeReference<CommonTopicReceiver<StatusGatewayReceiver>>() {}); |
||||||
|
|
||||||
|
String topic = message.getHeaders().get(MqttHeaders.RECEIVED_TOPIC).toString(); |
||||||
|
|
||||||
|
// set gateway's domain
|
||||||
|
statusReceiver.getData().setDomain(DeviceDomainEnum.GATEWAY.getVal()); |
||||||
|
// set gateway's sn
|
||||||
|
statusReceiver.getData().setSn( |
||||||
|
topic.substring((BASIC_PRE + PRODUCT).length(), |
||||||
|
topic.indexOf(STATUS_SUF))); |
||||||
|
} catch (Exception e) { |
||||||
|
e.printStackTrace(); |
||||||
|
} |
||||||
|
return statusReceiver; |
||||||
|
} |
||||||
|
|
||||||
|
/** |
||||||
|
* Handles the routing of status topic messages. Depending on the data, it is assigned to different channels for handling. |
||||||
|
* @param receiver |
||||||
|
* @return |
||||||
|
*/ |
||||||
|
@Router(inputChannel = ChannelName.INBOUND_STATUS_ROUTER) |
||||||
|
public String resolveStatusRouter(CommonTopicReceiver<StatusGatewayReceiver> receiver) { |
||||||
|
// Determine whether the drone is online or offline according to whether the data of the sub-device is empty.
|
||||||
|
return CollectionUtils.isEmpty(receiver.getData().getSubDevices()) ? |
||||||
|
ChannelName.INBOUND_STATUS_OFFLINE : ChannelName.INBOUND_STATUS_ONLINE; |
||||||
|
} |
||||||
|
|
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
package com.dji.sample.manage.model; |
||||||
|
|
||||||
|
import java.util.concurrent.locks.LockSupport; |
||||||
|
|
||||||
|
/** |
||||||
|
* The demo is only for functional closure, which is not recommended. |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/22 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
public class Chan<T> { |
||||||
|
|
||||||
|
private static final long THREAD_WAIT_TIME = 1000_000 * 500; |
||||||
|
|
||||||
|
private volatile T data; |
||||||
|
|
||||||
|
private volatile Thread t; |
||||||
|
|
||||||
|
private Chan () { |
||||||
|
|
||||||
|
} |
||||||
|
|
||||||
|
public static Chan getInstance() { |
||||||
|
return ChanSingleton.INSTANCE; |
||||||
|
} |
||||||
|
|
||||||
|
public T get(Object blocker) { |
||||||
|
this.t = Thread.currentThread(); |
||||||
|
LockSupport.parkNanos(blocker, THREAD_WAIT_TIME); |
||||||
|
this.t = null; |
||||||
|
return data; |
||||||
|
} |
||||||
|
|
||||||
|
public void put(T data) { |
||||||
|
this.data = data; |
||||||
|
if (t == null) { |
||||||
|
return; |
||||||
|
} |
||||||
|
LockSupport.unpark(t); |
||||||
|
} |
||||||
|
|
||||||
|
private static class ChanSingleton { |
||||||
|
private static final Chan<?> INSTANCE = new Chan<>(); |
||||||
|
} |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.dji.sample.manage.model; |
||||||
|
|
||||||
|
import java.time.LocalDateTime; |
||||||
|
import java.util.concurrent.ConcurrentHashMap; |
||||||
|
|
||||||
|
/** |
||||||
|
* The demo is only for functional closure, which is not recommended, |
||||||
|
* and it is recommended to use caching for handling. |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/25 |
||||||
|
*/ |
||||||
|
public class DeviceStatusManager { |
||||||
|
|
||||||
|
public static final ConcurrentHashMap<String, LocalDateTime> STATUS_MANAGER = |
||||||
|
new ConcurrentHashMap<>(16); |
||||||
|
|
||||||
|
public static final Integer DEFAULT_ALIVE_SECOND = 30; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,34 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/22 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class CapacityCameraDTO { |
||||||
|
|
||||||
|
private Integer id; |
||||||
|
|
||||||
|
private String deviceSn; |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
private String description; |
||||||
|
|
||||||
|
private String index; |
||||||
|
|
||||||
|
private String type; |
||||||
|
|
||||||
|
private List<CapacityVideoDTO> videosList; |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/22 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
public class CapacityDeviceDTO { |
||||||
|
|
||||||
|
private String sn; |
||||||
|
|
||||||
|
private String name; |
||||||
|
|
||||||
|
private List<CapacityCameraDTO> camerasList; |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/22 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class CapacityVideoDTO { |
||||||
|
|
||||||
|
private Integer id; |
||||||
|
|
||||||
|
private String index; |
||||||
|
|
||||||
|
private String type; |
||||||
|
} |
@ -0,0 +1,47 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonNaming; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
||||||
|
public class DeviceDTO { |
||||||
|
|
||||||
|
private String deviceSn; |
||||||
|
|
||||||
|
private String deviceName; |
||||||
|
|
||||||
|
private String workspaceId; |
||||||
|
|
||||||
|
private String deviceIndex; |
||||||
|
|
||||||
|
private String deviceDesc; |
||||||
|
|
||||||
|
private String childDeviceSn; |
||||||
|
|
||||||
|
private String domain; |
||||||
|
|
||||||
|
private Integer type; |
||||||
|
|
||||||
|
private Integer subType; |
||||||
|
|
||||||
|
private List<DeviceDTO> gatewaysList; |
||||||
|
|
||||||
|
private List<DevicePayloadDTO> payloadsList; |
||||||
|
|
||||||
|
private IconUrlDTO iconUrl; |
||||||
|
} |
@ -0,0 +1,28 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/23 |
||||||
|
*/ |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
@Data |
||||||
|
public class DeviceDictionaryDTO { |
||||||
|
|
||||||
|
private Integer domain; |
||||||
|
|
||||||
|
private Integer deviceType; |
||||||
|
|
||||||
|
private Integer subType; |
||||||
|
|
||||||
|
private String deviceName; |
||||||
|
|
||||||
|
private String deviceDesc; |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class DeviceModelDTO { |
||||||
|
|
||||||
|
private String key; |
||||||
|
|
||||||
|
private String domain; |
||||||
|
|
||||||
|
private String type; |
||||||
|
|
||||||
|
private String subType; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,29 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonNaming; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
||||||
|
public class DevicePayloadDTO { |
||||||
|
|
||||||
|
private String payloadSn; |
||||||
|
|
||||||
|
private String payloadName; |
||||||
|
|
||||||
|
private Integer payloadIndex; |
||||||
|
|
||||||
|
private String payloadDesc; |
||||||
|
} |
@ -0,0 +1,25 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.3 |
||||||
|
* @date 2022/1/5 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class IconUrlDTO { |
||||||
|
|
||||||
|
@JsonProperty("normal_icon_url") |
||||||
|
private String normalUrl; |
||||||
|
|
||||||
|
@JsonProperty("selected_icon_url") |
||||||
|
private String selectUrl; |
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/23 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) |
||||||
|
public class LiveDTO { |
||||||
|
|
||||||
|
private String url; |
||||||
|
|
||||||
|
private String username; |
||||||
|
|
||||||
|
private String password; |
||||||
|
} |
@ -0,0 +1,26 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* Receive live parameters. |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/22 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class LiveTypeDTO { |
||||||
|
|
||||||
|
@JsonProperty("url_type") |
||||||
|
private Integer urlType; |
||||||
|
|
||||||
|
private String url; |
||||||
|
|
||||||
|
@JsonProperty("video_id") |
||||||
|
private String videoId; |
||||||
|
|
||||||
|
@JsonProperty("video_quality") |
||||||
|
private Integer videoQuality; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,20 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/23 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class LiveUrlAgoraDTO { |
||||||
|
|
||||||
|
private String channel; |
||||||
|
|
||||||
|
private String sn; |
||||||
|
|
||||||
|
private String token; |
||||||
|
|
||||||
|
private Integer uid; |
||||||
|
} |
@ -0,0 +1,27 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/23 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class LiveUrlGB28181DTO { |
||||||
|
|
||||||
|
private String serverIP; |
||||||
|
|
||||||
|
private Integer serverPort; |
||||||
|
|
||||||
|
private String serverID; |
||||||
|
|
||||||
|
private String agentID; |
||||||
|
|
||||||
|
private String agentPassword; |
||||||
|
|
||||||
|
private Integer localPort; |
||||||
|
|
||||||
|
private String channel; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,18 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/23 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
public class LiveUrlRTSPDTO { |
||||||
|
|
||||||
|
private String userName; |
||||||
|
|
||||||
|
private String password; |
||||||
|
|
||||||
|
private Integer port; |
||||||
|
} |
@ -0,0 +1,22 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class TelemetryDTO { |
||||||
|
|
||||||
|
private TelemetryDeviceDTO host; |
||||||
|
|
||||||
|
private String sn; |
||||||
|
} |
@ -0,0 +1,32 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
public class TelemetryDeviceDTO { |
||||||
|
|
||||||
|
private Double latitude; |
||||||
|
|
||||||
|
private Double longitude; |
||||||
|
|
||||||
|
private Double altitude; |
||||||
|
|
||||||
|
private Float attitudeHead; |
||||||
|
|
||||||
|
private Double elevation; |
||||||
|
|
||||||
|
private Float horizontalSpeed; |
||||||
|
|
||||||
|
private Float verticalSpeed; |
||||||
|
} |
@ -0,0 +1,24 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.util.List; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
public class TopologyDTO { |
||||||
|
|
||||||
|
private List<TopologyDeviceDTO> hosts; |
||||||
|
|
||||||
|
private List<TopologyDeviceDTO> parents; |
||||||
|
} |
@ -0,0 +1,35 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonInclude; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean |
||||||
|
* @version 0.2 |
||||||
|
* @date 2021/12/8 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@JsonInclude(JsonInclude.Include.NON_NULL) |
||||||
|
public class TopologyDeviceDTO { |
||||||
|
|
||||||
|
private String sn; |
||||||
|
|
||||||
|
private DeviceModelDTO deviceModel; |
||||||
|
|
||||||
|
@Builder.Default |
||||||
|
private Boolean onlineStatus = true; |
||||||
|
|
||||||
|
private String deviceCallsign; |
||||||
|
|
||||||
|
private String userId; |
||||||
|
|
||||||
|
private String userCallsign; |
||||||
|
|
||||||
|
private IconUrlDTO iconUrls; |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.annotation.JsonProperty; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
public class UserDTO { |
||||||
|
|
||||||
|
@JsonProperty("user_id") |
||||||
|
private String userId; |
||||||
|
|
||||||
|
private String username; |
||||||
|
|
||||||
|
@JsonProperty("workspace_id") |
||||||
|
private String workspaceId; |
||||||
|
|
||||||
|
@JsonProperty("user_type") |
||||||
|
private Integer userType; |
||||||
|
|
||||||
|
@JsonProperty("mqtt_username") |
||||||
|
private String mqttUsername; |
||||||
|
|
||||||
|
@JsonProperty("mqtt_password") |
||||||
|
private String mqttPassword; |
||||||
|
|
||||||
|
@JsonProperty("access_token") |
||||||
|
private String accessToken; |
||||||
|
|
||||||
|
@JsonProperty("mqtt_addr") |
||||||
|
private String mqttAddr; |
||||||
|
} |
@ -0,0 +1,14 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import lombok.Data; |
||||||
|
import lombok.NonNull; |
||||||
|
|
||||||
|
@Data |
||||||
|
public class UserLoginDTO { |
||||||
|
|
||||||
|
@NonNull |
||||||
|
private String username; |
||||||
|
|
||||||
|
@NonNull |
||||||
|
private String password; |
||||||
|
} |
@ -0,0 +1,33 @@ |
|||||||
|
package com.dji.sample.manage.model.dto; |
||||||
|
|
||||||
|
import com.fasterxml.jackson.databind.PropertyNamingStrategy; |
||||||
|
import com.fasterxml.jackson.databind.annotation.JsonNaming; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/22 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
@JsonNaming(PropertyNamingStrategy.SnakeCaseStrategy.class) |
||||||
|
public class WorkspaceDTO { |
||||||
|
|
||||||
|
public static final String DEFAULT_WORKSPACE_ID = "e3dea0f5-37f2-4d79-ae58-490af3228069"; |
||||||
|
|
||||||
|
private Integer id; |
||||||
|
|
||||||
|
private String workspaceId; |
||||||
|
|
||||||
|
private String workspaceName; |
||||||
|
|
||||||
|
private String workspaceDesc; |
||||||
|
|
||||||
|
private String platformName; |
||||||
|
} |
@ -0,0 +1,37 @@ |
|||||||
|
package com.dji.sample.manage.model.entity; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableId; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@TableName(value = "manage_camera_video") |
||||||
|
@Data |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@Builder |
||||||
|
public class CameraVideoEntity implements Serializable { |
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO) |
||||||
|
private Integer id; |
||||||
|
|
||||||
|
@TableField(value = "camera_id") |
||||||
|
private Integer cameraId; |
||||||
|
|
||||||
|
@TableField(value = "video_index") |
||||||
|
private String videoIndex; |
||||||
|
|
||||||
|
@TableField(value = "video_type") |
||||||
|
private String videoType; |
||||||
|
} |
@ -0,0 +1,46 @@ |
|||||||
|
package com.dji.sample.manage.model.entity; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableId; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@TableName(value = "manage_capacity_camera") |
||||||
|
public class CapacityCameraEntity implements Serializable { |
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO) |
||||||
|
private Integer id; |
||||||
|
|
||||||
|
@TableField(value = "device_sn") |
||||||
|
private String deviceSn; |
||||||
|
|
||||||
|
@TableField(value = "name") |
||||||
|
private String name; |
||||||
|
|
||||||
|
@TableField(value = "description") |
||||||
|
private String description; |
||||||
|
|
||||||
|
@TableField(value = "camera_index") |
||||||
|
private String cameraIndex; |
||||||
|
|
||||||
|
@TableField(value = "coexist_video_number_max") |
||||||
|
private Integer coexistVideoNumberMax; |
||||||
|
|
||||||
|
@TableField(value = "available_video_number") |
||||||
|
private Integer availableVideoNumber; |
||||||
|
} |
@ -0,0 +1,45 @@ |
|||||||
|
package com.dji.sample.manage.model.entity; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.IdType; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableField; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableId; |
||||||
|
import com.baomidou.mybatisplus.annotation.TableName; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/15 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@TableName("manage_device_dictionary") |
||||||
|
public class DeviceDictionaryEntity implements Serializable { |
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO) |
||||||
|
private Integer id; |
||||||
|
|
||||||
|
@TableField(value = "domain") |
||||||
|
private Integer domain; |
||||||
|
|
||||||
|
@TableField(value = "device_type") |
||||||
|
private Integer deviceType; |
||||||
|
|
||||||
|
@TableField(value = "sub_type") |
||||||
|
private Integer subType; |
||||||
|
|
||||||
|
@TableField(value = "device_name") |
||||||
|
private String deviceName; |
||||||
|
|
||||||
|
@TableField(value = "device_desc") |
||||||
|
private String deviceDesc; |
||||||
|
|
||||||
|
} |
@ -0,0 +1,69 @@ |
|||||||
|
package com.dji.sample.manage.model.entity; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* The entity class of the device |
||||||
|
* |
||||||
|
* @author sean.zhou |
||||||
|
* @version 0.1 |
||||||
|
* @date 2021/11/10 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@NoArgsConstructor |
||||||
|
@AllArgsConstructor |
||||||
|
@TableName(value = "manage_device") |
||||||
|
public class DeviceEntity implements Serializable { |
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO) |
||||||
|
private Integer id; |
||||||
|
|
||||||
|
@TableField(value = "device_sn") |
||||||
|
private String deviceSn; |
||||||
|
|
||||||
|
@TableField(value = "device_name") |
||||||
|
private String deviceName; |
||||||
|
|
||||||
|
@TableField(value = "workspace_id") |
||||||
|
private String workspaceId; |
||||||
|
|
||||||
|
@TableField(value = "device_type") |
||||||
|
private Integer deviceType; |
||||||
|
|
||||||
|
@TableField(value = "sub_type") |
||||||
|
private Integer subType; |
||||||
|
|
||||||
|
@TableField(value = "domain") |
||||||
|
private Integer domain; |
||||||
|
|
||||||
|
@TableField(value = "version") |
||||||
|
private Integer version; |
||||||
|
|
||||||
|
@TableField(value = "device_index") |
||||||
|
private String deviceIndex; |
||||||
|
|
||||||
|
@TableField(value = "child_sn") |
||||||
|
private String childSn; |
||||||
|
|
||||||
|
@TableField(value = "create_time", fill = FieldFill.INSERT) |
||||||
|
private Long createTime; |
||||||
|
|
||||||
|
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) |
||||||
|
private Long updateTime; |
||||||
|
|
||||||
|
@TableField(value = "device_desc") |
||||||
|
private String deviceDesc; |
||||||
|
|
||||||
|
@TableField(value = "url_normal") |
||||||
|
private String urlNormal; |
||||||
|
|
||||||
|
@TableField(value = "url_select") |
||||||
|
private String urlSelect; |
||||||
|
} |
@ -0,0 +1,56 @@ |
|||||||
|
package com.dji.sample.manage.model.entity; |
||||||
|
|
||||||
|
import com.baomidou.mybatisplus.annotation.*; |
||||||
|
import lombok.AllArgsConstructor; |
||||||
|
import lombok.Builder; |
||||||
|
import lombok.Data; |
||||||
|
import lombok.NoArgsConstructor; |
||||||
|
|
||||||
|
import java.io.Serializable; |
||||||
|
|
||||||
|
/** |
||||||
|
* @author sean.zhou |
||||||
|
* @date 2021/11/19 |
||||||
|
* @version 0.1 |
||||||
|
*/ |
||||||
|
@Data |
||||||
|
@Builder |
||||||
|
@AllArgsConstructor |
||||||
|
@NoArgsConstructor |
||||||
|
@TableName(value = "manage_device_payload") |
||||||
|
public class DevicePayloadEntity implements Serializable { |
||||||
|
|
||||||
|
@TableId(type = IdType.AUTO) |
||||||
|
private Integer id; |
||||||
|
|
||||||
|
@TableField(value = "payload_sn") |
||||||
|
private String payloadSn; |
||||||
|
|
||||||
|
@TableField(value = "payload_name") |
||||||
|
private String payloadName; |
||||||
|
|
||||||
|
@TableField(value = "payload_type") |
||||||
|
private Integer payloadType; |
||||||
|
|
||||||
|
@TableField(value = "sub_type") |
||||||
|
private Integer subType; |
||||||
|
|
||||||
|
@TableField(value = "version") |
||||||
|
private Integer version; |
||||||
|
|
||||||
|
@TableField(value = "payload_index") |
||||||
|
private Integer payloadIndex; |
||||||
|
|
||||||
|
@TableField(value = "device_sn") |
||||||
|
private String deviceSn; |
||||||
|
|
||||||
|
@TableField(value = "create_time", fill = FieldFill.INSERT) |
||||||
|
private Long createTime; |
||||||
|
|
||||||
|
@TableField(value = "update_time", fill = FieldFill.INSERT_UPDATE) |
||||||
|
private Long updateTime; |
||||||
|
|
||||||
|
@TableField(value = "payload_desc") |
||||||
|
private String payloadDesc; |
||||||
|
|
||||||
|
} |
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue