You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by qi...@apache.org on 2022/08/03 12:30:42 UTC
[iotdb-web-workbench] 08/29: Add GH actions Support till version 13 Fixed all licensing for RAT Plugin Minor Update in Readme and License
This is an automated email from the ASF dual-hosted git repository.
qiaojialin pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb-web-workbench.git
commit 63a507fcbb5456941ddce2c6807a54729fac667c
Author: Julian Feinauer <j....@pragmaticminds.de>
AuthorDate: Sat Sep 11 10:54:52 2021 +0200
Add GH actions
Support till version 13
Fixed all licensing for RAT Plugin
Minor Update in Readme and License
---
.github/workflows/default.yml | 55 +
NOTICE | 5 +-
README.md | 1 +
README_zh.md | 19 +-
backend/.drone.yml | 68 +
backend/Dockerfile | 24 +
README.md => backend/README.md | 37 +-
backend/build.gradle | 66 +
backend/build.sh | 20 +
README.md => backend/doc/config.md | 28 +-
backend/doc/deploy.md | 65 +
backend/doc/intro.md | 55 +
README.md => backend/doc/log.md | 10 +-
backend/doc/maven.md | 46 +
backend/doc/note.md | 74 +
README.md => backend/doc/promise.md | 9 +-
README.md => backend/doc/release.md | 8 +-
README.md => backend/doc/rest.md | 11 +-
README.md => backend/doc/rule.md | 17 +-
backend/doc/swagger.md | 51 +
backend/doc/validate.md | 68 +
backend/gradlew | 188 ++
backend/pom.xml | 239 +++
backend/settings.gradle | 20 +
.../org/apache/iotdb/admin/AdminApplication.java | 39 +
.../iotdb/admin/aop/BaseExceptionAdvice.java | 44 +
.../apache/iotdb/admin/aop/ParamValidAspect.java | 78 +
.../admin/common/exception/BaseException.java | 43 +
.../iotdb/admin/common/exception/ErrorCode.java | 286 +++
.../admin/common/utils/AuthenticationUtils.java | 49 +
.../apache/iotdb/admin/config/FilterConfig.java | 46 +
.../iotdb/admin/config/MybatisPlusConfig.java | 51 +
.../apache/iotdb/admin/config/SecurityConfig.java | 49 +
.../apache/iotdb/admin/config/SwaggerConfig.java | 79 +
.../iotdb/admin/config/ValidatorConfiguration.java | 41 +
.../admin/controller/ConnectionController.java | 125 ++
.../iotdb/admin/controller/HealthController.java | 51 +
.../iotdb/admin/controller/IotDBController.java | 867 +++++++++
.../iotdb/admin/controller/QueryController.java | 133 ++
.../iotdb/admin/controller/UserController.java | 121 ++
.../java/org/apache/iotdb/admin/demo/JDBC.java | 159 ++
.../org/apache/iotdb/admin/demo/NativeAPI.java | 123 ++
.../org/apache/iotdb/admin/filter/TokenFilter.java | 57 +
.../iotdb/admin/mapper/ConnectionMapper.java | 29 +
.../apache/iotdb/admin/mapper/DeviceMapper.java | 28 +
.../org/apache/iotdb/admin/mapper/GroupMapper.java | 28 +
.../iotdb/admin/mapper/MeasurementMapper.java | 29 +
.../org/apache/iotdb/admin/mapper/QueryMapper.java | 29 +
.../org/apache/iotdb/admin/mapper/UserMapper.java | 29 +
.../iotdb/admin/model/dto/ConnectionDTO.java | 53 +
.../org/apache/iotdb/admin/model/dto/CountDTO.java | 33 +
.../apache/iotdb/admin/model/dto/DeviceDTO.java | 36 +
.../iotdb/admin/model/dto/DeviceInfoDTO.java | 41 +
.../org/apache/iotdb/admin/model/dto/GroupDTO.java | 41 +
.../apache/iotdb/admin/model/dto/IotDBRole.java | 39 +
.../apache/iotdb/admin/model/dto/IotDBUser.java | 45 +
.../apache/iotdb/admin/model/dto/IotDBUserDTO.java | 31 +
.../iotdb/admin/model/dto/MeasurementDTO.java | 37 +
.../iotdb/admin/model/dto/PrivilegeInfoDTO.java | 40 +
.../org/apache/iotdb/admin/model/dto/QueryDTO.java | 35 +
.../apache/iotdb/admin/model/dto/SearchDTO.java | 36 +
.../apache/iotdb/admin/model/dto/Timeseries.java | 42 +
.../iotdb/admin/model/entity/Connection.java | 65 +
.../apache/iotdb/admin/model/entity/Device.java | 54 +
.../iotdb/admin/model/entity/Measurement.java | 43 +
.../org/apache/iotdb/admin/model/entity/Query.java | 42 +
.../iotdb/admin/model/entity/StorageGroup.java | 54 +
.../org/apache/iotdb/admin/model/entity/User.java | 49 +
.../org/apache/iotdb/admin/model/vo/BaseVO.java | 58 +
.../org/apache/iotdb/admin/model/vo/ConnVO.java | 38 +
.../apache/iotdb/admin/model/vo/ConnectionVO.java | 40 +
.../apache/iotdb/admin/model/vo/DeviceInfo.java | 34 +
.../apache/iotdb/admin/model/vo/DeviceInfoVO.java | 33 +
.../org/apache/iotdb/admin/model/vo/DeviceVO.java | 33 +
.../apache/iotdb/admin/model/vo/GroupInfoVO.java | 37 +
.../org/apache/iotdb/admin/model/vo/GroupVO.java | 36 +
.../apache/iotdb/admin/model/vo/IotDBUserVO.java | 34 +
.../apache/iotdb/admin/model/vo/MeasurementVO.java | 34 +
.../iotdb/admin/model/vo/MeasuremtnInfoVO.java | 33 +
.../org/apache/iotdb/admin/model/vo/PathVO.java | 32 +
.../apache/iotdb/admin/model/vo/PrivilegeInfo.java | 39 +
.../org/apache/iotdb/admin/model/vo/QueryVO.java | 31 +
.../org/apache/iotdb/admin/model/vo/RecordVO.java | 33 +
.../iotdb/admin/model/vo/RoleWithPrivilegesVO.java | 34 +
.../apache/iotdb/admin/model/vo/SqlResultVO.java | 37 +
.../iotdb/admin/model/vo/StorageGroupVO.java | 31 +
.../iotdb/admin/service/ConnectionService.java | 41 +
.../apache/iotdb/admin/service/DeviceService.java | 43 +
.../apache/iotdb/admin/service/GroupService.java | 44 +
.../apache/iotdb/admin/service/IotDBService.java | 96 +
.../iotdb/admin/service/MeasurementService.java | 36 +
.../apache/iotdb/admin/service/QueryService.java | 39 +
.../apache/iotdb/admin/service/UserService.java | 32 +
.../admin/service/impl/ConnectionServiceImpl.java | 128 ++
.../admin/service/impl/DeviceServiceImpl.java | 144 ++
.../iotdb/admin/service/impl/GroupServiceImpl.java | 157 ++
.../iotdb/admin/service/impl/IotDBServiceImpl.java | 1857 ++++++++++++++++++++
.../admin/service/impl/MeasurementServiceImpl.java | 142 ++
.../iotdb/admin/service/impl/QueryServiceImpl.java | 109 ++
.../iotdb/admin/service/impl/UserServiceImpl.java | 85 +
backend/src/main/resources/META-INF/app.properties | 20 +
.../src/main/resources/application-dev.properties | 30 +
.../src/main/resources/application-prod.properties | 30 +
.../src/main/resources/application-test.properties | 26 +
backend/src/main/resources/application.properties | 21 +
backend/src/main/resources/log4j2-prod.xml | 120 ++
backend/src/main/resources/log4j2.xml | 120 ++
.../test/java/org/apache/iotdb/admin/DemoJDBC.java | 41 +
.../admin/controller/ConnectionControllerTest.java | 118 ++
.../admin/controller/IotDBControllerTest.java | 380 ++++
.../admin/controller/QueryControllerTest.java | 134 ++
.../iotdb/admin/controller/TestSystemInfo.java | 47 +
112 files changed, 9275 insertions(+), 25 deletions(-)
diff --git a/.github/workflows/default.yml b/.github/workflows/default.yml
new file mode 100644
index 0000000..d0b7938
--- /dev/null
+++ b/.github/workflows/default.yml
@@ -0,0 +1,55 @@
+# This workflow will build a Java project with Maven
+# For more information see: https://help.github.com/actions/language-and-framework-guides/building-and-testing-java-with-maven
+
+name: Main Mac and Linux
+
+on:
+ push:
+ branches:
+ - master
+ - 'rel/*'
+ - Vector
+ paths-ignore:
+ - 'docs/**'
+ pull_request:
+ branches:
+ - master
+ - 'rel/*'
+ - cluster_new
+ - Vector
+ paths-ignore:
+ - 'docs/**'
+ # allow manually run the action:
+ workflow_dispatch:
+
+env:
+ MAVEN_OPTS: -Dhttp.keepAlive=false -Dmaven.wagon.http.pool=false -Dmaven.wagon.http.retryHandler.class=standard -Dmaven.wagon.http.retryHandler.count=3
+
+jobs:
+ unix:
+ strategy:
+ fail-fast: false
+ max-parallel: 20
+ matrix:
+ java: [ 8, 11, 13 ]
+ os: [ ubuntu-latest, macos-latest ]
+ runs-on: ${{ matrix.os}}
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Set up JDK ${{ matrix.java }}
+ uses: actions/setup-java@v1
+ with:
+ java-version: ${{ matrix.java }}
+ - name: Cache Maven packages
+ uses: actions/cache@v2
+ with:
+ path: ~/.m2
+ key: ${{ runner.os }}-m2-${{ hashFiles('**/pom.xml') }}
+ restore-keys: ${{ runner.os }}-m2-
+ - name: Check Apache Rat
+ run: cd backend && mvn -B apache-rat:check -P site -P code-coverage
+ - name: IT/UT Test
+ shell: bash
+ # we do not compile client-cpp for saving time, it is tested in client.yml
+ run: cd backend && mvn -B clean post-integration-test -Dtest.port.closed=true -P '!testcontainer'
diff --git a/NOTICE b/NOTICE
index e983e45..3b945c0 100644
--- a/NOTICE
+++ b/NOTICE
@@ -21,4 +21,7 @@ Apache Commons Collections
Copyright 2001-2019 The Apache Software Foundation
This product includes software developed at
-The Apache Software Foundation (http://www.apache.org/).
\ No newline at end of file
+The Apache Software Foundation (http://www.apache.org/).
+
+============================================================================
+
diff --git a/README.md b/README.md
index 06ee6a0..adf58fc 100644
--- a/README.md
+++ b/README.md
@@ -18,6 +18,7 @@
under the License.
-->
+
[English](./README.md) | [中文](./README_ZH.md)
# Overview
diff --git a/README_zh.md b/README_zh.md
index 06ee6a0..9f1cb6d 100644
--- a/README_zh.md
+++ b/README_zh.md
@@ -18,9 +18,22 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+[English](./README.md) | [中文](./README_zh.md)
+
+# IoTDB-Workbench
+
+IotDB-Workbench是IotDB的可视化管理工具,可对IotDB的数据进行增删改查、权限控制等,简化IotDB的使用及学习成本。
+在我们心中IotDB是最棒的时序数据库之一,我们将一直不遗余力地推动国产时序数据库IotDB的应用和发展,为本土开源能力的提高、开源生态的发展,贡献自己的力量,欢迎大家加入IotDB Admin的开发及维护,期待你的加入:
+
+![微信](backend/doc/image/wechat.png)
+
+## 后端服务运行
+
+[后端服务设计及运行说明](backend/README.md)
+
+## 前端服务运行
+
+[前端服务运行说明](frontend/README.md)
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
diff --git a/backend/.drone.yml b/backend/.drone.yml
new file mode 100644
index 0000000..9307f0d
--- /dev/null
+++ b/backend/.drone.yml
@@ -0,0 +1,68 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+---
+kind: pipeline
+name: deploy-testing-environment-preview.1.0
+git_image: hub.d.cisdigital.cn/drone/git
+platform:
+ os: linux
+ arch: amd64
+
+steps:
+ - name: tag
+ image: hub.segma.tech/drone/drone-tag:v1.1
+ environment:
+ TAG_FILE: .tags
+
+ - name: build
+ image: hub.segma.tech/drone/maven-plugin:3.6.1-jdk-8-alpine
+ commands:
+ - mvn clean package -D maven.test.skip=true
+
+ - name: docker
+ image: hub.segma.tech/drone/plugins/docker:19.03.8
+ environment:
+ PLUGIN_DEBUG: true
+ settings:
+ dockerfile: ./Dockerfile
+ username:
+ from_secret: docker_username
+ password:
+ from_secret: docker_password
+ repo: hub.d.cisdigital.cn/iot-dacoo/iotdb
+ registry: hub.d.cisdigital.cn
+ insecure: true
+
+ - name: deploy
+ image: hub.d.cisdigital.cn/drone/drone-paas-plugin:latest
+ settings:
+ application_id: 62
+ application_cluster: dev_paas
+ application_deployment_id: 725
+ application_deployment_replicas: 1
+ application_deployment_image: hub.d.cisdigital.cn/iot-dacoo/iotdb
+ server_url: http://drone-paas-server.kube-drone:8080
+
+trigger:
+ branch:
+ - master
+ - dev
+ event:
+ - push
\ No newline at end of file
diff --git a/backend/Dockerfile b/backend/Dockerfile
new file mode 100644
index 0000000..f6e39cc
--- /dev/null
+++ b/backend/Dockerfile
@@ -0,0 +1,24 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+FROM hub.segma.tech/library/java:8-jre-centos7-apollo
+
+COPY target/service-1.0.0.jar /app/app.jar
+
+ENTRYPOINT ["java", "-jar", "/app/app.jar"]
diff --git a/README.md b/backend/README.md
similarity index 58%
copy from README.md
copy to backend/README.md
index 06ee6a0..63d3d6e 100644
--- a/README.md
+++ b/backend/README.md
@@ -18,9 +18,40 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 后端服务设计及运行说明
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+[IoTDB-Workbench快速入门](doc/intro.md)
+## Building the Backend
+
+The backend can be built using maven by using
+
+```
+mvn clean install
+```
+
+## 开发环境搭建
+
+[Maven配置](doc/maven.md)
+
+[日志如何配置](doc/log.md)
+
+[接口文档配置](doc/swagger.md)
+
+[统一参数验证](doc/validate.md)
+
+[常用实践约定](doc/promise.md)
+
+[接口规范](doc/rest.md)
+
+[代码规范checkstyle](doc/rule.md)
+
+[代码规范和注释](doc/note.md)
+
+## 线上部署
+
+[项目部署](doc/deploy.md)
+
+## 发布日志
+[release-note](doc/release.md)
diff --git a/backend/build.gradle b/backend/build.gradle
new file mode 100644
index 0000000..8b92fc3
--- /dev/null
+++ b/backend/build.gradle
@@ -0,0 +1,66 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+apply plugin: 'java'
+apply plugin: 'maven'
+
+group = 'cn.cisdigital.demo'
+version = '1.0.0'
+
+description = """demo项目"""
+
+sourceCompatibility = 1.5
+targetCompatibility = 1.5
+tasks.withType(JavaCompile) {
+ options.encoding = 'UTF-8'
+}
+
+
+
+repositories {
+
+ maven { url "http://maven.aliyun.com/nexus/content/groups/public/" }
+ maven { url "http://10.73.1.87:8088/nexus/content/groups/public/" }
+ maven { url "http://repo.maven.apache.org/maven2" }
+}
+dependencies {
+ compile(group: 'org.springframework.boot', name: 'spring-boot-starter-web', version:'2.3.3.RELEASE') {
+exclude(module: 'spring-boot-starter-logging')
+ }
+ compile(group: 'mysql', name: 'mysql-connector-java', version:'5.1.47') {
+exclude(module: 'protobuf-java')
+ }
+ compile group: 'org.springframework.boot', name: 'spring-boot-starter-log4j2', version:'2.3.3.RELEASE'
+ compile group: 'org.projectlombok', name: 'lombok', version:'1.18.12'
+ compile group: 'com.alibaba', name: 'druid-spring-boot-starter', version:'1.1.17'
+ compile group: 'com.baomidou', name: 'mybatis-plus-boot-starter', version:'3.4.0'
+ compile group: 'com.alibaba', name: 'fastjson', version:'1.2.73'
+ compile group: 'org.apache.commons', name: 'commons-lang3', version:'3.11'
+ compile group: 'com.ctrip.framework.apollo', name: 'apollo-client', version:'1.2.0'
+ compile group: 'io.springfox', name: 'springfox-swagger2', version:'2.7.0'
+ compile group: 'io.springfox', name: 'springfox-swagger-ui', version:'2.7.0'
+ compile group: 'cn.cisdigital', name: 'exception-component', version:'1.0.0'
+ compile group: 'com.dianping.cat', name: 'cat-client', version:'3.0.0'
+ compile group: 'org.hibernate.validator', name: 'hibernate-validator', version:'6.0.9.Final'
+ compile group: 'org.aspectj', name: 'aspectjweaver', version:'1.9.6'
+ testCompile(group: 'org.springframework.boot', name: 'spring-boot-starter-test', version:'2.3.3.RELEASE') {
+exclude(module: 'junit-vintage-engine')
+ }
+ testCompile group: 'junit', name: 'junit', version:'4.13'
+}
diff --git a/backend/build.sh b/backend/build.sh
new file mode 100755
index 0000000..40fdd9a
--- /dev/null
+++ b/backend/build.sh
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+#!/usr/bin/env bash
\ No newline at end of file
diff --git a/README.md b/backend/doc/config.md
similarity index 54%
copy from README.md
copy to backend/doc/config.md
index 06ee6a0..bd1b453 100644
--- a/README.md
+++ b/backend/doc/config.md
@@ -18,9 +18,31 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 配置中心 Apollo
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+##接入步骤
+1. 添加依赖 ,在pom.xml 中添加依赖,如不需要apolo,可以去掉该依赖
+```xml
+<dependency>
+ <groupId>com.ctrip.framework.apollo</groupId>
+ <artifactId>apollo-client</artifactId>
+ <version>1.2.0</version>
+</dependency>
+```
+
+版本号请使用1.2.0,服务器版本xxx
+
+2. 在application.properties文件中增加必要配置
+
+```properties
+ #配置中心服务地址
+ apollo.meta=http://192.168.1.241:8081
+ #开启配置中心
+ apollo.bootstrap.enabled=true
+ # 采用配置的形式注入命名空间application
+ apollo.bootstrap.namespaces=application
+```
+
+3. 编写读取配置的类。参考bean包下面的TestBean类。
diff --git a/backend/doc/deploy.md b/backend/doc/deploy.md
new file mode 100644
index 0000000..c608a17
--- /dev/null
+++ b/backend/doc/deploy.md
@@ -0,0 +1,65 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# 部署流程
+
+## 后端部署
+
+1 通过backend/src/main/resources/application-xxx.properties文件配置项目,注意修改数据源的路径。
+
+![](image/配置文件.PNG)
+
+2 打包
+
+![](image/打包.png)
+
+3 打包之后,将jar包上传到指定服务器并运行。
+
+首先请确定服务器上安装了sqlite3(一般Linux系统自带sqlite3,如果没有请安装)。
+通过如下命令将jar包挂载到后台运行:
+nohup java -jar xxx.jar >/dev/null 2>&1 &
+
+至此后端部署完成。
+
+## 前端结合后端部署
+
+1 在服务器安装nginx服务器,命令如下:
+
+yum install -y nginx
+
+2 安装完成后,配置nginx的配置文件,可通过nginx -t 获取配置文件路径:
+
+![](image/nginx配置文件位置.png)
+
+3 vim xxx.conf编辑nginx配置
+
+配置信息如下:
+
+![](image/nginx配置文件.png)
+
+黄框内容为监听端口号配置;
+红框内容以“/”映射前端资源文件,请指定为你的dist文件路径;
+绿框以“/api”映射后台服务地址,与application-xxx.properties文件中配置的端口号和上下文根保持一致;
+如果你需要多个服务则需配置多个server
+
+4 保存配置后,命令行输入nginx启动nginx
+
+浏览器调用服务器ip地址,端口号为黄框里指定的端口号,请求到服务器资源则部署成功。
diff --git a/backend/doc/intro.md b/backend/doc/intro.md
new file mode 100644
index 0000000..b57f038
--- /dev/null
+++ b/backend/doc/intro.md
@@ -0,0 +1,55 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# IoTDB-Workbench快速入门
+
+该项目IoTDB-Workbench,为IoTDB的可视化监控程序。
+
+## 支持的环境
+
+目前支持的开发环境如下:
+
+- Java 1.8
+- Maven 3.3.9 或以上
+- Gradle
+- 推荐IntelliJ IDEA 2017或以上
+
+## 目录结构说明
+
+- doc : 文档目录,一些帮助文档
+- src : 源码文件
+- Dockerfile : docker镜像打包文件
+- pom.xml : Maven Pom文件
+- README.md : 帮助文件目录
+
+## 使用的公用库
+
+由于是开源软件,使用的所有库都应该是maven公有仓库能找的,满足轻量、稳定2个特性。
+
+## 快速启动
+
+项目提供maven、gradle两种构建工具,以maven为例启动项目:
+首先通过IntelliJ IDEA打开本项目,右键点击pom.xml,点击Add as Maven Project导入项目相关依赖。
+![](image/pom.PNG)
+导入完成后启动AdminApplication项目,如果未报错并出现如下界面则代表项目运行成功。
+![](image/启动成功.PNG)
+本系统默认登录用户为root,密码为123456。
+具体部署步骤请参考[部署文档](deploy.md)
\ No newline at end of file
diff --git a/README.md b/backend/doc/log.md
similarity index 61%
copy from README.md
copy to backend/doc/log.md
index 06ee6a0..536f83b 100644
--- a/README.md
+++ b/backend/doc/log.md
@@ -18,9 +18,13 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 日志配置
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+日志使用的是log4j,日志配置文件在src/main/resources/log4j2.xml中,log4j2.xml中默认路径写的是:
+<property name="log.home">/data/applogs/app-test</property>
+
+window系统请更改路径。
+
+默认我们已经配置好了日志,如果启动的时候报`ERROR Unable to create file /data/applogs/app/projectservicedemo_debug.log java.io.IOException: Could not create directory /data/applogs/app`的错误,那么可能你没有/data目录的权限,这时候你需要换一个目录。
diff --git a/backend/doc/maven.md b/backend/doc/maven.md
new file mode 100644
index 0000000..6b03b5a
--- /dev/null
+++ b/backend/doc/maven.md
@@ -0,0 +1,46 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# Maven 仓库配置
+
+本文介绍如何配置Maven仓库
+
+## Maven 安装
+
+无论你是mac电脑还是window电脑,都可以到Maven官网直接下载[Maven 3.8.2](https://dlcdn.apache.org/maven/maven-3/3.8.2/binaries/apache-maven-3.8.2-bin.tar.gz)
+
+然后找一个目录解压,路径最好不要有中文,然后在Idea中引用该Maven。在下图中找到"Maven Setting"
+
+![](image/maven配置.jpg)
+
+然后按照如下内容进行配置
+
+![](image/maven详细配置.jpg)
+
+## Maven 配置
+
+Maven也请使用jdk 1.8,在Idea的Build Tools->Maven->Runner中设置JRE为1.8。
+
+尝试执行右边的Maven Projects窗口中的Lifecycle中的compile命令,看是否编译成功,如失败可以添加`-X`参数,查看错误原因。
+
+如果出现编译错误:Error:java: 无效的目标发行版: 11
+
+请到 Build,Execution,Deployment->Compiler->Java Compiler设置 Per-module btyecode为1.8,默认可能为11。
diff --git a/backend/doc/note.md b/backend/doc/note.md
new file mode 100644
index 0000000..16f74b0
--- /dev/null
+++ b/backend/doc/note.md
@@ -0,0 +1,74 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# Controller格式
+
+```java
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.xxx;
+
+import org.apache.iotdb.xxx;
+import org.apache.iotdb.rpc.xxx;
+import org.apache.iotdb.service.rpc.xxx;
+
+import org.apache.thrift.xxx;
+
+import java.io.InputStream;
+import java.io.Reader;
+import java.math.BigDecimal;
+import java.math.MathContext;
+import java.net.URL;
+import java.sql.Array;
+import java.sql.Blob;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.SQLXML;
+import java.sql.Statement;
+import java.sql.Time;
+import java.sql.Timestamp;
+import java.util.Calendar;
+import java.util.List;
+import java.util.Map;
+```
+
+排列整齐 不同层级之间用空格分开
+
+## 注释
+
+注释使用英文注释
diff --git a/README.md b/backend/doc/promise.md
similarity index 79%
copy from README.md
copy to backend/doc/promise.md
index 06ee6a0..1f9c2ad 100644
--- a/README.md
+++ b/backend/doc/promise.md
@@ -18,9 +18,12 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 常用实践约定
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+本章讨论常用默认的IoTDB-Workbench约定
+
+## 理论约定
+
+1. 随着SpringBoot的流行,我们现在更多采用基于注解式的配置从而替换掉了基于XML的配置。
diff --git a/README.md b/backend/doc/release.md
similarity index 84%
copy from README.md
copy to backend/doc/release.md
index 06ee6a0..0e4c436 100644
--- a/README.md
+++ b/backend/doc/release.md
@@ -18,9 +18,11 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 发布日志
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+## 1.0.0
+
+1. xxx
+2. xxx
diff --git a/README.md b/backend/doc/rest.md
similarity index 79%
copy from README.md
copy to backend/doc/rest.md
index 06ee6a0..0b25e53 100644
--- a/README.md
+++ b/backend/doc/rest.md
@@ -18,9 +18,14 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 接口规范
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+有时候,会犯一些错误,例如直接会定义如下的一些接口:
+- /user/delete
+- /user/add
+- /user/update
+- /user/select
+
+这样的接口太数据库化,读起来虽然比较容易
diff --git a/README.md b/backend/doc/rule.md
similarity index 51%
copy from README.md
copy to backend/doc/rule.md
index 06ee6a0..31b6225 100644
--- a/README.md
+++ b/backend/doc/rule.md
@@ -18,9 +18,20 @@
under the License.
-->
-[English](./README.md) | [中文](./README_ZH.md)
-# Overview
+# 阿里巴巴java规范checkstyle
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
+我们使用阿里巴巴java规范泰山版(1.6.0)
+需使用idea(版本2018.3+)安装插件,自动检查代码规范,具体操作步骤如下:
+
+1、Mac:IntelliJ IDEA -> Preferences -> Plugins -> Installed plugins from Disk -> 选择doc目录下的code-guidelines进行安装
+ Windows:File -> Settings -> Plugins -> Installed plugins from Disk -> 选择doc目录下的code-guidelines进行安装
+
+2、重启idea
+
+##在线安装java规范checkstyle
+1、Mac:IntelliJ IDEA -> Preferences -> Plugins -> Browse repositories -> 搜索Alibaba Java Coding Guidelines -> 直接install进行在线安装
+ Windows:File -> Settings -> Plugins -> Marketplace -> 搜索Alibaba Java Coding Guidelines -> 直接install进行在线安装
+
+2、重启idea
\ No newline at end of file
diff --git a/backend/doc/swagger.md b/backend/doc/swagger.md
new file mode 100644
index 0000000..37e9b0d
--- /dev/null
+++ b/backend/doc/swagger.md
@@ -0,0 +1,51 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# swagger的使用
+
+swagger在前后端联调开发中,启动非常重要的作用,如下:
+
+1. 保持接口和文档的一致性
+2. 使注释更为丰富
+
+
+
+1、框架依赖中已包含swagger接口组件。
+```xml
+<dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger2</artifactId>
+ <version>2.7.0</version>
+</dependency>
+<dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <version>2.7.0</version>
+</dependency>
+```
+
+## 网页地址
+
+你可以通过http://localhost:8080/swagger-ui.html这个地址获得接口信息。
+
+## 生产环境、测试环境、开发环境配置
+
+在生产环境中需要把swagger去掉,请参考配置类Swagger2Config中的@Profile({"dev", "test"})注解。(当前配置表示加载在dev和test文件使用,只在开发环境和测试环境的时候加载该类)
\ No newline at end of file
diff --git a/backend/doc/validate.md b/backend/doc/validate.md
new file mode 100644
index 0000000..ceb0f5b
--- /dev/null
+++ b/backend/doc/validate.md
@@ -0,0 +1,68 @@
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+
+# 参数验证
+
+参数验证一般有很多种方法:
+
+1. 直接写在controller中,有时候,特别是新人,98%会忘记写参数验证
+2. 切面,注解形式的参数验证
+
+我们认为第2种方式会好于第一种方式,所以我们使用了成熟的hibernat验证框架对参数进行验证
+
+## hibernat参数验证配置
+
+在开发中经常需要写一些字段校验的代码,比如字段非空,字段长度限制,邮箱格式验证等等,写这些与业务逻辑关系不大的代码有几个麻烦:
+
+1. 验证代码繁琐,重复劳动
+2. 方法内代码显得冗长
+3. 每次要看哪些参数验证是否完整,需要去翻阅验证逻辑代码
+hibernate validator(官方文档)提供了一套比较完善、便捷的验证实现方式。
+
+spring-boot-starter-web包里面有hibernate-validator包,不需要引用hibernate validator依赖。
+
+## 校验框架的使用方式
+
+接入步骤:
+
+1、引入依赖
+
+```xml
+<dependency>
+ <groupId>org.hibernate.validator</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ <version>6.0.9.Final</version>
+</dependency>
+```
+
+2、在需要校验的类上的属性上加上相关注解
+
+如DemoUser中name上加@NotNull和@Length注解
+
+3、进行aop配置,创建ParamValidAspect切面配置(可选)。
+
+
+## 注意事项:
+
+>如果不接入ParamValidAspect切面配置,校验框架会自动抛出Spring的参数校验的异常;如果使用了自定义切面配置,
+可以在doAround方法中对相关的参数校验做特殊的处理。本项目中对参数校验进行了统一的特殊处理(切面配置),返回与
+异常主见中的异常保持一致的错误状态码。建议以该项目的方式进行切面配置,从而遵循异常状态码规范。
+
diff --git a/backend/gradlew b/backend/gradlew
new file mode 100755
index 0000000..f4f9798
--- /dev/null
+++ b/backend/gradlew
@@ -0,0 +1,188 @@
+#!/usr/bin/env sh
+
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+##############################################################################
+##
+## Gradle start up script for UN*X
+##
+##############################################################################
+
+# Attempt to set APP_HOME
+# Resolve links: $0 may be a link
+PRG="$0"
+# Need this for relative symlinks.
+while [ -h "$PRG" ] ; do
+ ls=`ls -ld "$PRG"`
+ link=`expr "$ls" : '.*-> \(.*\)$'`
+ if expr "$link" : '/.*' > /dev/null; then
+ PRG="$link"
+ else
+ PRG=`dirname "$PRG"`"/$link"
+ fi
+done
+SAVED="`pwd`"
+cd "`dirname \"$PRG\"`/" >/dev/null
+APP_HOME="`pwd -P`"
+cd "$SAVED" >/dev/null
+
+APP_NAME="Gradle"
+APP_BASE_NAME=`basename "$0"`
+
+# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
+DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
+
+# Use the maximum available, or set MAX_FD != -1 to use that value.
+MAX_FD="maximum"
+
+warn () {
+ echo "$*"
+}
+
+die () {
+ echo
+ echo "$*"
+ echo
+ exit 1
+}
+
+# OS specific support (must be 'true' or 'false').
+cygwin=false
+msys=false
+darwin=false
+nonstop=false
+case "`uname`" in
+ CYGWIN* )
+ cygwin=true
+ ;;
+ Darwin* )
+ darwin=true
+ ;;
+ MINGW* )
+ msys=true
+ ;;
+ NONSTOP* )
+ nonstop=true
+ ;;
+esac
+
+CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
+
+
+# Determine the Java command to use to start the JVM.
+if [ -n "$JAVA_HOME" ] ; then
+ if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
+ # IBM's JDK on AIX uses strange locations for the executables
+ JAVACMD="$JAVA_HOME/jre/sh/java"
+ else
+ JAVACMD="$JAVA_HOME/bin/java"
+ fi
+ if [ ! -x "$JAVACMD" ] ; then
+ die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+ fi
+else
+ JAVACMD="java"
+ which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
+
+Please set the JAVA_HOME variable in your environment to match the
+location of your Java installation."
+fi
+
+# Increase the maximum file descriptors if we can.
+if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
+ MAX_FD_LIMIT=`ulimit -H -n`
+ if [ $? -eq 0 ] ; then
+ if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
+ MAX_FD="$MAX_FD_LIMIT"
+ fi
+ ulimit -n $MAX_FD
+ if [ $? -ne 0 ] ; then
+ warn "Could not set maximum file descriptor limit: $MAX_FD"
+ fi
+ else
+ warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
+ fi
+fi
+
+# For Darwin, add options to specify how the application appears in the dock
+if $darwin; then
+ GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
+fi
+
+# For Cygwin or MSYS, switch paths to Windows format before running java
+if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
+ APP_HOME=`cygpath --path --mixed "$APP_HOME"`
+ CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
+
+ JAVACMD=`cygpath --unix "$JAVACMD"`
+
+ # We build the pattern for arguments to be converted via cygpath
+ ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
+ SEP=""
+ for dir in $ROOTDIRSRAW ; do
+ ROOTDIRS="$ROOTDIRS$SEP$dir"
+ SEP="|"
+ done
+ OURCYGPATTERN="(^($ROOTDIRS))"
+ # Add a user-defined pattern to the cygpath arguments
+ if [ "$GRADLE_CYGPATTERN" != "" ] ; then
+ OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
+ fi
+ # Now convert the arguments - kludge to limit ourselves to /bin/sh
+ i=0
+ for arg in "$@" ; do
+ CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
+ CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
+
+ if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
+ eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
+ else
+ eval `echo args$i`="\"$arg\""
+ fi
+ i=`expr $i + 1`
+ done
+ case $i in
+ 0) set -- ;;
+ 1) set -- "$args0" ;;
+ 2) set -- "$args0" "$args1" ;;
+ 3) set -- "$args0" "$args1" "$args2" ;;
+ 4) set -- "$args0" "$args1" "$args2" "$args3" ;;
+ 5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
+ 6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
+ 7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
+ 8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
+ 9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
+ esac
+fi
+
+# Escape application args
+save () {
+ for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
+ echo " "
+}
+APP_ARGS=`save "$@"`
+
+# Collect all arguments for the java command, following the shell quoting and substitution rules
+eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
+
+exec "$JAVACMD" "$@"
diff --git a/backend/pom.xml b/backend/pom.xml
new file mode 100644
index 0000000..6413aba
--- /dev/null
+++ b/backend/pom.xml
@@ -0,0 +1,239 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<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.3.3.RELEASE</version>
+ <relativePath/> <!-- lookup parent from repository -->
+ </parent>
+ <groupId>org.apache.iotdb.admin</groupId>
+ <artifactId>workbench</artifactId>
+ <version>1.0.0</version>
+ <packaging>jar</packaging>
+ <name>IoTDB Workbench</name>
+ <description>Apache IoTDB Workbench开源项目</description>
+
+ <properties>
+ <!-- 对应java 1.8,如果编译错误,可能需要调整 -->
+ <java.version>1.8</java.version>
+ <skipTests>true</skipTests>
+ </properties>
+
+
+ <dependencies>
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-web</artifactId>
+ <exclusions>
+ <exclusion>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-logging</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-log4j2</artifactId>
+ </dependency>
+
+
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-security</artifactId>
+ </dependency>
+
+ <!--sqlite驱动-->
+ <dependency>
+ <groupId>org.xerial</groupId>
+ <artifactId>sqlite-jdbc</artifactId>
+ <version>3.34.0</version>
+ </dependency>
+
+ <!--jwt-->
+ <dependency>
+ <groupId>com.auth0</groupId>
+ <artifactId>java-jwt</artifactId>
+ <version>3.4.0</version>
+ </dependency>
+
+ <!-- get set方法自动生成 -->
+ <dependency>
+ <groupId>org.projectlombok</groupId>
+ <artifactId>lombok</artifactId>
+ <optional>true</optional>
+ </dependency>
+
+ <!-- mybatis-plus -->
+ <dependency>
+ <groupId>com.baomidou</groupId>
+ <artifactId>mybatis-plus-boot-starter</artifactId>
+ <version>3.4.0</version>
+ </dependency>
+ <!-- 数据库结束 -->
+
+ <!-- 常用工具库 -->
+ <dependency>
+ <groupId>com.alibaba</groupId>
+ <artifactId>fastjson</artifactId>
+ <version>1.2.73</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.11</version>
+ </dependency>
+ <!-- 常用工具库结束 -->
+
+
+ <!-- spring单元测试 -->
+ <dependency>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-starter-test</artifactId>
+ <scope>test</scope>
+ <exclusions>
+ <exclusion>
+ <groupId>org.junit.vintage</groupId>
+ <artifactId>junit-vintage-engine</artifactId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ <scope>test</scope>
+ </dependency>
+ <!-- spring单元测试结束 -->
+
+ <!-- swagger 组件,用于自动生成api接口文档 -->
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger2</artifactId>
+ <version>2.7.0</version>
+ </dependency>
+ <dependency>
+ <groupId>io.springfox</groupId>
+ <artifactId>springfox-swagger-ui</artifactId>
+ <version>2.7.0</version>
+ </dependency>
+ <!-- swagger 组件结束-->
+
+ <!-- 校验框架-->
+ <dependency>
+ <groupId>org.hibernate.validator</groupId>
+ <artifactId>hibernate-validator</artifactId>
+ <version>6.0.9.Final</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.aspectj</groupId>
+ <artifactId>aspectjweaver</artifactId>
+ <version>1.9.6</version>
+ </dependency>
+ <!-- 校验框架结束-->
+
+ <dependency>
+ <groupId>org.apache.iotdb</groupId>
+ <artifactId>iotdb-session</artifactId>
+ <version>0.12.0</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>logback-classic</artifactId>
+ <groupId>ch.qos.logback</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.iotdb</groupId>
+ <artifactId>iotdb-jdbc</artifactId>
+ <version>0.12.0</version>
+ <exclusions>
+ <exclusion>
+ <artifactId>logback-classic</artifactId>
+ <groupId>ch.qos.logback</groupId>
+ </exclusion>
+ </exclusions>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.springframework.boot</groupId>
+ <artifactId>spring-boot-maven-plugin</artifactId>
+ <version>2.5.3</version>
+ <executions>
+ <execution>
+ <goals>
+ <goal>repackage</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <!--https://blog.csdn.net/eguid/article/details/78291497-->
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>3.8.1</version>
+ <configuration>
+ <verbose>true</verbose>
+ <fork>true</fork>
+ <executable>${JAVA_HOME}/bin/javac</executable>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ <executions>
+ <execution>
+ <id>license-check</id>
+ <phase>verify</phase>
+ <goals>
+ <goal>check</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+
+ </plugins>
+
+ </build>
+
+ <repositories>
+ <repository>
+ <id>central</id>
+ <name>Central Repository</name>
+ <url>https://repo.maven.apache.org/maven2</url>
+ <releases>
+ <enabled>true</enabled>
+ </releases>
+ <snapshots>
+ <enabled>true</enabled>
+ </snapshots>
+ </repository>
+ </repositories>
+</project>
diff --git a/backend/settings.gradle b/backend/settings.gradle
new file mode 100644
index 0000000..c9e1192
--- /dev/null
+++ b/backend/settings.gradle
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+rootProject.name = 'service'
diff --git a/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java b/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java
new file mode 100644
index 0000000..55adaf8
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin;
+
+import org.mybatis.spring.annotation.MapperScan;
+import org.springframework.boot.SpringApplication;
+import org.springframework.boot.autoconfigure.SpringBootApplication;
+import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
+
+/**
+ * 后端代码启动类
+ * 1. MapperScan需要配置为mapper所在的包,自动扫描mapper,MapperScan是用于数据库组件自动扫描使用的。
+ */
+@SpringBootApplication
+@MapperScan("org.apache.iotdb.admin.mapper")
+@EnableWebSecurity
+public class AdminApplication {
+
+ public static void main(String[] args) {
+ SpringApplication.run(AdminApplication.class, args);
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/aop/BaseExceptionAdvice.java b/backend/src/main/java/org/apache/iotdb/admin/aop/BaseExceptionAdvice.java
new file mode 100644
index 0000000..da38b49
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/aop/BaseExceptionAdvice.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.aop;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.vo.BaseVO;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.bind.annotation.ResponseBody;
+
+/**
+ * 通用异常处理拦截器
+ */
+@Slf4j
+@ControllerAdvice
+public class BaseExceptionAdvice {
+
+ @ExceptionHandler(BaseException.class)
+ @ResponseBody
+ public BaseVO handleBaseException(BaseException e) {
+ log.error("调用接口异常", e);
+ BaseVO result = new BaseVO(e.getErrorCode(), e.getMessage(), null);
+ return result;
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/aop/ParamValidAspect.java b/backend/src/main/java/org/apache/iotdb/admin/aop/ParamValidAspect.java
new file mode 100644
index 0000000..5b9cb07
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/aop/ParamValidAspect.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.aop;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.aspectj.lang.ProceedingJoinPoint;
+import org.aspectj.lang.annotation.Around;
+import org.aspectj.lang.annotation.Aspect;
+import org.aspectj.lang.annotation.Pointcut;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.Path;
+import javax.validation.Validator;
+import java.util.Set;
+
+/**
+ * 参数验证
+ */
+@Aspect
+@Slf4j
+@Component
+public class ParamValidAspect {
+
+ @Autowired
+ private Validator validator;
+
+
+ /**
+ * 定义校验包的未知
+ */
+ @Pointcut("execution(* org.apache.iotdb.admin.controller..*.*(..))")
+ public void pointcut() {
+ }
+
+ /**
+ * 处理参数校验错误的具体方法,抛出异常组件中的异常,遵循异常规范
+ */
+ @Around("pointcut()")
+ public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
+ Object[] args = pjp.getArgs();
+ for (Object arg : args) {
+ if (arg != null) {
+ Set<ConstraintViolation<Object>> constraintViolations = validator.validate(arg);
+ if (constraintViolations.size() > 0) {
+ for (ConstraintViolation<Object> constraintViolation : constraintViolations) {
+ Path property = constraintViolation.getPropertyPath();
+ String name = property.iterator().next().getName();
+ //打印具体异常信息,对应校验框架注解中的message
+ log.error("[" + name + "]" + constraintViolation.getMessage());
+ throw new BaseException(ErrorCode.WRONG_PARAM, "参数错误:" + constraintViolation.getMessage());
+ }
+ }
+ }
+ }
+ return pjp.proceed();
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/common/exception/BaseException.java b/backend/src/main/java/org/apache/iotdb/admin/common/exception/BaseException.java
new file mode 100644
index 0000000..41eaa70
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/common/exception/BaseException.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.common.exception;
+
+/**
+ * 异常类
+ */
+public class BaseException extends Exception {
+
+ private String errorCode;
+ private String message;
+
+ public BaseException(String errorCode, String message) {
+ this.errorCode = errorCode;
+ this.message = message;
+ }
+
+ public String getErrorCode() {
+ return errorCode;
+ }
+
+ @Override
+ public String getMessage() {
+ return message;
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/common/exception/ErrorCode.java b/backend/src/main/java/org/apache/iotdb/admin/common/exception/ErrorCode.java
new file mode 100644
index 0000000..1fa47da
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/common/exception/ErrorCode.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.common.exception;
+
+/**
+ * 错误码类
+ */
+public class ErrorCode {
+
+ // 连接相关
+ public static final String ALIAS_REPEAT = "CONN-0001";
+ public static final String ALIAS_REPEAT_MSG = "别名重复";
+
+ public static final String INSERT_CONN_FAIL = "CONN-0002";
+ public static final String INSERT_CONN_FAIL_MSG = "添加或更新连接失败";
+
+ public static final String DELETE_CONN_FAIL = "CONN-0003";
+ public static final String DELETE_CONN_FAIL_MSG = "删除连接失败";
+
+ public static final String NO_CONN = "CONN-0004";
+ public static final String NO_CONN_MSG = "连接不存在";
+
+ public static final String GET_CONN_FAIL = "CONN-0005";
+ public static final String GET_CONN_FAIL_MSG = "获取连接失败";
+
+ public static final String CHECK_FAIL = "CONN-0006";
+ public static final String CHECK_FAIL_MSG = "没有权限或连接不存在";
+
+ public static final String TEST_CONN_FAIL = "CONN-0007";
+ public static final String TEST_CONN_FAIL_MSG = "连接不可达或连接超时";
+
+ public static final String TEST_CONN_WRONG = "CONN-0008";
+ public static final String TEST_CONN_WRONG_MSG = "连接失败,主机输入不合法";
+
+ public static final String TIME_OUT = "CONN-0009";
+ public static final String TIME_OUT_MSG = "连接超时";
+
+ public static final String TEST_CONN_FAIL_PWD = "CONN-0010";
+ public static final String TEST_CONN_FAIL_PWD_MSG = "连接失败,用户名或密码错误";
+
+ // 登录相关
+ public static final String LOGIN_FAIL_USER = "USER-0001";
+ public static final String LOGIN_FAIL_USER_MSG = "登录失败,用户不存在";
+
+ public static final String USER_EXIST = "USER-0002";
+ public static final String USER_EXIST_MSG = "用户已存在";
+
+ public static final String LOGIN_FAIL_PWD = "USER-0003";
+ public static final String LOGIN_FAIL_PWD_MSG = "登录失败,密码错误";
+
+ public static final String INSERT_USER_FAIL = "USER-0004";
+ public static final String INSERT_USER_FAIL_MSG = "插入失败";
+
+ public static final String WRONG_USER_PARAM = "USER-0005";
+ public static final String WRONG_USER_PARAM_MSG = "请输入合法的用户名和密码";
+
+ public static final String DELETE_USER_FAIL = "USER-0006";
+ public static final String DELETE_USER_FAIL_MSG = "删除用户失败";
+
+ public static final String NO_USER = "USER-0007";
+ public static final String NO_USER_MSG = "用户未指定";
+
+ public static final String USER_AUTH_FAIL = "USER-0008";
+ public static final String USER_AUTH_FAIL_MSG = "用户不一致,不能进行操作";
+
+ public static final String TOKEN_ERR = "USER-0009";
+ public static final String TOKEN_ERR_MSG = "请登录或token失效";
+
+ public static final String GET_TOKEN_FAIL = "USER-0010";
+ public static final String GET_TOKEN_FAIL_MSG = "获取token失败";
+
+ public static final String SET_JWT_FAIL = "USER-0011";
+ public static final String SET_JWT_FAIL_MSG = "JWT编解码失败";
+
+ // iotDB相关
+ public static final String INSERT_TS_FAIL = "IOTDB-0001";
+ public static final String INSERT_TS_FAIL_MSG = "插入时间序列失败";
+
+ public static final String DELETE_TS_FAIL = "IOTDB-0002";
+ public static final String DELETE_TS_FAIL_MSG = "删除时间序列失败";
+
+ public static final String DB_BOOL_WRONG = "IOTDB-0003";
+ public static final String DB_BOOL_WRONG_MSG = "Boolean值输入错误,0为false,1为true";
+
+ public static final String DB_DATATYPE_WRONG = "IOTDB-0004";
+ public static final String DB_DATATYPE_WRONG_MSG = "TSDataType类型传入错误";
+
+ public static final String GET_DBCONN_FAIL = "IOTDB-005";
+ public static final String GET_DBCONN_FAIL_MSG = "获取数据库连接失败";
+
+ public static final String GET_SESSION_FAIL = "IOTDB-0006";
+ public static final String GET_SESSION_FAIL_MSG = "获取session失败";
+
+ public static final String CLOSE_DBCONN_FAIL = "IOTDB-0007";
+ public static final String CLOSE_DBCONN_FAIL_MSG = "关闭连接失败";
+
+ public static final String SQL_EP = "IOTDB-0008";
+ public static final String SQL_EP_MSG = "没有权限或sql异常";
+
+ public static final String QUERY_FAIL = "IOTDB-0009";
+ public static final String QUERY_FAIL_MSG = "sql查询失败";
+
+ public static final String SQL_PARAM_WRONG = "IOTDB-0010";
+ public static final String SQL_PARAM_WRONG_MSG = "sql参数不合法";
+
+ public static final String WRONG_DB_PARAM = "IOTDB-0011";
+ public static final String WRONG_DB_PARAM_MSG = "输入参数不合法";
+
+ public static final String GET_USER_FAIL = "IOTDB-0012";
+ public static final String GET_USER_FAIL_MSG = "获取用户信息失败";
+
+ public static final String GET_SQL_ONE_VALUE_FAIL = "IOTDB-0013";
+ public static final String GET_SQL_ONE_VALUE_FAIL_MSG = "获取值失败";
+
+ public static final String SET_TTL_FAIL = "IOTDB-0014";
+ public static final String SET_TTL_FAIL_MSG = "设置存活时间失败";
+
+ public static final String DEL_TTL_FAIL = "IOTDB-0015";
+ public static final String DEL_TTL_FAIL_MSG = "删除存活时间失败";
+
+ public static final String GET_SQL_ONE_COLUMN_FAIL = "IOTDB-0016";
+ public static final String GET_SQL_ONE_COLUMN_FAIL_MSG = "获取列表失败";
+
+ public static final String GET_SQL_SET_FAIL = "IOTDB-0017";
+ public static final String GET_SQL_SET_FAIL_MSG = "获取列表集合失败";
+
+ public static final String INSERT_DEV_FAIL = "IOTDB-0018";
+ public static final String INSERT_DEV_FAIL_MSG = "插入实体失败";
+
+ public static final String GET_MSM_FAIL = "IOTDB-0019";
+ public static final String GET_MSM_FAIL_MSG = "获取物理量数据信息失败";
+
+ public static final String NO_SUCH_FIELD = "IOTDB-0020";
+ public static final String NO_SUCH_FIELD_MSG = "返回集没此属性";
+
+ public static final String GET_LAST_VALUE_FAIL = "IOTDB-0021";
+ public static final String GET_LAST_VALUE_FAIL_MSG = "获取物理量最新值失败";
+
+ public static final String SET_GROUP_FAIL = "IOTDB-0022";
+ public static final String SET_GROUP_FAIL_MSG = "创建存储组失败";
+
+ public static final String DELETE_GROUP_FAIL = "IOTDB-0023";
+ public static final String DELETE_GROUP_FAIL_MSG = "删除存储组失败";
+
+ public static final String DELETE_DB_USER_FAIL = "IOTDB-0024";
+ public static final String DELETE_DB_USER_FAIL_MSG = "删除数据库用户失败";
+
+ public static final String DELETE_DB_ROLE_FAIL = "IOTDB-0025";
+ public static final String DELETE_DB_ROLE_FAIL_MSG = "删除数据库角色失败";
+
+ public static final String SET_DB_USER_FAIL = "IOTDB-0026";
+ public static final String SET_DB_USER_FAIL_MSG = "创建数据库用户失败";
+
+ public static final String SET_DB_ROLE_FAIL = "IOTDB-0027";
+ public static final String SET_DB_ROLE_FAIL_MSG = "创建数据库角色或对应权限时失败";
+
+ public static final String NO_TYPE = "IOTDB-0028";
+ public static final String NO_TYPE_MSG = "粒度类型不存在";
+
+ public static final String PRIV_ROOT_FAIL = "IOTDB-0029";
+ public static final String PRIV_ROOT_FAIL_MSG = "根路径权限操作失败";
+
+ public static final String PRIV_GROUP_FAIL = "IOTDB-0030";
+ public static final String PRIV_GROUP_FAIL_MSG = "组路径权限操作失败";
+
+ public static final String PRIV_DEVICE_FAIL = "IOTDB-0031";
+ public static final String PRIV_DEVICE_FAIL_MSG = "实体路径权限操作失败";
+
+ public static final String PRIV_TIMESERIES_FAIL = "IOTDB-0032";
+ public static final String PRIV_TIMESERIES_FAIL_MSG = "物理量路径权限操作失败";
+
+ public static final String GET_RECORD_FAIL = "IOTDB-0033";
+ public static final String GET_RECORD_FAIL_MSG = "获取物理量记录失败";
+
+ public static final String NO_SQL = "IOTDB-0034";
+ public static final String NO_SQL_MSG = "没有sql执行语句";
+
+ public static final String UPDATE_GROUP_INFO_FAIL = "IOTDB-0035";
+ public static final String UPDATE_GROUP_INFO_FAIL_MSG = "更新组信息失败";
+
+ public static final String NO_GROUP_INFO = "IOTDB-0036";
+ public static final String NO_GROUP_INFO_MSG = "不存在存储组信息";
+
+ public static final String NO_GROUP = "IOTDB-0037";
+ public static final String NO_GROUP_MSG = "不存在存储组";
+
+ public static final String NO_DEVICE_INFO = "IOTDB-0038";
+ public static final String NO_DEVICE_INFO_MSG = "不存在设备信息";
+
+ public static final String UPDATE_PWD_FAIL = "IOTDB-0039";
+ public static final String UPDATE_PWD_FAIL_MSG = "修改账号密码失败";
+
+ public static final String NO_QUERY = "IOTDB-0040";
+ public static final String NO_QUERY_MSG = "不存在此查询";
+
+ public static final String NO_ALL_NUM_SEARCH = "IOTDB-0041";
+ public static final String NO_ALL_NUM_SEARCH_MSG = "不支持纯数字查询";
+
+ public static final String NO_PRI_SET_TTL = "IOTDB-0042";
+ public static final String NO_PRI_SET_TTL_MSG = "没有权限设置存活时间";
+
+ public static final String NO_PRI_CREATE_TIMESERIES = "IOTDB-0043";
+ public static final String NO_PRI_CREATE_TIMESERIES_MSG = "没有权限创建物理量";
+
+ public static final String NO_PRI_READ_TIMESERIES = "IOTDB-0044";
+ public static final String NO_PRI_READ_TIMESERIES_MSG = "没有权限查看物理量";
+
+ public static final String NO_PRI_DELETE_TIMESERIES = "IOTDB-0045";
+ public static final String NO_PRI_DELETE_TIMESERIES_MSG = "没有权限删除物理量";
+
+ public static final String CONN_REFUSED = "IOTDB-0046";
+ public static final String CONN_REFUSED_MSG = "连接错误,检查输入";
+
+ public static final String WRONG_USER = "IOTDB-0047";
+ public static final String WRONG_USER_MSG = "连接用户名或密码错误";
+
+ public static final String NO_PRI_SET_GROUP = "IOTDB-0048";
+ public static final String NO_PRI_SET_GROUP_MSG = "没有权限操作存储组";
+
+ public static final String NO_PRI_DELETE_GROUP = "IOTDB-0048";
+ public static final String NO_PRI_DELETE_GROUP_MSG = "没有权限删除存储组";
+
+ public static final String NO_SUPPORT_SQL = "IOTDB-0049";
+ public static final String NO_SUPPORT_SQL_MSG = "不支持此sql执行";
+
+ public static final String TTL_WRONG = "IOTDB-0050";
+ public static final String TTL_WRONG_MSG = "存活时间必须大于等于0";
+
+ public static final String NO_PRI_TIMESERIES_DATA = "IOTDB-0051";
+ public static final String NO_PRI_TIMESERIES_DATA_MSG = "没有权限查看测点数据";
+
+ public static final String NO_SUP_CONTAIN_ROOT = "IOTDB-0052";
+ public static final String NO_SUP_CONTAIN_ROOT_MSG = "不支持包含\"root\"的输入";
+
+ // 存储组表相关
+ public static final String INSERT_GROUP_INFO_FAIL = "GROUP-0001";
+ public static final String INSERT_GROUP_INFO_FAIL_MSG = "插入存储组信息失败";
+
+ public static final String DELETE_GROUP_INFO_FAIL = "GROUP-0002";
+ public static final String DELETE_GROUP_INFO_FAIL_MSG = "删除存储组信息失败";
+
+ // 实体表相关
+ public static final String DELETE_DEVICE_INFO_FAIL = "DEV-0001";
+ public static final String DELETE_DEVICE_INFO_FAIL_MSG = "删除实体信息失败";
+
+ public static final String SET_DEVICE_INFO_FAIL = "DEV-0002";
+ public static final String SET_DEVICE_INFO_FAIL_MSG = "插入实体信息失败";
+
+ // 物理量表相关
+ public static final String DELETE_MEASUREMENT_INFO_FAIL = "MEASU-0001";
+ public static final String DELETE_MEASUREMENT_INFO_FAIL_MSG = "删除物理量信息失败";
+
+ public static final String SET_MEASUREMENT_INFO_FAIL = "MEASU-0002";
+ public static final String SET_MEASUREMENT_INFO_FAIL_MSG = "插入物理量信息失败";
+
+ public static final String GET_MSM_DES_FAIL = "MEASU-0003";
+ public static final String GET_MSM_DES_FAIL_MSG = "获取物理量描述信息失败";
+
+ // 查询表相关
+ public static final String QUERY_EXIST = "QUERY-0001";
+ public static final String QUERY_EXIST_MSG = "脚本名已存在";
+
+ public static final String QUERY_NOT_EXIST = "QUERY-0002";
+ public static final String QUERY_NOT_EXIST_MSG = "脚本不存在";
+
+
+ // 参数校验相关
+ public static final String WRONG_PARAM = "PARAM-0001";
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/common/utils/AuthenticationUtils.java b/backend/src/main/java/org/apache/iotdb/admin/common/utils/AuthenticationUtils.java
new file mode 100644
index 0000000..efe1f84
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/common/utils/AuthenticationUtils.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.common.utils;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+
+import javax.servlet.http.HttpServletRequest;
+
+/**
+ * 校验工具类
+ */
+public class AuthenticationUtils {
+
+ public static void userAuthentication(Integer userId, HttpServletRequest request) throws BaseException {
+ if (userId == null) {
+ throw new BaseException(ErrorCode.NO_USER, ErrorCode.NO_USER_MSG);
+ }
+ DecodedJWT authorization = JWT.decode(request.getHeader("Authorization"));
+ Integer tokenUserId = authorization.getClaim("userId").asInt();
+ if (!tokenUserId.equals(userId)) {
+ throw new BaseException(ErrorCode.USER_AUTH_FAIL, ErrorCode.USER_AUTH_FAIL_MSG);
+ }
+ }
+
+ public static Integer getUserId(HttpServletRequest request) {
+ DecodedJWT authentication = JWT.decode(request.getHeader("Authorization"));
+ return authentication.getClaim("userId").asInt();
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/config/FilterConfig.java b/backend/src/main/java/org/apache/iotdb/admin/config/FilterConfig.java
new file mode 100644
index 0000000..50dafeb
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/FilterConfig.java
@@ -0,0 +1,46 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.config;
+
+import org.apache.iotdb.admin.filter.TokenFilter;
+import org.springframework.stereotype.Component;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistration;
+import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
+import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 拦截器配置类
+ */
+@Component
+public class FilterConfig implements WebMvcConfigurer {
+
+ @Override
+ public void addInterceptors(InterceptorRegistry registry) {
+ InterceptorRegistration interceptorRegistration = registry.addInterceptor(new TokenFilter());
+ List<String> paths = new ArrayList();
+ paths.add("/servers/**");
+ paths.add("/get");
+ interceptorRegistration.addPathPatterns(paths);
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/config/MybatisPlusConfig.java b/backend/src/main/java/org/apache/iotdb/admin/config/MybatisPlusConfig.java
new file mode 100644
index 0000000..becedc1
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/MybatisPlusConfig.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.config;
+
+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;
+
+/**
+ * 该类是Mybatis-Plus的配置类,mybatis以插件的形式来实现特定功能
+ */
+@Configuration
+public class MybatisPlusConfig {
+
+ /**
+ * 分页插件配置,对相关数据库进行拦截并分页
+ *
+ * @return 分页拦截器
+ */
+ @Bean
+ public MybatisPlusInterceptor paginationInterceptor() {
+ MybatisPlusInterceptor interceptor = new MybatisPlusInterceptor();
+ // 使用不同的数据库,可以更改DbType.MYSQL的类型
+ PaginationInnerInterceptor paginationInnerInterceptor = new PaginationInnerInterceptor(DbType.MYSQL);
+ // 每页最多100条,可以更改,但不建议太大
+ paginationInnerInterceptor.setMaxLimit(100L);
+ interceptor.addInnerInterceptor(paginationInnerInterceptor);
+ return interceptor;
+ }
+
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/config/SecurityConfig.java b/backend/src/main/java/org/apache/iotdb/admin/config/SecurityConfig.java
new file mode 100644
index 0000000..bf93858
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/SecurityConfig.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.config.annotation.web.builders.HttpSecurity;
+import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+
+/**
+ * 加密算法配置类 hash算法
+ */
+@Configuration
+public class SecurityConfig extends WebSecurityConfigurerAdapter {
+
+ @Override
+ protected void configure(HttpSecurity http) throws Exception {
+ http.authorizeRequests()
+ .antMatchers("/**")
+ .permitAll()
+ .anyRequest()
+ .authenticated()
+ .and().csrf().disable();
+ }
+
+ @Bean
+ public BCryptPasswordEncoder bCryptPasswordEncoder() {
+ return new BCryptPasswordEncoder();
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/config/SwaggerConfig.java b/backend/src/main/java/org/apache/iotdb/admin/config/SwaggerConfig.java
new file mode 100644
index 0000000..45a0374
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/SwaggerConfig.java
@@ -0,0 +1,79 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.config;
+
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.context.annotation.Profile;
+import springfox.documentation.builders.ApiInfoBuilder;
+import springfox.documentation.builders.ParameterBuilder;
+import springfox.documentation.builders.PathSelectors;
+import springfox.documentation.builders.RequestHandlerSelectors;
+import springfox.documentation.schema.ModelRef;
+import springfox.documentation.service.ApiInfo;
+import springfox.documentation.service.Parameter;
+import springfox.documentation.spi.DocumentationType;
+import springfox.documentation.spring.web.plugins.Docket;
+import springfox.documentation.swagger2.annotations.EnableSwagger2;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * swagger配置类
+ */
+@Configuration
+@EnableSwagger2
+@Profile({"dev", "test"})
+public class SwaggerConfig {
+
+ @Bean
+ public Docket createRestApi() {
+ return new Docket(DocumentationType.SWAGGER_2)
+ .apiInfo(apiinfo())
+ .enable(true)
+ .globalOperationParameters(jwtToken())
+ .select()
+ .apis(RequestHandlerSelectors.basePackage("org.apache.iotdb.admin.controller"))
+ .paths(PathSelectors.any())
+ .build();
+ }
+
+ private ApiInfo apiinfo() {
+ return new ApiInfoBuilder()
+ .title("IOTDB接口文档")
+ .description("iotDB层级关系 存储组 -> 实体(设备) -> 测点(时间序列)")
+ .build();
+ }
+
+ private List<Parameter> jwtToken() {
+
+ ParameterBuilder tokenPar = new ParameterBuilder();
+ List<Parameter> pars = new ArrayList<>();
+ tokenPar.name("Authorization")
+ .description("jwt令牌")
+ .modelRef(new ModelRef("string"))
+ .parameterType("header")
+ .required(false);
+ pars.add(tokenPar.build());
+ return pars;
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/config/ValidatorConfiguration.java b/backend/src/main/java/org/apache/iotdb/admin/config/ValidatorConfiguration.java
new file mode 100644
index 0000000..ff63d55
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/ValidatorConfiguration.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.config;
+
+import org.hibernate.validator.HibernateValidator;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.validation.Validation;
+import javax.validation.Validator;
+import javax.validation.ValidatorFactory;
+
+/**
+ * 校验框架配置类
+ */
+@Configuration
+public class ValidatorConfiguration {
+
+ @Bean("validator")
+ public Validator getValidatorFactory() {
+ ValidatorFactory validatorFactory = Validation.byProvider(HibernateValidator.class).configure().failFast(true).buildValidatorFactory();
+ return validatorFactory.getValidator();
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/ConnectionController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/ConnectionController.java
new file mode 100644
index 0000000..71dbdd3
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/ConnectionController.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.common.utils.AuthenticationUtils;
+import org.apache.iotdb.admin.model.dto.ConnectionDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.vo.BaseVO;
+import org.apache.iotdb.admin.model.vo.ConnVO;
+import org.apache.iotdb.admin.model.vo.ConnectionVO;
+import org.apache.iotdb.admin.service.ConnectionService;
+import org.apache.iotdb.session.Session;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.net.InetSocketAddress;
+import java.net.Socket;
+import java.util.List;
+
+@RestController
+@Api(value = "连接相关接口")
+public class ConnectionController {
+
+ @Autowired
+ private ConnectionService connectionService;
+
+ @PostMapping("/servers")
+ @ApiOperation("保存或更新连接")
+ public BaseVO saveOrUpdateConnection(@RequestBody Connection connection, HttpServletRequest request) throws BaseException {
+ AuthenticationUtils.userAuthentication(connection.getUserId(), request);
+ if (connection.getId() != null) {
+ connectionService.update(connection);
+ return BaseVO.success("更新成功", null);
+ }
+ connectionService.insert(connection);
+
+ return BaseVO.success("保存成功", null);
+ }
+
+ @DeleteMapping("/servers/{serverId}")
+ @ApiOperation("删除连接")
+ public BaseVO deleteConnection(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ Integer userId = AuthenticationUtils.getUserId(request);
+ connectionService.check(serverId, userId);
+ connectionService.deleteById(serverId, userId);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/servers/{serverId}")
+ @ApiOperation("获取连接具体配置")
+ public BaseVO<Connection> getConnection(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ Integer userId = AuthenticationUtils.getUserId(request);
+ connectionService.check(serverId, userId);
+ return BaseVO.success("获取成功", connectionService.getById(serverId));
+ }
+
+ @GetMapping("/servers")
+ @ApiOperation("获取所有连接")
+ public BaseVO<ConnectionVO> getAllConnections(@RequestParam("userId") Integer userId, HttpServletRequest request) throws BaseException {
+ AuthenticationUtils.userAuthentication(userId, request);
+ List<ConnVO> connVOs = connectionService.getAllConnections(userId);
+ ConnectionVO connectionVO = new ConnectionVO(connVOs, userId, null);
+ return BaseVO.success("获取成功", connectionVO);
+ }
+
+ @PostMapping("/test")
+ @ApiOperation("连通性测试")
+ public BaseVO testConnection(@RequestBody ConnectionDTO conn) throws BaseException {
+ Socket socket = null;
+ try {
+ socket = new Socket();
+ socket.connect(new InetSocketAddress(conn.getHost(), conn.getPort()), 5000);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.TEST_CONN_FAIL, ErrorCode.TEST_CONN_FAIL_MSG);
+ } finally {
+ try {
+ if (socket != null) {
+ socket.close();
+ }
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.TEST_CONN_FAIL, ErrorCode.TEST_CONN_FAIL_MSG);
+ }
+ }
+ Session session = null;
+ try {
+ session = new Session(conn.getHost(), conn.getPort(), conn.getUsername(), conn.getPassword());
+ session.open();
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.TEST_CONN_FAIL_PWD, ErrorCode.TEST_CONN_FAIL_PWD_MSG);
+ } finally {
+ try {
+ if (session != null) {
+ session.close();
+ }
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.TEST_CONN_FAIL_PWD, ErrorCode.TEST_CONN_FAIL_PWD_MSG);
+ }
+ }
+ return BaseVO.success("连通成功", null);
+ }
+
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java
new file mode 100644
index 0000000..62efb35
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import java.io.IOException;
+import javax.servlet.http.HttpServletResponse;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.springframework.stereotype.Controller;
+import org.springframework.web.bind.annotation.GetMapping;
+
+/**
+ * 运维平台通过存活、就绪探针表示应用是否存活,就绪。这个类大家最好不好删除,url地址也不要改变
+ */
+@Controller
+public class HealthController {
+
+ /**
+ * 存活探针,运维平台会每格一段时间,请求一下这个接口,如果这个接口返回200,那么表示存活,
+ * 如果多次返回500,则表示这个程序已经死了,会重启这个程序。
+ */
+ @GetMapping(value = "/healthz/liveness")
+ public void liveness(HttpServletResponse response) throws IOException, BaseException {
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+
+ /**
+ * 就绪探针,运维平台会每格一段时间,请求一下这个接口,如果这个接口返回200,那么表示程序已经可用,
+ * 如果多次返回500,则表示这个程序未启动成功,会重启这个程序。
+ */
+ @GetMapping(value = "/healthz/readiness")
+ public void readiness(HttpServletResponse response) throws IOException {
+ response.setStatus(HttpServletResponse.SC_OK);
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/IotDBController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/IotDBController.java
new file mode 100644
index 0000000..8153022
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/IotDBController.java
@@ -0,0 +1,867 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.common.utils.AuthenticationUtils;
+import org.apache.iotdb.admin.model.dto.*;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.Device;
+import org.apache.iotdb.admin.model.entity.StorageGroup;
+import org.apache.iotdb.admin.model.vo.*;
+import org.apache.iotdb.admin.service.*;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@RestController
+@Api(value = "iotdb操作相关接口")
+@RequestMapping("/servers/{serverId}")
+public class IotDBController {
+
+ @Autowired
+ private ConnectionService connectionService;
+
+ @Autowired
+ private IotDBService iotDBService;
+
+ @Autowired
+ private GroupService groupService;
+
+ @Autowired
+ private DeviceService deviceService;
+
+ @Autowired
+ private MeasurementService measurementService;
+
+
+ @GetMapping("/storageGroups/info")
+ @ApiOperation("获得存储组信息列表")
+ public BaseVO<List<GroupInfoVO>> getAllStorageGroupsInfo(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ List<String> groupNames = iotDBService.getAllStorageGroups(connection);
+ List<GroupInfoVO> groupInfoList = new ArrayList<>();
+ if (groupNames == null || groupNames.size() == 0) {
+ return BaseVO.success("获取成功", groupInfoList);
+ }
+ String host = connection.getHost();
+ List<Integer> deviceCounts = iotDBService.getDevicesCount(connection, groupNames);
+ List<String> descriptions = groupService.getGroupDescription(host, groupNames);
+ for (int i = 0; i < groupNames.size(); i++) {
+ GroupInfoVO groupInfoVO = new GroupInfoVO();
+ groupInfoVO.setGroupName(groupNames.get(i).replaceFirst("root.", ""));
+ groupInfoVO.setDeviceCount(deviceCounts.get(i));
+ groupInfoVO.setDescription(descriptions.get(i));
+ groupInfoList.add(groupInfoVO);
+ }
+ return BaseVO.success("获取成功", groupInfoList);
+ }
+
+ @GetMapping("/storageGroups")
+ @ApiOperation("获得存储组列表")
+ public BaseVO<List<StorageGroupVO>> getAllStorageGroups(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ List<StorageGroupVO> storageGroupVOList = new ArrayList<>();
+ List<String> groupNames = iotDBService.getAllStorageGroups(connection);
+ if (groupNames == null || groupNames.size() == 0) {
+ return BaseVO.success("获取成功", storageGroupVOList);
+ }
+ String host = connection.getHost();
+ for (String groupName : groupNames) {
+ StorageGroupVO storageGroupVO = new StorageGroupVO();
+ Integer id = groupService.getGroupId(host, groupName);
+ storageGroupVO.setGroupId(id);
+ groupName = groupName.replaceFirst("root.", "");
+ storageGroupVO.setGroupName(groupName);
+ storageGroupVOList.add(storageGroupVO);
+ }
+ return BaseVO.success("获取成功", storageGroupVOList);
+ }
+
+ @PostMapping("/storageGroups")
+ @ApiOperation("新增或修改存储组")
+ public BaseVO saveStorageGroup(@PathVariable("serverId") Integer serverId,
+ @RequestBody GroupDTO groupDTO,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ String groupName = groupDTO.getGroupName();
+ String checkName = groupName.toLowerCase();
+ if (checkName.contains("root")) {
+ throw new BaseException(ErrorCode.NO_SUP_CONTAIN_ROOT, ErrorCode.NO_SUP_CONTAIN_ROOT_MSG);
+ }
+ groupName = "root." + groupName;
+ Long ttl = groupDTO.getTtl();
+ String ttlUnit = groupDTO.getTtlUnit();
+ Integer groupId = groupDTO.getGroupId();
+ groupDTO.setGroupName(groupName);
+
+ List<String> groupNames = iotDBService.getAllStorageGroups(connection);
+ if (groupId == null) {
+ if (!groupNames.contains(groupDTO.getGroupName())) {
+ iotDBService.saveStorageGroup(connection, groupName);
+ }
+ groupService.setStorageGroupInfo(connection, groupDTO);
+ } else {
+ groupService.updateStorageGroupInfo(connection, groupDTO);
+ }
+ if (ttl != null && ttlUnit != null) {
+ if (ttl >= 0) {
+ Long times = switchTime(ttlUnit);
+ iotDBService.saveGroupTtl(connection, groupName, ttl * times);
+ } else {
+ throw new BaseException(ErrorCode.TTL_WRONG, ErrorCode.TTL_WRONG_MSG);
+ }
+ } else {
+ if (ttl == null && ttlUnit == null) {
+ iotDBService.cancelGroupTtl(connection, groupName);
+ } else {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ return BaseVO.success("新增或更新成功", null);
+ }
+
+ @DeleteMapping("/storageGroups/{groupName}")
+ @ApiOperation("删除存储组")
+ public BaseVO deleteStorageGroup(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ String host = connection.getHost();
+ iotDBService.deleteStorageGroup(connection, groupName);
+ groupService.deleteGroupInfo(host, groupName);
+ deviceService.deleteDeviceInfo(host, groupName);
+ measurementService.deleteMeasurementInfo(host, groupName);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/storageGroups/{groupName}")
+ @ApiOperation("存储组详情获取")
+ public BaseVO<GroupVO> getStorageGroup(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ String host = connection.getHost();
+ StorageGroup group = groupService.getGroupInfo(host, groupName);
+ String ttl = iotDBService.getGroupTTL(connection, groupName);
+ String ttlUnit;
+ GroupVO groupVO = new GroupVO();
+ if (ttl != null && !"null".equalsIgnoreCase(ttl)) {
+ Long totalTime = Long.valueOf(ttl);
+ ttlUnit = getTTL(totalTime);
+ Long times = switchTime(ttlUnit);
+ ttl = String.valueOf(totalTime / times);
+ groupVO.setTtl(ttl);
+ groupVO.setTtiUnit(ttlUnit);
+ } else {
+ groupVO.setTtl(null);
+ }
+ if (group != null) {
+ groupVO.setCreator(group.getCreator());
+ groupVO.setDescription(group.getDescription());
+ Date date = new Date(group.getCreateTime());
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ String createTime = simpleDateFormat.format(date);
+ groupVO.setCreateTime(createTime);
+ }
+ groupVO.setGroupName(groupName.replaceFirst("root.", ""));
+ groupVO.setAlias(connection.getAlias());
+ return BaseVO.success("获取成功", groupVO);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/info")
+ @ApiOperation("获取指定存储组下的实体(设备)信息列表")
+ public BaseVO<DeviceInfoVO> getDevicesInfoByGroupName(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @RequestParam("pageSize") Integer pageSize,
+ @RequestParam("pageNum") Integer pageNum,
+ @RequestParam(value = "keyword", required = false) String keyword,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (pageSize == null || pageNum == null) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ CountDTO countDTO = iotDBService.getDevicesByGroup(connection, groupName, pageSize, pageNum, keyword);
+ List<String> deviceNames = countDTO.getObjects();
+ DeviceInfoVO deviceInfoVO = new DeviceInfoVO();
+ Integer totalPage = countDTO.getTotalPage();
+ Integer totalCount = countDTO.getTotalCount();
+ deviceInfoVO.setTotalCount(totalCount);
+ deviceInfoVO.setTotalPage(totalPage);
+ List<Integer> lines = iotDBService.getTimeseriesCount(connection, deviceNames);
+ List<Device> devices = deviceService.getDevices(connection.getHost(), deviceNames);
+ List<DeviceInfo> deviceInfos = new ArrayList<>();
+ if (deviceNames != null) {
+ for (int i = 0; i < deviceNames.size(); i++) {
+ String deviceName = deviceNames.get(i);
+ if (groupName.equals(deviceName)) {
+ continue;
+ }
+ DeviceInfo deviceInfo = new DeviceInfo();
+ deviceInfo.setDeviceName(deviceName.replaceFirst(groupName + ".", ""));
+ deviceInfo.setLine(lines.get(i));
+ if (devices.get(i) != null) {
+ deviceInfo.setDeviceId(devices.get(i).getId());
+ deviceInfo.setCreator(devices.get(i).getCreator());
+ deviceInfo.setDescription(devices.get(i).getDescription());
+ }
+ deviceInfos.add(deviceInfo);
+ }
+ }
+ deviceInfoVO.setDeviceInfos(deviceInfos);
+ return BaseVO.success("获取成功", deviceInfoVO);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices")
+ @ApiOperation("获取指定存储组下的实体(设备)列表")
+ public BaseVO<List<String>> getDevicesByGroupName(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ List<String> deviceNamesStr = iotDBService.getDevices(connection, groupName);
+ List<String> deviceNames = new ArrayList<>();
+ for (String s : deviceNamesStr) {
+ String deviceName;
+ if (groupName.equals(s)) {
+ continue;
+ } else {
+ deviceName = s.replaceFirst(groupName + ".", "");
+ }
+ deviceNames.add(deviceName);
+ }
+ return BaseVO.success("获取成功", deviceNames);
+ }
+
+ @PostMapping("/storageGroups/{groupName}/devices")
+ @ApiOperation("新增或编辑实体(设备)")
+ public BaseVO<List<String>> saveOrUpdateDevice(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @RequestBody DeviceInfoDTO deviceInfoDTO,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (deviceInfoDTO.getDeviceDTOList() == null || deviceInfoDTO.getDeviceDTOList().size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceInfoDTO.setDeviceName(groupName + "." + deviceInfoDTO.getDeviceName());
+ for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+ deviceDTO.setTimeseries(deviceInfoDTO.getDeviceName() + "." + deviceDTO.getTimeseries());
+ }
+ String host = connection.getHost();
+ iotDBService.createDeviceWithMeasurements(connection, deviceInfoDTO);
+ if (deviceInfoDTO.getDeviceId() == null) {
+ deviceService.setDeviceInfo(connection, deviceInfoDTO);
+ measurementService.setMeasurementsInfo(host, deviceInfoDTO);
+ } else {
+ deviceService.updateDeviceInfo(deviceInfoDTO);
+ measurementService.updateMeasurementsInfo(host, deviceInfoDTO);
+ }
+ return BaseVO.success("新增或更新成功", null);
+ }
+
+
+ @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}")
+ @ApiOperation("删除实体(设备)")
+ public BaseVO deleteDevice(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ String host = connection.getHost();
+ iotDBService.deleteTimeseriesByDevice(connection, deviceName);
+ deviceService.deleteDeviceInfoByDeviceName(host, deviceName);
+ measurementService.deleteMeasurementInfoByDeviceName(host, deviceName);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/{deviceName}")
+ @ApiOperation("获取实体(设备)详情")
+ public BaseVO<DeviceVO> getDeviceInfo(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ HttpServletRequest request) throws BaseException {
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ String host = connection.getHost();
+ DeviceVO deviceVO = deviceService.getDevice(host, deviceName);
+ return BaseVO.success("获取成功", deviceVO);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/info")
+ @ApiOperation("获取指定实体(设备)下的物理量列表详情")
+ public BaseVO<MeasuremtnInfoVO> getMeasurementsByDeviceName(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ @RequestParam("pageSize") Integer pageSize,
+ @RequestParam("pageNum") Integer pageNum,
+ @RequestParam(value = "keyword", required = false) String keyword,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ CountDTO countDTO = iotDBService.getMeasurementsByDevice(connection, deviceName, pageSize, pageNum, keyword);
+ List<MeasurementDTO> measurementDTOList = countDTO.getObjects();
+ List<MeasurementVO> measurementVOList = new ArrayList<>();
+ String host = connection.getHost();
+ if (measurementDTOList != null) {
+ for (MeasurementDTO measurementDTO : measurementDTOList) {
+ MeasurementVO measurementVO = new MeasurementVO();
+ BeanUtils.copyProperties(measurementDTO, measurementVO);
+ if (measurementVO.getTimeseries() != null) {
+ measurementVO.setTimeseries(measurementVO.getTimeseries().replaceFirst(deviceName + ".", ""));
+ }
+ String description = measurementService.getDescription(host, measurementDTO.getTimeseries());
+ String newValue = iotDBService.getLastMeasurementValue(connection, measurementDTO.getTimeseries());
+ measurementVO.setNewValue(newValue);
+ measurementVO.setDescription(description);
+ measurementVOList.add(measurementVO);
+ }
+ }
+ MeasuremtnInfoVO measuremtnInfoVO = new MeasuremtnInfoVO();
+ measuremtnInfoVO.setTotalCount(countDTO.getTotalCount());
+ measuremtnInfoVO.setTotalPage(countDTO.getTotalPage());
+ measuremtnInfoVO.setMeasurementVOList(measurementVOList);
+ return BaseVO.success("获取成功", measuremtnInfoVO);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/{timeseriesName}")
+ @ApiOperation("获取指定物理量的最新两百条数据记录")
+ public BaseVO<RecordVO> getMeasurementInfo(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ @PathVariable("timeseriesName") String timeseriesName,
+ HttpServletRequest request) throws BaseException {
+ if (groupName == null || !groupName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ RecordVO recordVO = iotDBService.getRecords(connection, deviceName, timeseriesName);
+ return BaseVO.success("获取成功", recordVO);
+ }
+
+ @PostMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries")
+ @ApiOperation("创建时间序列 (未使用)")
+ public BaseVO insertTimeseries(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ @RequestBody Timeseries timeseries,
+ HttpServletRequest request) throws BaseException {
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ iotDBService.insertTimeseries(connection, deviceName, timeseries);
+ return BaseVO.success("创建成功", null);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/info")
+ @ApiOperation("指定设备下的所有物理量 (未使用)")
+ public BaseVO<SqlResultVO> showTimeseries(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ HttpServletRequest request) throws BaseException {
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ SqlResultVO resultVO = iotDBService.showTimeseries(connection, deviceName);
+ return BaseVO.success("获取成功", resultVO);
+ }
+
+ @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries")
+ @ApiOperation("指定设备下的物理量列表")
+ public BaseVO<List<String>> getTimeseries(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ HttpServletRequest request) throws BaseException {
+ if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ List<String> timeseriesStr = iotDBService.getTimeseries(connection, deviceName);
+ List<String> timeseries = new ArrayList<>();
+ for (String s : timeseriesStr) {
+ timeseries.add(s.replaceFirst(deviceName + ".", ""));
+ }
+ return BaseVO.success("获取成功", timeseries);
+ }
+
+ @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/{timeseriesName}")
+ @ApiOperation("删除物理量")
+ public BaseVO deleteTimeseries(@PathVariable("serverId") Integer serverId,
+ @PathVariable("groupName") String groupName,
+ @PathVariable("deviceName") String deviceName,
+ @PathVariable("timeseriesName") String timeseriesName,
+ HttpServletRequest request) throws BaseException {
+ if (timeseriesName == null || !timeseriesName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ groupName = "root." + groupName;
+ deviceName = groupName + "." + deviceName;
+ timeseriesName = deviceName + "." + timeseriesName;
+ iotDBService.deleteTimeseries(connection, timeseriesName);
+ String host = connection.getHost();
+ measurementService.deleteMeasurementInfo(host, timeseriesName);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/users")
+ @ApiOperation("获取数据库用户列表")
+ public BaseVO<List<String>> getIotDBUserList(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ List<String> users = iotDBService.getIotDBUserList(connection);
+ String username = connection.getUsername();
+ if (users == null) {
+ users = new ArrayList<>();
+ users.add(username);
+ return BaseVO.success("获取成功", users);
+ }
+ // 前端需要将当前用户处于列表第一位
+ List<String> newUsers = new ArrayList<>();
+ newUsers.add(username);
+ for (String user : users) {
+ if (username.equalsIgnoreCase(user)) {
+ continue;
+ }
+ newUsers.add(user);
+ }
+ return BaseVO.success("获取成功", newUsers);
+ }
+
+ @GetMapping("/roles")
+ @ApiOperation("获取数据库角色列表 (未使用)")
+ public BaseVO<List<String>> getIotDBRoleList(@PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ List<String> roles = iotDBService.getIotDBRoleList(connection);
+ return BaseVO.success("获取成功", roles);
+ }
+
+ @GetMapping("/users/{userName}")
+ @ApiOperation("获取数据源用户的具体信息或其他用户的权限信息")
+ public BaseVO<IotDBUserVO> getIotDBUser(@PathVariable("serverId") Integer serverId,
+ @PathVariable("userName") String userName,
+ HttpServletRequest request) throws BaseException {
+ if (userName == null || !userName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ IotDBUserVO iotDBUserVO = iotDBService.getIotDBUser(connection, userName);
+ return BaseVO.success("获取成功", iotDBUserVO);
+ }
+
+ @PostMapping("/users/{userName}")
+ @ApiOperation("数据库用户赋权")
+ public BaseVO setUserPrivileges(@PathVariable("serverId") Integer serverId,
+ @PathVariable("userName") String userName,
+ @RequestBody PrivilegeInfoDTO privilegeInfoDTO,
+ HttpServletRequest request) throws BaseException {
+ if (userName == null || !userName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (privilegeInfoDTO == null) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ Integer type = privilegeInfoDTO.getType();
+ if (type != null && (type > 3 || type < 0)) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+// Integer delType = pathCheckAndGetDelType(privilegeInfoDTO);
+ pathCheck(privilegeInfoDTO);
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.setUserPrivileges(connection, userName, privilegeInfoDTO);
+ return BaseVO.success("操作成功", null);
+ }
+
+ private void pathCheck(PrivilegeInfoDTO privilegeInfoDTO) throws BaseException {
+ Integer type = privilegeInfoDTO.getType();
+ List<String> groupPaths = privilegeInfoDTO.getGroupPaths();
+ List<String> devicePaths = privilegeInfoDTO.getDevicePaths();
+ List<String> timeseriesPaths = privilegeInfoDTO.getTimeseriesPaths();
+ List<String> delDevicePaths = privilegeInfoDTO.getDelDevicePaths();
+ List<String> delGroupPaths = privilegeInfoDTO.getDelGroupPaths();
+ List<String> delTimeseriesPaths = privilegeInfoDTO.getDelTimeseriesPaths();
+ if (type == null) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ switch (type) {
+ case 0:
+ if (groupPaths != null && groupPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (devicePaths != null && devicePaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (timeseriesPaths != null && timeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delDevicePaths != null && delDevicePaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delGroupPaths != null && delGroupPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delTimeseriesPaths != null && delTimeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ break;
+ case 1:
+ if (devicePaths != null && devicePaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (timeseriesPaths != null && timeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delDevicePaths != null && delDevicePaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delTimeseriesPaths != null && delTimeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ break;
+ case 2:
+ if (groupPaths != null && groupPaths.size() > 0) {
+ if (groupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (devicePaths == null || devicePaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (devicePaths != null && devicePaths.size() > 0) {
+ if (groupPaths == null || groupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (timeseriesPaths != null && timeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delGroupPaths != null && delGroupPaths.size() > 0) {
+ if (delGroupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delDevicePaths == null || delDevicePaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (delDevicePaths != null && delDevicePaths.size() > 0) {
+ if (delGroupPaths == null || delGroupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (delTimeseriesPaths != null && delTimeseriesPaths.size() > 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ break;
+ case 3:
+ if (groupPaths != null && groupPaths.size() > 0) {
+ if (groupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (devicePaths == null || devicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (timeseriesPaths == null || timeseriesPaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (devicePaths != null && devicePaths.size() > 0) {
+ if (devicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (groupPaths == null || groupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (timeseriesPaths == null || timeseriesPaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (timeseriesPaths != null && timeseriesPaths.size() > 0) {
+ if (groupPaths == null || groupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (devicePaths == null || devicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (delGroupPaths != null && delGroupPaths.size() > 0) {
+ if (delGroupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delDevicePaths == null || delDevicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delTimeseriesPaths == null || delTimeseriesPaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (delDevicePaths != null && delDevicePaths.size() > 0) {
+ if (delDevicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delGroupPaths == null || delGroupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delTimeseriesPaths == null || delTimeseriesPaths.size() == 0) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ if (delTimeseriesPaths != null && delTimeseriesPaths.size() > 0) {
+ if (delGroupPaths == null || delGroupPaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ if (delDevicePaths == null || delDevicePaths.size() != 1) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ }
+ break;
+ default:
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+// if (delTimeseriesPaths != null && delTimeseriesPaths.size() > 0) {
+// if (delGroupPaths == null || delGroupPaths.size() != 1) {
+// throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+// }
+// if (delDevicePaths == null || delDevicePaths.size() != 1) {
+// throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+// }
+// return 3;
+// }
+// if (delDevicePaths != null && delDevicePaths.size() > 0) {
+// if (delGroupPaths == null || delGroupPaths.size() != 1) {
+// throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+// }
+// return 2;
+// }
+// if (delGroupPaths != null && delGroupPaths.size() > 0) {
+// return 1;
+// }
+// return 0;
+ }
+
+ @PostMapping("/users/pwd")
+ @ApiOperation("改变用户密码")
+ public BaseVO updatePassword(@PathVariable("serverId") Integer serverId,
+ @RequestBody IotDBUser iotDBUser,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.updatePwd(connection, iotDBUser);
+ return BaseVO.success("修改成功", null);
+ }
+
+ @DeleteMapping("/users/{userName}")
+ @ApiOperation("删除数据库用户")
+ public BaseVO deleteIotDBUser(@PathVariable("serverId") Integer serverId,
+ @PathVariable("userName") String userName,
+ HttpServletRequest request) throws BaseException {
+ if (userName == null || !userName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.deleteIotDBUser(connection, userName);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @DeleteMapping("/roles/{roleName}")
+ @ApiOperation("删除数据库角色 (未使用)")
+ public BaseVO deleteIotDBRole(@PathVariable("serverId") Integer serverId,
+ @PathVariable("roleName") String roleName,
+ HttpServletRequest request) throws BaseException {
+ if (roleName == null || roleName.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.deleteIotDBRole(connection, roleName);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @PostMapping("/users")
+ @ApiOperation("创建数据库用户")
+ public BaseVO setIotDBUser(@PathVariable("serverId") Integer serverId,
+ @RequestBody IotDBUser iotDBUser,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.setIotDBUser(connection, iotDBUser);
+ return BaseVO.success("创建成功", null);
+ }
+
+ @PostMapping("/roles")
+ @ApiOperation("创建数据角色 (未使用)")
+ public BaseVO setIotDBUser(@PathVariable("serverId") Integer serverId,
+ @RequestBody IotDBRole iotDBRole,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ iotDBService.setIotDBRole(connection, iotDBRole);
+ return BaseVO.success("创建成功", null);
+ }
+
+ private void check(HttpServletRequest request, Integer serverId) throws BaseException {
+ Integer userId = AuthenticationUtils.getUserId(request);
+ connectionService.check(serverId, userId);
+ }
+
+
+ private Long switchTime(String ttlUnit) throws BaseException {
+ Long time = 0L;
+ switch (ttlUnit) {
+ case "second":
+ time = 1000L;
+ break;
+ case "minute":
+ time = 60 * 1000L;
+ break;
+ case "hour":
+ time = 60 * 60 * 1000L;
+ break;
+ case "day":
+ time = 24 * 60 * 60 * 1000L;
+ break;
+ case "week":
+ time = 7 * 24 * 60 * 60 * 1000L;
+ break;
+ case "month":
+ time = 30 * 24 * 60 * 60 * 1000L;
+ break;
+ case "year":
+ time = 12 * 30 * 24 * 60 * 60 * 1000L;
+ break;
+ default:
+ throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+ }
+ return time;
+ }
+
+ private String getTTL(Long time) {
+ long yearTime = 31104000000L;
+ long monthTime = 2592000000L;
+ long weekTime = 604800000L;
+ long dayTime = 86400000L;
+ long hourTime = 3600000L;
+ long minuteTime = 60000L;
+ long secondTime = 1000L;
+ if (time == 0) {
+ return "milliSecond";
+ }
+ if ((time / yearTime != 0) && (time % yearTime == 0)) {
+ return "year";
+ }
+ if ((time / monthTime != 0) && (time % monthTime == 0)) {
+ return "month";
+ }
+ if ((time / weekTime != 0) && (time % weekTime == 0)) {
+ return "week";
+ }
+ if ((time / dayTime != 0) && (time % dayTime == 0)) {
+ return "day";
+ }
+ if ((time / hourTime != 0) && (time % hourTime == 0)) {
+ return "hour";
+ }
+ if ((time / minuteTime != 0) && (time % minuteTime == 0)) {
+ return "minute";
+ }
+ if ((time / secondTime != 0) && (time % secondTime == 0)) {
+ return "second";
+ }
+ return null;
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/QueryController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/QueryController.java
new file mode 100644
index 0000000..88ec329
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/QueryController.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.common.utils.AuthenticationUtils;
+import org.apache.iotdb.admin.model.dto.SearchDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.Query;
+import org.apache.iotdb.admin.model.vo.BaseVO;
+import org.apache.iotdb.admin.model.vo.QueryVO;
+import org.apache.iotdb.admin.model.vo.SqlResultVO;
+import org.apache.iotdb.admin.service.ConnectionService;
+import org.apache.iotdb.admin.service.IotDBService;
+import org.apache.iotdb.admin.service.QueryService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import java.util.List;
+
+@RestController
+@Api(value = "查询相关接口")
+@RequestMapping("/servers/{serverId}")
+public class QueryController {
+
+ @Autowired
+ private ConnectionService connectionService;
+
+ @Autowired
+ private IotDBService iotDBService;
+
+ @Autowired
+ private QueryService queryService;
+
+ @PostMapping("/querySql")
+ @ApiOperation("用于查询器查询")
+ public BaseVO<List<SqlResultVO>> query(@PathVariable("serverId") Integer serverId,
+ @RequestBody SearchDTO searchDTO,
+ HttpServletRequest request) throws BaseException {
+ List<String> sqls = searchDTO.getSqls();
+ if (sqls == null || sqls.size() == 0) {
+ throw new BaseException(ErrorCode.NO_SQL, ErrorCode.NO_SQL_MSG);
+ }
+ check(request, serverId);
+ Connection connection = connectionService.getById(serverId);
+ Long timestamp = searchDTO.getTimestamp();
+ List<SqlResultVO> sqlResultVOList = iotDBService.queryAll(connection, sqls, timestamp);
+ return BaseVO.success("查询成功", sqlResultVOList);
+ }
+
+ @PostMapping("/query")
+ @ApiOperation("用于查询脚本保存或编辑")
+ public BaseVO saveQuery(@PathVariable("serverId") Integer serverId,
+ @RequestBody Query query,
+ HttpServletRequest request) throws BaseException {
+ String sqls = query.getSqls();
+ if (sqls == null || "".equals(sqls)) {
+ throw new BaseException(ErrorCode.NO_SQL, ErrorCode.NO_SQL_MSG);
+ }
+ check(request, serverId);
+ if (query.getId() != null) {
+ queryService.update(serverId, query);
+ return BaseVO.success("更新成功", null);
+ }
+ queryService.save(serverId, query);
+ return BaseVO.success("保存成功", null);
+ }
+
+ @GetMapping("/query")
+ @ApiOperation("获取脚本列表")
+ public BaseVO<List<QueryVO>> getQueries(@PathVariable("serverId") Integer serverId,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ List<QueryVO> queryVOList = queryService.getQueryList(serverId);
+ return BaseVO.success("获取成功", queryVOList);
+ }
+
+ @DeleteMapping("/query/{queryId}")
+ @ApiOperation("删除脚本")
+ public BaseVO deleteQuery(@PathVariable("serverId") Integer serverId,
+ @PathVariable("queryId") Integer queryId,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ queryService.deleteQuery(queryId);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/query/{queryId}")
+ @ApiOperation("获取指定脚本")
+ public BaseVO<Query> getQuery(@PathVariable("serverId") Integer serverId,
+ @PathVariable("queryId") Integer queryId,
+ HttpServletRequest request) throws BaseException {
+ check(request, serverId);
+ Query query = queryService.getQuery(queryId);
+ return BaseVO.success("获取成功", query);
+ }
+
+ @GetMapping("/stop")
+ @ApiOperation("用于查询终止")
+ public BaseVO query(@PathVariable("serverId") Integer serverId, @RequestParam("timestamp") Long timestamp, HttpServletRequest request)
+ throws BaseException {
+ check(request, serverId);
+ iotDBService.stopQuery(serverId, timestamp);
+ return BaseVO.success("停止成功", null);
+ }
+
+ public void check(HttpServletRequest request, Integer serverId) throws BaseException {
+ Integer userId = AuthenticationUtils.getUserId(request);
+ connectionService.check(serverId, userId);
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java
new file mode 100644
index 0000000..8fbbc3d
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java
@@ -0,0 +1,121 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import com.auth0.jwt.interfaces.DecodedJWT;
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.common.utils.AuthenticationUtils;
+import org.apache.iotdb.admin.model.entity.User;
+import org.apache.iotdb.admin.model.vo.BaseVO;
+import org.apache.iotdb.admin.model.vo.ConnVO;
+import org.apache.iotdb.admin.model.vo.ConnectionVO;
+import org.apache.iotdb.admin.service.ConnectionService;
+import org.apache.iotdb.admin.service.UserService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.web.bind.annotation.*;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.InetAddress;
+import java.util.Calendar;
+import java.util.List;
+
+@RestController
+@Api(value = "登录相关接口")
+public class UserController {
+
+ @Autowired
+ private UserService userService;
+
+ @Autowired
+ private ConnectionService connectionService;
+
+ private static final Logger logger = LoggerFactory.getLogger(UserController.class);
+
+ @PostMapping("/login")
+ @ApiOperation("登录")
+ public BaseVO<ConnectionVO> login(@RequestParam("name") String name, @RequestParam("password") String password, HttpServletResponse response)
+ throws BaseException {
+ if (name == null || password == null || name.length() < 4 || password.length() < 4) {
+ throw new BaseException(ErrorCode.WRONG_USER_PARAM, ErrorCode.WRONG_USER_PARAM_MSG);
+ }
+ User user = userService.login(name, password);
+ int userId = user.getId();
+ List<ConnVO> connVOs = connectionService.getAllConnections(userId);
+ ConnectionVO connectionVO = new ConnectionVO(connVOs, userId, name);
+ response.addHeader("Authorization", getToken(user));
+ return BaseVO.success("登录成功", connectionVO);
+ }
+
+ @PostMapping("/save")
+ @ApiOperation("创建用户 (未使用)")
+ public BaseVO save(@RequestBody User user) throws BaseException {
+ userService.insert(user);
+ return BaseVO.success("保存成功", null);
+ }
+
+
+ @DeleteMapping("/delete")
+ @ApiOperation("删除用户 (未使用)")
+ public BaseVO delete(@RequestParam("userId") Integer userId, HttpServletRequest request) throws BaseException {
+ AuthenticationUtils.userAuthentication(userId, request);
+ userService.delete(userId);
+ return BaseVO.success("删除成功", null);
+ }
+
+ @GetMapping("/get")
+ @ApiOperation("二次登录获取用户信息")
+ public BaseVO<User> getUser(HttpServletRequest request) {
+ String authorization = request.getHeader("Authorization");
+ DecodedJWT decode = JWT.decode(authorization);
+ User user = new User();
+ if (decode != null) {
+ Integer userId = decode.getClaim("userId").asInt();
+ String name = decode.getClaim("name").asString();
+ user.setId(userId);
+ user.setName(name);
+ }
+ return BaseVO.success("获取成功", user);
+ }
+
+ private String getToken(User user) throws BaseException {
+ Calendar instance = Calendar.getInstance();
+ try {
+ instance.add(Calendar.HOUR, 24);
+ String token = JWT.create()
+ .withClaim("userId", user.getId())
+ .withClaim("name", user.getName())
+ .withExpiresAt(instance.getTime())
+ .sign(Algorithm.HMAC256("IOTDB:" + InetAddress.getLocalHost().getHostAddress()));
+ logger.info(user.getName() + "登录成功");
+ return token;
+ } catch (Exception e) {
+ logger.info(e.getMessage());
+ throw new BaseException(ErrorCode.GET_TOKEN_FAIL, ErrorCode.GET_TOKEN_FAIL_MSG);
+ }
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/demo/JDBC.java b/backend/src/main/java/org/apache/iotdb/admin/demo/JDBC.java
new file mode 100644
index 0000000..3cb100a
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/demo/JDBC.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.demo;
+
+
+import java.sql.*;
+
+/**
+ * JDBC demo代码
+ */
+public class JDBC {
+
+ public static void main(String[] args) throws SQLException {
+ Connection connection = getConnection();
+ if (connection == null) {
+ System.out.println("get connection defeat");
+ return;
+ }
+ Statement statement = connection.createStatement();
+ //创建存储组
+ try {
+ statement.execute("SET STORAGE GROUP TO root.demo");
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ //展示存储组
+ statement.execute("SHOW STORAGE GROUP");
+ outputResult(statement.getResultSet());
+ //创建时间序列
+ //不同的数据类型有不同的编码方式. 这里以INT32作为例子
+ try {
+ statement.execute("CREATE TIMESERIES root.demo.s0 WITH DATATYPE=INT32,ENCODING=RLE;");
+ } catch (SQLException e) {
+ System.out.println(e.getMessage());
+ }
+ //展示时间序列
+ statement.execute("SHOW TIMESERIES root.demo");
+ outputResult(statement.getResultSet());
+ //展示设备
+ statement.execute("SHOW DEVICES");
+ outputResult(statement.getResultSet());
+ //计算时间序列个数
+ statement.execute("COUNT TIMESERIES root");
+ outputResult(statement.getResultSet());
+ //计算给定级别的nodes个数
+ statement.execute("COUNT NODES root LEVEL=3");
+ outputResult(statement.getResultSet());
+ //计算时间序列以级别3分组的个数
+ statement.execute("COUNT TIMESERIES root GROUP BY LEVEL=3");
+ outputResult(statement.getResultSet());
+
+ //批量执行插入语句
+ statement.addBatch("insert into root.demo(timestamp,s0) values(1,1);");
+ statement.addBatch("insert into root.demo(timestamp,s0) values(1,1);");
+ statement.addBatch("insert into root.demo(timestamp,s0) values(2,15);");
+ statement.addBatch("insert into root.demo(timestamp,s0) values(2,17);");
+ statement.addBatch("insert into root.demo(timestamp,s0) values(4,12);");
+ statement.executeBatch();
+ statement.clearBatch();
+
+ //查询语句
+ String sql = "select * from root.demo";
+ ResultSet resultSet = statement.executeQuery(sql);
+ System.out.println("sql: " + sql);
+ outputResult(resultSet);
+
+ //精确的查询语句
+ sql = "select s0 from root.demo where time = 4;";
+ resultSet = statement.executeQuery(sql);
+ System.out.println("sql: " + sql);
+ outputResult(resultSet);
+
+ //时间范围查询
+ sql = "select s0 from root.demo where time >= 2 and time < 5;";
+ resultSet = statement.executeQuery(sql);
+ System.out.println("sql: " + sql);
+ outputResult(resultSet);
+
+ //聚合查询
+ sql = "select count(s0) from root.demo;";
+ resultSet = statement.executeQuery(sql);
+ System.out.println("sql: " + sql);
+ outputResult(resultSet);
+
+ //删除时间序列
+ statement.execute("delete timeseries root.demo.s0");
+
+ //关闭连接
+ statement.close();
+ connection.close();
+ }
+
+
+ public static Connection getConnection() {
+ // JDBC driver name and database URL
+ String driver = "org.apache.iotdb.jdbc.IoTDBDriver";
+ String url = "jdbc:iotdb://127.0.0.1:6667/";
+
+ // Database credentials
+ String username = "root";
+ String password = "root";
+
+ Connection connection = null;
+ try {
+ Class.forName(driver);
+ connection = DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ e.printStackTrace();
+ } catch (SQLException e) {
+ e.printStackTrace();
+ }
+ return connection;
+ }
+
+
+ /**
+ * This is an example of outputting the results in the ResultSet
+ */
+ private static void outputResult(ResultSet resultSet) throws SQLException {
+ if (resultSet != null) {
+ System.out.println("--------------------------");
+ final ResultSetMetaData metaData = resultSet.getMetaData();
+ final int columnCount = metaData.getColumnCount();
+ for (int i = 0; i < columnCount; i++) {
+ System.out.print(metaData.getColumnLabel(i + 1) + " ");
+ }
+ System.out.println();
+ while (resultSet.next()) {
+ for (int i = 1; ; i++) {
+ System.out.print(resultSet.getString(i));
+ if (i < columnCount) {
+ System.out.print(", ");
+ } else {
+ System.out.println();
+ break;
+ }
+ }
+ }
+ System.out.println("--------------------------\n");
+ }
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/demo/NativeAPI.java b/backend/src/main/java/org/apache/iotdb/admin/demo/NativeAPI.java
new file mode 100644
index 0000000..11259c1
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/demo/NativeAPI.java
@@ -0,0 +1,123 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.demo;
+
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+import org.apache.iotdb.session.Session;
+import org.apache.iotdb.session.SessionDataSet;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 原生api demo代码
+ */
+public class NativeAPI {
+
+ public static void main(String[] args) throws IoTDBConnectionException, StatementExecutionException {
+ //建立连接
+ Session session = new Session("localhost", 6667, "root", "root");
+ session.open();
+// SessionPool sessionPool = new SessionPool("localhost", 6667,"root","root",3);
+// sessionPool.insertRecord();
+ //创建存储组
+ session.setStorageGroup("root.fyx");
+ //创建时间序列
+ /**
+ * path:层级路径
+ * TSDataType数据类型:六种 支持编码方式
+ * boolean PLAIN,RLE
+ * int32 PLAIN,RLE,TS_2DIFF,GORILLA
+ * int64 PLAIN,RLE,TS_2DIFF,GORILLA
+ * float PLAIN,RLE,TS_2DIFF,GORILLA
+ * double PLAIN,RLE,TS_2DIFF,GORILLA
+ * text(字符串) PLAIN
+ *
+ * TSEncoding编码方式:
+ * PLAIN编码:不编码 压缩效率高 空间存储效率低
+ * 二阶差分编码(TS_2DIFF):适合单调序列数据 不适合编码波动较大的数据
+ * 游程编码(RLE):比较适合整数值连续出现的序列
+ * GORILLA编码:无损编码,它比较适合编码前后值比较接近的数值序列
+ * 定频数据编码(REGULAR):仅适用于整型 允许数据缺失
+ *
+ * CompressionType压缩方式:
+ * UMCOMPRESSED
+ * SNAPPY
+ * LZ4
+ * GZIP
+ * SDT
+ * PAA
+ * PLA
+ */
+ session.createTimeseries("root.fyx.cq.dev.temp", TSDataType.FLOAT, TSEncoding.RLE, CompressionType.SNAPPY, null, null, null, null);
+ //创建多个时间序列
+// session.createMultiTimeseries();
+ //插入数据
+ List<String> measurements = new ArrayList<>();
+ List<TSDataType> types = new ArrayList<>();
+ measurements.add("temp");
+ types.add(TSDataType.FLOAT);
+ for (long time = 0; time < 10; time++) {
+ List<Object> values = new ArrayList<>();
+ values.add(time * 6.6f);
+ //如果不加type,服务器会做类型推断,会有额外耗时
+ session.insertRecord("root.fyx.cq.dev", time, measurements, types, values);
+ }
+ //执行非查询语句的sql
+ session.executeNonQueryStatement("insert into root.fyx.cq.dev(timestamp,temp) values(now(),66.66)");
+ //执行查询语句的sql
+ SessionDataSet sessionDataSet = session.executeQueryStatement("select * from root.fyx.cq.dev");
+ //数据处理
+ int fetchSize = sessionDataSet.getFetchSize();
+ List<String> columnNames = sessionDataSet.getColumnNames();
+ List<TSDataType> columnTypes = sessionDataSet.getColumnTypes();
+ System.out.println(columnNames);
+ System.out.println(columnTypes);
+ if (fetchSize > 0) {
+ while (sessionDataSet.hasNext()) {
+ RowRecord next = sessionDataSet.next();
+ List<Field> fields = next.getFields();
+ // 查询结果第一个为时间戳
+ long timestamp = next.getTimestamp();
+ System.out.print(timestamp + "\t");
+ for (int i = 0; i < fields.size(); i++) {
+ Field field = fields.get(i);
+ // 这里的需要按照类型获取
+ System.out.print(field.getObjectValue(field.getDataType()));
+ }
+ System.out.println();
+ }
+ }
+ sessionDataSet.closeOperationHandle();
+ //删除时间序列
+ session.deleteTimeseries("root.fyx.cq.dev.temp");
+ //删除存储组
+ session.deleteStorageGroup("root.fyx");
+ session.close();
+ }
+
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/filter/TokenFilter.java b/backend/src/main/java/org/apache/iotdb/admin/filter/TokenFilter.java
new file mode 100644
index 0000000..59be4fa
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/filter/TokenFilter.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.filter;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.JWTVerifier;
+import com.auth0.jwt.algorithms.Algorithm;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.springframework.web.servlet.HandlerInterceptor;
+
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+
+/**
+ * 拦截器
+ */
+public class TokenFilter implements HandlerInterceptor {
+
+ @Override
+ public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws BaseException {
+ JWTVerifier jwtVerifier;
+ try {
+ jwtVerifier = JWT.require(Algorithm.HMAC256("IOTDB:" + InetAddress.getLocalHost().getHostAddress())).build();
+ } catch (UnknownHostException e) {
+ e.printStackTrace();
+ throw new BaseException(ErrorCode.SET_JWT_FAIL, ErrorCode.SET_JWT_FAIL_MSG);
+ }
+ try {
+ String authorization = request.getHeader("Authorization");
+ jwtVerifier.verify(authorization);
+ } catch (Exception e) {
+ e.printStackTrace();
+ throw new BaseException(ErrorCode.TOKEN_ERR, ErrorCode.TOKEN_ERR_MSG);
+ }
+ return true;
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/ConnectionMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/ConnectionMapper.java
new file mode 100644
index 0000000..a9db0bb
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/ConnectionMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface ConnectionMapper extends BaseMapper<Connection> {
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/DeviceMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/DeviceMapper.java
new file mode 100644
index 0000000..b870411
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/DeviceMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.Device;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface DeviceMapper extends BaseMapper<Device> {
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/GroupMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/GroupMapper.java
new file mode 100644
index 0000000..5752ff6
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/GroupMapper.java
@@ -0,0 +1,28 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.StorageGroup;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface GroupMapper extends BaseMapper<StorageGroup> {
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/MeasurementMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/MeasurementMapper.java
new file mode 100644
index 0000000..be3a017
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/MeasurementMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.Measurement;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface MeasurementMapper extends BaseMapper<Measurement> {
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/QueryMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/QueryMapper.java
new file mode 100644
index 0000000..d0c8858
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/QueryMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.Query;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface QueryMapper extends BaseMapper<Query> {
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/mapper/UserMapper.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/UserMapper.java
new file mode 100644
index 0000000..55889c2
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/UserMapper.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.mapper;
+
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.apache.iotdb.admin.model.entity.User;
+import org.springframework.stereotype.Component;
+
+@Component
+public interface UserMapper extends BaseMapper<User> {
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/ConnectionDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/ConnectionDTO.java
new file mode 100644
index 0000000..a87dac6
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/ConnectionDTO.java
@@ -0,0 +1,53 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class ConnectionDTO implements Serializable {
+
+ @NotBlank(message = "主机地址不能为空或为null")
+ @Pattern(regexp = "^((2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3})|(localhost)$", message = "主机号输入不合法")
+ private String host;
+
+ @NotNull(message = "端口号不能为null")
+ @Range(min = 0, max = 65535, message = "端口号输入不合法")
+ private Integer port;
+
+ @NotBlank(message = "用户名不能为空或为null")
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "用户名不能包含空格")
+ private String username;
+
+ @NotBlank(message = "密码不能为空或为null")
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "密码不能包含空格")
+ private String password;
+
+}
+
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
new file mode 100644
index 0000000..c04efa3
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class CountDTO<T> implements Serializable {
+
+ private List<T> objects;
+ private Integer totalCount;
+ private Integer totalPage;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java
new file mode 100644
index 0000000..5050673
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DeviceDTO implements Serializable {
+
+ private String timeseries;
+
+ private String dataType;
+
+ private String encoding;
+
+ private String description;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
new file mode 100644
index 0000000..3733e54
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class DeviceInfoDTO implements Serializable {
+
+ private List<DeviceDTO> deviceDTOList;
+
+ @NotNull(message = "设备名不能为null")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String deviceName;
+
+ private String description;
+
+ private Integer deviceId;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/GroupDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/GroupDTO.java
new file mode 100644
index 0000000..5aa6070
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/GroupDTO.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class GroupDTO implements Serializable {
+
+ @NotNull(message = "存储组名不能为null")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String groupName;
+ private String description;
+ private Long ttl;
+ private String ttlUnit;
+ private Integer groupId;
+
+}
+
+
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBRole.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBRole.java
new file mode 100644
index 0000000..6d2ba60
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBRole.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 传输role信息类
+ */
+@Data
+public class IotDBRole implements Serializable {
+
+ @Length(min = 4, message = "长度必须大于等于4")
+ private String roleName;
+
+ private List<String> privileges;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUser.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUser.java
new file mode 100644
index 0000000..767ad92
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUser.java
@@ -0,0 +1,45 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+/**
+ * 传输User信息类
+ */
+@Data
+public class IotDBUser implements Serializable {
+
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String userName;
+
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String password;
+
+// private List<String> privileges;
+//
+// private List<String> roles;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUserDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUserDTO.java
new file mode 100644
index 0000000..562fc62
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/IotDBUserDTO.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class IotDBUserDTO implements Serializable {
+
+ private List<PrivilegeInfoDTO> privilegesInfos;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/MeasurementDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/MeasurementDTO.java
new file mode 100644
index 0000000..b9e6fc7
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/MeasurementDTO.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MeasurementDTO implements Serializable {
+
+ private String timeseries;
+ private String alias;
+ private String storagegroup;
+ private String dataType;
+ private String encoding;
+ private String compression;
+ private String tags;
+ private String attributes;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/PrivilegeInfoDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/PrivilegeInfoDTO.java
new file mode 100644
index 0000000..69488b6
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/PrivilegeInfoDTO.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class PrivilegeInfoDTO implements Serializable {
+
+ // 0 1 2 3 对应 root、storageGroup、device、timeseries
+ private Integer type;
+ private List<String> groupPaths;
+ private List<String> devicePaths;
+ private List<String> timeseriesPaths;
+ private List<String> privileges;
+ private List<String> cancelPrivileges;
+ private List<String> delGroupPaths;
+ private List<String> delDevicePaths;
+ private List<String> delTimeseriesPaths;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/QueryDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/QueryDTO.java
new file mode 100644
index 0000000..ca8a86a
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/QueryDTO.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class QueryDTO implements Serializable {
+
+
+ @NotNull(message = "未指定脚本名")
+ private String queryName;
+
+ private String sqls;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
new file mode 100644
index 0000000..4d0c8ba
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class SearchDTO implements Serializable {
+
+ private List<String> sqls;
+
+ @NotNull(message = "不能为null")
+ private Long timestamp;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/Timeseries.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/Timeseries.java
new file mode 100644
index 0000000..ecf72cf
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/Timeseries.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.dto;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * 传输时间序列信息的类
+ */
+@Data
+public class Timeseries implements Serializable {
+
+ private List<String> measurements = new ArrayList<>();
+
+ private List<String> types = new ArrayList<>();
+
+ private long time;
+
+ private List<String> values;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/Connection.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Connection.java
new file mode 100644
index 0000000..6672db9
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Connection.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+import org.hibernate.validator.constraints.Range;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class Connection implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotBlank(message = "主机地址不能为空或为null")
+ @Pattern(regexp = "^((2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})(\\.(2(5[0-5]{1}|[0-4]\\d{1})|[0-1]?\\d{1,2})){3})|(localhost)$", message = "主机号输入不合法")
+ private String host;
+
+ @NotNull(message = "端口号不能为null")
+ @Range(min = 0, max = 65535, message = "端口号输入不合法")
+ private Integer port;
+
+ @NotBlank(message = "用户名不能为空或为null")
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "用户名不能包含空格")
+ private String username;
+
+ @NotBlank(message = "密码不能为空或为null")
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "密码不能包含空格")
+ private String password;
+
+ @NotBlank(message = "连接名不能为空或为null")
+ @Length(min = 3, max = 100, message = "连接名长度必须在3-100之间")
+ @Pattern(regexp = "^[^ ]+$", message = "连接名不能包含空格")
+ private String alias;
+
+ @NotNull(message = "用户id不能为null")
+ private Integer userId;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/Device.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Device.java
new file mode 100644
index 0000000..8d0abc4
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Device.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class Device implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotNull(message = "未指定所属主机")
+ private String host;
+
+ private String description;
+
+ @NotBlank
+ @Length(min = 4, message = "创建者名长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "创建者名不能包含空格")
+ private String creator;
+
+ @NotNull(message = "未指定创建时间")
+ private Long createTime;
+
+ @NotBlank
+ @Pattern(regexp = "^[^ ]+$", message = "设备名不能包含空格")
+ private String deviceName;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/Measurement.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Measurement.java
new file mode 100644
index 0000000..c6178a6
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Measurement.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class Measurement implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotNull(message = "未指定所属主机")
+ private String host;
+
+ @NotNull(message = "未指定测点名")
+ private String measurementName;
+
+ private String description;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/Query.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Query.java
new file mode 100644
index 0000000..0d98620
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Query.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+
+import javax.validation.constraints.NotNull;
+import java.io.Serializable;
+
+@Data
+public class Query implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotNull(message = "未指定所属连接id")
+ private Integer connectionId;
+
+ @NotNull(message = "未指定脚本名")
+ private String queryName;
+
+ private String sqls;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/StorageGroup.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/StorageGroup.java
new file mode 100644
index 0000000..51e9e0e
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/StorageGroup.java
@@ -0,0 +1,54 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class StorageGroup implements Serializable {
+
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotNull(message = "未指定所属主机")
+ private String host;
+
+ private String description;
+
+ @NotBlank
+ @Length(min = 4, message = "创建者名长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "创建者名不能包含空格")
+ private String creator;
+
+ @NotNull(message = "未指定创建时间")
+ private Long createTime;
+
+ @NotBlank
+ private String groupName;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/entity/User.java b/backend/src/main/java/org/apache/iotdb/admin/model/entity/User.java
new file mode 100644
index 0000000..9df52b7
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/User.java
@@ -0,0 +1,49 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.entity;
+
+import com.baomidou.mybatisplus.annotation.IdType;
+import com.baomidou.mybatisplus.annotation.TableId;
+import lombok.Data;
+import org.hibernate.validator.constraints.Length;
+
+import javax.validation.constraints.NotBlank;
+import javax.validation.constraints.Null;
+import javax.validation.constraints.Pattern;
+import java.io.Serializable;
+
+@Data
+public class User implements Serializable {
+
+ @Null
+ @TableId(type = IdType.AUTO)
+ private Integer id;
+
+ @NotBlank
+ @Length(min = 4, message = "长度必须大于等于4")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String name;
+
+ @NotBlank
+ @Length(min = 6, message = "长度必须大于等于6")
+ @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+ private String password;
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/BaseVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/BaseVO.java
new file mode 100644
index 0000000..07f1179
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/BaseVO.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+/**
+ * 返回信息类
+ */
+@Data
+public class BaseVO<T> {
+
+ /**
+ * 0 表示成功 其他表示错误类型
+ */
+ private String code;
+
+ /**
+ * 定义出错时候用户可读的信息
+ */
+ private String message;
+
+ /**
+ * 这是一个返回数据的通用类型模板
+ */
+ private T data;
+
+ public BaseVO() {
+ }
+
+ public BaseVO(String code, String message, T data) {
+ this.code = code;
+ this.message = message;
+ this.data = data;
+ }
+
+ public static <T> BaseVO<T> success(String message, T data) {
+ return new BaseVO<>("0", message, data);
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnVO.java
new file mode 100644
index 0000000..da2e511
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnVO.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+
+/**
+ * 展示别名及serverId
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ConnVO implements Serializable {
+
+ private Integer id;
+ private String alias;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnectionVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnectionVO.java
new file mode 100644
index 0000000..dbc50ce
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/ConnectionVO.java
@@ -0,0 +1,40 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * 展示用户的连接列表
+ */
+@Data
+@AllArgsConstructor
+@NoArgsConstructor
+public class ConnectionVO implements Serializable {
+
+ List<ConnVO> aliasList;
+ Integer userId;
+ String name;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfo.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfo.java
new file mode 100644
index 0000000..60a5a21
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfo.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DeviceInfo implements Serializable {
+
+ private String deviceName;
+ private String description;
+ private String creator;
+ private Integer line;
+ private Integer deviceId;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfoVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfoVO.java
new file mode 100644
index 0000000..88f47bd
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceInfoVO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class DeviceInfoVO implements Serializable {
+
+ private List<DeviceInfo> deviceInfos;
+ private Integer totalCount;
+ private Integer totalPage;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
new file mode 100644
index 0000000..de0fec7
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class DeviceVO implements Serializable {
+
+ private String description;
+ private String creator;
+ private String time;
+ private Integer deviceId;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupInfoVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupInfoVO.java
new file mode 100644
index 0000000..5a3b320
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupInfoVO.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.AllArgsConstructor;
+import lombok.Data;
+import lombok.NoArgsConstructor;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+@NoArgsConstructor
+@AllArgsConstructor
+public class GroupInfoVO implements Serializable {
+
+ private String groupName;
+ private Integer deviceCount;
+ private String description;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupVO.java
new file mode 100644
index 0000000..efbf29c
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupVO.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class GroupVO implements Serializable {
+
+ private String groupName;
+ private String alias;
+ private String description;
+ private String creator;
+ private String createTime;
+ private String ttl;
+ private String ttiUnit;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/IotDBUserVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/IotDBUserVO.java
new file mode 100644
index 0000000..f5976ad
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/IotDBUserVO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class IotDBUserVO implements Serializable {
+
+ private String userName;
+ private String password;
+ private List<PrivilegeInfo> privilegesInfo;
+// private List<RoleWithPrivilegesVO> roleWithPrivileges;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasurementVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasurementVO.java
new file mode 100644
index 0000000..3e7574d
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasurementVO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class MeasurementVO implements Serializable {
+
+ private String timeseries;
+ private String dataType;
+ private String encoding;
+ private String description;
+ private String newValue;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
new file mode 100644
index 0000000..35334dc
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class MeasuremtnInfoVO implements Serializable {
+
+ private List<MeasurementVO> measurementVOList;
+ private Integer totalCount;
+ private Integer totalPage;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/PathVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/PathVO.java
new file mode 100644
index 0000000..0c9884e
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/PathVO.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class PathVO implements Serializable {
+
+ private String groupName;
+ private String deviceName;
+ private String timeseriesName;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/PrivilegeInfo.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/PrivilegeInfo.java
new file mode 100644
index 0000000..f1fc85a
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/PrivilegeInfo.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+@Data
+public class PrivilegeInfo implements Serializable {
+
+ // 0 1 2 3 对应 root、storageGroup、device、timeseries
+ private Integer type;
+ private List<String> groupPaths;
+ private List<String> devicePaths;
+ private List<String> timeseriesPaths;
+ private List<String> privileges;
+ private List<String> allTimeseriesPaths;
+ private List<String> allDevicePaths;
+ private List<String> allGroupPaths;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/QueryVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/QueryVO.java
new file mode 100644
index 0000000..51d6ddc
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/QueryVO.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class QueryVO implements Serializable {
+
+ private Integer id;
+ private String queryName;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/RecordVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/RecordVO.java
new file mode 100644
index 0000000..6b34ee1
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/RecordVO.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.Date;
+import java.util.List;
+
+@Data
+public class RecordVO implements Serializable {
+
+ private List<Date> timeList;
+ private List<Long> valueList;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/RoleWithPrivilegesVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/RoleWithPrivilegesVO.java
new file mode 100644
index 0000000..21ecfd7
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/RoleWithPrivilegesVO.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+/**
+ * 角色及其对应权限
+ */
+@Data
+public class RoleWithPrivilegesVO implements Serializable {
+
+ private String role;
+ private String privilege;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/SqlResultVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/SqlResultVO.java
new file mode 100644
index 0000000..c810248
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/SqlResultVO.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+import java.util.List;
+
+/**
+ * sql查询的元数据列表和数据列表
+ */
+@Data
+public class SqlResultVO implements Serializable {
+
+ private List<String> metaDataList;
+ private List<List<String>> valueList;
+ private String queryTime;
+ private Long line;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/StorageGroupVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/StorageGroupVO.java
new file mode 100644
index 0000000..f6876a6
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/StorageGroupVO.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.model.vo;
+
+import lombok.Data;
+
+import java.io.Serializable;
+
+@Data
+public class StorageGroupVO implements Serializable {
+
+ private String groupName;
+ private Integer groupId;
+}
\ No newline at end of file
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/ConnectionService.java b/backend/src/main/java/org/apache/iotdb/admin/service/ConnectionService.java
new file mode 100644
index 0000000..5b63a64
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/ConnectionService.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.vo.ConnVO;
+
+import java.util.List;
+
+public interface ConnectionService {
+
+ List<ConnVO> getAllConnections(Integer id);
+
+ void insert(Connection connection) throws BaseException;
+
+ void deleteById(Integer serverId, Integer userId) throws BaseException;
+
+ Connection getById(Integer serverId) throws BaseException;
+
+ void check(Integer serverId, Integer userId) throws BaseException;
+
+ void update(Connection connection) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/DeviceService.java b/backend/src/main/java/org/apache/iotdb/admin/service/DeviceService.java
new file mode 100644
index 0000000..5d9d202
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/DeviceService.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.dto.DeviceInfoDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.Device;
+import org.apache.iotdb.admin.model.vo.DeviceVO;
+
+import java.util.List;
+
+public interface DeviceService {
+
+ List<Device> getDevices(String host, List<String> deviceNames);
+
+ void deleteDeviceInfo(String host, String groupName) throws BaseException;
+
+ void deleteDeviceInfoByDeviceName(String host, String deviceName) throws BaseException;
+
+ void setDeviceInfo(Connection connection, DeviceInfoDTO deviceInfoDTO) throws BaseException;
+
+ DeviceVO getDevice(String host, String deviceName);
+
+ void updateDeviceInfo(DeviceInfoDTO deviceInfoDTO) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/GroupService.java b/backend/src/main/java/org/apache/iotdb/admin/service/GroupService.java
new file mode 100644
index 0000000..1155d55
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/GroupService.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.dto.GroupDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.StorageGroup;
+
+import java.util.List;
+
+public interface GroupService {
+
+ List<String> getGroupDescription(String host, List<String> groupNames) throws BaseException;
+
+ void setStorageGroupInfo(Connection connection, GroupDTO groupDTO) throws BaseException;
+
+ boolean isExist(String host, String groupName);
+
+ void deleteGroupInfo(String host, String groupName) throws BaseException;
+
+ StorageGroup getGroupInfo(String host, String groupName);
+
+ void updateStorageGroupInfo(Connection connection, GroupDTO groupDTO) throws BaseException;
+
+ Integer getGroupId(String host, String groupName);
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/IotDBService.java b/backend/src/main/java/org/apache/iotdb/admin/service/IotDBService.java
new file mode 100644
index 0000000..82c15a3
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/IotDBService.java
@@ -0,0 +1,96 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.dto.*;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.vo.IotDBUserVO;
+import org.apache.iotdb.admin.model.vo.RecordVO;
+import org.apache.iotdb.admin.model.vo.SqlResultVO;
+
+import java.util.List;
+
+public interface IotDBService {
+
+ List<String> getAllStorageGroups(Connection connection) throws BaseException;
+
+ void saveStorageGroup(Connection connection, String groupName) throws BaseException;
+
+ void deleteStorageGroup(Connection connection, String groupName) throws BaseException;
+
+ CountDTO getDevicesByGroup(Connection connection, String groupName, Integer pageSize, Integer pageNum, String keyword) throws BaseException;
+
+ CountDTO getMeasurementsByDevice(Connection connection, String deviceName, Integer pageSize, Integer pageNum, String keyword) throws BaseException;
+
+ List<String> getIotDBUserList(Connection connection) throws BaseException;
+
+ List<String> getIotDBRoleList(Connection connection) throws BaseException;
+
+ IotDBUserVO getIotDBUser(Connection connection, String userName) throws BaseException;
+
+ void deleteIotDBUser(Connection connection, String userName) throws BaseException;
+
+ void deleteIotDBRole(Connection connection, String roleName) throws BaseException;
+
+ void setIotDBUser(Connection connection, IotDBUser iotDBUserVO) throws BaseException;
+
+ void setIotDBRole(Connection connection, IotDBRole iotDBRole) throws BaseException;
+
+ void insertTimeseries(Connection connection, String deviceName, Timeseries timeseries) throws BaseException;
+
+ void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException;
+
+ SqlResultVO showTimeseries(Connection connection, String deviceName) throws BaseException;
+
+ List<Integer> getDevicesCount(Connection connection, List<String> groupNames) throws BaseException;
+
+ void saveGroupTtl(Connection connection, String groupName, long l) throws BaseException;
+
+ void cancelGroupTtl(Connection connection, String groupName) throws BaseException;
+
+ Integer getDeviceCount(Connection connection, String groupName) throws BaseException;
+
+ List<Integer> getTimeseriesCount(Connection connection, List<String> deviceNames) throws BaseException;
+
+ void deleteTimeseriesByDevice(Connection connection, String deviceName) throws BaseException;
+
+ void createDeviceWithMeasurements(Connection connection, DeviceInfoDTO deviceInfoDTO) throws BaseException;
+
+ Integer getMeasurementsCount(Connection connection, String deviceName) throws BaseException;
+
+ String getLastMeasurementValue(Connection connection, String timeseries) throws BaseException;
+
+ String getGroupTTL(Connection connection, String groupName) throws BaseException;
+
+ List<String> getDevices(Connection connection, String groupName) throws BaseException;
+
+ List<String> getTimeseries(Connection connection, String deviceName) throws BaseException;
+
+ void setUserPrivileges(Connection connection, String userName, PrivilegeInfoDTO privilegeInfoDTO) throws BaseException;
+
+ RecordVO getRecords(Connection connection, String deviceName, String timeseriesName) throws BaseException;
+
+ List<SqlResultVO> queryAll(Connection connection, List<String> sqls, Long timestamp) throws BaseException;
+
+ void updatePwd(Connection connection, IotDBUser iotDBUser) throws BaseException;
+
+ void stopQuery(Integer serverId, Long timestamp) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/MeasurementService.java b/backend/src/main/java/org/apache/iotdb/admin/service/MeasurementService.java
new file mode 100644
index 0000000..64240db
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/MeasurementService.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.dto.DeviceInfoDTO;
+
+public interface MeasurementService {
+
+ void deleteMeasurementInfo(String host, String groupName) throws BaseException;
+
+ void deleteMeasurementInfoByDeviceName(String host, String deviceName) throws BaseException;
+
+ void setMeasurementsInfo(String host, DeviceInfoDTO deviceInfoDTO) throws BaseException;
+
+ String getDescription(String host, String timeseries) throws BaseException;
+
+ void updateMeasurementsInfo(String host, DeviceInfoDTO deviceInfoDTO) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/QueryService.java b/backend/src/main/java/org/apache/iotdb/admin/service/QueryService.java
new file mode 100644
index 0000000..613966f
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/QueryService.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.entity.Query;
+import org.apache.iotdb.admin.model.vo.QueryVO;
+
+import java.util.List;
+
+public interface QueryService {
+
+ void save(Integer serverId, Query query) throws BaseException;
+
+ void update(Integer serverId, Query query) throws BaseException;
+
+ List<QueryVO> getQueryList(Integer serverId);
+
+ void deleteQuery(Integer queryId) throws BaseException;
+
+ Query getQuery(Integer queryId) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java b/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
new file mode 100644
index 0000000..d263646
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.model.entity.User;
+
+public interface UserService {
+
+ User login(String name, String password) throws BaseException;
+
+ void insert(User user) throws BaseException;
+
+ void delete(Integer userId) throws BaseException;
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/ConnectionServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/ConnectionServiceImpl.java
new file mode 100644
index 0000000..40dedbc
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/ConnectionServiceImpl.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.ConnectionMapper;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.vo.ConnVO;
+import org.apache.iotdb.admin.service.ConnectionService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class ConnectionServiceImpl extends ServiceImpl<ConnectionMapper, Connection> implements ConnectionService {
+
+ @Autowired
+ private ConnectionMapper connectionMapper;
+
+ @Override
+ public List<ConnVO> getAllConnections(Integer userId) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("user_id", userId);
+ List<Connection> connections = connectionMapper.selectList(queryWrapper);
+ List<ConnVO> ConnVOs = new ArrayList();
+ for (Connection connection : connections) {
+ ConnVOs.add(new ConnVO(connection.getId(), connection.getAlias()));
+ }
+ return ConnVOs;
+ }
+
+ @Override
+ public void insert(Connection connection) throws BaseException {
+ String alias = connection.getAlias();
+ Integer userId = connection.getUserId();
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("user_id", userId);
+ queryWrapper.eq("alias", alias);
+ Connection existConnection = connectionMapper.selectOne(queryWrapper);
+ // 别名唯一
+ if (existConnection != null) {
+ throw new BaseException(ErrorCode.ALIAS_REPEAT, ErrorCode.ALIAS_REPEAT_MSG);
+ }
+ if ("127.0.0.1".equals(connection.getHost())) {
+ connection.setHost("localhost");
+ }
+ int flag = connectionMapper.insert(connection);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.INSERT_CONN_FAIL, ErrorCode.INSERT_CONN_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void deleteById(Integer serverId, Integer userId) throws BaseException {
+ try {
+ connectionMapper.deleteById(serverId);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_CONN_FAIL, ErrorCode.DELETE_CONN_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public Connection getById(Integer serverId) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", serverId);
+ try {
+ Connection connection = connectionMapper.selectOne(queryWrapper);
+ if (connection == null) {
+ throw new BaseException(ErrorCode.NO_CONN, ErrorCode.NO_CONN_MSG);
+ }
+ return connection;
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.GET_CONN_FAIL, ErrorCode.GET_CONN_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void check(Integer serverId, Integer userId) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", serverId);
+ queryWrapper.eq("user_id", userId);
+ Connection connection = connectionMapper.selectOne(queryWrapper);
+ if (connection == null) {
+ throw new BaseException(ErrorCode.CHECK_FAIL, ErrorCode.CHECK_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void update(Connection connection) throws BaseException {
+ String alias = connection.getAlias();
+ Integer userId = connection.getUserId();
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("user_id", userId);
+ queryWrapper.eq("alias", alias);
+ Connection existConnection = connectionMapper.selectOne(queryWrapper);
+ // 别名唯一
+ if (existConnection != null && !connection.getId().equals(existConnection.getId())) {
+ throw new BaseException(ErrorCode.ALIAS_REPEAT, ErrorCode.ALIAS_REPEAT_MSG);
+ }
+ int flag = connectionMapper.updateById(connection);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.INSERT_CONN_FAIL, ErrorCode.INSERT_CONN_FAIL_MSG);
+ }
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/DeviceServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/DeviceServiceImpl.java
new file mode 100644
index 0000000..d507d91
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/DeviceServiceImpl.java
@@ -0,0 +1,144 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.DeviceMapper;
+import org.apache.iotdb.admin.model.dto.DeviceInfoDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.Device;
+import org.apache.iotdb.admin.model.vo.DeviceVO;
+import org.apache.iotdb.admin.service.DeviceService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.text.SimpleDateFormat;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+
+@Service
+public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> implements DeviceService {
+
+
+ @Autowired
+ private DeviceMapper deviceMapper;
+
+ @Override
+ public List<Device> getDevices(String host, List<String> deviceNames) {
+ List<Device> devices = new ArrayList<>();
+ for (String deviceName : deviceNames) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("device_name", deviceName);
+ Device device = deviceMapper.selectOne(queryWrapper);
+ devices.add(device);
+ }
+ return devices;
+ }
+
+ @Override
+ public void deleteDeviceInfo(String host, String groupName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.like("device_name", groupName);
+ try {
+ deviceMapper.delete(queryWrapper);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_DEVICE_INFO_FAIL, ErrorCode.DELETE_DEVICE_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void deleteDeviceInfoByDeviceName(String host, String deviceName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("device_name", deviceName);
+ try {
+ deviceMapper.delete(queryWrapper);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_DEVICE_INFO_FAIL, ErrorCode.DELETE_DEVICE_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void setDeviceInfo(Connection connection, DeviceInfoDTO deviceInfoDTO) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", connection.getHost());
+ queryWrapper.eq("device_name", deviceInfoDTO.getDeviceName());
+ Device existDevice = deviceMapper.selectOne(queryWrapper);
+ if (existDevice == null) {
+ Device device = new Device();
+ device.setCreator(connection.getUsername());
+ device.setDeviceName(deviceInfoDTO.getDeviceName());
+ device.setCreateTime(System.currentTimeMillis());
+ device.setHost(connection.getHost());
+ device.setDescription(deviceInfoDTO.getDescription());
+ int flag = deviceMapper.insert(device);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.SET_DEVICE_INFO_FAIL, ErrorCode.SET_DEVICE_INFO_FAIL_MSG);
+ }
+ return;
+ }
+ existDevice.setDescription(deviceInfoDTO.getDescription());
+ int flag = deviceMapper.updateById(existDevice);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.SET_DEVICE_INFO_FAIL, ErrorCode.SET_DEVICE_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public DeviceVO getDevice(String host, String deviceName) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("device_name", deviceName);
+ Device device = deviceMapper.selectOne(queryWrapper);
+ // 非系统创建的设备没有设备信息
+ DeviceVO deviceVO = new DeviceVO();
+ if (device != null) {
+ deviceVO.setCreator(device.getCreator());
+ deviceVO.setDescription(device.getDescription());
+ deviceVO.setDeviceId(device.getId());
+ Long createTime = device.getCreateTime();
+ Date date = new Date(createTime);
+ SimpleDateFormat sdf = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ String time = sdf.format(date);
+ deviceVO.setTime(time);
+ return deviceVO;
+ }
+ return deviceVO;
+ }
+
+ @Override
+ public void updateDeviceInfo(DeviceInfoDTO deviceInfoDTO) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", deviceInfoDTO.getDeviceId());
+ Device existDevice = deviceMapper.selectOne(queryWrapper);
+ if (existDevice != null) {
+ existDevice.setDescription(deviceInfoDTO.getDescription());
+ deviceMapper.updateById(existDevice);
+ return;
+ }
+ throw new BaseException(ErrorCode.NO_DEVICE_INFO, ErrorCode.NO_DEVICE_INFO_MSG);
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/GroupServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/GroupServiceImpl.java
new file mode 100644
index 0000000..7ae2122
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/GroupServiceImpl.java
@@ -0,0 +1,157 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.GroupMapper;
+import org.apache.iotdb.admin.model.dto.GroupDTO;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.entity.StorageGroup;
+import org.apache.iotdb.admin.service.GroupService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class GroupServiceImpl extends ServiceImpl<GroupMapper, StorageGroup> implements GroupService {
+
+
+ @Autowired
+ private GroupMapper groupMapper;
+
+ @Override
+ public List<String> getGroupDescription(String host, List<String> groupNames) throws BaseException {
+ List<String> descriptions = new ArrayList<>();
+ for (String groupName : groupNames) {
+ descriptions.add(getDescription(host, groupName));
+ }
+ return descriptions;
+ }
+
+ @Override
+ public void setStorageGroupInfo(Connection connection, GroupDTO groupDTO) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ String host = connection.getHost();
+ String groupName = groupDTO.getGroupName();
+ String description = groupDTO.getDescription();
+ if ("127.0.0.1".equals(host)) {
+ host = "localhost";
+ }
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ StorageGroup storageGroup = groupMapper.selectOne(queryWrapper);
+ if (storageGroup != null) {
+ storageGroup.setDescription(description);
+ int flag = groupMapper.updateById(storageGroup);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.INSERT_GROUP_INFO_FAIL, ErrorCode.INSERT_GROUP_INFO_FAIL_MSG);
+ }
+ return;
+ }
+ String username = connection.getUsername();
+ StorageGroup group = new StorageGroup();
+ group.setCreateTime(System.currentTimeMillis());
+ group.setCreator(username);
+ group.setGroupName(groupName);
+ group.setDescription(description);
+ group.setHost(host);
+ int flag = groupMapper.insert(group);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.INSERT_GROUP_INFO_FAIL, ErrorCode.INSERT_GROUP_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public boolean isExist(String host, String groupName) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ StorageGroup group = groupMapper.selectOne(queryWrapper);
+ if (group != null) {
+ return true;
+ }
+ return false;
+ }
+
+ @Override
+ public void deleteGroupInfo(String host, String groupName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ try {
+ groupMapper.delete(queryWrapper);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_GROUP_INFO_FAIL, ErrorCode.DELETE_GROUP_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public StorageGroup getGroupInfo(String host, String groupName) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ return groupMapper.selectOne(queryWrapper);
+ }
+
+ @Override
+ public void updateStorageGroupInfo(Connection connection, GroupDTO groupDTO) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", connection.getHost());
+ queryWrapper.eq("group_name", groupDTO.getGroupName());
+ StorageGroup storageGroup = groupMapper.selectOne(queryWrapper);
+ if (storageGroup != null) {
+ storageGroup.setDescription(groupDTO.getDescription());
+ int flag = groupMapper.updateById(storageGroup);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.UPDATE_GROUP_INFO_FAIL, ErrorCode.UPDATE_GROUP_INFO_FAIL_MSG);
+ }
+ return;
+ }
+ throw new BaseException(ErrorCode.NO_GROUP_INFO, ErrorCode.NO_GROUP_INFO_MSG);
+ }
+
+ @Override
+ public Integer getGroupId(String host, String groupName) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ StorageGroup group = groupMapper.selectOne(queryWrapper);
+ if (group != null) {
+ return group.getId();
+ }
+ return null;
+ }
+
+ private String getDescription(String host, String groupName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("group_name", groupName);
+ StorageGroup storageGroup = groupMapper.selectOne(queryWrapper);
+ if (storageGroup != null) {
+ return storageGroup.getDescription();
+ }
+ return null;
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/IotDBServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/IotDBServiceImpl.java
new file mode 100644
index 0000000..5a69eac
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/IotDBServiceImpl.java
@@ -0,0 +1,1857 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.model.dto.*;
+import org.apache.iotdb.admin.model.entity.Connection;
+import org.apache.iotdb.admin.model.vo.*;
+import org.apache.iotdb.admin.service.IotDBService;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+import org.apache.iotdb.session.pool.SessionDataSetWrapper;
+import org.apache.iotdb.session.pool.SessionPool;
+import org.apache.iotdb.tsfile.file.metadata.enums.CompressionType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSDataType;
+import org.apache.iotdb.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.stereotype.Service;
+
+import java.lang.reflect.Field;
+import java.sql.*;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+import java.util.*;
+import java.util.concurrent.*;
+
+@Service
+public class IotDBServiceImpl implements IotDBService {
+
+ private static final Logger logger = LoggerFactory.getLogger(IotDBServiceImpl.class);
+
+ private static final HashMap<String, Boolean> SPECIAL_PRIVILEGES = new HashMap();
+
+ private static final String NO_NEED_PRIVILEGES = "SET_STORAGE_GROUP";
+
+ private static final List<String> PRIVILEGES = new ArrayList<>();
+
+ private static final HashMap<String, Boolean> QUERY_STOP = new HashMap<>();
+
+ static {
+ SPECIAL_PRIVILEGES.put("CREATE_TIMESERIES", true);
+ SPECIAL_PRIVILEGES.put("INSERT_TIMESERIES", true);
+ SPECIAL_PRIVILEGES.put("READ_TIMESERIES", true);
+ SPECIAL_PRIVILEGES.put("DELETE_TIMESERIES", true);
+ }
+
+ static {
+ PRIVILEGES.add("SET_STORAGE_GROUP");
+ PRIVILEGES.add("CREATE_TIMESERIES");
+ PRIVILEGES.add("INSERT_TIMESERIES");
+ PRIVILEGES.add("READ_TIMESERIES");
+ PRIVILEGES.add("DELETE_TIMESERIES");
+ PRIVILEGES.add("CREATE_USER");
+ PRIVILEGES.add("DELETE_USER");
+ PRIVILEGES.add("MODIFY_PASSWORD");
+ PRIVILEGES.add("LIST_USER");
+ PRIVILEGES.add("GRANT_USER_PRIVILEGE");
+ PRIVILEGES.add("REVOKE_USER_PRIVILEGE");
+ PRIVILEGES.add("CREATE_FUNCTION");
+ PRIVILEGES.add("DROP_FUNCTION");
+ PRIVILEGES.add("CREATE_TRIGGER");
+ PRIVILEGES.add("DROP_TRIGGER");
+ PRIVILEGES.add("START_TRIGGER");
+ PRIVILEGES.add("STOP_TRIGGER");
+ }
+
+
+ @Override
+ public List<String> getAllStorageGroups(Connection connection) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show storage group";
+ List<String> users = executeQueryOneColumn(sessionPool, sql);
+ sessionPool.close();
+ return users;
+ }
+
+ @Override
+ public void saveStorageGroup(Connection connection, String groupName) throws BaseException {
+ paramValid(groupName);
+ SessionPool sessionPool = getSessionPool(connection);
+ try {
+ sessionPool.setStorageGroup(groupName);
+ } catch (StatementExecutionException e) {
+ // 300为存储组重复或者其前/后路径上已经有存储组了
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_SET_GROUP, ErrorCode.NO_PRI_SET_GROUP_MSG);
+ }
+ if (e.getStatusCode() == 300) {
+ throw new BaseException(ErrorCode.SET_GROUP_FAIL, ErrorCode.SET_GROUP_FAIL_MSG);
+ }
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_GROUP_FAIL, ErrorCode.SET_GROUP_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public void deleteStorageGroup(Connection connection, String groupName) throws BaseException {
+ paramValid(groupName);
+ SessionPool sessionPool = getSessionPool(connection);
+ try {
+ sessionPool.deleteStorageGroup(groupName);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_DELETE_GROUP, ErrorCode.NO_PRI_DELETE_GROUP_MSG);
+ }
+ throw new BaseException(ErrorCode.DELETE_GROUP_FAIL, ErrorCode.DELETE_GROUP_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_GROUP_FAIL, ErrorCode.DELETE_GROUP_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public CountDTO getDevicesByGroup(Connection connection, String groupName, Integer pageSize, Integer pageNum, String keyword) throws BaseException {
+ paramValid(groupName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show devices " + groupName;
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ List<String> values = new ArrayList<>();
+ int count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ if (keyword != null || "".equals(keyword)) {
+ String deviceName = fields.get(0).toString();
+ deviceName = StringUtils.removeStart(deviceName, groupName + ".");
+ if (deviceName.contains(keyword)) {
+ count++;
+ } else {
+ continue;
+ }
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ values.add(fields.get(0).toString());
+ }
+ } else {
+ count++;
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ values.add(fields.get(0).toString());
+ }
+ }
+ }
+ }
+ CountDTO countDTO = new CountDTO();
+ countDTO.setObjects(values);
+ countDTO.setTotalCount(count);
+ Integer totalPage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
+ countDTO.setTotalPage(totalPage);
+ return countDTO;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public CountDTO getMeasurementsByDevice(Connection connection, String deviceName, Integer pageSize, Integer pageNum, String keyword) throws BaseException {
+ paramValid(deviceName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show timeseries " + deviceName;
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ List<MeasurementDTO> results = new ArrayList<>();
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ int count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ if (keyword != null || "".equals(keyword)) {
+ String measurementName = fields.get(0).toString();
+ measurementName = StringUtils.removeStart(measurementName, deviceName + ".");
+ if (measurementName.contains(keyword)) {
+ count++;
+ } else {
+ continue;
+ }
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ MeasurementDTO t = new MeasurementDTO();
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ for (int i = 0; i < fields.size(); i++) {
+ Field field = MeasurementDTO.class.getDeclaredField(columnNames.get(i).replaceAll(" ", ""));
+ field.setAccessible(true);
+ field.set(t, fields.get(i).toString());
+ }
+ results.add(t);
+ }
+ } else {
+ count++;
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ MeasurementDTO t = new MeasurementDTO();
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ for (int i = 0; i < fields.size(); i++) {
+ Field field = MeasurementDTO.class.getDeclaredField(columnNames.get(i).replaceAll(" ", ""));
+ field.setAccessible(true);
+ field.set(t, fields.get(i).toString());
+ }
+ results.add(t);
+ }
+ }
+ }
+ }
+ CountDTO countDTO = new CountDTO();
+ countDTO.setObjects(results);
+ countDTO.setTotalCount(count);
+ Integer totalPage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
+ countDTO.setTotalPage(totalPage);
+ return countDTO;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ }
+
+ @Override
+ public List<String> getIotDBUserList(Connection connection) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "list user";
+ List<String> users = executeQueryOneColumn(sessionPool, sql);
+ sessionPool.close();
+ return users;
+ }
+
+ @Override
+ public List<String> getIotDBRoleList(Connection connection) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "list role";
+ List<String> roles = executeQueryOneColumn(sessionPool, sql);
+ sessionPool.close();
+ return roles;
+ }
+
+ @Override
+ public IotDBUserVO getIotDBUser(Connection connection, String userName) throws BaseException {
+ paramValid(userName);
+ IotDBUserVO iotDBUserVO = new IotDBUserVO();
+ iotDBUserVO.setUserName(userName);
+ if (userName.equals(connection.getUsername())) {
+ iotDBUserVO.setPassword(connection.getPassword());
+ } else {
+ iotDBUserVO.setPassword(null);
+ }
+ if ("root".equalsIgnoreCase(userName)) {
+ List<PrivilegeInfo> privilegeInfos = new ArrayList<>();
+ PrivilegeInfo privilegeInfo = new PrivilegeInfo();
+ privilegeInfo.setType(0);
+ privilegeInfo.setPrivileges(PRIVILEGES);
+ privilegeInfos.add(privilegeInfo);
+ iotDBUserVO.setPrivilegesInfo(privilegeInfos);
+ return iotDBUserVO;
+ }
+ SessionPool sessionpool = getSessionPool(connection);
+ String sql = "list user privileges " + userName;
+ try {
+ SessionDataSetWrapper sessionDataSetWrapper = sessionpool.executeQueryStatement(sql);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ if (batchSize > 0) {
+ List<String> privileges = new ArrayList<>();
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord next = sessionDataSetWrapper.next();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = next.getFields();
+ for (int i = 0; i < fields.size(); i++) {
+ org.apache.iotdb.tsfile.read.common.Field field = fields.get(i);
+ if (i == 0) {
+ if (field != null && field.toString().length() > 0) {
+ break;
+ }
+ continue;
+ }
+ privileges.add(field.toString());
+ }
+ }
+ // privileges String内容形式 "path : 权限1 权限2 权限3"
+ // 组装成权限信息集合
+ List<PrivilegeInfo> privilegeInfos = new ArrayList<>();
+ if (privileges != null && privileges.size() > 0) {
+ privilegeInfos = privilegesStrSwitchToObject(sessionpool, privileges);
+ }
+ iotDBUserVO.setPrivilegesInfo(privilegeInfos);
+ }
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.GET_USER_FAIL, ErrorCode.GET_USER_FAIL_MSG);
+ } finally {
+ if (sessionpool != null) {
+ sessionpool.close();
+ }
+ }
+ return iotDBUserVO;
+ }
+
+ @Override
+ public void deleteIotDBUser(Connection connection, String userName) throws BaseException {
+ paramValid(userName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "drop user " + userName;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_DB_USER_FAIL, ErrorCode.DELETE_DB_USER_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_DB_USER_FAIL, ErrorCode.DELETE_DB_USER_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public void deleteIotDBRole(Connection connection, String roleName) throws BaseException {
+ paramValid(roleName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "drop role " + roleName;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_DB_ROLE_FAIL, ErrorCode.DELETE_DB_ROLE_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_DB_ROLE_FAIL, ErrorCode.DELETE_DB_ROLE_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public void setIotDBUser(Connection connection, IotDBUser iotDBUser) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String userName = iotDBUser.getUserName();
+ String password = iotDBUser.getPassword();
+ String sql = "create user " + userName + " '" + password + "'";
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_DB_USER_FAIL, ErrorCode.SET_DB_USER_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_DB_USER_FAIL, ErrorCode.SET_DB_USER_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+// // 用户角色
+// for (String role : iotDBUser.getRoles()) {
+// paramValid(role);
+// sql = "grant " + role + " to " + userName;
+// customExecute(conn, sql);
+// }
+// // 用户授权
+// List<String> privileges = iotDBUser.getPrivileges();
+// for (String privilege : privileges) {
+// sql = handlerPrivilegeStrToSql(privilege, userName, null);
+// if (sql != null) {
+// customExecute(conn, sql);
+// }
+// }
+ }
+
+ @Override
+ public void setIotDBRole(Connection connection, IotDBRole iotDBRole) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String roleName = iotDBRole.getRoleName();
+ String sql = "create role " + roleName;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ List<String> privileges = iotDBRole.getPrivileges();
+ for (String privilege : privileges) {
+ sql = handlerPrivilegeStrToSql(privilege, null, roleName);
+ if (sql != null) {
+ sessionPool.executeNonQueryStatement(sql);
+ }
+ }
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_DB_ROLE_FAIL, ErrorCode.SET_DB_ROLE_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_DB_ROLE_FAIL, ErrorCode.SET_DB_ROLE_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+// @Override
+// public SqlResultVO query(Connection connection, String sql) throws BaseException {
+// java.sql.Connection conn = getConnection(connection);
+// SqlResultVO sqlResultVO = sqlQuery(conn, sql);
+// closeConnection(conn);
+// return sqlResultVO;
+// }
+
+ @Override
+ public void insertTimeseries(Connection connection, String deviceName, Timeseries timeseries) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ try {
+ List<TSDataType> types = handleTypeStr(timeseries.getTypes());
+ List<Object> values = handleValueStr(timeseries.getValues(), types);
+ sessionPool.insertRecord(deviceName, timeseries.getTime(), timeseries.getMeasurements(), types, values);
+ } catch (IoTDBConnectionException e) {
+ throw new BaseException(ErrorCode.INSERT_TS_FAIL, ErrorCode.INSERT_TS_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ throw new BaseException(ErrorCode.INSERT_TS_FAIL, ErrorCode.INSERT_TS_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+
+ }
+
+ @Override
+ public void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ try {
+ sessionPool.deleteTimeseries(timeseriesName);
+ } catch (IoTDBConnectionException e) {
+ throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_DELETE_TIMESERIES, ErrorCode.NO_PRI_DELETE_TIMESERIES_MSG);
+ }
+ throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public SqlResultVO showTimeseries(Connection connection, String deviceName) throws BaseException {
+ paramValid(deviceName);
+ java.sql.Connection conn = getConnection(connection);
+ String sql = "show timeseries " + deviceName;
+ SqlResultVO resultVO = sqlQuery(conn, sql);
+ closeConnection(conn);
+ return resultVO;
+ }
+
+ @Override
+ public List<Integer> getDevicesCount(Connection connection, List<String> groupNames) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ List<Integer> devicesCount = new ArrayList<>();
+ for (String groupName : groupNames) {
+ String sql = "count devices " + groupName;
+ String value = executeQueryOneValue(sessionPool, sql);
+ if (value == null) {
+ devicesCount.add(0);
+ continue;
+ }
+ Integer count = Integer.valueOf(value);
+ devicesCount.add(count);
+ }
+ sessionPool.close();
+ return devicesCount;
+ }
+
+ @Override
+ public void saveGroupTtl(Connection connection, String groupName, long l) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "set ttl to " + groupName + " " + l;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_SET_TTL, ErrorCode.NO_PRI_SET_TTL_MSG);
+ }
+ throw new BaseException(ErrorCode.SET_TTL_FAIL, ErrorCode.SET_TTL_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SET_TTL_FAIL, ErrorCode.SET_TTL_FAIL_MSG);
+ } finally {
+ sessionPool.close();
+ }
+ }
+
+ @Override
+ public void cancelGroupTtl(Connection connection, String groupName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "unset ttl to " + groupName;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ } finally {
+ sessionPool.close();
+ }
+ }
+
+ @Override
+ public Integer getDeviceCount(Connection connection, String groupName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "count devices " + groupName;
+ String value = executeQueryOneValue(sessionPool, sql);
+ if (value == null) {
+ return 0;
+ }
+ Integer count = Integer.valueOf(value);
+ return count;
+ }
+
+ @Override
+ public List<Integer> getTimeseriesCount(Connection connection, List<String> deviceNames) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ List<Integer> lines = new ArrayList<>();
+ for (String deviceName : deviceNames) {
+ String sql = "count timeseries " + deviceName;
+ String value = executeQueryOneValue(sessionPool, sql);
+ if (value == null) {
+ lines.add(0);
+ continue;
+ }
+ Integer count = Integer.valueOf(value);
+ lines.add(count);
+ }
+ sessionPool.close();
+ return lines;
+ }
+
+ @Override
+ public void deleteTimeseriesByDevice(Connection connection, String deviceName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "delete timeseries " + deviceName + ".*";
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_DELETE_TIMESERIES, ErrorCode.NO_PRI_DELETE_TIMESERIES_MSG);
+ }
+ throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void createDeviceWithMeasurements(Connection connection, DeviceInfoDTO deviceInfoDTO) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ List<String> typesStr = new ArrayList<>();
+ List<String> encodingsStr = new ArrayList<>();
+ List<String> measurements = new ArrayList<>();
+ for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+ typesStr.add(deviceDTO.getDataType());
+ encodingsStr.add(deviceDTO.getEncoding());
+ measurements.add(deviceDTO.getTimeseries());
+ }
+ List<TSDataType> types = handleTypeStr(typesStr);
+ List<TSEncoding> encodings = handleEncodingStr(encodingsStr);
+ List<CompressionType> compressionTypes = new ArrayList<>();
+ for (int i = 0; i < types.size(); i++) {
+ compressionTypes.add(CompressionType.SNAPPY);
+ }
+ try {
+ sessionPool.createMultiTimeseries(measurements, types, encodings, compressionTypes, null, null, null, null);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.INSERT_DEV_FAIL, ErrorCode.INSERT_DEV_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ if (e.getMessage().contains("No permissions")) {
+ throw new BaseException(ErrorCode.NO_PRI_CREATE_TIMESERIES, ErrorCode.NO_PRI_CREATE_TIMESERIES_MSG);
+ }
+ if (!e.getMessage().contains("PathAlreadyExistException")) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.INSERT_DEV_FAIL, ErrorCode.INSERT_DEV_FAIL_MSG);
+ }
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ }
+
+ @Override
+ public Integer getMeasurementsCount(Connection connection, String deviceName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "count timeseries " + deviceName;
+ String valueStr = executeQueryOneValue(sessionPool, sql);
+ return Integer.valueOf(valueStr);
+ }
+
+ @Override
+ public String getLastMeasurementValue(Connection connection, String timeseries) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ int index = timeseries.lastIndexOf(".");
+ String sql = "select last_value(" + timeseries.substring(index + 1) + ") from " + timeseries.substring(0, index);
+ String value;
+ try {
+ value = executeQueryOneValue(sessionPool, sql);
+ } finally {
+ sessionPool.close();
+ }
+ return value;
+ }
+
+ @Override
+ public String getGroupTTL(Connection connection, String groupName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show ttl on " + groupName;
+ String queryField = "ttl";
+ String ttl = executeQueryOneLine(sessionPool, sql, queryField);
+ return ttl;
+ }
+
+ @Override
+ public List<String> getDevices(Connection connection, String groupName) throws BaseException {
+ paramValid(groupName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show devices " + groupName;
+ List<String> devicesName = executeQueryOneColumn(sessionPool, sql);
+ return devicesName;
+ }
+
+ @Override
+ public List<String> getTimeseries(Connection connection, String deviceName) throws BaseException {
+ paramValid(deviceName);
+ SessionPool sessionPool = getSessionPool(connection);
+ String sql = "show timeseries " + deviceName;
+ SqlResultVO sqlResultVO = executeQuery(sessionPool, sql, true);
+ List<String> metaDataList = sqlResultVO.getMetaDataList();
+ int index = -1;
+ if (metaDataList != null) {
+ for (int i = 0; i < metaDataList.size(); i++) {
+ if ("timeseries".equalsIgnoreCase(metaDataList.get(i))) {
+ index = i;
+ break;
+ }
+ }
+ }
+ if (index == -1) {
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ }
+ List<List<String>> valueList = sqlResultVO.getValueList();
+ List<String> timeseries = new ArrayList<>();
+ for (List<String> list : valueList) {
+ timeseries.add(list.get(index));
+ }
+ return timeseries;
+ }
+
+ @Override
+ public void setUserPrivileges(Connection connection, String userName, PrivilegeInfoDTO privilegeInfoDTO) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ // 授权
+ List<String> privileges = privilegeInfoDTO.getPrivileges();
+ if (notNullAndNotZero(privileges)) {
+ grantOrRevoke("grant", privileges, userName, privilegeInfoDTO, sessionPool);
+ }
+ // 取消授权
+ List<String> cancelPrivileges = privilegeInfoDTO.getCancelPrivileges();
+ if (notNullAndNotZero(cancelPrivileges)) {
+ grantOrRevoke("revoke", cancelPrivileges, userName, privilegeInfoDTO, sessionPool);
+ }
+ cancelPathPrivileges(userName, privilegeInfoDTO, sessionPool);
+ sessionPool.close();
+ }
+
+ private void cancelPathPrivileges(String userName, PrivilegeInfoDTO privilegeInfoDTO, SessionPool sessionPool) {
+ Integer type = privilegeInfoDTO.getType();
+ List<String> delDevicePaths = privilegeInfoDTO.getDelDevicePaths();
+ List<String> delGroupPaths = privilegeInfoDTO.getDelGroupPaths();
+ List<String> delTimeseriesPaths = privilegeInfoDTO.getDelTimeseriesPaths();
+ switch (type) {
+ case 1:
+ if (notNullAndNotZero(delGroupPaths)) {
+ Set<String> privileges = SPECIAL_PRIVILEGES.keySet();
+ for (String delGroupPath : delGroupPaths) {
+ for (String privilegesStr : privileges) {
+ String sql = "revoke user " + userName + " privileges '" + privilegesStr + "' on root."
+ + delGroupPath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ }
+ break;
+ case 2:
+ if (notNullAndNotZero(delDevicePaths)) {
+ Set<String> privileges = SPECIAL_PRIVILEGES.keySet();
+ String onlyGroupPath = delGroupPaths.get(0);
+ for (String delDevicePath : delDevicePaths) {
+ for (String privilegesStr : privileges) {
+ String sql = "revoke user " + userName + " privileges '" + privilegesStr + "' on root."
+ + onlyGroupPath + "." + delDevicePath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ }
+ break;
+ case 3:
+ if (notNullAndNotZero(delTimeseriesPaths)) {
+ Set<String> privileges = SPECIAL_PRIVILEGES.keySet();
+ String onlyGroupPath = delGroupPaths.get(0);
+ String onlyDevicePath = delDevicePaths.get(0);
+ for (String delTimeseriesPath : delTimeseriesPaths) {
+ for (String privilegesStr : privileges) {
+ String sql = "revoke user " + userName + " privileges '" + privilegesStr + "' on root."
+ + onlyGroupPath + "." + onlyDevicePath + "." + delTimeseriesPath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ @Override
+ public RecordVO getRecords(Connection connection, String deviceName, String timeseriesName) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ RecordVO recordVO = new RecordVO();
+ List<Date> timeList = new ArrayList<>();
+ List<Long> valueList = new ArrayList<>();
+ String sql = "select time," + timeseriesName + " from " + deviceName + " order by time desc limit 200 offset 0";
+ try {
+ SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord next = sessionDataSetWrapper.next();
+ Date date = new Date(next.getTimestamp());
+ timeList.add(date);
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = next.getFields();
+ Long value = Long.valueOf(fields.get(0).toString());
+ valueList.add(value);
+ }
+ }
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_RECORD_FAIL, ErrorCode.GET_RECORD_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_RECORD_FAIL, ErrorCode.GET_RECORD_FAIL_MSG);
+ }
+ recordVO.setTimeList(timeList);
+ recordVO.setValueList(valueList);
+ return recordVO;
+ }
+
+ @Override
+ public List<SqlResultVO> queryAll(Connection connection, List<String> sqls, Long timestamp) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ List<SqlResultVO> results;
+ String id_plus_timestamp;
+ try {
+ results = new ArrayList<>();
+ Integer id = connection.getId();
+ id_plus_timestamp = id + ":" + timestamp;
+ QUERY_STOP.put(id_plus_timestamp, true);
+ for (String sql : sqls) {
+ int firstSpaceIndex = sql.indexOf(" ");
+ String judge = sql.substring(0, firstSpaceIndex);
+ if ("show".equalsIgnoreCase(judge) || "count".equalsIgnoreCase(judge) || "list".equalsIgnoreCase(judge)) {
+ SqlResultVO sqlResultVO = executeQuery(sessionPool, sql, false, id_plus_timestamp, false);
+ results.add(sqlResultVO);
+ continue;
+ }
+ if ("select".equalsIgnoreCase(judge)) {
+ SqlResultVO sqlResultVO = executeQuery(sessionPool, sql, false, id_plus_timestamp, true);
+ results.add(sqlResultVO);
+ continue;
+ }
+ try {
+ if (QUERY_STOP.get(id_plus_timestamp)) {
+ String sqlCheck = sql.toLowerCase();
+ if (sqlCheck != null && sqlCheck.contains("insert")) {
+ String s = sqlCheck;
+ String[] split = s.split("\\.");
+ if (split.length <= 2) {
+ throw new BaseException(ErrorCode.NO_SUPPORT_SQL, ErrorCode.NO_SUPPORT_SQL_MSG);
+ }
+ }
+ if (sqlCheck != null && sqlCheck.contains("create timeseries")) {
+ String s = sqlCheck;
+ String[] split = s.split("\\.");
+ if (split.length <= 3) {
+ throw new BaseException(ErrorCode.NO_SUPPORT_SQL, ErrorCode.NO_SUPPORT_SQL_MSG);
+ }
+ }
+ long start = System.currentTimeMillis();
+ sessionPool.executeNonQueryStatement(sql);
+ long end = System.currentTimeMillis();
+ double time = (end - start + 0.0d) / 1000;
+ String queryTime = time + "s";
+ SqlResultVO sqlResultVO = new SqlResultVO();
+ sqlResultVO.setQueryTime(queryTime);
+ sqlResultVO.setLine(0L);
+ results.add(sqlResultVO);
+ }
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG + ":" + sql + "执行出错,错误信息[" + e.getMessage() + "]");
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG + ":" + sql + "执行出错,错误信息[" + e.getMessage() + "]");
+ }
+ }
+ } finally {
+ if (sessionPool != null) {
+ sessionPool.close();
+ }
+ }
+ QUERY_STOP.remove(id_plus_timestamp);
+ return results;
+ }
+
+ @Override
+ public void updatePwd(Connection connection, IotDBUser iotDBUser) throws BaseException {
+ SessionPool sessionPool = getSessionPool(connection);
+ String userName = iotDBUser.getUserName();
+ String newPWD = iotDBUser.getPassword();
+ String sql = "alter user " + userName + " set password '" + newPWD + "'";
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.UPDATE_PWD_FAIL, ErrorCode.UPDATE_PWD_FAIL_MSG);
+ } catch (IoTDBConnectionException e) {
+ e.printStackTrace();
+ }
+ }
+
+ @Override
+ public void stopQuery(Integer serverId, Long timestamp) throws BaseException {
+ String notStopKey = serverId + ":" + timestamp;
+ if (QUERY_STOP.containsKey(notStopKey)) {
+ QUERY_STOP.put(notStopKey, false);
+ return;
+ }
+ throw new BaseException(ErrorCode.NO_QUERY, ErrorCode.NO_QUERY_MSG);
+ }
+
+
+ private void grantOrRevoke(String word, List<String> privileges, String userName, PrivilegeInfoDTO privilegesInfo, SessionPool sessionPool)
+ throws BaseException {
+ Integer type = privilegesInfo.getType();
+// String privilegesStr = String.join("','", privileges); 一起存会有bug
+ for (String privilegesStr : privileges) {
+ if (type == 0) {
+ String sql = word + " user " + userName + " privileges '" + privilegesStr + "' on root";
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ continue;
+ }
+ if (type == 1) {
+ List<String> groupPaths = privilegesInfo.getGroupPaths();
+ if (notNullAndNotZero(groupPaths)) {
+ for (String groupPath : groupPaths) {
+ String sql = word + " user " + userName + " privileges '" + privilegesStr + "' on root."
+ + groupPath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ continue;
+ }
+ if (type == 2) {
+ List<String> groupPaths = privilegesInfo.getGroupPaths();
+ List<String> devicePaths = privilegesInfo.getDevicePaths();
+ if (notNullAndNotZero(groupPaths) && groupPaths.size() == 1 && notNullAndNotZero(devicePaths)) {
+ String onlyGroupPath = groupPaths.get(0);
+ for (String devicePath : devicePaths) {
+ String sql = word + " user " + userName + " privileges '" + privilegesStr + "' on root."
+ + onlyGroupPath + "." + devicePath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ continue;
+ }
+ if (type == 3) {
+ List<String> groupPaths = privilegesInfo.getGroupPaths();
+ List<String> devicePaths = privilegesInfo.getDevicePaths();
+ List<String> timeseriesPaths = privilegesInfo.getTimeseriesPaths();
+ if (notNullAndNotZero(groupPaths) && groupPaths.size() == 1 && notNullAndNotZero(devicePaths)
+ && devicePaths.size() == 1 && notNullAndNotZero(timeseriesPaths)) {
+ String onlyGroupPath = groupPaths.get(0);
+ String onlyDevicePath = devicePaths.get(0);
+ for (String timeseriesPath : timeseriesPaths) {
+ String sql = word + " user " + userName + " privileges '" + privilegesStr + "' on root."
+ + onlyGroupPath + "." + onlyDevicePath + "." + timeseriesPath;
+ try {
+ sessionPool.executeNonQueryStatement(sql);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ }
+ }
+ }
+ continue;
+ }
+ throw new BaseException(ErrorCode.NO_TYPE, ErrorCode.NO_TYPE_MSG);
+ }
+ }
+
+
+ /**
+ * 判断集合不为空且长度大于0
+ */
+ private boolean notNullAndNotZero(List list) {
+ if (list != null && list.size() > 0) {
+ return true;
+ }
+ return false;
+ }
+
+ private String executeQueryOneLine(SessionPool sessionPool, String sql, String queryField) throws BaseException {
+ try {
+ SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ int index = -1;
+ for (int i = 0; i < columnNames.size(); i++) {
+ if (queryField.equals(columnNames.get(i))) {
+ index = i;
+ }
+ }
+ if (index == -1) {
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ }
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ if (batchSize > 0) {
+ if (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ return rowRecord.getFields().get(index).toString();
+ }
+ }
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ }
+ throw new BaseException(ErrorCode.NO_GROUP, ErrorCode.NO_GROUP_MSG);
+ }
+
+ private SqlResultVO executeQuery(SessionPool sessionPool, String sql, Boolean closePool) throws BaseException {
+ SqlResultVO sqlResultVO = new SqlResultVO();
+ List<List<String>> valuelist = new ArrayList<>();
+ try {
+ SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ long start = System.currentTimeMillis();
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ sqlResultVO.setMetaDataList(columnNames);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ // 记录行数
+ long count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ List<String> strList = new ArrayList<>();
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ count++;
+ for (org.apache.iotdb.tsfile.read.common.Field field : rowRecord.getFields()) {
+ strList.add(field.toString());
+ }
+ valuelist.add(strList);
+ }
+ long end = System.currentTimeMillis();
+ double time = (end - start + 0.0d) / 1000;
+ String queryTime = time + "s";
+ sqlResultVO.setQueryTime(queryTime);
+ sqlResultVO.setLine(count);
+ }
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } finally {
+ if (sessionPool != null && closePool) {
+ sessionPool.close();
+ }
+ }
+ sqlResultVO.setValueList(valuelist);
+ return sqlResultVO;
+ }
+
+ private SqlResultVO executeQuery(SessionPool sessionPool, String sql, Boolean closePool, String notStopKey, boolean timeFlag) throws BaseException {
+ SqlResultVO sqlResultVO = new SqlResultVO();
+ List<List<String>> valuelist = new ArrayList<>();
+ try {
+ SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ long start = System.currentTimeMillis();
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ sqlResultVO.setMetaDataList(columnNames);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ // 记录行数
+ long count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext() && QUERY_STOP.get(notStopKey)) {
+ List<String> strList = new ArrayList<>();
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ if (timeFlag) {
+ long timestamp = rowRecord.getTimestamp();
+ SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
+ Date date = new Date(timestamp);
+ String timeStr = simpleDateFormat.format(date);
+ strList.add(timeStr);
+ }
+ count++;
+ for (org.apache.iotdb.tsfile.read.common.Field field : rowRecord.getFields()) {
+ strList.add(field.toString());
+ }
+ valuelist.add(strList);
+ }
+ long end = System.currentTimeMillis();
+ double time = (end - start + 0.0d) / 1000;
+ String queryTime = time + "s";
+ sqlResultVO.setQueryTime(queryTime);
+ sqlResultVO.setLine(count);
+ }
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ if (e.getStatusCode() == 602) {
+ throw new BaseException(ErrorCode.NO_PRI_TIMESERIES_DATA, ErrorCode.NO_PRI_TIMESERIES_DATA_MSG);
+ }
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } finally {
+ if (sessionPool != null && closePool) {
+ sessionPool.close();
+ }
+ }
+ sqlResultVO.setValueList(valuelist);
+ return sqlResultVO;
+ }
+
+
+ private <T> CountDTO executeQuery(Class<T> clazz, SessionPool sessionPool, String sql, Integer pageSize, Integer pageNum, String keyword)
+ throws BaseException {
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ List<T> results = new ArrayList<>();
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ int count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ count++;
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ T t = clazz.newInstance();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+ for (int i = 0; i < fields.size(); i++) {
+ Field field = clazz.getDeclaredField(columnNames.get(i).replaceAll(" ", ""));
+ field.setAccessible(true);
+ field.set(t, fields.get(i).toString());
+ }
+ results.add(t);
+ }
+ }
+ }
+ CountDTO countDTO = new CountDTO();
+ countDTO.setObjects(results);
+ countDTO.setTotalCount(count);
+ Integer totalPage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
+ countDTO.setTotalPage(totalPage);
+ return countDTO;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ }
+
+ private String executeQueryOneValue(SessionPool sessionPool, String sql) throws BaseException {
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ String value = null;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ value = fields.get(0).toString();
+ break;
+ }
+ }
+ return value;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_VALUE_FAIL, ErrorCode.GET_SQL_ONE_VALUE_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ if (e.getStatusCode() == 602 && sql != null && sql.contains("select")) {
+ throw new BaseException(ErrorCode.NO_PRI_READ_TIMESERIES, ErrorCode.NO_PRI_READ_TIMESERIES_MSG);
+ }
+ throw new BaseException(ErrorCode.GET_SQL_ONE_VALUE_FAIL, ErrorCode.GET_SQL_ONE_VALUE_FAIL_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ }
+
+ private CountDTO executeQueryOneColumn(SessionPool sessionPool, String sql, Integer pageSize, Integer pageNum) throws BaseException {
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ List<String> values = new ArrayList<>();
+ int count = 0;
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ count++;
+ if (count >= pageSize * (pageNum - 1) + 1 && count <= pageSize * pageNum) {
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ values.add(fields.get(0).toString());
+ }
+ }
+ }
+ CountDTO countDTO = new CountDTO();
+ countDTO.setObjects(values);
+ countDTO.setTotalCount(count);
+ Integer totalPage = count % pageSize == 0 ? count / pageSize : count / pageSize + 1;
+ countDTO.setTotalPage(totalPage);
+ return countDTO;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ }
+
+ private List<String> executeQueryOneColumn(SessionPool sessionPool, String sql) throws BaseException {
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ Callable call = () -> sessionPool.executeQueryStatement(sql);
+ ExecutorService service = Executors.newFixedThreadPool(1);
+ Future submit = service.submit(call);
+ sessionDataSetWrapper = (SessionDataSetWrapper) submit.get(60, TimeUnit.SECONDS);
+ int batchSize = sessionDataSetWrapper.getBatchSize();
+ List<String> values = new ArrayList<>();
+ if (batchSize > 0) {
+ while (sessionDataSetWrapper.hasNext()) {
+ RowRecord rowRecord = sessionDataSetWrapper.next();
+ List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+ values.add(fields.get(0).toString());
+ }
+ }
+ return values;
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
+ } catch (InterruptedException e) {
+ e.printStackTrace();
+ throw new BaseException(ErrorCode.TIME_OUT, ErrorCode.TIME_OUT_MSG);
+ } catch (ExecutionException e) {
+ e.printStackTrace();
+ if (e.getMessage().contains("600")) {
+ throw new BaseException(ErrorCode.WRONG_USER, ErrorCode.WRONG_USER_MSG);
+ }
+ throw new BaseException(ErrorCode.CONN_REFUSED, ErrorCode.CONN_REFUSED_MSG);
+ } catch (TimeoutException e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.TIME_OUT, ErrorCode.TIME_OUT_MSG);
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ }
+
+
+ private List<PrivilegeInfo> privilegesStrSwitchToObject(SessionPool sessionPool, List<String> privileges) throws BaseException {
+ List<PrivilegeInfo> results = new ArrayList<>();
+ List<String> pathStr = new ArrayList<>();
+ List<List<String>> privilegeStr = new ArrayList<>();
+ HashMap<String, Boolean> rootPrivileges = new HashMap();
+ // 遍历集合 将路径和权限集合分别装 过程中 将root相关内容处理
+ for (int i = 0; i < privileges.size(); i++) {
+ String[] split = privileges.get(i).split(":");
+ String[] s = split[1].trim().split(" ");
+ String path = split[0].trim();
+ //为root特殊处理
+ if ("root".equals(path)) {
+ for (String s1 : s) {
+ if (rootPrivileges.containsKey(s1)) {
+ continue;
+ }
+ rootPrivileges.put(s1, true);
+ }
+ continue;
+ }
+ List<String> list = new ArrayList<>();
+ pathStr.add(path);
+ // 其他粒度下 只需要存储SPECIAL_PRIVILEGES四种权限
+ for (String s1 : s) {
+ if (SPECIAL_PRIVILEGES.containsKey(s1)) {
+ list.add(s1);
+ continue;
+ }
+ // 除了root这一层级 其他此权限不生效 不添加进root权限集合
+ if (NO_NEED_PRIVILEGES.equals(s1)) {
+ continue;
+ }
+ if (rootPrivileges.containsKey(s1)) {
+ continue;
+ }
+ rootPrivileges.put(s1, true);
+ }
+ privilegeStr.add(list);
+ }
+ // 先处理root 生成对象
+ Set<String> strings = rootPrivileges.keySet();
+ List<String> rootPrivilege = Arrays.asList(strings.toArray(new String[0]));
+ if (rootPrivilege != null && rootPrivilege.size() > 0) {
+ PrivilegeInfo privilegeInfo = new PrivilegeInfo();
+ privilegeInfo.setType(0);
+ privilegeInfo.setPrivileges(rootPrivilege);
+ results.add(privilegeInfo);
+ }
+ // 处理非root String存储形式 "权限1 权限2 权限3.." List存储相同并集下的path路径
+ Map<String, List<String>> privilegeOne = new HashMap<>();
+ Map<String, List<String>> privilegeTwo = new HashMap<>();
+ Map<String, List<String>> privilegeThree = new HashMap<>();
+ for (int i = 0; i < pathStr.size(); i++) {
+ String s = pathStr.get(i);
+ List<String> list = privilegeStr.get(i);
+ String str = String.join(" ", list);
+ // 通过路径获取所属粒度
+ int type = findType(sessionPool, s);
+ if (type == 1) {
+ // 判断相同的权限集合 放入同一list
+ if (privilegeOne.containsKey(str)) {
+ List<String> typeList = privilegeOne.get(str);
+ typeList.add(s);
+ continue;
+ }
+ ArrayList<String> newStr = new ArrayList();
+ newStr.add(s);
+ privilegeOne.put(str, newStr);
+ continue;
+ }
+ if (type == 2) {
+ // 判断相同的权限集合 放入同一list
+ if (privilegeTwo.containsKey(str)) {
+ List<String> typeList = privilegeTwo.get(str);
+ // 相同粒度 同一范围下做前缀判断 相同则为一个并集
+ int existEnd = typeList.get(0).lastIndexOf(".");
+ int end = s.lastIndexOf(".");
+ if (typeList.get(0).substring(0, existEnd).equals(s.substring(0, end))) {
+ typeList.add(s);
+ continue;
+ }
+ }
+ ArrayList<String> newStr = new ArrayList();
+ newStr.add(s);
+ privilegeTwo.put(str, newStr);
+ continue;
+ }
+ if (type == 3) {
+ if (privilegeThree.containsKey(str)) {
+ List<String> typeList = privilegeThree.get(str);
+ int existEnd = typeList.get(0).lastIndexOf(".");
+ int end = s.lastIndexOf(".");
+ if (typeList.get(0).substring(0, existEnd).equals(s.substring(0, end))) {
+ typeList.add(s);
+ continue;
+ }
+ }
+ ArrayList<String> newStr = new ArrayList();
+ newStr.add(s);
+ privilegeThree.put(str, newStr);
+ }
+ }
+ Set<String> oneKeys = privilegeOne.keySet();
+ Set<String> twoKeys = privilegeTwo.keySet();
+ Set<String> threeKeys = privilegeThree.keySet();
+ // 封装成PrivilegeInfo返回 字符串处理
+ for (String oneKey : oneKeys) {
+ PrivilegeInfo oneInfo = new PrivilegeInfo();
+ List<String> groupPath = new ArrayList<>();
+ List<String> list = privilegeOne.get(oneKey);
+ for (String s : list) {
+ String groupName = s.replaceFirst("root.", "");
+ groupPath.add(groupName);
+ }
+ List<String> privilegesOne = Arrays.asList(oneKey.split(" "));
+ String sql = "show storage group";
+ List<String> allGroupPathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allGroupPaths = new ArrayList<>();
+ for (String s : allGroupPathsStr) {
+ String field = s.replaceFirst("root.", "");
+ allGroupPaths.add(field);
+ }
+ // 展示数据
+ oneInfo.setType(1);
+ oneInfo.setPrivileges(privilegesOne);
+ // allxxx内容为前端编辑修改时需要的数据
+ oneInfo.setGroupPaths(groupPath);
+ oneInfo.setAllGroupPaths(allGroupPaths);
+ results.add(oneInfo);
+ }
+ for (String twoKey : twoKeys) {
+ PrivilegeInfo twoInfo = new PrivilegeInfo();
+ List<String> groupPath = new ArrayList<>();
+ List<String> devicePath = new ArrayList<>();
+ List<String> list = privilegeTwo.get(twoKey);
+ // 得到 组名、设备名、测点名 便于后续字符串操作
+ PathVO pathVO = splitPathToPathVO(sessionPool, list.get(0));
+ groupPath.add(pathVO.getGroupName());
+ for (String s : list) {
+ String deviceName = s.replaceFirst("root." + pathVO.getGroupName() + ".", "");
+ devicePath.add(deviceName);
+ }
+ List<String> privilegesTwo = Arrays.asList(twoKey.split(" "));
+ String sql = "show storage group";
+ List<String> allGroupPathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allGroupPaths = new ArrayList<>();
+ for (String s : allGroupPathsStr) {
+ String field = s.replaceFirst("root.", "");
+ allGroupPaths.add(field);
+ }
+ int end = list.get(0).lastIndexOf(".");
+ sql = "show devices " + list.get(0).substring(0, end) + ".*";
+ List<String> allDevicePathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allDevicePaths = new ArrayList<>();
+ for (String s : allDevicePathsStr) {
+ String field = s.replaceFirst(list.get(0).substring(0, end) + ".", "");
+ allDevicePaths.add(field);
+ }
+ // 展示数据
+ twoInfo.setType(2);
+ twoInfo.setPrivileges(privilegesTwo);
+ twoInfo.setGroupPaths(groupPath);
+ twoInfo.setDevicePaths(devicePath);
+ // allxxx内容为前端编辑修改时需要的数据
+ twoInfo.setAllGroupPaths(allGroupPaths);
+ twoInfo.setAllDevicePaths(allDevicePaths);
+ results.add(twoInfo);
+ }
+ for (String threeKey : threeKeys) {
+ PrivilegeInfo threeInfo = new PrivilegeInfo();
+ List<String> groupPath = new ArrayList<>();
+ List<String> devicePath = new ArrayList<>();
+ List<String> timeseriesPath = new ArrayList<>();
+ List<String> list = privilegeThree.get(threeKey);
+ // 得到 组名、设备名、测点名 便于后续字符串操作
+ PathVO pathVO = splitPathToPathVO(sessionPool, list.get(0));
+ groupPath.add(pathVO.getGroupName());
+ devicePath.add(pathVO.getDeviceName());
+ for (String s : list) {
+ String timeseriesName = s.replaceFirst("root." + pathVO.getGroupName() + "." + pathVO.getDeviceName() + ".", "");
+ timeseriesPath.add(timeseriesName);
+ }
+ List<String> privilegesOne = Arrays.asList(threeKey.split(" "));
+ String sql = "show storage group";
+ List<String> allGroupPathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allGroupPaths = new ArrayList<>();
+ for (String s : allGroupPathsStr) {
+ String field = s.replaceFirst("root.", "");
+ allGroupPaths.add(field);
+ }
+ sql = "show devices root." + pathVO.getGroupName() + ".*";
+ List<String> allDevicePathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allDevicePaths = new ArrayList<>();
+ for (String s : allDevicePathsStr) {
+ String deviceName = s.replaceFirst("root." + pathVO.getGroupName() + ".", "");
+ allDevicePaths.add(deviceName);
+ }
+ int end = list.get(0).lastIndexOf(".");
+ sql = "show timeseries " + list.get(0).substring(0, end) + ".*";
+ List<String> allTimeseriesPathsStr = executeQueryOneColumn(sessionPool, sql);
+ List<String> allTimeseriesPaths = new ArrayList<>();
+ for (String s : allTimeseriesPathsStr) {
+ String field = s.replaceFirst(list.get(0).substring(0, end) + ".", "");
+ allTimeseriesPaths.add(field);
+ }
+ // 展示数据
+ threeInfo.setType(3);
+ threeInfo.setPrivileges(privilegesOne);
+ threeInfo.setGroupPaths(groupPath);
+ threeInfo.setDevicePaths(devicePath);
+ threeInfo.setTimeseriesPaths(timeseriesPath);
+ // allxxx内容为前端编辑修改时需要的数据
+ threeInfo.setAllGroupPaths(allGroupPaths);
+ threeInfo.setAllDevicePaths(allDevicePaths);
+ threeInfo.setAllTimeseriesPaths(allTimeseriesPaths);
+ results.add(threeInfo);
+ }
+ return results;
+ }
+
+ private PathVO splitPathToPathVO(SessionPool sessionPool, String s) throws BaseException {
+ PathVO pathVO = new PathVO();
+ while (!"root".equals(s)) {
+ String sql = "count devices " + s;
+ Integer isDevice = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
+ sql = "count storage group " + s;
+ Integer isGroup = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
+ // 为测点
+ if (isDevice == 0 && isGroup == 0) {
+ int mid = s.lastIndexOf(".");
+ String timeseriesName = s.substring(mid + 1);
+ pathVO.setTimeseriesName(timeseriesName);
+ s = s.substring(0, mid);
+ continue;
+ }
+ // 既是存储组也是实体
+ if (isDevice == 1 && isGroup == 1) {
+ String deviceName = s.replaceFirst("root.", "");
+ String groupName = s.replaceFirst("root.", "");
+ pathVO.setGroupName(groupName);
+ pathVO.setDeviceName(deviceName);
+ break;
+ }
+ // 是存储组 判断是否还为实体
+ if (isDevice > 1 && isGroup == 1) {
+ sql = "show devices " + s;
+ List<String> list = executeQueryOneColumn(sessionPool, sql);
+ if (list.contains(s)) {
+ String deviceName = s.replaceFirst("root.", "");
+ String groupName = s.replaceFirst("root.", "");
+ pathVO.setGroupName(groupName);
+ pathVO.setDeviceName(deviceName);
+ break;
+ }
+ String groupName = s.replaceFirst("root.", "");
+ pathVO.setGroupName(groupName);
+ }
+ // 为存储组
+ if (isDevice == 0 && isGroup == 1) {
+ String groupName = s.replaceFirst("root.", "");
+ pathVO.setGroupName(groupName);
+ break;
+ }
+ // 实体 实体之下还可以有实体 需要遍历有多少层级
+ if (isDevice >= 1 && isGroup == 0) {
+ String oldS = s;
+ while (true) {
+ int mid = s.lastIndexOf(".");
+ s = s.substring(0, mid);
+ sql = "count storage group " + s;
+ isGroup = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
+ if (isGroup > 0) {
+ String deviceName = oldS.replaceFirst(s + ".", "");
+ String groupName = s.replaceFirst("root.", "");
+ pathVO.setGroupName(groupName);
+ pathVO.setDeviceName(deviceName);
+ break;
+ }
+ }
+ break;
+ }
+ }
+ return pathVO;
+ }
+
+ private int findType(SessionPool sessionPool, String s) throws BaseException {
+ // 主要用于判断s路径是否已经不存在 iotdb存在已删除路径的权限还会展示出来的问题
+ String sql = "count timeseries " + s;
+ SessionDataSetWrapper sessionDataSetWrapper = null;
+ try {
+ sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+ } catch (IoTDBConnectionException e) {
+ logger.error(e.getMessage());
+ return -1;
+ } catch (StatementExecutionException e) {
+ logger.error(e.getMessage());
+ return -1;
+ } finally {
+ if (sessionDataSetWrapper != null) {
+ sessionDataSetWrapper.close();
+ }
+ }
+ sql = "count storage group " + s;
+ Integer isGroup = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
+ if (isGroup == 1) {
+ return 1;
+ }
+ // 无效路径 既不是root 也不是存储组 不展示到页面
+ if (isGroup > 1) {
+ return -1;
+ }
+ sql = "count devices " + s;
+ Integer isDevices = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
+ if (isDevices == 1) {
+ return 2;
+ }
+ return 3;
+ }
+
+ private List<TSEncoding> handleEncodingStr(List<String> encoding) {
+ List<TSEncoding> list = new ArrayList<>();
+ for (String s : encoding) {
+ switch (s) {
+ case "PLAIN":
+ list.add(TSEncoding.PLAIN);
+ break;
+ case "PLAIN_DICTIONARY":
+ list.add(TSEncoding.PLAIN_DICTIONARY);
+ break;
+ case "RLE":
+ list.add(TSEncoding.RLE);
+ break;
+ case "DIFF":
+ list.add(TSEncoding.DIFF);
+ break;
+ case "TS_2DIFF":
+ list.add(TSEncoding.TS_2DIFF);
+ break;
+ case "BITMAP":
+ list.add(TSEncoding.BITMAP);
+ break;
+ case "GORILLA_V1":
+ list.add(TSEncoding.GORILLA_V1);
+ break;
+ case "REGULAR":
+ list.add(TSEncoding.REGULAR);
+ break;
+ case "GORILLA":
+ list.add(TSEncoding.GORILLA);
+ break;
+ }
+ }
+ return list;
+ }
+
+ private List<Object> handleValueStr(List<String> values, List<TSDataType> types) throws BaseException {
+ List<Object> list = new ArrayList<>();
+ for (int i = 0; i < types.size(); i++) {
+ TSDataType type = types.get(i);
+ if (type == TSDataType.BOOLEAN) {
+ Integer booleanNum = Integer.valueOf(values.get(i));
+ Boolean flag = null;
+ if (booleanNum == 0) {
+ flag = false;
+ }
+ if (booleanNum == 1) {
+ flag = true;
+ }
+ if (flag != null) {
+ list.add(flag);
+ continue;
+ }
+ throw new BaseException(ErrorCode.DB_BOOL_WRONG, ErrorCode.DB_BOOL_WRONG_MSG);
+ }
+ if (type == TSDataType.INT32 || type == TSDataType.INT64) {
+ Integer intNum = Integer.valueOf(values.get(i));
+ list.add(intNum);
+ continue;
+ }
+ if (type == TSDataType.FLOAT) {
+ Float floatNum = Float.valueOf(values.get(i));
+ list.add(floatNum);
+ continue;
+ }
+ if (type == TSDataType.DOUBLE) {
+ Double doubleNum = Double.valueOf(values.get(i));
+ list.add(doubleNum);
+ continue;
+ }
+ list.add(values.get(i));
+ }
+ return list;
+ }
+
+ private List<TSDataType> handleTypeStr(List<String> types) throws BaseException {
+ List<TSDataType> list = new ArrayList<>();
+ for (String type : types) {
+ TSDataType tsDataType;
+ switch (type) {
+ case "BOOLEAN":
+ tsDataType = TSDataType.BOOLEAN;
+ break;
+ case "INT32":
+ tsDataType = TSDataType.INT32;
+ break;
+ case "INT64":
+ tsDataType = TSDataType.INT64;
+ break;
+ case "FLOAT":
+ tsDataType = TSDataType.FLOAT;
+ break;
+ case "DOUBLE":
+ tsDataType = TSDataType.DOUBLE;
+ break;
+ case "TEXT":
+ tsDataType = TSDataType.TEXT;
+ break;
+ default:
+ throw new BaseException(ErrorCode.DB_DATATYPE_WRONG, ErrorCode.DB_DATATYPE_WRONG_MSG);
+ }
+ list.add(tsDataType);
+ }
+ return list;
+ }
+
+
+ public static java.sql.Connection getConnection(Connection connection) throws BaseException {
+ String driver = "org.apache.iotdb.jdbc.IoTDBDriver";
+ String url = "jdbc:iotdb://" + connection.getHost() + ":" + connection.getPort() + "/";
+ String username = connection.getUsername();
+ String password = connection.getPassword();
+ java.sql.Connection conn;
+ try {
+ Class.forName(driver);
+ conn = DriverManager.getConnection(url, username, password);
+ } catch (ClassNotFoundException e) {
+ throw new BaseException(ErrorCode.GET_DBCONN_FAIL, ErrorCode.GET_DBCONN_FAIL_MSG);
+ } catch (SQLException e) {
+ throw new BaseException(ErrorCode.GET_DBCONN_FAIL, ErrorCode.GET_DBCONN_FAIL_MSG);
+ }
+ return conn;
+ }
+
+ public static SessionPool getSessionPool(Connection connection) throws BaseException {
+ String host = connection.getHost();
+ Integer port = connection.getPort();
+ String username = connection.getUsername();
+ String password = connection.getPassword();
+ SessionPool sessionPool = null;
+ try {
+ sessionPool = new SessionPool(host, port, username, password, 3);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+ }
+ return sessionPool;
+ }
+// public static SessionPool getSession(Connection connection) throws BaseException {
+// if(sessionPool == null){
+// host = connection.getHost();
+// port = connection.getPort();
+// username = connection.getUsername();
+// password = connection.getPassword();
+// sessionPool = new SessionPool(host,port,username,password,3);
+// return sessionPool;
+// }
+// if(host == connection.getHost() && port.equals(connection.getPort()) && username == connection.getUsername() && password == connection.getPassword()){
+// return sessionPool;
+// }
+// sessionPool.close();
+// host = connection.getHost();
+// port = connection.getPort();
+// username = connection.getUsername();
+// password = connection.getPassword();
+// sessionPool = new SessionPool(host,port,username,password,3);
+// return sessionPool;
+// }
+
+ private void closeConnection(java.sql.Connection conn) throws BaseException {
+ try {
+ if (conn != null) {
+ conn.close();
+ }
+ } catch (SQLException e) {
+ throw new BaseException(ErrorCode.CLOSE_DBCONN_FAIL, ErrorCode.CLOSE_DBCONN_FAIL_MSG);
+ }
+ }
+
+ private String handlerPrivilegeStrToSql(String privilege, String userName, String roleName) {
+ int i = privilege.indexOf(":");
+ String path = privilege.substring(0, i).trim();
+ String[] privileges = privilege.substring(i + 1).trim().split(" ");
+ int len = privileges.length;
+ if (len == 0) {
+ return null;
+ }
+ StringBuilder str = new StringBuilder();
+ if (userName != null) {
+ str.append("grant user " + userName + " privileges ");
+ } else {
+ str.append("grant role " + roleName + " privileges ");
+ }
+ for (int j = 0; i < len - 1; j++) {
+ str.append("'" + privileges[j] + "',");
+ }
+ str.append("'" + privileges[len - 1] + "' on " + path);
+ return str.toString();
+ }
+
+
+ private SqlResultVO sqlQuery(java.sql.Connection conn, String sql) throws BaseException {
+ PreparedStatement statement = null;
+ ResultSet resultSet = null;
+ try {
+ statement = conn.prepareStatement(sql);
+ resultSet = statement.executeQuery();
+ ResultSetMetaData metaData = resultSet.getMetaData();
+ int columnCount = metaData.getColumnCount();
+ SqlResultVO sqlResultVO = new SqlResultVO();
+ List<String> metaDataList = new ArrayList<>();
+ for (int i = 0; i < columnCount; i++) {
+ metaDataList.add(metaData.getColumnLabel(i + 1));
+ }
+ sqlResultVO.setMetaDataList(metaDataList);
+ List<List<String>> valuelist = new ArrayList<>();
+ while (resultSet.next()) {
+ List<String> strList = new ArrayList<>();
+ for (int i = 0; i < columnCount; i++) {
+ strList.add(resultSet.getString(i + 1));
+ }
+ valuelist.add(strList);
+ }
+ sqlResultVO.setValueList(valuelist);
+ return sqlResultVO;
+ } catch (SQLException e) {
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ } finally {
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException e) {
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ }
+ }
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException e) {
+ throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+ }
+ }
+ closeConnection(conn);
+ }
+ }
+
+ /**
+ * 防止sql注入对参数进行校验不能有空格
+ *
+ * @param field 拼接sql的字段
+ */
+ private void paramValid(String field) throws BaseException {
+ if (field != null) {
+ if (!field.matches("^[^ ]+$")) {
+ throw new BaseException(ErrorCode.SQL_PARAM_WRONG, ErrorCode.SQL_PARAM_WRONG_MSG);
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/MeasurementServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/MeasurementServiceImpl.java
new file mode 100644
index 0000000..52a6f65
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/MeasurementServiceImpl.java
@@ -0,0 +1,142 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.MeasurementMapper;
+import org.apache.iotdb.admin.model.dto.DeviceDTO;
+import org.apache.iotdb.admin.model.dto.DeviceInfoDTO;
+import org.apache.iotdb.admin.model.entity.Measurement;
+import org.apache.iotdb.admin.service.MeasurementService;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class MeasurementServiceImpl extends ServiceImpl<MeasurementMapper, Measurement> implements MeasurementService {
+
+ @Autowired
+ private MeasurementMapper measurementMapper;
+
+ private static final Logger logger = LoggerFactory.getLogger(IotDBServiceImpl.class);
+
+ @Override
+ public void deleteMeasurementInfo(String host, String groupName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.like("measurement_name", groupName);
+ try {
+ measurementMapper.delete(queryWrapper);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_MEASUREMENT_INFO_FAIL, ErrorCode.DELETE_MEASUREMENT_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void deleteMeasurementInfoByDeviceName(String host, String deviceName) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.like("measurement_name", deviceName);
+ try {
+ measurementMapper.delete(queryWrapper);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_MEASUREMENT_INFO_FAIL, ErrorCode.DELETE_MEASUREMENT_INFO_FAIL_MSG);
+ }
+ }
+
+ @Override
+ public void setMeasurementsInfo(String host, DeviceInfoDTO deviceInfoDTO) throws BaseException {
+ List<String> descriptions = new ArrayList<>();
+ List<String> measurements = new ArrayList<>();
+ for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+ descriptions.add(deviceDTO.getDescription());
+ measurements.add(deviceDTO.getTimeseries());
+ }
+ for (int i = 0; i < measurements.size(); i++) {
+ Measurement mea = new Measurement();
+ mea.setDescription(descriptions.get(i));
+ mea.setMeasurementName(measurements.get(i));
+ mea.setHost(host);
+ int flag = measurementMapper.insert(mea);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.SET_MEASUREMENT_INFO_FAIL, ErrorCode.SET_MEASUREMENT_INFO_FAIL_MSG);
+ }
+ }
+ }
+
+ @Override
+ public String getDescription(String host, String timeseries) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("measurement_name", timeseries);
+ Measurement measurement = null;
+ try {
+ measurement = measurementMapper.selectOne(queryWrapper);
+ } catch (Exception e) {
+ logger.error(e.getMessage());
+ throw new BaseException(ErrorCode.GET_MSM_DES_FAIL, ErrorCode.GET_MSM_DES_FAIL_MSG);
+ }
+ if (measurement != null) {
+ return measurement.getDescription();
+ }
+ return null;
+ }
+
+ @Override
+ public void updateMeasurementsInfo(String host, DeviceInfoDTO deviceInfoDTO) throws BaseException {
+ List<String> descriptions = new ArrayList<>();
+ List<String> measurements = new ArrayList<>();
+ for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+ descriptions.add(deviceDTO.getDescription());
+ measurements.add(deviceDTO.getTimeseries());
+ }
+ for (int i = 0; i < measurements.size(); i++) {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("host", host);
+ queryWrapper.eq("measurement_name", measurements.get(i));
+ Measurement existMeasurement = measurementMapper.selectOne(queryWrapper);
+ // 未创建的测点
+ if (existMeasurement == null) {
+ Measurement mea = new Measurement();
+ mea.setDescription(descriptions.get(i));
+ mea.setMeasurementName(measurements.get(i));
+ mea.setHost(host);
+ int flag = measurementMapper.insert(mea);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.SET_MEASUREMENT_INFO_FAIL, ErrorCode.SET_MEASUREMENT_INFO_FAIL_MSG);
+ }
+ continue;
+ }
+ // 已创建的测点更新描述
+ existMeasurement.setDescription(descriptions.get(i));
+ int flag = measurementMapper.updateById(existMeasurement);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.SET_MEASUREMENT_INFO_FAIL, ErrorCode.SET_MEASUREMENT_INFO_FAIL_MSG);
+ }
+ }
+ }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/QueryServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/QueryServiceImpl.java
new file mode 100644
index 0000000..76dd6ae
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/QueryServiceImpl.java
@@ -0,0 +1,109 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.QueryMapper;
+import org.apache.iotdb.admin.model.entity.Query;
+import org.apache.iotdb.admin.model.vo.QueryVO;
+import org.apache.iotdb.admin.service.QueryService;
+import org.springframework.beans.BeanUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Service
+public class QueryServiceImpl extends ServiceImpl<QueryMapper, Query> implements QueryService {
+
+ @Autowired
+ private QueryMapper queryMapper;
+
+ @Override
+ public void save(Integer serverId, Query inputQuery) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("connection_id", serverId);
+ queryWrapper.eq("query_name", inputQuery.getQueryName());
+ Query query = queryMapper.selectOne(queryWrapper);
+ if (query == null) {
+ Query newQuery = new Query();
+ newQuery.setConnectionId(serverId);
+ newQuery.setQueryName(inputQuery.getQueryName());
+ newQuery.setSqls(inputQuery.getSqls());
+ queryMapper.insert(newQuery);
+ return;
+ }
+ throw new BaseException(ErrorCode.QUERY_EXIST, ErrorCode.QUERY_EXIST_MSG);
+ }
+
+ @Override
+ public void update(Integer serverId, Query inputQuery) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", inputQuery.getId());
+ Query query = queryMapper.selectOne(queryWrapper);
+ if (query != null) {
+ query.setQueryName(inputQuery.getQueryName());
+ query.setSqls(inputQuery.getSqls());
+ queryMapper.updateById(query);
+ return;
+ }
+ throw new BaseException(ErrorCode.QUERY_EXIST, ErrorCode.QUERY_EXIST_MSG);
+ }
+
+ @Override
+ public List<QueryVO> getQueryList(Integer serverId) {
+ QueryWrapper<Query> queryWrapper = new QueryWrapper();
+ queryWrapper.eq("connection_id", serverId);
+ List<Query> queries = queryMapper.selectList(queryWrapper);
+ List<QueryVO> queryVOList = new ArrayList<>();
+ for (Query query : queries) {
+ QueryVO queryVO = new QueryVO();
+ BeanUtils.copyProperties(query, queryVO);
+ queryVOList.add(queryVO);
+ }
+ return queryVOList;
+ }
+
+ @Override
+ public void deleteQuery(Integer queryId) throws BaseException {
+ QueryWrapper<Query> queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", queryId);
+ int flag = queryMapper.delete(queryWrapper);
+ if (flag <= 0) {
+ throw new BaseException(ErrorCode.QUERY_NOT_EXIST, ErrorCode.QUERY_NOT_EXIST_MSG);
+ }
+ }
+
+ @Override
+ public Query getQuery(Integer queryId) throws BaseException {
+ QueryWrapper<Query> queryWrapper = new QueryWrapper();
+ queryWrapper.eq("id", queryId);
+ Query query = queryMapper.selectOne(queryWrapper);
+ if (query == null) {
+ throw new BaseException(ErrorCode.QUERY_NOT_EXIST, ErrorCode.QUERY_NOT_EXIST_MSG);
+ }
+ return query;
+ }
+
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/UserServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/UserServiceImpl.java
new file mode 100644
index 0000000..8610c39
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/UserServiceImpl.java
@@ -0,0 +1,85 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.service.impl;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.UserMapper;
+import org.apache.iotdb.admin.model.entity.User;
+import org.apache.iotdb.admin.service.UserService;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
+import org.springframework.stereotype.Service;
+
+@Service
+public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements UserService {
+
+
+ @Autowired
+ private UserMapper userMapper;
+
+ @Autowired
+ private BCryptPasswordEncoder bCryptPasswordEncoder;
+
+ @Override
+ public User login(String name, String password) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("name", name);
+ User user = userMapper.selectOne(queryWrapper);
+ if (user != null) {
+ if (!bCryptPasswordEncoder.matches(password, user.getPassword())) {
+ throw new BaseException(ErrorCode.LOGIN_FAIL_PWD, ErrorCode.LOGIN_FAIL_PWD_MSG);
+ }
+ return user;
+ } else {
+ throw new BaseException(ErrorCode.LOGIN_FAIL_USER, ErrorCode.LOGIN_FAIL_USER_MSG);
+ }
+ }
+
+ @Override
+ public void insert(User user) throws BaseException {
+ QueryWrapper queryWrapper = new QueryWrapper();
+ queryWrapper.eq("name", user.getName());
+ User existUser = userMapper.selectOne(queryWrapper);
+ if (existUser == null) {
+ user.setPassword(bCryptPasswordEncoder.encode(user.getPassword()));
+ try {
+ userMapper.insert(user);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.INSERT_USER_FAIL, ErrorCode.INSERT_USER_FAIL_MSG);
+ }
+ } else {
+ throw new BaseException(ErrorCode.USER_EXIST, ErrorCode.USER_EXIST_MSG);
+ }
+ }
+
+ @Override
+ public void delete(Integer userId) throws BaseException {
+ try {
+ userMapper.deleteById(userId);
+ } catch (Exception e) {
+ throw new BaseException(ErrorCode.DELETE_USER_FAIL, ErrorCode.DELETE_USER_FAIL_MSG);
+ }
+ }
+
+
+}
diff --git a/backend/src/main/resources/META-INF/app.properties b/backend/src/main/resources/META-INF/app.properties
new file mode 100644
index 0000000..ca3692a
--- /dev/null
+++ b/backend/src/main/resources/META-INF/app.properties
@@ -0,0 +1,20 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+app.name=test
\ No newline at end of file
diff --git a/backend/src/main/resources/application-dev.properties b/backend/src/main/resources/application-dev.properties
new file mode 100644
index 0000000..4a14685
--- /dev/null
+++ b/backend/src/main/resources/application-dev.properties
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# 指定日志配置文件的位置
+logging.config=classpath:log4j2.xml
+
+# 配置端口号和上下文根
+server.port=8080
+server.servlet.context-path=/api
+
+# 指定数据源和连接驱动
+# 如下配置数据源的方式会导致项目重新打包后数据丢失,仅为了开发时方便测试,实际部署项目时请参考application-prod.properties文件配置
+spring.datasource.url=jdbc:sqlite::resource:sqlite/iotdb.db
+spring.datasource.driver-class-name=org.sqlite.JDBC
\ No newline at end of file
diff --git a/backend/src/main/resources/application-prod.properties b/backend/src/main/resources/application-prod.properties
new file mode 100644
index 0000000..b6b57f8
--- /dev/null
+++ b/backend/src/main/resources/application-prod.properties
@@ -0,0 +1,30 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# 指定日志配置文件的位置
+logging.config=classpath:log4j2-prod.xml
+
+# 配置端口号和上下文根
+server.port=8081
+server.servlet.context-path=/api
+
+# 指定数据源和连接驱动
+# 请将backend/src/main/resources/sqlite下的iotdb.db文件复制一份到你的服务器上,并将以下路径修改为你的iotdb.db文件路径
+spring.datasource.url=jdbc:sqlite:/usr/local/iotdb/data/iotdb1.db
+spring.datasource.driver-class-name=org.sqlite.JDBC
\ No newline at end of file
diff --git a/backend/src/main/resources/application-test.properties b/backend/src/main/resources/application-test.properties
new file mode 100644
index 0000000..2d959b0
--- /dev/null
+++ b/backend/src/main/resources/application-test.properties
@@ -0,0 +1,26 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+logging.config=classpath:log4j2.xml
+
+server.port=8079
+server.servlet.context-path=/api
+
+spring.datasource.url=jdbc:sqlite:/usr/local/iotdb/data/iotdb.db
+spring.datasource.driver-class-name=org.sqlite.JDBC
\ No newline at end of file
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
new file mode 100644
index 0000000..5aa2fca
--- /dev/null
+++ b/backend/src/main/resources/application.properties
@@ -0,0 +1,21 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements. See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership. The ASF licenses this file
+# to you under the Apache License, Version 2.0 (the
+# "License"); you may not use this file except in compliance
+# with the License. You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing,
+# software distributed under the License is distributed on an
+# "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+# KIND, either express or implied. See the License for the
+# specific language governing permissions and limitations
+# under the License.
+#
+
+# 指定配置文件。dev、prod、test分别表示开发、生产、测试环境
+spring.profiles.active=dev
\ No newline at end of file
diff --git a/backend/src/main/resources/log4j2-prod.xml b/backend/src/main/resources/log4j2-prod.xml
new file mode 100644
index 0000000..3a0f519
--- /dev/null
+++ b/backend/src/main/resources/log4j2-prod.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<configuration status="ERROR">
+
+ <Properties>
+ <!--应用名-->
+ <property name="app">IoTDB-Workbench</property>
+ <property name="log.root.level">INFO</property>
+ <property name="log.home">/data/applogs/app-prod</property>
+ <property name="log.default.pattern">%-d{yyyy-MM-dd HH:mm:ss.SSS} [%p] [${app}] %l %m%n</property>
+ <property name="log.stats.pattern">%m%n</property>
+ </Properties>
+
+ <appenders>
+ <Console name="STDOUT" target="SYSTEM_OUT">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ </Console>
+
+ <RollingFile name="ROLLING_DEBUG" fileName="${log.home}/${app}_debug.log"
+ filePattern="${log.home}/debug.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <!--<DirectWriteRolloverStrategy maxFiles="10"/>-->
+ <Filters>
+ <ThresholdFilter level="DEBUG" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_INFO" fileName="${log.home}/${app}_info.log"
+ filePattern="${log.home}/info.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <Filters>
+ <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
+ <ThresholdFilter level="INFO" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_WARN" fileName="${log.home}/${app}_warn.log"
+ filePattern="${log.home}/warn.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <Filters>
+ <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
+ <ThresholdFilter level="WARN" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_ERROR" fileName="${log.home}/${app}_error.log"
+ filePattern="${log.home}/error.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <!--<DirectWriteRolloverStrategy maxFiles="10"/>-->
+ <Filters>
+ <ThresholdFilter level="ERROR" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+
+
+ </appenders>
+
+ <loggers>
+ <!--level日志级别: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
+ <Root level="${log.root.level}">
+ <AppenderRef ref="STDOUT"/>
+ <AppenderRef ref="ROLLING_INFO"/>
+ <AppenderRef ref="ROLLING_WARN"/>
+ <AppenderRef ref="ROLLING_ERROR"/>
+ <!--<AppenderRef ref="ROLLING_DEBUG"/>-->
+ </Root>
+
+
+ <!--<logger name="com.alibaba" level="ERROR"/>-->
+ <!--<logger name="org" level="ERROR"/>-->
+
+ </loggers>
+
+</configuration>
+
diff --git a/backend/src/main/resources/log4j2.xml b/backend/src/main/resources/log4j2.xml
new file mode 100644
index 0000000..21772ee
--- /dev/null
+++ b/backend/src/main/resources/log4j2.xml
@@ -0,0 +1,120 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+ ~ Licensed to the Apache Software Foundation (ASF) under one
+ ~ or more contributor license agreements. See the NOTICE file
+ ~ distributed with this work for additional information
+ ~ regarding copyright ownership. The ASF licenses this file
+ ~ to you under the Apache License, Version 2.0 (the
+ ~ "License"); you may not use this file except in compliance
+ ~ with the License. You may obtain a copy of the License at
+ ~
+ ~ http://www.apache.org/licenses/LICENSE-2.0
+ ~
+ ~ Unless required by applicable law or agreed to in writing,
+ ~ software distributed under the License is distributed on an
+ ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ ~ KIND, either express or implied. See the License for the
+ ~ specific language governing permissions and limitations
+ ~ under the License.
+ -->
+
+<configuration status="ERROR">
+
+ <Properties>
+ <!--应用名-->
+ <property name="app">IoTDB-Workbench</property>
+ <property name="log.root.level">INFO</property>
+ <property name="log.home">/data/applogs/app-test</property>
+ <property name="log.default.pattern">%-d{yyyy-MM-dd HH:mm:ss.SSS} [%p] [${app}] %l %m%n</property>
+ <property name="log.stats.pattern">%m%n</property>
+ </Properties>
+
+ <appenders>
+ <Console name="STDOUT" target="SYSTEM_OUT">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ </Console>
+
+ <RollingFile name="ROLLING_DEBUG" fileName="${log.home}/${app}_debug.log"
+ filePattern="${log.home}/debug.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <!--<DirectWriteRolloverStrategy maxFiles="10"/>-->
+ <Filters>
+ <ThresholdFilter level="DEBUG" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_INFO" fileName="${log.home}/${app}_info.log"
+ filePattern="${log.home}/info.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <Filters>
+ <ThresholdFilter level="WARN" onMatch="DENY" onMismatch="NEUTRAL"/>
+ <ThresholdFilter level="INFO" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_WARN" fileName="${log.home}/${app}_warn.log"
+ filePattern="${log.home}/warn.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <Filters>
+ <ThresholdFilter level="ERROR" onMatch="DENY" onMismatch="NEUTRAL"/>
+ <ThresholdFilter level="WARN" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+ <RollingFile name="ROLLING_ERROR" fileName="${log.home}/${app}_error.log"
+ filePattern="${log.home}/error.log.%i">
+ <PatternLayout>
+ <Pattern>${log.default.pattern}</Pattern>
+ </PatternLayout>
+ <Policies>
+ <SizeBasedTriggeringPolicy size="100 MB" />
+ </Policies>
+ <DefaultRolloverStrategy max="10"/>
+ <!--<DirectWriteRolloverStrategy maxFiles="10"/>-->
+ <Filters>
+ <ThresholdFilter level="ERROR" onMatch="ACCEPT"/>
+ </Filters>
+ </RollingFile>
+
+
+
+ </appenders>
+
+ <loggers>
+ <!--level日志级别: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
+ <Root level="${log.root.level}">
+ <AppenderRef ref="STDOUT"/>
+ <AppenderRef ref="ROLLING_INFO"/>
+ <AppenderRef ref="ROLLING_WARN"/>
+ <AppenderRef ref="ROLLING_ERROR"/>
+ <!--<AppenderRef ref="ROLLING_DEBUG"/>-->
+ </Root>
+
+
+ <!--<logger name="com.alibaba" level="ERROR"/>-->
+ <!--<logger name="org" level="ERROR"/>-->
+
+ </loggers>
+
+</configuration>
+
diff --git a/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java b/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java
new file mode 100644
index 0000000..dcf0780
--- /dev/null
+++ b/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java
@@ -0,0 +1,41 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin;
+
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.context.junit4.SpringRunner;
+
+/**
+ * ${DESCRIPTION}
+ *
+ * @author fanli
+ */
+@RunWith(SpringRunner.class)
+@SpringBootTest
+public class DemoJDBC {
+
+
+ @Test
+ public void testSelect() {
+
+ }
+}
diff --git a/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java b/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
new file mode 100644
index 0000000..df531d9
--- /dev/null
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import org.junit.jupiter.api.Test;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.annotation.Rollback;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.RequestBuilder;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.transaction.annotation.Transactional;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.net.InetAddress;
+import java.util.Calendar;
+
+@SpringBootTest
+class ConnectionControllerTest {
+
+ private MockMvc mvc;
+
+ @Autowired
+ private WebApplicationContext wac;
+
+ private String token = getToken();
+
+ @Transactional
+ @Rollback
+ @Test
+ void saveOrUpdateConnection() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"alias\": \"tttt\",\n" +
+ " \"host\": \"localhost\",\n" +
+ " \"password\": \"root\",\n" +
+ " \"port\": 6667,\n" +
+ " \"userId\": 1,\n" +
+ " \"username\": \"root\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Transactional
+ @Rollback
+ @Test
+ void deleteConnection() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Test
+ void getConnection() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Test
+ void getAllConnections() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers")
+ .contextPath("/api")
+ .param("userId", "1")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ private String getToken() {
+ Calendar instance = Calendar.getInstance();
+ try {
+ instance.add(Calendar.HOUR, 24);
+ String token = JWT.create()
+ .withClaim("userId", 1)
+ .withClaim("name", "root")
+ .withExpiresAt(instance.getTime())
+ .sign(Algorithm.HMAC256("IOTDB:" + InetAddress.getLocalHost().getHostAddress()));
+ return token;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+}
\ No newline at end of file
diff --git a/backend/src/test/java/org/apache/iotdb/admin/controller/IotDBControllerTest.java b/backend/src/test/java/org/apache/iotdb/admin/controller/IotDBControllerTest.java
new file mode 100644
index 0000000..d724a47
--- /dev/null
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/IotDBControllerTest.java
@@ -0,0 +1,380 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.admin.controller;
+
+import com.auth0.jwt.JWT;
+import com.auth0.jwt.algorithms.Algorithm;
+import org.junit.jupiter.api.MethodOrderer;
+import org.junit.jupiter.api.Order;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.TestMethodOrder;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.test.web.servlet.MockMvc;
+import org.springframework.test.web.servlet.RequestBuilder;
+import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
+import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
+import org.springframework.test.web.servlet.setup.MockMvcBuilders;
+import org.springframework.web.context.WebApplicationContext;
+
+import java.net.InetAddress;
+import java.util.Calendar;
+
+@SpringBootTest
+@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
+class IotDBControllerTest {
+
+ private MockMvc mvc;
+ @Autowired
+ private WebApplicationContext wac;
+
+
+ private String token = getToken();
+
+ private String getToken() {
+ Calendar instance = Calendar.getInstance();
+ try {
+ instance.add(Calendar.HOUR, 24);
+ String token = JWT.create()
+ .withClaim("userId", 1)
+ .withClaim("name", "root")
+ .withExpiresAt(instance.getTime())
+ .sign(Algorithm.HMAC256("IOTDB:" + InetAddress.getLocalHost().getHostAddress()));
+ return token;
+ } catch (Exception e) {
+ e.printStackTrace();
+ return null;
+ }
+ }
+
+ @Order(1)
+ @Test
+ void saveStorageGroup() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/storageGroups")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"description\": \"a group\",\n" +
+ " \"groupName\": \"group1\",\n" +
+ " \"ttl\": 1,\n" +
+ " \"ttlUnit\": \"day\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/storageGroups")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"description\": \"a group2\",\n" +
+ " \"groupName\": \"group2\",\n" +
+ " \"ttl\": 2,\n" +
+ " \"ttlUnit\": \"day\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(2)
+ @Test
+ void getAllStorageGroupsInfo() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/info")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(3)
+ @Test
+ void getAllStorageGroups() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(4)
+ @Test
+ void getStorageGroup() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(5)
+ @Test
+ void deleteStorageGroup() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1/storageGroups/group2")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(6)
+ @Test
+ void saveOrUpdateDevice() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"description\": \"a device1\",\n" +
+ " \"deviceDTOList\": [\n" +
+ " {\n" +
+ " \"dataType\": \"INT64\",\n" +
+ " \"description\": \"a dev1\",\n" +
+ " \"encoding\": \"PLAIN\",\n" +
+ " \"timeseries\": \"s1\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"deviceName\": \"dev1\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"description\": \"a device1\",\n" +
+ " \"deviceDTOList\": [\n" +
+ " {\n" +
+ " \"dataType\": \"INT64\",\n" +
+ " \"description\": \"a dev1\",\n" +
+ " \"encoding\": \"PLAIN\",\n" +
+ " \"timeseries\": \"s1\"\n" +
+ " }\n" +
+ " ],\n" +
+ " \"deviceName\": \"dev2\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(7)
+ @Test
+ void getDeviceInfo() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(8)
+ @Test
+ void getDevicesInfoByGroupName() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/info")
+ .param("pageSize", "10")
+ .param("pageNum", "1")
+ .param("keyword", "d")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(9)
+ @Test
+ void getDevicesByGroupName() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(10)
+ @Test
+ void deleteDevice() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev2")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(11)
+ @Test
+ void getMeasurementsByDeviceName() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev1/info")
+ .param("pageSize", "10")
+ .param("pageNum", "1")
+ .param("keyword", "s")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(12)
+ @Test
+ void getMeasurementInfo() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(13)
+ @Test
+ void getTimeseries() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev1/timeseries")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(14)
+ @Test
+ void deleteTimeseries() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1/storageGroups/group1/devices/dev1/timeseries/s1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(15)
+ @Test
+ void setIotDBUser() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/users")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"password\": \"1234\",\n" +
+ " \"userName\": \"lisi\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(16)
+ @Test
+ void getIotDBUserList() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/users")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(17)
+ @Test
+ void setUserPrivileges() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/users/lisi")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"cancelPrivileges\": [],\n" +
+ " \"delDevicePaths\": [],\n" +
+ " \"delGroupPaths\": [],\n" +
+ " \"delTimeseriesPaths\": [],\n" +
+ " \"devicePaths\": [],\n" +
+ " \"groupPaths\": [\n" +
+ " \"group1\"\n" +
+ " ],\n" +
+ " \"privileges\": [\n" +
+ " \"CREATE_TIMESERIES\"\n" +
+ " ],\n" +
+ " \"timeseriesPaths\": [],\n" +
+ " \"type\": 1\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(18)
+ @Test
+ void getIotDBUser() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .get("http://127.0.0.1:8080/api/servers/1/users/lisi")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(19)
+ @Test
+ void updatePassword() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .post("http://127.0.0.1:8080/api/servers/1/users/pwd")
+ .contextPath("/api")
+ .content("{\n" +
+ " \"password\": \"2222\",\n" +
+ " \"userName\": \"lisi\"\n" +
+ "}")
+ .header("Authorization", token)
+ .header("Content-Type", "application/json");
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(20)
+ @Test
+ void deleteIotDBUser() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1/users/lisi")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+ @Order(21)
+ @Test
+ void deleteStorageGroup2() throws Exception {
+ mvc = MockMvcBuilders.webAppContextSetup(wac).build();
+ RequestBuilder request = MockMvcRequestBuilders
+ .delete("http://127.0.0.1:8080/api/servers/1/storageGroups/group1")
+ .contextPath("/api")
+ .header("Authorization", token);
+ mvc.perform(request).andExpect(MockMvcResultMatchers.status().isOk());
+ }
+
+}
\ No newline at end of file
diff --git a/backend/src/test/java/org/apache/iotdb/admin/controller/QueryControllerTest.java b/backend/src/test/java/org/apache/iotdb/admin/controller/QueryControllerTest.java
new file mode 100644
index 0000000..cc06ff8
--- /dev/null
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/QueryControllerTest.java
@@ -0,0 +1,134 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
... 179 lines suppressed ...