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:59 UTC

[iotdb-web-workbench] 25/29: iotdb-web-workbench 1.1.0 verson code (#10)

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 77e581d0d937f8d66475d70214dee5646370eee1
Author: zhengqiang-cisdi <lo...@qq.com>
AuthorDate: Tue Jan 11 08:58:29 2022 +0800

    iotdb-web-workbench 1.1.0 verson code (#10)
    
    * Add German translation
    
    * fix(pages)删除deep选择器warning
    
    * feat(project)vue升级到vue3.2
    
    * 导入导出csv模块
    
    * 1.增加物理量数据的删改查接口2.修改csv模块
    
    * feat(docs)添加apache 许可注释
    
    * 1.获取设备列表接口变更2.增加判断设备是否存在的接口
    
    * 将存储组、实体和物理量改为全路径名
    
    * 增加获取iotdb统计信息的接口
    
    * 变更“新增或编辑实体”接口
    
    * 变更“获取指定设备下的物理量详情”接口
    
    * 变更“获取指定物理量的最新两百条数据记录”接口
    
    * 增加"随机导入物理量数据"接口
    
    * 1.完善"随机导入物理量数据"接口;2.解决由于存在子实体引起的一些问题
    
    * 增加"导出指定实体下的物理量数据"接口
    
    * 增加角色相关的部分接口
    
    * 增加角色相关接口
    
    * 修改了“新增或编辑实体”接口
    
    * 修改"获取指定实体下的物理量数据"接口,以满足不同的时间范围条件
    
    * 数据连接切图
    
    * 修改"导出指定实体下的物理量数据"接口
    
    * 增加"获取iotdb数据模型"接口
    
    * 修改“获取指定设备下的物理量详情”接口
    
    * 添加spotless插件,格式化代码
    
    * 1.增加获取用户/角色权限管理权限接口;2.优化部分错误码提示
    
    * 1.增加修改用户/角色权限管理权限接口
    
    * 优化连接池和结果集的关闭
    
    * feat(指令): elementPlus全局组件注册
    
    * feat(用户角色): 部分页面完成
    
    * feat(lefttree)add page left menu tree
    
    * 添加获取数据管理权限相关接口
    
    * feat(用户角色): api接口更新
    
    * 添加修改数据管理权限相关接口
    
    * feat(用户角色): 部分接口对接
    
    * 1.1权限管理权限联调&&账号权限截图
    
    * feat(角色): 用户管理权限弹窗完成
    
    * feat(treemenu):support twin tab
    
    * fix(lefttree)add child device new button
    
    * 增加获取用户所有权限管理权限的接口
    
    * feat(element): 全局tag样式新增el-tag-deep-green
    
    * feat(用户角色): 数据管理权限列表
    
    * feat(用户角色): 展示态修改
    
    * feat(element): checkbox pager 样式
    
    * feat(权限): 前端限制权限添加
    
    * 修复ttl单位的bug
    
    * fix(menutree): fix menutree icon
    
    * fix(#9628): 标签可以为空
    
    * feat(styleint): deep不报错
    
    * feat(实体): eslint stylelint修复
    
    * fix(logo): fix logo png
    
    * fix(style): fix page style
    
    * fix(style): tab color fix
    
    * popconfirm 英文
    
    * 修复编辑物理量的bug
    
    * fix(style): tab css global error  fix
    
    * feat(menu): add feedback menu entry
    
    * fix(query btn):fix create query btn bug
    
    * fix(sql): 运行结果统计修改
    
    Co-authored-by: wangdan-cisdi <47...@qq.com>
    Co-authored-by: huangrui <hu...@163.com>
    Co-authored-by: wenjin <12...@qq.com>
    Co-authored-by: julian <j....@pragmaticminds.de>
    Co-authored-by: qhy <97...@qq.com>
    Co-authored-by: qhy <qh...@163.com>
    Co-authored-by: benqhy <85...@users.noreply.github.com>
    Co-authored-by: shuhong.liu <01...@cisdi.com.cn>
    Co-authored-by: curiosityLiu <81...@qq.com>
    Co-authored-by: Xiangdong Huang <hx...@apache.org>
---
 .gitignore                                         |  118 +-
 README.md                                          |   33 +-
 backend/Dockerfile                                 |    7 -
 backend/README.md                                  |    8 -
 backend/doc/config.md                              |   48 -
 backend/doc/image/welcome.PNG                      |  Bin 0 -> 26247 bytes
 backend/doc/intro.md                               |    8 +-
 backend/doc/note.md                                |   37 +-
 backend/gradle/wrapper/gradle-wrapper.jar          |  Bin 0 -> 59203 bytes
 backend/gradle/wrapper/gradle-wrapper.properties   |    5 +
 backend/pom.xml                                    |   35 +-
 .../org/apache/iotdb/admin/AdminApplication.java   |    3 +-
 .../iotdb/admin/aop/BaseExceptionAdvice.java       |    4 +-
 .../apache/iotdb/admin/aop/ParamValidAspect.java   |    7 +-
 .../apache/iotdb/admin/common/ScheduledTask.java   |   64 +
 .../admin/common/exception/BaseException.java      |    1 -
 .../iotdb/admin/common/exception/ErrorCode.java    |  392 ++-
 .../admin/common/utils/AuthenticationUtils.java    |    2 +-
 .../DeviceDTO.java => config/FileProperties.java}  |   25 +-
 .../apache/iotdb/admin/config/FilterConfig.java    |    3 +-
 .../iotdb/admin/config/MybatisPlusConfig.java      |   10 +-
 .../apache/iotdb/admin/config/SecurityConfig.java  |    3 +-
 .../apache/iotdb/admin/config/SwaggerConfig.java   |   10 +-
 .../iotdb/admin/config/ValidatorConfiguration.java |    2 +-
 .../admin/controller/ConnectionController.java     |   25 +-
 .../iotdb/admin/controller/FileController.java     |  131 +
 .../iotdb/admin/controller/HealthController.java   |    7 +-
 .../iotdb/admin/controller/IotDBController.java    |  889 ++++--
 .../iotdb/admin/controller/QueryController.java    |   30 +-
 .../iotdb/admin/controller/UserController.java     |   37 +-
 .../java/org/apache/iotdb/admin/demo/JDBC.java     |  152 -
 .../org/apache/iotdb/admin/demo/NativeAPI.java     |  113 -
 .../org/apache/iotdb/admin/filter/TokenFilter.java |    2 -
 .../vo/DeviceVO.java => mapper/RoleMapper.java}    |   17 +-
 .../{CountDTO.java => AuthorityPrivilegeDTO.java}  |    7 +-
 .../iotdb/admin/model/dto/ConnectionDTO.java       |   20 +-
 .../org/apache/iotdb/admin/model/dto/CountDTO.java |    1 -
 .../dto/{SearchDTO.java => DataDeleteDTO.java}     |   12 +-
 .../dto/{SearchDTO.java => DataQueryDTO.java}      |   13 +-
 .../dto/{DeviceInfoDTO.java => DataUpdateDTO.java} |   18 +-
 .../apache/iotdb/admin/model/dto/DeviceDTO.java    |   15 +
 .../iotdb/admin/model/dto/DeviceInfoDTO.java       |    8 +-
 .../org/apache/iotdb/admin/model/dto/GroupDTO.java |    4 +-
 .../apache/iotdb/admin/model/dto/IotDBRole.java    |   11 +-
 .../apache/iotdb/admin/model/dto/IotDBUser.java    |   13 +-
 .../iotdb/admin/model/dto/MeasurementDTO.java      |    1 -
 .../iotdb/admin/model/dto/PrivilegeInfoDTO.java    |    3 +-
 .../{DeviceInfoDTO.java => RandomImportDTO.java}   |   22 +-
 .../model/dto/{CountDTO.java => RoleGrantDTO.java} |    8 +-
 .../apache/iotdb/admin/model/dto/SearchDTO.java    |    2 +-
 .../model/dto/{CountDTO.java => UserGrantDTO.java} |    8 +-
 .../iotdb/admin/model/entity/Connection.java       |   28 +-
 .../apache/iotdb/admin/model/entity/Device.java    |   10 +-
 .../iotdb/admin/model/entity/Measurement.java      |    4 +-
 .../org/apache/iotdb/admin/model/entity/Query.java |    4 +-
 .../model/entity/{Measurement.java => Role.java}   |   13 +-
 .../iotdb/admin/model/entity/StorageGroup.java     |    8 +-
 .../org/apache/iotdb/admin/model/entity/User.java  |    8 +-
 .../org/apache/iotdb/admin/model/vo/BaseVO.java    |    6 +-
 .../org/apache/iotdb/admin/model/vo/ConnVO.java    |    6 +-
 .../apache/iotdb/admin/model/vo/ConnectionVO.java  |    1 -
 .../model/vo/{QueryVO.java => DataCountVO.java}    |    9 +-
 .../model/vo/{MeasurementVO.java => DataInfo.java} |    9 +-
 .../vo/{GroupInfoVO.java => DataModelVO.java}      |   41 +-
 .../DataPrivilegeVO.java}                          |   14 +-
 .../model/vo/{SqlResultVO.java => DataVO.java}     |    9 +-
 .../apache/iotdb/admin/model/vo/DeviceInfo.java    |    3 +-
 .../apache/iotdb/admin/model/vo/DeviceInfoVO.java  |    1 -
 .../org/apache/iotdb/admin/model/vo/DeviceVO.java  |    1 -
 .../apache/iotdb/admin/model/vo/GroupInfoVO.java   |    1 -
 .../org/apache/iotdb/admin/model/vo/GroupVO.java   |    1 -
 .../{MeasuremtnInfoVO.java => ImportDataVO.java}   |   16 +-
 .../apache/iotdb/admin/model/vo/MeasurementVO.java |    7 +-
 .../iotdb/admin/model/vo/MeasuremtnInfoVO.java     |    1 -
 .../vo/{MeasuremtnInfoVO.java => NodeTreeVO.java}  |   19 +-
 .../org/apache/iotdb/admin/model/vo/QueryVO.java   |    1 -
 .../org/apache/iotdb/admin/model/vo/RecordVO.java  |    7 +-
 .../admin/model/vo/{DeviceVO.java => RoleVO.java}  |   11 +-
 .../apache/iotdb/admin/model/vo/SqlResultVO.java   |    2 -
 .../iotdb/admin/model/vo/StorageGroupVO.java       |    1 -
 .../model/vo/{RecordVO.java => UserRolesVO.java}   |    8 +-
 .../iotdb/admin/service/ConnectionService.java     |    1 -
 .../apache/iotdb/admin/service/DeviceService.java  |    1 -
 .../service/{UserService.java => FileService.java} |   11 +-
 .../apache/iotdb/admin/service/GroupService.java   |    1 -
 .../apache/iotdb/admin/service/IotDBService.java   |   88 +-
 .../iotdb/admin/service/MeasurementService.java    |    1 -
 .../apache/iotdb/admin/service/QueryService.java   |    3 +-
 .../service/{UserService.java => RoleService.java} |   12 +-
 .../apache/iotdb/admin/service/UserService.java    |    1 -
 .../admin/service/impl/ConnectionServiceImpl.java  |   16 +-
 .../admin/service/impl/DeviceServiceImpl.java      |    2 +-
 .../iotdb/admin/service/impl/FileServiceImpl.java  |   77 +
 .../iotdb/admin/service/impl/GroupServiceImpl.java |    3 -
 .../iotdb/admin/service/impl/IotDBServiceImpl.java | 3010 +++++++++++++-------
 .../admin/service/impl/MeasurementServiceImpl.java |    4 +-
 .../iotdb/admin/service/impl/QueryServiceImpl.java |    4 +-
 .../iotdb/admin/service/impl/RoleServiceImpl.java  |   99 +
 .../org/apache/iotdb/admin/tool/ExportCsv.java     |  214 ++
 .../org/apache/iotdb/admin/tool/ImportCsv.java     |  388 +++
 .../src/main/resources/application-dev.properties  |   19 +-
 .../src/main/resources/application-prod.properties |   17 +-
 .../src/main/resources/application-test.properties |    9 +-
 backend/src/main/resources/application.properties  |    2 +-
 backend/src/main/resources/banner.txt              |    8 +
 backend/src/main/resources/file/template.csv       |   34 +
 backend/src/main/resources/log4j2-prod.xml         |    3 +-
 backend/src/main/resources/log4j2.xml              |    3 +-
 backend/src/main/resources/sqlite/iotdb.db         |  Bin 36864 -> 36864 bytes
 .../test/java/org/apache/iotdb/admin/DemoJDBC.java |   38 -
 .../admin/controller/ConnectionControllerTest.java |    1 -
 .../admin/controller/IotDBControllerTest.java      |    1 -
 .../admin/controller/QueryControllerTest.java      |    2 -
 ...ControllerTest.java => UserControllerTest.java} |   52 +-
 frontend/.eslintignore                             |    2 +-
 frontend/.eslintrc.js                              |    2 +-
 frontend/.prettierrc.js                            |    3 +-
 frontend/.stylelintrc.js                           |    4 +-
 frontend/babel.config.js                           |    2 +-
 frontend/package-lock.json                         | 1175 ++++----
 frontend/package.json                              |    8 +-
 frontend/public/iconfont.js                        |   77 +-
 frontend/public/index.html                         |   19 -
 frontend/src/App.vue                               |   34 +-
 frontend/src/assets/data.png                       |  Bin 0 -> 908 bytes
 frontend/src/assets/device.png                     |  Bin 0 -> 598 bytes
 frontend/src/assets/logo.png                       |  Bin 7465 -> 4184 bytes
 frontend/src/assets/storage.png                    |  Bin 0 -> 1178 bytes
 frontend/src/components/Echarts.vue                |   32 +-
 frontend/src/components/FormTable.vue              |  188 +-
 frontend/src/components/HelloWorld.vue             |   32 +-
 frontend/src/components/StandTable.vue             |  384 ++-
 frontend/src/components/TreeSelect.vue             |  196 ++
 frontend/src/directive/icon.js                     |    2 +-
 frontend/src/directive/index.js                    |    2 +-
 frontend/src/i18n/cn.js                            |  157 +-
 frontend/src/i18n/de.js                            |  131 +-
 frontend/src/i18n/en.js                            |  550 ++--
 frontend/src/i18n/index.js                         |    2 +-
 frontend/src/lib/Button.vue                        |   21 +
 frontend/src/main.js                               |    6 +-
 frontend/src/plugins/element_plus.js               |  168 ++
 frontend/src/plugins/event_bus.js                  |    6 +
 frontend/src/plugins/index.js                      |   12 +
 frontend/src/router/index.js                       |   16 +-
 frontend/src/shims-vue.d.ts                        |   19 -
 frontend/src/store/dataBaseM/index.js              |   41 +-
 frontend/src/store/index.js                        |   21 +-
 frontend/src/store/moduleA/index.js                |    2 +-
 frontend/src/store/storage/index.js                |    2 +-
 frontend/src/styles/element.scss                   |  150 +-
 frontend/src/styles/reset.scss                     |    9 +-
 frontend/src/styles/variables.scss                 |    8 +-
 frontend/src/util/api_axios.js                     |    2 +-
 frontend/src/util/axios.js                         |   10 +-
 frontend/src/util/constant.js                      |    6 +
 frontend/src/util/export.js                        |   31 +
 frontend/src/util/setOperation.js                  |   33 +
 frontend/src/views/About/index.vue                 |   43 +-
 .../views/DataBaseM/components/dataListTree.vue    |  212 +-
 .../src/views/DataBaseM/components/iconTypes.vue   |   54 +-
 .../src/views/DataBaseM/hooks/useElementResize.js  |    2 +-
 frontend/src/views/DataBaseM/index.vue             |  113 +-
 frontend/src/views/Device/api/index.js             |   10 +-
 frontend/src/views/Device/index.vue                |  204 +-
 frontend/src/views/DeviceMessage/api/index.js      |   46 +-
 .../src/views/DeviceMessage/components/action.vue  |   72 +-
 frontend/src/views/DeviceMessage/index.vue         |  957 ++++++-
 frontend/src/views/Home.vue                        |   34 +-
 frontend/src/views/Login/index.vue                 |   71 +-
 frontend/src/views/Root/hooks/useLangSwitch.js     |    8 +-
 frontend/src/views/Root/index.vue                  |   49 +-
 frontend/src/views/Source/api/index.js             |  110 +
 frontend/src/views/Source/components/dataModal.vue |  189 ++
 .../src/views/Source/components/dataModalAll.vue   |  326 +++
 frontend/src/views/Source/components/empty.vue     |   40 +-
 frontend/src/views/Source/components/newSource.vue |   55 +-
 .../src/views/Source/components/permitDialog.vue   |  541 ++++
 .../views/Source/components/role/AuthManage.vue    |  398 +++
 .../views/Source/components/role/DataManage.vue    |  409 +++
 .../Source/components/role/DialogGrantUser.vue     |  211 ++
 .../src/views/Source/components/role/Index.vue     |   50 +
 .../views/Source/components/role/PowerManage.vue   |  101 +
 .../src/views/Source/components/role/RoleInfo.vue  |  191 ++
 .../src/views/Source/components/role/RoleList.vue  |  270 ++
 .../src/views/Source/components/roleDialog.vue     |  228 ++
 frontend/src/views/Source/components/treeData.vue  |  351 +++
 frontend/src/views/Source/index.vue                | 1759 ++++++++----
 frontend/src/views/SqlSerch/api/index.js           |   25 +-
 .../src/views/SqlSerch/components/codemirror.vue   |   81 +-
 .../src/views/SqlSerch/components/eltooltip.vue    |   34 +-
 .../src/views/SqlSerch/components/formserch.vue    |   36 +-
 .../views/SqlSerch/components/formserchData.vue    |   56 +-
 .../src/views/SqlSerch/components/sqlDrawer.vue    |   75 +-
 frontend/src/views/SqlSerch/hooks/codemirror.js    |    2 +-
 frontend/src/views/SqlSerch/hooks/function.js      |    2 +-
 frontend/src/views/SqlSerch/hooks/keywords.js      |   52 +-
 frontend/src/views/SqlSerch/hooks/selectList.js    |    2 +-
 .../src/views/SqlSerch/hooks/useElementResize.js   |    3 +-
 frontend/src/views/SqlSerch/index.vue              |  174 +-
 frontend/src/views/storage/index.vue               |  224 +-
 frontend/src/views/storage/newStorage.vue          |   65 +-
 frontend/tests/unit/example.spec.js                |   19 -
 frontend/vue.config.js                             |    4 +-
 package-lock.json                                  |    3 +
 205 files changed, 13317 insertions(+), 4978 deletions(-)

diff --git a/.gitignore b/.gitignore
index a0b9c7b..73dfeae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,109 +1,13 @@
-**/*.pid
-**/gc.log*
-**/logs/*
-**/lib/**
-**/data/**
-
-# Python runtime file
-**/__pycache__/**
-
-# Eclipse IDE files
-**/.classpath
-**/.project
-**/.settings/
-# src/main/resources/
-# intellij IDE files
-**/*.iml
-**/.idea/
-**/*.log
-**/*.ipr
-**/*.iws
-# Apple OS X related
-**/.DS_Store
-derby-tsfile-db
-
-# build generated
-**/target/
-
-# intermediately generated locally
-
-tsfile-timeseries/src/main/resources/logback.out.out.xml
-tsfile-timeseries/src/main/resources/logback.out.xml
-tsfile-service/derby-tsfile-db/
-tsfile-timeseries/src/test/resources/data
-src/main/resources/metadata/mlog.txt
-tsfile-jdbc/src/main/resources/output/queryRes.csv
-
-*.txt
-
-*.jar
-*.gz
-*.tar.gz
-*.tar
-#src/test/resources/logback.xml
-
-### CSV ###
+.gradle
+.gradle/
+gradle/
+build/
+.idea/
+.mvn/
+*.iml
 *.csv
-### Maven ###
-grafana/target/
-!grafana/.mvn/wrapper/maven-wrapper.jar
-grafana/.mvn/
-
-grafana/logs/
-*.log
-
-### STS ###
-.apt_generated
-.classpath
-.factorypath
-.project
-.settings
-.springBeans
-
-
-### NetBeans ###
-**/nbproject/private/
-**/nbbuild/
-**/dist/
-**/nbdist/
-**/.nb-gradle/
-grafana/data/
-
-### vscode project
-**/.vscode/
-
-
-grafana/data/test.csv
-**/lib/
-/target/
-*.tsfile
-tsfile/src/test/resources/*.ts
-
-### Apache release ###
-local-snapshots-dir/
-venv/
-
-partitions.tmp
-partitions
-node_identifier
-
-### temporary file of the distributed version ###
-remote/
-
-# gitpod
-.theia/
-
-classes/
-
-### Cmake files ###
-*.cmake
-Makefile
-**/CMakeFiles/
-
-### cluster test data
-node1/
-node2/
-node3/
+!template.csv
+*.txt
+target/
+*.versionsBackup
 
-# Exclude copied license
-/client-py/LICENSE
diff --git a/README.md b/README.md
index 6d6c312..c2a9c75 100644
--- a/README.md
+++ b/README.md
@@ -1,29 +1,24 @@
-<!--
+[![License](https://img.shields.io/badge/license-Apache%202-4EB1BA.svg)](https://www.apache.org/licenses/LICENSE-2.0.html)
+[![GitHub release](https://img.shields.io/github/release/apache/iotdb.svg)](https://github.com/loveher147/iotdb-admin/releases)
+![](https://img.shields.io/badge/java--language-1.8-blue.svg)
 
-    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
+# IoTDB-Workbench
 
-        http://www.apache.org/licenses/LICENSE-2.0
+IoTDB-Workbench是IoTDB的可视化管理工具,可对IoTDB的数据进行增删改查、权限控制等,简化IoTDB的使用及学习成本。
+在我们心中IoTDB是最棒的时序数据库之一,我们将一直不遗余力地推动国产时序数据库IoTDB的应用和发展,为本土开源能力的提高、开源生态的发展,贡献自己的力量,欢迎大家加入IoTDB-Workbench的开发及维护,期待你的加入:
 
-    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.
+![微信](backend/doc/image/wechat.png)
 
--->
+## 后端服务运行
+
+[后端服务设计及运行说明](backend/README.md)
+
+## 前端服务运行
+
+[前端服务运行说明](frontend/README.md)
 
-[English](./README.md) | [中文](./README_zh.md)
 
-# Overview
 
-This code repo is a web based workbench for [Apache IoTDB](https://iotdb.apache.org)
 
 ## Docker
 
diff --git a/backend/Dockerfile b/backend/Dockerfile
index 62723a4..cccb7ff 100644
--- a/backend/Dockerfile
+++ b/backend/Dockerfile
@@ -17,13 +17,6 @@
 # under the License.
 #
 
-FROM maven:3.8.2-amazoncorretto-8 as builder
-
-WORKDIR /app
-
-COPY . .
-
-RUN mvn package
 
 
 
diff --git a/backend/README.md b/backend/README.md
index 63d3d6e..2e5c067 100644
--- a/backend/README.md
+++ b/backend/README.md
@@ -23,14 +23,6 @@
 
 [IoTDB-Workbench快速入门](doc/intro.md)
 
-## Building the Backend
-
-The backend can be built using maven by using
-
-```
-mvn clean install
-```
-
 ## 开发环境搭建
 
 [Maven配置](doc/maven.md)
diff --git a/backend/doc/config.md b/backend/doc/config.md
deleted file mode 100644
index bd1b453..0000000
--- a/backend/doc/config.md
+++ /dev/null
@@ -1,48 +0,0 @@
-<!--
-
-    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.
-
--->
-
-# 配置中心 Apollo
-
-##接入步骤
-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/image/welcome.PNG b/backend/doc/image/welcome.PNG
new file mode 100644
index 0000000..1eac27b
Binary files /dev/null and b/backend/doc/image/welcome.PNG differ
diff --git a/backend/doc/intro.md b/backend/doc/intro.md
index b57f038..7984784 100644
--- a/backend/doc/intro.md
+++ b/backend/doc/intro.md
@@ -49,7 +49,9 @@
 项目提供maven、gradle两种构建工具,以maven为例启动项目:  
 首先通过IntelliJ IDEA打开本项目,右键点击pom.xml,点击Add as Maven Project导入项目相关依赖。
 ![](image/pom.PNG)  
-导入完成后启动AdminApplication项目,如果未报错并出现如下界面则代表项目运行成功。  
+导入完成后启动AdminApplication项目,启动成功后你应该能看到如下界面。  
 ![](image/启动成功.PNG)  
-本系统默认登录用户为root,密码为123456。  
-具体部署步骤请参考[部署文档](deploy.md)
\ No newline at end of file
+接着,你可以通过浏览器访问127.0.0.1:8080/api/,看到如下页面则代表后端启动成功。
+![](image/welcome.PNG)  
+具体部署步骤请参考[部署文档](deploy.md)  
+本系统默认登录用户为root,密码为123456。  
\ No newline at end of file
diff --git a/backend/doc/note.md b/backend/doc/note.md
index 16f74b0..5c9312e 100644
--- a/backend/doc/note.md
+++ b/backend/doc/note.md
@@ -23,29 +23,29 @@
 
 ```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.
- */
+* 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.iotdb.service.rpc.xxx;
 
 import org.apache.thrift.xxx;
 
@@ -70,5 +70,4 @@ import java.util.Map;
 排列整齐 不同层级之间用空格分开
 
 ## 注释
-
 注释使用英文注释
diff --git a/backend/gradle/wrapper/gradle-wrapper.jar b/backend/gradle/wrapper/gradle-wrapper.jar
new file mode 100644
index 0000000..e708b1c
Binary files /dev/null and b/backend/gradle/wrapper/gradle-wrapper.jar differ
diff --git a/backend/gradle/wrapper/gradle-wrapper.properties b/backend/gradle/wrapper/gradle-wrapper.properties
new file mode 100644
index 0000000..da9702f
--- /dev/null
+++ b/backend/gradle/wrapper/gradle-wrapper.properties
@@ -0,0 +1,5 @@
+distributionBase=GRADLE_USER_HOME
+distributionPath=wrapper/dists
+distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
+zipStoreBase=GRADLE_USER_HOME
+zipStorePath=wrapper/dists
diff --git a/backend/pom.xml b/backend/pom.xml
index 63f9921..45d3bea 100644
--- a/backend/pom.xml
+++ b/backend/pom.xml
@@ -19,7 +19,7 @@
   -->
 
 <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">
+         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>
@@ -32,10 +32,9 @@
   <version>1.0.0</version>
   <packaging>jar</packaging>
   <name>IoTDB Workbench</name>
-  <description>Apache IoTDB Workbench开源项目</description>
+  <description>Apache IoTDB Workbench</description>
 
   <properties>
-    <!-- 对应java 1.8,如果编译错误,可能需要调整 -->
     <java.version>1.8</java.version>
     <skipTests>true</skipTests>
     <spotless.version>2.4.2</spotless.version>
@@ -66,36 +65,30 @@
       <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>
@@ -107,10 +100,8 @@
       <artifactId>commons-lang3</artifactId>
       <version>3.11</version>
     </dependency>
-    <!-- 常用工具库结束 -->
 
 
-    <!-- spring单元测试 -->
     <dependency>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-test</artifactId>
@@ -127,9 +118,7 @@
       <artifactId>junit</artifactId>
       <scope>test</scope>
     </dependency>
-    <!-- spring单元测试结束 -->
 
-    <!-- swagger 组件,用于自动生成api接口文档 -->
     <dependency>
       <groupId>io.springfox</groupId>
       <artifactId>springfox-swagger2</artifactId>
@@ -140,9 +129,7 @@
       <artifactId>springfox-swagger-ui</artifactId>
       <version>2.7.0</version>
     </dependency>
-    <!-- swagger 组件结束-->
 
-    <!-- 校验框架-->
     <dependency>
       <groupId>org.hibernate.validator</groupId>
       <artifactId>hibernate-validator</artifactId>
@@ -154,12 +141,11 @@
       <artifactId>aspectjweaver</artifactId>
       <version>1.9.6</version>
     </dependency>
-    <!-- 校验框架结束-->
 
     <dependency>
       <groupId>org.apache.iotdb</groupId>
       <artifactId>iotdb-session</artifactId>
-      <version>0.12.0</version>
+      <version>0.12.1</version>
       <exclusions>
         <exclusion>
           <artifactId>logback-classic</artifactId>
@@ -171,7 +157,7 @@
     <dependency>
       <groupId>org.apache.iotdb</groupId>
       <artifactId>iotdb-jdbc</artifactId>
-      <version>0.12.0</version>
+      <version>0.12.1</version>
       <exclusions>
         <exclusion>
           <artifactId>logback-classic</artifactId>
@@ -195,17 +181,7 @@
           </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>
@@ -220,6 +196,7 @@
           </execution>
         </executions>
       </plugin>
+
       <plugin>
         <groupId>com.diffplug.spotless</groupId>
         <artifactId>spotless-maven-plugin</artifactId>
diff --git a/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java b/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java
index 9ac6ffd..2795859 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/AdminApplication.java
@@ -22,12 +22,13 @@ 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.scheduling.annotation.EnableScheduling;
 import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
 
-/** 后端代码启动类 1. MapperScan需要配置为mapper所在的包,自动扫描mapper,MapperScan是用于数据库组件自动扫描使用的。 */
 @SpringBootApplication
 @MapperScan("org.apache.iotdb.admin.mapper")
 @EnableWebSecurity
+@EnableScheduling
 public class AdminApplication {
 
   public static void main(String[] 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
index 0f76a83..bd4fee0 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/aop/BaseExceptionAdvice.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/aop/BaseExceptionAdvice.java
@@ -27,7 +27,7 @@ import org.springframework.web.bind.annotation.ControllerAdvice;
 import org.springframework.web.bind.annotation.ExceptionHandler;
 import org.springframework.web.bind.annotation.ResponseBody;
 
-/** 通用异常处理拦截器 */
+/** Global exception handler */
 @Slf4j
 @ControllerAdvice
 public class BaseExceptionAdvice {
@@ -35,7 +35,7 @@ public class BaseExceptionAdvice {
   @ExceptionHandler(BaseException.class)
   @ResponseBody
   public BaseVO handleBaseException(BaseException e) {
-    log.error("调用接口异常", e);
+    log.error("Base exception:", 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
index f58767f..a12ab6c 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/aop/ParamValidAspect.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/aop/ParamValidAspect.java
@@ -36,7 +36,6 @@ import javax.validation.Validator;
 
 import java.util.Set;
 
-/** 参数验证 */
 @Aspect
 @Slf4j
 @Component
@@ -44,11 +43,10 @@ public class ParamValidAspect {
 
   @Autowired private Validator validator;
 
-  /** 定义校验包的未知 */
+  /** Define the location of the package to be verified */
   @Pointcut("execution(* org.apache.iotdb.admin.controller..*.*(..))")
   public void pointcut() {}
 
-  /** 处理参数校验错误的具体方法,抛出异常组件中的异常,遵循异常规范 */
   @Around("pointcut()")
   public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
     Object[] args = pjp.getArgs();
@@ -59,10 +57,9 @@ public class ParamValidAspect {
           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());
+                ErrorCode.WRONG_PARAM, "Parameter error:" + constraintViolation.getMessage());
           }
         }
       }
diff --git a/backend/src/main/java/org/apache/iotdb/admin/common/ScheduledTask.java b/backend/src/main/java/org/apache/iotdb/admin/common/ScheduledTask.java
new file mode 100644
index 0000000..bbc635e
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/common/ScheduledTask.java
@@ -0,0 +1,64 @@
+/*
+ * 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;
+
+import org.apache.iotdb.admin.config.FileProperties;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.scheduling.annotation.Scheduled;
+import org.springframework.stereotype.Component;
+
+import java.io.File;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+
+/** Periodically delete files generated during CSV import and export */
+@Slf4j
+@Component
+public class ScheduledTask {
+  private final Path fileStorageLocation;
+
+  private final File fileStorageDirectory;
+
+  @Autowired
+  public ScheduledTask(FileProperties fileProperties) {
+    fileStorageLocation = Paths.get(fileProperties.getTempDir()).toAbsolutePath().normalize();
+    fileStorageDirectory = new File(fileStorageLocation.toString());
+    try {
+      Files.createDirectories(fileStorageLocation);
+    } catch (Exception e) {
+      log.error("Could not create the directory:" + fileStorageLocation, e);
+      throw new RuntimeException("Could not create the directory:" + fileStorageLocation, e);
+    }
+  }
+
+  @Scheduled(fixedRate = 1000 * 60 * 10L)
+  public void scheduledTask() {
+    File[] files = fileStorageDirectory.listFiles();
+    for (File file : files) {
+      if (file.lastModified() < System.currentTimeMillis() - 1000 * 60 * 10L) {
+        file.delete();
+        log.info("Delete file:" + file.getAbsolutePath());
+      }
+    }
+  }
+}
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
index 38c4a20..587605f 100644
--- 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
@@ -19,7 +19,6 @@
 
 package org.apache.iotdb.admin.common.exception;
 
-/** 异常类 */
 public class BaseException extends Exception {
 
   private String errorCode;
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
index 499ab83..2084338 100644
--- 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
@@ -19,265 +19,401 @@
 
 package org.apache.iotdb.admin.common.exception;
 
-/** 错误码类 */
 public class ErrorCode {
 
-  // 连接相关
+  // Connection
   public static final String ALIAS_REPEAT = "CONN-0001";
-  public static final String ALIAS_REPEAT_MSG = "别名重复";
+  public static final String ALIAS_REPEAT_MSG = "Connection alias already exists";
 
   public static final String INSERT_CONN_FAIL = "CONN-0002";
-  public static final String INSERT_CONN_FAIL_MSG = "添加或更新连接失败";
+  public static final String INSERT_CONN_FAIL_MSG = "Failed to update or create connection";
 
   public static final String DELETE_CONN_FAIL = "CONN-0003";
-  public static final String DELETE_CONN_FAIL_MSG = "删除连接失败";
+  public static final String DELETE_CONN_FAIL_MSG = "Failed to delete connection";
 
   public static final String NO_CONN = "CONN-0004";
-  public static final String NO_CONN_MSG = "连接不存在";
+  public static final String NO_CONN_MSG = "The connection doesn't exist";
 
   public static final String GET_CONN_FAIL = "CONN-0005";
-  public static final String GET_CONN_FAIL_MSG = "获取连接失败";
+  public static final String GET_CONN_FAIL_MSG = "Failed to get connection";
 
   public static final String CHECK_FAIL = "CONN-0006";
-  public static final String CHECK_FAIL_MSG = "没有权限或连接不存在";
+  public static final String CHECK_FAIL_MSG =
+      "The connection doesn't exist or the account doesn't have permissions";
 
   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 TEST_CONN_FAIL_MSG = "Unreachable connection";
 
   public static final String TIME_OUT = "CONN-0009";
-  public static final String TIME_OUT_MSG = "连接超时";
+  public static final String TIME_OUT_MSG = "Connection timeout";
 
   public static final String TEST_CONN_FAIL_PWD = "CONN-0010";
-  public static final String TEST_CONN_FAIL_PWD_MSG = "连接失败,用户名或密码错误";
+  public static final String TEST_CONN_FAIL_PWD_MSG = "The user name or password is incorrect";
 
-  // 登录相关
+  // Login
   public static final String LOGIN_FAIL_USER = "USER-0001";
-  public static final String LOGIN_FAIL_USER_MSG = "登录失败,用户不存在";
+  public static final String LOGIN_FAIL_USER_MSG = "The user does not exist";
 
   public static final String USER_EXIST = "USER-0002";
-  public static final String USER_EXIST_MSG = "用户已存在";
+  public static final String USER_EXIST_MSG = "The user name already exists";
 
   public static final String LOGIN_FAIL_PWD = "USER-0003";
-  public static final String LOGIN_FAIL_PWD_MSG = "登录失败,密码错误";
+  public static final String LOGIN_FAIL_PWD_MSG = "Login failed, password is incorrect";
 
   public static final String INSERT_USER_FAIL = "USER-0004";
-  public static final String INSERT_USER_FAIL_MSG = "插入失败";
+  public static final String INSERT_USER_FAIL_MSG = "Failed to create user";
 
   public static final String WRONG_USER_PARAM = "USER-0005";
-  public static final String WRONG_USER_PARAM_MSG = "请输入合法的用户名和密码";
+  public static final String WRONG_USER_PARAM_MSG = "Please enter a valid user name and password";
 
   public static final String DELETE_USER_FAIL = "USER-0006";
-  public static final String DELETE_USER_FAIL_MSG = "删除用户失败";
+  public static final String DELETE_USER_FAIL_MSG = "Failed to delete user";
 
   public static final String NO_USER = "USER-0007";
-  public static final String NO_USER_MSG = "用户未指定";
+  public static final String NO_USER_MSG = "User not specified";
 
   public static final String USER_AUTH_FAIL = "USER-0008";
-  public static final String USER_AUTH_FAIL_MSG = "用户不一致,不能进行操作";
+  public static final String USER_AUTH_FAIL_MSG = "Validation fails, the users are inconsistent";
 
   public static final String TOKEN_ERR = "USER-0009";
-  public static final String TOKEN_ERR_MSG = "请登录或token失效";
+  public static final String TOKEN_ERR_MSG = "No login or token is invalid";
 
   public static final String GET_TOKEN_FAIL = "USER-0010";
-  public static final String GET_TOKEN_FAIL_MSG = "获取token失败";
+  public static final String GET_TOKEN_FAIL_MSG = "Failed to get token";
 
   public static final String SET_JWT_FAIL = "USER-0011";
-  public static final String SET_JWT_FAIL_MSG = "JWT编解码失败";
+  public static final String SET_JWT_FAIL_MSG = "JWT encoding or decoding failed";
+
+  // CSV
+  public static final String FILE_NAME_ILLEGAL = "CSV-0001";
+  public static final String FILE_NAME_ILLEGAL_MSG = "The file must be a CSV file";
+
+  public static final String UPLOAD_FILE_FAIL = "CSV-0002";
+  public static final String UPLOAD_FILE_FAIL_MSG = "Failed to upload the CSV file";
+
+  public static final String FILE_FIRST_LINE_ILLEGAL = "CSV-0003";
+  public static final String FILE_FIRST_LINE_ILLEGAL_MSG =
+      "The CSV file format is incorrect.Please check line 1";
+
+  public static final String FILE_LINE_ILLEGAL = "CSV-0004";
+  public static final String FILE_LINE_ILLEGAL_MSG = "CSV file format error, illegal line:";
+
+  public static final String FILE_FORMAT_ILLEGAL = "CSV-0005";
+  public static final String FILE_FORMAT_ILLEGAL_MSG =
+      "CSV file format error. The number of columns in the data row cannot be smaller than that in the first row";
+
+  public static final String FILE_TIME_ILLEGAL = "CSV-0006";
+  public static final String FILE_TIME_ILLEGAL_MSG =
+      "The timestamp format of the CSV file is incorrect";
+
+  public static final String FILE_IO_FAIL = "CSV-0007";
+  public static final String FILE_IO_FAIL_MSG = "File read or write failed due to:";
+
+  public static final String IMPORT_CSV_FAIL = "CSV-0008";
+  public static final String IMPORT_CSV_FAIL_MSG = "Failed to import CSV file because:";
 
-  // iotDB相关
+  public static final String CREATE_FILE_FAIL = "CSV-0009";
+  public static final String CREATE_FILE_FAIL_MSG = "Failed to create file";
+
+  public static final String EXPORT_CSV_FAIL = "CSV-0010";
+  public static final String EXPORT_CSV_FAIL_MSG = "Failed to export the CSV file because:";
+
+  public static final String FILE_NOT_FOUND = "CSV-0011";
+  public static final String FILE_NOT_FOUND_MSG = "File not found";
+
+  // IoTDB
   public static final String INSERT_TS_FAIL = "IOTDB-0001";
-  public static final String INSERT_TS_FAIL_MSG = "插入时间序列失败";
+  public static final String INSERT_TS_FAIL_MSG = "Failed to create measurement";
 
   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 DELETE_TS_FAIL_MSG = "Failed to delete measurement";
 
   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 DB_DATATYPE_WRONG_MSG = "The data type of measurement is wrong";
 
   public static final String GET_SESSION_FAIL = "IOTDB-0006";
-  public static final String GET_SESSION_FAIL_MSG = "获取session失败";
+  public static final String GET_SESSION_FAIL_MSG = "Failed to connect to IoTDB database";
 
   public static final String CLOSE_DBCONN_FAIL = "IOTDB-0007";
-  public static final String CLOSE_DBCONN_FAIL_MSG = "关闭连接失败";
+  public static final String CLOSE_DBCONN_FAIL_MSG = "Failed to close connection";
 
   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 SQL_EP_MSG = "No privileges or SQL errors";
 
   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 WRONG_DB_PARAM_MSG = "The input parameter is invalid";
 
   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 GET_SQL_ONE_VALUE_FAIL_MSG = "Failed to get data value";
 
   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 SET_TTL_FAIL_MSG = "Failed to set the TTL.";
 
   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_SQL_ONE_COLUMN_FAIL_MSG = "Failed to get the data list";
 
   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 GET_MSM_FAIL_MSG = "Failed to get the measurement information";
 
   public static final String SET_GROUP_FAIL = "IOTDB-0022";
-  public static final String SET_GROUP_FAIL_MSG = "创建存储组失败";
+  public static final String SET_GROUP_FAIL_MSG = "Failed to create storage group";
 
   public static final String DELETE_GROUP_FAIL = "IOTDB-0023";
-  public static final String DELETE_GROUP_FAIL_MSG = "删除存储组失败";
+  public static final String DELETE_GROUP_FAIL_MSG = "Failed to delete storage group";
 
   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_USER_FAIL_MSG = "Failed to delete IoTDB user";
 
   public static final String DELETE_DB_ROLE_FAIL = "IOTDB-0025";
-  public static final String DELETE_DB_ROLE_FAIL_MSG = "删除数据库角色失败";
+  public static final String DELETE_DB_ROLE_FAIL_MSG = "Failed to delete IoTDB role";
 
   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_USER_FAIL_MSG = "Failed to create IoTDB user";
 
   public static final String SET_DB_ROLE_FAIL = "IOTDB-0027";
-  public static final String SET_DB_ROLE_FAIL_MSG = "创建数据库角色或对应权限时失败";
+  public static final String SET_DB_ROLE_FAIL_MSG = "Failed to create IoTDB role";
 
   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 NO_TYPE_MSG = "Privileges type does not exist";
 
   public static final String GET_RECORD_FAIL = "IOTDB-0033";
-  public static final String GET_RECORD_FAIL_MSG = "获取物理量记录失败";
+  public static final String GET_RECORD_FAIL_MSG = "Failed to get the measurement record";
 
   public static final String NO_SQL = "IOTDB-0034";
-  public static final String NO_SQL_MSG = "没有sql执行语句";
+  public static final String NO_SQL_MSG = "The query script has no SQL statements";
 
   public static final String UPDATE_GROUP_INFO_FAIL = "IOTDB-0035";
-  public static final String UPDATE_GROUP_INFO_FAIL_MSG = "更新组信息失败";
+  public static final String UPDATE_GROUP_INFO_FAIL_MSG =
+      "Failed to update the storage group information";
 
   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_GROUP_INFO_MSG = "The storage group information doesn't exist";
 
   public static final String NO_DEVICE_INFO = "IOTDB-0038";
-  public static final String NO_DEVICE_INFO_MSG = "不存在设备信息";
+  public static final String NO_DEVICE_INFO_MSG = "The entity information doesn't exist";
 
   public static final String UPDATE_PWD_FAIL = "IOTDB-0039";
-  public static final String UPDATE_PWD_FAIL_MSG = "修改账号密码失败";
+  public static final String UPDATE_PWD_FAIL_MSG = "Failed to change the account password";
 
   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_QUERY_MSG = "The query does not exist or has ended";
 
   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_SET_TTL_MSG = "No privilege to set the TTL";
 
   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_CREATE_TIMESERIES_MSG =
+      "No privilege to create the measurement";
 
   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_READ_TIMESERIES_MSG = "No privilege to read the measurement";
 
   public static final String NO_PRI_DELETE_TIMESERIES = "IOTDB-0045";
-  public static final String NO_PRI_DELETE_TIMESERIES_MSG = "没有权限删除物理量";
+  public static final String NO_PRI_DELETE_TIMESERIES_MSG =
+      "No privilege to delete the measurement";
 
   public static final String CONN_REFUSED = "IOTDB-0046";
-  public static final String CONN_REFUSED_MSG = "连接错误,检查输入";
+  public static final String CONN_REFUSED_MSG = "Connecting to IoTDB error";
 
   public static final String WRONG_USER = "IOTDB-0047";
-  public static final String WRONG_USER_MSG = "连接用户名或密码错误";
+  public static final String WRONG_USER_MSG =
+      "The user name or password of connection is incorrect";
 
   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_SET_GROUP_MSG = "No privilege to set the storage group";
 
   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 NO_PRI_DELETE_GROUP_MSG = "No privilege to delete the storage group";
 
   public static final String TTL_WRONG = "IOTDB-0050";
-  public static final String TTL_WRONG_MSG = "存活时间必须大于等于0";
+  public static final String TTL_WRONG_MSG = "The TTL must be greater than or equal to 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_PRI_TIMESERIES_DATA_MSG =
+      "No privilege to read the measurement data";
 
   public static final String NO_SUP_CONTAIN_ROOT = "IOTDB-0052";
-  public static final String NO_SUP_CONTAIN_ROOT_MSG = "不支持包含\"root\"的输入";
+  public static final String NO_SUP_CONTAIN_ROOT_MSG =
+      "Root must and can only be the beginning of a path";
+
+  public static final String GET_DATA_FAIL = "IOTDB-0053";
+  public static final String GET_DATA_FAIL_MSG = "Failed to get measurement data";
+
+  public static final String UPDATE_DATA_FAIL = "IOTDB-0054";
+  public static final String UPDATE_DATA_FAIL_MSG = "Failed to update measurement data";
+
+  public static final String DELETE_DATA_FAIL = "IOTDB-0055";
+  public static final String DELETE_DATA_FAIL_MSG = "Failed to delete measurement data";
+
+  public static final String GET_DATA_COUNT_FAIL = "IOTDB-0056";
+  public static final String GET_DATA_COUNT_FAIL_MSG = "Failed to obtain data statistics";
+
+  public static final String DB_COMPRESSION_WRONG = "IOTDB-0057";
+  public static final String DB_COMPRESSION_WRONG_MSG =
+      "The compression type is passed in incorrectly";
+
+  public static final String DB_ENCODING_WRONG = "IOTDB-0058";
+  public static final String DB_ENCODING_WRONG_MSG = "The encoding type is passed in incorrectly";
+
+  public static final String UPSERT_ALIAS_FAIL = "IOTDB-0059";
+  public static final String UPSERT_ALIAS_FAIL_MSG =
+      "Failed to set the alias. Please check whether the alias already exists under the current entity";
 
-  // 存储组表相关
+  public static final String UPSERT_TAGS_FAIL = "IOTDB-0060";
+  public static final String UPSERT_TAGS_FAIL_MSG = "Failed to set the tags";
+
+  public static final String UPSERT_ATTRIBUTES_FAIL = "IOTDB-0061";
+  public static final String UPSERT_ATTRIBUTES_FAIL_MSG = "Failed to set the attributes";
+
+  public static final String GET_MEASUREMENT_DATA_COUNT_FAIL = "IOTDB-0062";
+  public static final String GET_MEASUREMENT_DATA_COUNT_FAIL_MSG =
+      "Failed to get measurement data statistics";
+
+  public static final String RANDOM_IMPORT_DATA_FAIL = "IOTDB-0063";
+  public static final String RANDOM_IMPORT_DATA_FAIL_MSG =
+      "Failed to import measurement data randomly";
+
+  public static final String NO_MEASUREMENT = "IOTDB-0064";
+  public static final String NO_MEASUREMENT_MSG = " No measurement, cannot insert data";
+
+  public static final String ROLE_GET_USERS_FAIL = "IOTDB-0065";
+  public static final String ROLE_GET_USERS_FAIL_MSG = "Failed to get the user list for the role";
+
+  public static final String REVOKE_ROLE = "IOTDB-0066";
+  public static final String REVOKE_ROLE_MSG = "Failed to revoke the role of user.";
+
+  public static final String GRANT_ROLE = "IOTDB-0067";
+  public static final String GRANT_ROLE_MSG = "Failed to grant role to the user";
+
+  public static final String NO_PRI_DO_THIS = "IOTDB-0068";
+  public static final String NO_PRI_DO_THIS_MSG = "No privilege to do this";
+
+  public static final String NO_PRI_CREATE_USER = "IOTDB-0069";
+  public static final String NO_PRI_CREATE_USER_MSG = "No privilege to create user";
+
+  public static final String NO_PRI_DELETE_USER = "IOTDB-0070";
+  public static final String NO_PRI_DELETE_USER_MSG = "No privilege to delete user";
+
+  public static final String NO_PRI_CREATE_ROLE = "IOTDB-0071";
+  public static final String NO_PRI_CREATE_ROLE_MSG = "No privilege to create role";
+
+  public static final String NO_PRI_DELETE_ROLE = "IOTDB-0072";
+  public static final String NO_PRI_DELETE_ROLE_MSG = "No privilege to delete role";
+
+  public static final String NO_PRI_LIST_ROLE = "IOTDB-0073";
+  public static final String NO_PRI_LIST_ROLE_MSG = "No privilege to list role";
+
+  public static final String NO_PRI_GRANT_USER_ROLE = "IOTDB-0074";
+  public static final String NO_PRI_GRANT_USER_ROLE_MSG = "No privilege to grant user role";
+
+  public static final String NO_PRI_REVOKE_USER_ROLE = "IOTDB-0075";
+  public static final String NO_PRI_REVOKE_USER_ROLE_MSG = "No privilege to revoke user role";
+
+  public static final String NO_PRI_GRANT_PRIVILEGE = "IOTDB-0076";
+  public static final String NO_PRI_GRANT_PRIVILEGE_MSG = "No privilege to authorize user or role";
+
+  public static final String GET_USER_PRIVILEGE_FAIL = "IOTDB-0080";
+  public static final String GET_USER_PRIVILEGE_FAIL_MSG =
+      "Failed to get user privilege information";
+
+  public static final String GET_ROLE_PRIVILEGE_FAIL = "IOTDB-0081";
+  public static final String GET_ROLE_PRIVILEGE_FAIL_MSG =
+      "Failed to get role privilege information";
+
+  public static final String NOT_SUPPORT_ALL_DIGIT = "IOTDB-0082";
+  public static final String NOT_SUPPORT_ALL_DIGIT_MSG = "The name cannot contain only digits";
+
+  public static final String USER_NAME_EXISTS = "IOTDB-0083";
+  public static final String USER_NAME_EXISTS_MSG = "The user name already exists";
+
+  public static final String ROLE_NAME_EXISTS = "IOTDB-0083";
+  public static final String ROLE_NAME_EXISTS_MSG = "The role name already exists";
+
+  public static final String NO_SUP_CONTAIN_WORD = "IOTDB-0084";
+  public static final String NO_SUP_CONTAIN_WORD_MSG =
+      "As, null, or like cannot be used as a path name";
+
+  public static final String MEASUREMENTS_NAME_CONTAIN_DOT = "IOTDB-0085";
+  public static final String MEASUREMENTS_NAME_CONTAIN_DOT_MSG =
+      "The measurement layer name cannot have multiple layers";
+
+  public static final String MEASUREMENT_NAME_EQUALS_DEVICE = "IOTDB-0086";
+  public static final String MEASUREMENT_NAME_EQUALS_DEVICE_MSG =
+      "The entity name cannot be the same as an existing measurement";
+
+  public static final String GET_DATA_PRIVILEGE_FAIL = "IOTDB-0087";
+  public static final String GET_DATA_PRIVILEGE_FAIL_MSG =
+      "Failed to get data management privilege";
+
+  public static final String NO_PRI_INSERT_DATA = "IOTDB-0088";
+  public static final String NO_PRI_INSERT_DATA_MSG = "No privilege to insert data";
+
+  public static final String NO_PRI_ALTER_MEASUREMENT = "IOTDB-0089";
+  public static final String NO_PRI_ALTER_MEASUREMENT_MSG = "No privilege to update measurement";
+
+  public static final String NO_SUP_WORD = "IOTDB-0090";
+  public static final String NO_SUP_WORD_MSG = "The tag or attribute cannot be as, null, or like";
+
+  public static final String NO_SUP_ALL_DIGIT = "IOTDB-0091";
+  public static final String NO_SUP_ALL_DIGIT_MSG =
+      "The keys of tags or attributes cannot be pure numbers";
+
+  public static final String NO_SUP_ALIAS_WORD = "IOTDB-0092";
+  public static final String NO_SUP_ALIAS_WORD_MSG =
+      "Measurement alias cannot be as, like, or pure numbers";
+
+  public static final String TTL_OVER = "IOTDB-0093";
+  public static final String TTL_OVER_MSG = "The TTL is too long";
+
+  public static final String MEASUREMENT_ALREADY_EXIST = "IOTDB-0094";
+  public static final String MEASUREMENT_ALREADY_EXIST_MSG =
+      "Failed to create a measurement. Check whether the measurement has the same name as an existing measurement or alias";
+
+  // Storage group table
   public static final String INSERT_GROUP_INFO_FAIL = "GROUP-0001";
-  public static final String INSERT_GROUP_INFO_FAIL_MSG = "插入存储组信息失败";
+  public static final String INSERT_GROUP_INFO_FAIL_MSG =
+      "Failed to insert storage group information";
 
   public static final String DELETE_GROUP_INFO_FAIL = "GROUP-0002";
-  public static final String DELETE_GROUP_INFO_FAIL_MSG = "删除存储组信息失败";
+  public static final String DELETE_GROUP_INFO_FAIL_MSG =
+      "Failed to delete storage group information";
 
-  // 实体表相关
+  // Entity table
   public static final String DELETE_DEVICE_INFO_FAIL = "DEV-0001";
-  public static final String DELETE_DEVICE_INFO_FAIL_MSG = "删除实体信息失败";
+  public static final String DELETE_DEVICE_INFO_FAIL_MSG = "Failed to delete entity information";
 
   public static final String SET_DEVICE_INFO_FAIL = "DEV-0002";
-  public static final String SET_DEVICE_INFO_FAIL_MSG = "插入实体信息失败";
+  public static final String SET_DEVICE_INFO_FAIL_MSG = "Failed to insert entity information";
 
-  // 物理量表相关
+  // Measurement table
   public static final String DELETE_MEASUREMENT_INFO_FAIL = "MEASU-0001";
-  public static final String DELETE_MEASUREMENT_INFO_FAIL_MSG = "删除物理量信息失败";
+  public static final String DELETE_MEASUREMENT_INFO_FAIL_MSG =
+      "Failed to delete measurement information";
 
   public static final String SET_MEASUREMENT_INFO_FAIL = "MEASU-0002";
-  public static final String SET_MEASUREMENT_INFO_FAIL_MSG = "插入物理量信息失败";
+  public static final String SET_MEASUREMENT_INFO_FAIL_MSG =
+      "Failed to insert measurement information";
 
   public static final String GET_MSM_DES_FAIL = "MEASU-0003";
-  public static final String GET_MSM_DES_FAIL_MSG = "获取物理量描述信息失败";
+  public static final String GET_MSM_DES_FAIL_MSG = "Failed to get measurement information";
 
-  // 查询表相关
+  // query table
   public static final String QUERY_EXIST = "QUERY-0001";
-  public static final String QUERY_EXIST_MSG = "脚本名已存在";
+  public static final String QUERY_EXIST_MSG = "The query script name already exists";
 
   public static final String QUERY_NOT_EXIST = "QUERY-0002";
-  public static final String QUERY_NOT_EXIST_MSG = "脚本不存在";
+  public static final String QUERY_NOT_EXIST_MSG = "The query script name doesn't exist";
+
+  // role table
+  public static final String UPSERT_ROLE_INFO_FAIL = "ROLE-0001";
+  public static final String UPSERT_ROLE_INFO_FAIL_MSG = "Failed to upsert role information";
+
+  public static final String DELETE_ROLE_INFO_FAIL = "ROLE-0002";
+  public static final String DELETE_ROLE_INFO_FAIL_MSG = "Failed to delete role information";
+
+  public static final String GET_ROLE_INFO_FAIL = "ROLE-0003";
+  public static final String GET_ROLE_INFO_FAIL_MSG = "Failed to get role information";
 
-  // 参数校验相关
+  // Parameter verify
   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
index 98047dd..1b2e149 100644
--- 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
@@ -27,7 +27,7 @@ import com.auth0.jwt.interfaces.DecodedJWT;
 
 import javax.servlet.http.HttpServletRequest;
 
-/** 校验工具类 */
+/** Validation tool class */
 public class AuthenticationUtils {
 
   public static void userAuthentication(Integer userId, HttpServletRequest request)
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java b/backend/src/main/java/org/apache/iotdb/admin/config/FileProperties.java
similarity index 66%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/config/FileProperties.java
index e26eea3..a98351a 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/FileProperties.java
@@ -17,20 +17,21 @@
  * under the License.
  */
 
-package org.apache.iotdb.admin.model.dto;
+package org.apache.iotdb.admin.config;
 
-import lombok.Data;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.stereotype.Component;
 
-import java.io.Serializable;
+@Component
+@ConfigurationProperties(prefix = "file")
+public class FileProperties {
+  private String tempDir;
 
-@Data
-public class DeviceDTO implements Serializable {
+  public String getTempDir() {
+    return tempDir;
+  }
 
-  private String timeseries;
-
-  private String dataType;
-
-  private String encoding;
-
-  private String description;
+  public void setTempDir(String tempDir) {
+    this.tempDir = tempDir;
+  }
 }
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
index 3a00d52..6a6ed82 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/config/FilterConfig.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/FilterConfig.java
@@ -29,7 +29,7 @@ import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
 import java.util.ArrayList;
 import java.util.List;
 
-/** 拦截器配置类 */
+/** Interceptor configuration class */
 @Component
 public class FilterConfig implements WebMvcConfigurer {
 
@@ -39,6 +39,7 @@ public class FilterConfig implements WebMvcConfigurer {
     List<String> paths = new ArrayList();
     paths.add("/servers/**");
     paths.add("/get");
+    paths.add("/downloadFile/**");
     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
index 607aa1e..32b8ec2 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/config/MybatisPlusConfig.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/MybatisPlusConfig.java
@@ -25,22 +25,14 @@ import com.baomidou.mybatisplus.extension.plugins.inner.PaginationInnerIntercept
 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条,可以更改,但不建议太大
+        new PaginationInnerInterceptor(DbType.SQLITE);
     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
index e4c0340..2c25f3b 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/config/SecurityConfig.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/SecurityConfig.java
@@ -25,10 +25,9 @@ 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算法 */
+/** Encryption algorithm configuration class */
 @Configuration
 public class SecurityConfig extends WebSecurityConfigurerAdapter {
-
   @Override
   protected void configure(HttpSecurity http) throws Exception {
     http.authorizeRequests()
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
index 70eb759..1c46d70 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/config/SwaggerConfig.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/SwaggerConfig.java
@@ -19,6 +19,7 @@
 
 package org.apache.iotdb.admin.config;
 
+import io.swagger.annotations.ApiOperation;
 import org.springframework.context.annotation.Bean;
 import org.springframework.context.annotation.Configuration;
 import org.springframework.context.annotation.Profile;
@@ -36,7 +37,7 @@ import springfox.documentation.swagger2.annotations.EnableSwagger2;
 import java.util.ArrayList;
 import java.util.List;
 
-/** swagger配置类 */
+/** swagger configuration class */
 @Configuration
 @EnableSwagger2
 @Profile({"dev", "test"})
@@ -50,14 +51,15 @@ public class SwaggerConfig {
         .globalOperationParameters(jwtToken())
         .select()
         .apis(RequestHandlerSelectors.basePackage("org.apache.iotdb.admin.controller"))
+        .apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
         .paths(PathSelectors.any())
         .build();
   }
 
   private ApiInfo apiinfo() {
     return new ApiInfoBuilder()
-        .title("IOTDB接口文档")
-        .description("iotDB层级关系 存储组 -> 实体(设备) -> 测点(时间序列)")
+        .title("IoTDB-Workbench API")
+        .description("IoTDB hierarchy: storage group -> entity -> measurement")
         .build();
   }
 
@@ -67,7 +69,7 @@ public class SwaggerConfig {
     List<Parameter> pars = new ArrayList<>();
     tokenPar
         .name("Authorization")
-        .description("jwt令牌")
+        .description("java web token")
         .modelRef(new ModelRef("string"))
         .parameterType("header")
         .required(false);
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
index 4a7653f..3bf4945 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/config/ValidatorConfiguration.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/config/ValidatorConfiguration.java
@@ -27,7 +27,7 @@ import javax.validation.Validation;
 import javax.validation.Validator;
 import javax.validation.ValidatorFactory;
 
-/** 校验框架配置类 */
+/** Validator configuration classes */
 @Configuration
 public class ValidatorConfiguration {
 
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
index 90086d1..768972e 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/controller/ConnectionController.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/ConnectionController.java
@@ -42,56 +42,55 @@ import java.net.Socket;
 import java.util.List;
 
 @RestController
-@Api(value = "连接相关接口")
+@Api(value = "Connection related")
 public class ConnectionController {
 
   @Autowired private ConnectionService connectionService;
 
   @PostMapping("/servers")
-  @ApiOperation("保存或更新连接")
+  @ApiOperation("Upsert connection")
   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);
+      return BaseVO.success("Update successfully", null);
     }
     connectionService.insert(connection);
-
-    return BaseVO.success("保存成功", null);
+    return BaseVO.success("Save successfully", null);
   }
 
   @DeleteMapping("/servers/{serverId}")
-  @ApiOperation("删除连接")
+  @ApiOperation("Delete connection")
   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);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/servers/{serverId}")
-  @ApiOperation("获取连接具体配置")
+  @ApiOperation("Get detailed information of the specified connection")
   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));
+    return BaseVO.success("Get successfully", connectionService.getById(serverId));
   }
 
   @GetMapping("/servers")
-  @ApiOperation("获取所有连接")
+  @ApiOperation("Get all connection")
   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);
+    return BaseVO.success("Get successfully", connectionVO);
   }
 
   @PostMapping("/test")
-  @ApiOperation("连通性测试")
+  @ApiOperation("Connectivity test")
   public BaseVO testConnection(@RequestBody ConnectionDTO conn) throws BaseException {
     Socket socket = null;
     try {
@@ -123,6 +122,6 @@ public class ConnectionController {
         throw new BaseException(ErrorCode.TEST_CONN_FAIL_PWD, ErrorCode.TEST_CONN_FAIL_PWD_MSG);
       }
     }
-    return BaseVO.success("连通成功", null);
+    return BaseVO.success("Connection successfully", null);
   }
 }
diff --git a/backend/src/main/java/org/apache/iotdb/admin/controller/FileController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/FileController.java
new file mode 100644
index 0000000..ea0106b
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/FileController.java
@@ -0,0 +1,131 @@
+/*
+ * 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 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.Connection;
+import org.apache.iotdb.admin.model.vo.BaseVO;
+import org.apache.iotdb.admin.model.vo.ImportDataVO;
+import org.apache.iotdb.admin.service.ConnectionService;
+import org.apache.iotdb.admin.service.FileService;
+import org.apache.iotdb.admin.tool.ExportCsv;
+import org.apache.iotdb.admin.tool.ImportCsv;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.ClassPathResource;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.*;
+import org.springframework.web.multipart.MultipartFile;
+
+import javax.servlet.http.HttpServletRequest;
+
+@RestController
+@Api(value = "File related")
+public class FileController {
+  @Autowired private FileService fileService;
+
+  @Autowired private ConnectionService connectionService;
+
+  @Autowired private ImportCsv importCsv;
+
+  @Autowired private ExportCsv exportCsv;
+
+  @ApiOperation("Import measurement data from a CSV file")
+  @PostMapping("/servers/{serverId}/importData")
+  public BaseVO<ImportDataVO> importData(
+      @RequestParam("file") MultipartFile file,
+      @PathVariable("serverId") Integer serverId,
+      HttpServletRequest request)
+      throws BaseException {
+    check(request, serverId);
+    if (!file.getOriginalFilename().toLowerCase().endsWith(".csv")) {
+      throw new BaseException(ErrorCode.FILE_NAME_ILLEGAL, ErrorCode.FILE_NAME_ILLEGAL_MSG);
+    }
+    String fileName = "import" + System.currentTimeMillis() + ".csv";
+    String fileFullName = fileService.storeFile(file, fileName);
+
+    Connection connection = connectionService.getById(serverId);
+    String host = connection.getHost();
+    Integer port = connection.getPort();
+    String username = connection.getUsername();
+    String password = connection.getPassword();
+    ImportDataVO importDataVO =
+        importCsv.importCsv(host, port, username, password, fileFullName, null);
+
+    return BaseVO.success("Import data successfully", importDataVO);
+  }
+
+  @ApiOperation("Export the query result as a CSV file")
+  @GetMapping("/servers/{serverId}/exportData")
+  public ResponseEntity<Resource> exportData(
+      @PathVariable("serverId") Integer serverId,
+      @RequestParam("sql") String sql,
+      HttpServletRequest request)
+      throws BaseException {
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+
+    String host = connection.getHost();
+    Integer port = connection.getPort();
+    String username = connection.getUsername();
+    String password = connection.getPassword();
+    String fileName = exportCsv.exportCsv(host, port, username, password, sql, null);
+
+    Resource resource = fileService.loadFileAsResource(fileName);
+    return getResponseEntity(resource);
+  }
+
+  @GetMapping("/downloadFile/{fileName}")
+  public ResponseEntity<Resource> downloadFile(@PathVariable String fileName) throws BaseException {
+    Resource resource = fileService.loadFileAsResource(fileName);
+    return getResponseEntity(resource);
+  }
+
+  @ApiOperation("Download the CSV template file")
+  @GetMapping("/downloadFile/template")
+  public ResponseEntity<Resource> downloadTemplateFile() throws BaseException {
+    Resource resource = new ClassPathResource("file/template.csv");
+    if (!resource.exists()) {
+      throw new BaseException(ErrorCode.FILE_NOT_FOUND, ErrorCode.FILE_NOT_FOUND_MSG);
+    }
+    return getResponseEntity(resource);
+  }
+
+  private ResponseEntity<Resource> getResponseEntity(Resource resource) {
+    String contentType = "application/octet-stream";
+
+    return ResponseEntity.ok()
+        .contentType(MediaType.parseMediaType(contentType))
+        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + resource.getFilename())
+        .body(resource);
+  }
+
+  private 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/HealthController.java b/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java
index dbc4cd7..899b11a 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/HealthController.java
@@ -28,17 +28,18 @@ import javax.servlet.http.HttpServletResponse;
 
 import java.io.IOException;
 
-/** 运维平台通过存活、就绪探针表示应用是否存活,就绪。这个类大家最好不好删除,url地址也不要改变 */
+/**
+ * The operation and maintenance platform indicates whether the application is alive and ready
+ * through the alive and ready probe
+ */
 @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
index 5c4e86c..612816e 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/controller/IotDBController.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/IotDBController.java
@@ -25,25 +25,34 @@ 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.Role;
 import org.apache.iotdb.admin.model.entity.StorageGroup;
 import org.apache.iotdb.admin.model.vo.*;
 import org.apache.iotdb.admin.service.*;
+import org.apache.iotdb.admin.tool.ExportCsv;
 
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
 import io.swagger.annotations.Api;
 import io.swagger.annotations.ApiOperation;
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
 import org.springframework.beans.BeanUtils;
 import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
 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;
+import java.util.*;
 
+@Slf4j
 @RestController
-@Api(value = "iotdb操作相关接口")
+@Api(value = "IoTDB related")
 @RequestMapping("/servers/{serverId}")
 public class IotDBController {
 
@@ -57,8 +66,34 @@ public class IotDBController {
 
   @Autowired private MeasurementService measurementService;
 
+  @Autowired private RoleService roleService;
+
+  @Autowired private FileService fileService;
+
+  @Autowired private ExportCsv exportCsv;
+
+  @GetMapping("/dataCount")
+  @ApiOperation("Get IoTDB data statistics")
+  public BaseVO<DataCountVO> getDataCount(
+      @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    DataCountVO dataCountVO = iotDBService.getDataCount(connection);
+    return BaseVO.success("Get IoTDB data statistics successfully", dataCountVO);
+  }
+
+  @GetMapping("/dataModel")
+  @ApiOperation("Get IoTDB data model")
+  public BaseVO<DataModelVO> getDataModel(
+      @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    DataModelVO dataModelVO = iotDBService.getDataModel(connection);
+    return BaseVO.success("Get IoTDB data model successfully", dataModelVO);
+  }
+
   @GetMapping("/storageGroups/info")
-  @ApiOperation("获得存储组信息列表")
+  @ApiOperation("Get information of the storage group list")
   public BaseVO<List<GroupInfoVO>> getAllStorageGroupsInfo(
       @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
     check(request, serverId);
@@ -66,23 +101,23 @@ public class IotDBController {
     List<String> groupNames = iotDBService.getAllStorageGroups(connection);
     List<GroupInfoVO> groupInfoList = new ArrayList<>();
     if (groupNames == null || groupNames.size() == 0) {
-      return BaseVO.success("获取成功", groupInfoList);
+      return BaseVO.success("Get successfully", 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.setGroupName(groupNames.get(i));
       groupInfoVO.setDeviceCount(deviceCounts.get(i));
       groupInfoVO.setDescription(descriptions.get(i));
       groupInfoList.add(groupInfoVO);
     }
-    return BaseVO.success("获取成功", groupInfoList);
+    return BaseVO.success("Get successfully", groupInfoList);
   }
 
   @GetMapping("/storageGroups")
-  @ApiOperation("获得存储组列表")
+  @ApiOperation("Get storage group list")
   public BaseVO<List<StorageGroupVO>> getAllStorageGroups(
       @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
     check(request, serverId);
@@ -90,37 +125,43 @@ public class IotDBController {
     List<StorageGroupVO> storageGroupVOList = new ArrayList<>();
     List<String> groupNames = iotDBService.getAllStorageGroups(connection);
     if (groupNames == null || groupNames.size() == 0) {
-      return BaseVO.success("获取成功", storageGroupVOList);
+      return BaseVO.success("Get successfully", 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);
+    return BaseVO.success("Get successfully", storageGroupVOList);
+  }
+
+  @GetMapping("/storageGroups/nodeTree")
+  @ApiOperation("Get storage group list(Node tree structure)")
+  public BaseVO<List<NodeTreeVO>> getGroupsNodeTree(
+      @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    List<NodeTreeVO> groupsNodeTree = iotDBService.getGroupsNodeTree(connection);
+    return BaseVO.success("Get successfully", groupsNodeTree);
   }
 
   @PostMapping("/storageGroups")
-  @ApiOperation("新增或修改存储组")
+  @ApiOperation("Upsert storage group")
   public BaseVO saveStorageGroup(
       @PathVariable("serverId") Integer serverId,
       @RequestBody GroupDTO groupDTO,
       HttpServletRequest request)
       throws BaseException {
+    String groupName = groupDTO.getGroupName();
+    checkParameter(groupName);
     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();
+    checkTtl(ttl, ttlUnit);
     Integer groupId = groupDTO.getGroupId();
     groupDTO.setGroupName(groupName);
 
@@ -147,43 +188,37 @@ public class IotDBController {
         throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
       }
     }
-    return BaseVO.success("新增或更新成功", null);
+    return BaseVO.success("Upsert successfully", null);
   }
 
   @DeleteMapping("/storageGroups/{groupName}")
-  @ApiOperation("删除存储组")
+  @ApiOperation("Delete storage group")
   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);
-    }
+    checkParameter(groupName);
     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);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/storageGroups/{groupName}")
-  @ApiOperation("存储组详情获取")
+  @ApiOperation("Get detailed information of the specified storage group")
   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);
-    }
+    checkParameter(groupName);
     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);
@@ -207,13 +242,13 @@ public class IotDBController {
       String createTime = simpleDateFormat.format(date);
       groupVO.setCreateTime(createTime);
     }
-    groupVO.setGroupName(groupName.replaceFirst("root.", ""));
+    groupVO.setGroupName(groupName);
     groupVO.setAlias(connection.getAlias());
-    return BaseVO.success("获取成功", groupVO);
+    return BaseVO.success("Get successfully", groupVO);
   }
 
   @GetMapping("/storageGroups/{groupName}/devices/info")
-  @ApiOperation("获取指定存储组下的实体(设备)信息列表")
+  @ApiOperation("Gets information of entities under the specified storage group")
   public BaseVO<DeviceInfoVO> getDevicesInfoByGroupName(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
@@ -222,15 +257,9 @@ public class IotDBController {
       @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);
-    }
+    checkParameter(groupName);
     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();
@@ -245,12 +274,10 @@ public class IotDBController {
     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.setDeviceName(deviceName);
         deviceInfo.setLine(lines.get(i));
+        deviceInfo.setParents(iotDBService.getDeviceParents(connection, groupName, deviceName));
         if (devices.get(i) != null) {
           deviceInfo.setDeviceId(devices.get(i).getId());
           deviceInfo.setCreator(devices.get(i).getCreator());
@@ -260,116 +287,145 @@ public class IotDBController {
       }
     }
     deviceInfoVO.setDeviceInfos(deviceInfos);
-    return BaseVO.success("获取成功", deviceInfoVO);
+    return BaseVO.success("Get successfully", deviceInfoVO);
   }
 
   @GetMapping("/storageGroups/{groupName}/devices")
-  @ApiOperation("获取指定存储组下的实体(设备)列表")
-  public BaseVO<List<String>> getDevicesByGroupName(
+  @ApiOperation("Gets a list of entities under the specified storage group")
+  public BaseVO<List<String>> getDevicesByGroup(
       @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);
-    }
+    checkParameter(groupName);
     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);
+    final List<String> devices = iotDBService.getDevices(connection, groupName);
+    return BaseVO.success("Get successfully", devices);
+  }
+
+  @GetMapping("/storageGroups/{groupName}/devices/nodeTree")
+  @ApiOperation("Get entity list(Node tree structure) of the specified storage group")
+  public BaseVO<List<NodeTreeVO>> getDevicesNodeTreeByGroup(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    List<NodeTreeVO> deviceList = iotDBService.getDeviceNodeTree(connection, groupName);
+    return BaseVO.success("Get successfully", deviceList);
+  }
+
+  @GetMapping("/storageGroups/{groupName}/devices/tree")
+  @ApiOperation("Get entity list(Tree structure) of the specified storage group")
+  public BaseVO<NodeTreeVO> getDevicesTreeByGroup(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    NodeTreeVO deviceList = iotDBService.getDeviceList(connection, groupName);
+    return BaseVO.success("Get successfully", deviceList);
+  }
+
+  @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/parents")
+  @ApiOperation("Get the list of the parent entities of the specified entity")
+  public BaseVO<List<String>> getDeviceParents(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      @PathVariable("deviceName") String deviceName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    List<String> deviceParents = iotDBService.getDeviceParents(connection, groupName, deviceName);
+    return BaseVO.success("Get successfully", deviceParents);
+  }
+
+  @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/exist")
+  @ApiOperation("Check whether the device already exists")
+  public BaseVO<Boolean> deviceExist(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      @PathVariable("deviceName") String deviceName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName, deviceName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    Boolean isExist = iotDBService.deviceExist(connection, groupName, deviceName);
+    return BaseVO.success("Get successfully", isExist);
   }
 
   @PostMapping("/storageGroups/{groupName}/devices")
-  @ApiOperation("新增或编辑实体(设备)")
-  public BaseVO<List<String>> saveOrUpdateDevice(
+  @ApiOperation("Upsert entity")
+  public BaseVO 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);
+    for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+      checkParameter(groupName, deviceInfoDTO.getDeviceName(), deviceDTO.getTimeseries());
     }
     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());
-    }
+    iotDBService.upsertMeasurements(connection, deviceInfoDTO);
     String host = connection.getHost();
-    iotDBService.createDeviceWithMeasurements(connection, deviceInfoDTO);
     if (deviceInfoDTO.getDeviceId() == null) {
       deviceService.setDeviceInfo(connection, deviceInfoDTO);
-      measurementService.setMeasurementsInfo(host, deviceInfoDTO);
+      measurementService.updateMeasurementsInfo(host, deviceInfoDTO);
     } else {
       deviceService.updateDeviceInfo(deviceInfoDTO);
       measurementService.updateMeasurementsInfo(host, deviceInfoDTO);
     }
-    return BaseVO.success("新增或更新成功", null);
+    return BaseVO.success("Upsert successfully", null);
   }
 
   @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}")
-  @ApiOperation("删除实体(设备)")
+  @ApiOperation("Delete entity")
   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);
-    }
+    checkParameter(groupName, deviceName);
     check(request, serverId);
     Connection connection = connectionService.getById(serverId);
-    groupName = "root." + groupName;
-    deviceName = groupName + "." + deviceName;
     String host = connection.getHost();
-    iotDBService.deleteTimeseriesByDevice(connection, deviceName);
+    List<String> deletedTimeseriesList =
+        iotDBService.deleteTimeseriesByDevice(connection, deviceName);
     deviceService.deleteDeviceInfoByDeviceName(host, deviceName);
-    measurementService.deleteMeasurementInfoByDeviceName(host, deviceName);
-    return BaseVO.success("删除成功", null);
+    for (String timeseries : deletedTimeseriesList) {
+      measurementService.deleteMeasurementInfo(host, timeseries);
+    }
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/storageGroups/{groupName}/devices/{deviceName}")
-  @ApiOperation("获取实体(设备)详情")
+  @ApiOperation("Get information of the specified entity")
   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);
-    }
+    checkParameter(groupName, deviceName);
     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);
+    return BaseVO.success("Get successfully", deviceVO);
   }
 
   @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/info")
-  @ApiOperation("获取指定实体(设备)下的物理量列表详情")
+  @ApiOperation("Gets detailed information of measurements under the specified entity")
   public BaseVO<MeasuremtnInfoVO> getMeasurementsByDeviceName(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
@@ -379,16 +435,9 @@ public class IotDBController {
       @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);
-    }
+    checkParameter(groupName, deviceName);
     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();
@@ -398,16 +447,46 @@ public class IotDBController {
       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());
+        Integer dataCount =
+            iotDBService.getOneDataCount(connection, deviceName, measurementDTO.getTimeseries());
+        measurementVO.setDataCount(dataCount);
         measurementVO.setNewValue(newValue);
         measurementVO.setDescription(description);
+        ObjectMapper mapper = new ObjectMapper();
+        List<List<String>> tags = new ArrayList<>();
+        List<List<String>> attributes = new ArrayList<>();
+        try {
+          if (!"null".equals(measurementDTO.getTags())) {
+
+            Map<String, String> tagsMap = mapper.readValue(measurementDTO.getTags(), Map.class);
+            for (String key : tagsMap.keySet()) {
+              List<String> tag = new ArrayList<>();
+              tag.add(key);
+              tag.add(tagsMap.get(key));
+              tags.add(tag);
+            }
+          }
+          measurementVO.setTags(tags);
+          if (!"null".equals(measurementDTO.getAttributes())) {
+
+            Map<String, String> attributesMap =
+                mapper.readValue(measurementDTO.getAttributes(), Map.class);
+            for (String key : attributesMap.keySet()) {
+              List<String> attribute = new ArrayList<>();
+              attribute.add(key);
+              attribute.add(attributesMap.get(key));
+              attributes.add(attribute);
+            }
+          }
+          measurementVO.setAttributes(attributes);
+        } catch (JsonProcessingException e) {
+          log.error(e.getMessage());
+          throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
+        }
         measurementVOList.add(measurementVO);
       }
     }
@@ -415,119 +494,199 @@ public class IotDBController {
     measuremtnInfoVO.setTotalCount(countDTO.getTotalCount());
     measuremtnInfoVO.setTotalPage(countDTO.getTotalPage());
     measuremtnInfoVO.setMeasurementVOList(measurementVOList);
-    return BaseVO.success("获取成功", measuremtnInfoVO);
+    return BaseVO.success("Get successfully", measuremtnInfoVO);
   }
 
   @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/{timeseriesName}")
-  @ApiOperation("获取指定物理量的最新两百条数据记录")
+  @ApiOperation("Get the latest 200 data records of the specified measurement")
   public BaseVO<RecordVO> getMeasurementInfo(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
       @PathVariable("deviceName") String deviceName,
       @PathVariable("timeseriesName") String timeseriesName,
+      @RequestParam("dataType") String dataType,
       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);
-    }
+    checkParameter(groupName, deviceName, timeseriesName);
     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);
+    RecordVO recordVO = iotDBService.getRecords(connection, deviceName, timeseriesName, dataType);
+    return BaseVO.success("Get successfully", recordVO);
   }
 
-  @PostMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries")
-  @ApiOperation("创建时间序列  (未使用)")
-  public BaseVO insertTimeseries(
+  @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries")
+  @ApiOperation("Get the list of measurement under the specified entity")
+  public BaseVO<List<String>> getTimeseries(
       @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);
-    }
+    checkParameter(groupName, deviceName);
     check(request, serverId);
     Connection connection = connectionService.getById(serverId);
-    groupName = "root." + groupName;
-    deviceName = groupName + "." + deviceName;
-    iotDBService.insertTimeseries(connection, deviceName, timeseries);
-    return BaseVO.success("创建成功", null);
+    List<String> timeseries = iotDBService.getTimeseries(connection, deviceName);
+    return BaseVO.success("Get successfully", timeseries);
   }
 
-  @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/info")
-  @ApiOperation("指定设备下的所有物理量  (未使用)")
-  public BaseVO<SqlResultVO> showTimeseries(
+  @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/{timeseriesName}")
+  @ApiOperation("Delete measurement")
+  public BaseVO deleteTimeseries(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
       @PathVariable("deviceName") String deviceName,
+      @PathVariable("timeseriesName") String timeseriesName,
       HttpServletRequest request)
       throws BaseException {
-    if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
-      throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
-    }
+    checkParameter(groupName, deviceName, timeseriesName);
     check(request, serverId);
     Connection connection = connectionService.getById(serverId);
-    groupName = "root." + groupName;
-    deviceName = groupName + "." + deviceName;
-    SqlResultVO resultVO = iotDBService.showTimeseries(connection, deviceName);
-    return BaseVO.success("获取成功", resultVO);
+    iotDBService.deleteTimeseries(connection, timeseriesName);
+    String host = connection.getHost();
+    measurementService.deleteMeasurementInfo(host, timeseriesName);
+    return BaseVO.success("Delete successfully", null);
   }
 
-  @GetMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries")
-  @ApiOperation("指定设备下的物理量列表")
-  public BaseVO<List<String>> getTimeseries(
+  @PostMapping("/storageGroups/{groupName}/devices/{deviceName}/data")
+  @ApiOperation("Get measurement data of the specified entity")
+  public BaseVO<DataVO> getDataByDevice(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      @PathVariable("deviceName") String deviceName,
+      @RequestParam("pageSize") Integer pageSize,
+      @RequestParam("pageNum") Integer pageNum,
+      @RequestBody DataQueryDTO dataQueryDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName, deviceName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    DataVO dataVO =
+        iotDBService.getDataByDevice(connection, deviceName, pageSize, pageNum, dataQueryDTO);
+    return BaseVO.success("Get successfully", dataVO);
+  }
+
+  @PutMapping("/storageGroups/{groupName}/devices/{deviceName}/data")
+  @ApiOperation("Update measurement data")
+  public BaseVO updateDataByDevice(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
       @PathVariable("deviceName") String deviceName,
+      @RequestBody DataUpdateDTO dataUpdateDTO,
       HttpServletRequest request)
       throws BaseException {
-    if (deviceName == null || !deviceName.matches("^[^ ]+$")) {
+    if (dataUpdateDTO.getValueList().size() != dataUpdateDTO.getMeasurementList().size()) {
       throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
     }
+    for (String measurement : dataUpdateDTO.getMeasurementList()) {
+      checkParameter(groupName, deviceName, measurement);
+    }
     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 + ".", ""));
+    iotDBService.updateDataByDevice(connection, deviceName, dataUpdateDTO);
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}/data")
+  @ApiOperation("Delete measurement data")
+  public BaseVO deleteDataByDevice(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      @PathVariable("deviceName") String deviceName,
+      @RequestBody DataDeleteDTO dataDeleteDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    for (String measurement : dataDeleteDTO.getMeasurementList()) {
+      checkParameter(groupName, deviceName, measurement);
     }
-    return BaseVO.success("获取成功", timeseries);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.deleteDataByDevice(connection, deviceName, dataDeleteDTO);
+    return BaseVO.success("Delete successfully", null);
   }
 
-  @DeleteMapping("/storageGroups/{groupName}/devices/{deviceName}/timeseries/{timeseriesName}")
-  @ApiOperation("删除物理量")
-  public BaseVO deleteTimeseries(
+  @PostMapping("/storageGroups/{groupName}/devices/{deviceName}/randomImport")
+  @ApiOperation("Import measurement data of specified devices in batches")
+  public BaseVO randomImport(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("groupName") String groupName,
       @PathVariable("deviceName") String deviceName,
-      @PathVariable("timeseriesName") String timeseriesName,
+      @RequestBody RandomImportDTO randomImportDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkParameter(groupName, deviceName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.randomImport(connection, deviceName, randomImportDTO);
+    return BaseVO.success("Randomly import successfully", null);
+  }
+
+  @ApiOperation("Export measurement data of the specified entity")
+  @PostMapping("/storageGroups/{groupName}/devices/{deviceName}/exportData")
+  public ResponseEntity<Resource> exportData(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("groupName") String groupName,
+      @PathVariable("deviceName") String deviceName,
+      @RequestBody DataQueryDTO dataQueryDTO,
       HttpServletRequest request)
       throws BaseException {
-    if (timeseriesName == null || !timeseriesName.matches("^[^ ]+$")) {
+    List<String> measurementList = dataQueryDTO.getMeasurementList();
+    if (measurementList == null || measurementList.size() == 0) {
       throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
     }
+    for (String measurement : measurementList) {
+      checkParameter(groupName, deviceName, measurement);
+    }
     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);
+    Integer port = connection.getPort();
+    String username = connection.getUsername();
+    String password = connection.getPassword();
+
+    String sql = iotDBService.getSqlForExport(deviceName, dataQueryDTO);
+    String fileName = exportCsv.exportCsv(host, port, username, password, sql, null);
+
+    org.springframework.core.io.Resource resource = fileService.loadFileAsResource(fileName);
+    String contentType = "application/octet-stream";
+    return ResponseEntity.ok()
+        .contentType(MediaType.parseMediaType(contentType))
+        .header(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" + resource.getFilename())
+        .body(resource);
+  }
+
+  @PostMapping("/users")
+  @ApiOperation("Create IoTDB user")
+  public BaseVO setIotDBUser(
+      @PathVariable("serverId") Integer serverId,
+      @RequestBody IotDBUser iotDBUser,
+      HttpServletRequest request)
+      throws BaseException {
+    check(request, serverId);
+    if (iotDBUser.getUserName().matches("^\\d+$")) {
+      throw new BaseException(ErrorCode.NOT_SUPPORT_ALL_DIGIT, ErrorCode.NOT_SUPPORT_ALL_DIGIT_MSG);
+    }
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.setIotDBUser(connection, iotDBUser);
+    return BaseVO.success("Create successfully", null);
+  }
+
+  @DeleteMapping("/users/{userName}")
+  @ApiOperation("Delete IoTDB user")
+  public BaseVO deleteIotDBUser(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.deleteIotDBUser(connection, userName);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/users")
-  @ApiOperation("获取数据库用户列表")
+  @ApiOperation("Get IoTDB users")
   public BaseVO<List<String>> getIotDBUserList(
       @PathVariable("serverId") Integer serverId, HttpServletRequest request) throws BaseException {
     check(request, serverId);
@@ -537,9 +696,9 @@ public class IotDBController {
     if (users == null) {
       users = new ArrayList<>();
       users.add(username);
-      return BaseVO.success("获取成功", users);
+      return BaseVO.success("Get successfully", users);
     }
-    // 前端需要将当前用户处于列表第一位
+    // The page needs to place the current user first in the list
     List<String> newUsers = new ArrayList<>();
     newUsers.add(username);
     for (String user : users) {
@@ -548,62 +707,267 @@ public class IotDBController {
       }
       newUsers.add(user);
     }
-    return BaseVO.success("获取成功", newUsers);
+    return BaseVO.success("Get successfully", newUsers);
+  }
+
+  @GetMapping("/users/{userName}")
+  @ApiOperation("Get the password and role list of the specified user")
+  public BaseVO<UserRolesVO> getRolesOfUser(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    UserRolesVO userRolesVO = iotDBService.getRolesOfUser(connection, userName);
+    return BaseVO.success("Get successfully", userRolesVO);
+  }
+
+  @PostMapping("/users/pwd")
+  @ApiOperation("Alter user password")
+  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("Alter password successfully", null);
+  }
+
+  @PostMapping("/roles")
+  @ApiOperation("Upsert role")
+  public BaseVO upsertIotDBRole(
+      @PathVariable("serverId") Integer serverId,
+      @RequestBody IotDBRole iotDBRole,
+      HttpServletRequest request)
+      throws BaseException {
+    check(request, serverId);
+    if (iotDBRole.getRoleName().matches("^\\d+$")) {
+      throw new BaseException(ErrorCode.NOT_SUPPORT_ALL_DIGIT, ErrorCode.NOT_SUPPORT_ALL_DIGIT_MSG);
+    }
+    Connection connection = connectionService.getById(serverId);
+    if (iotDBRole.getId() == null) {
+      iotDBService.setIotDBRole(connection, iotDBRole);
+    }
+    roleService.upsertRoleInfo(connection.getHost(), connection.getPort(), iotDBRole);
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @DeleteMapping("/roles/{roleName}")
+  @ApiOperation("Delete role")
+  public BaseVO deleteIotDBRole(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.deleteIotDBRole(connection, roleName);
+    roleService.deleteRoleInfo(connection.getHost(), connection.getPort(), roleName);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/roles")
-  @ApiOperation("获取数据库角色列表   (未使用)")
+  @ApiOperation("Get all roles)")
   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);
+    return BaseVO.success("Get successfully", roles);
   }
 
-  @GetMapping("/users/{userName}")
-  @ApiOperation("获取数据源用户的具体信息或其他用户的权限信息")
-  public BaseVO<IotDBUserVO> getIotDBUser(
+  @GetMapping("/roles/{roleName}")
+  @ApiOperation("Get information and user list of the specified role")
+  public BaseVO<RoleVO> getIotDBRoleInfo(
       @PathVariable("serverId") Integer serverId,
-      @PathVariable("userName") String userName,
+      @PathVariable("roleName") String roleName,
       HttpServletRequest request)
       throws BaseException {
-    if (userName == null || !userName.matches("^[^ ]+$")) {
-      throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    RoleVO roleVO = iotDBService.getIotDBRoleInfo(connection, roleName);
+    Role roleInfo = roleService.getRoleInfo(connection.getHost(), connection.getPort(), roleName);
+    if (roleInfo != null) {
+      roleVO.setId(roleInfo.getId());
+      roleVO.setDescription(roleInfo.getDescription());
     }
+    return BaseVO.success("Get successfully", roleVO);
+  }
+
+  @PostMapping("/users/{userName}/grant")
+  @ApiOperation("Grant roles to specified user")
+  public BaseVO userGrant(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      @RequestBody UserGrantDTO userGrantDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
     check(request, serverId);
     Connection connection = connectionService.getById(serverId);
-    IotDBUserVO iotDBUserVO = iotDBService.getIotDBUser(connection, userName);
-    return BaseVO.success("获取成功", iotDBUserVO);
+    iotDBService.userGrant(connection, userName, userGrantDTO);
+    return BaseVO.success("Upsert successfully", null);
   }
 
-  @PostMapping("/users/{userName}")
-  @ApiOperation("数据库用户赋权")
+  @PostMapping("/roles/{roleName}/grant")
+  @ApiOperation("Grant specified role to users")
+  public BaseVO roleGrant(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      @RequestBody RoleGrantDTO roleGrantDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.roleGrant(connection, roleName, roleGrantDTO);
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @GetMapping("/users/{userName}/authorityPrivilege")
+  @ApiOperation("Get authority management privileges of user")
+  public BaseVO<Set<String>> getUserAuthorityPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    Set<String> userAuthorityPrivilege =
+        iotDBService.getUserAuthorityPrivilege(connection, userName);
+    return BaseVO.success("Get successfully", userAuthorityPrivilege);
+  }
+
+  @GetMapping("/users/{userName}/allAuthorityPrivilege")
+  @ApiOperation("Get all authority management privileges of user")
+  public BaseVO<Set<String>> getAllAuthorityPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    Set<String> userAuthorityPrivilege =
+        iotDBService.getAllAuthorityPrivilege(connection, userName);
+    return BaseVO.success("Get successfully", userAuthorityPrivilege);
+  }
+
+  @GetMapping("/roles/{roleName}/authorityPrivilege")
+  @ApiOperation("Get authority management privileges of role")
+  public BaseVO<Set<String>> getRoleAuthorityPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    Set<String> roleAuthorityPrivilege =
+        iotDBService.getRoleAuthorityPrivilege(connection, roleName);
+    return BaseVO.success("Get successfully", roleAuthorityPrivilege);
+  }
+
+  @PostMapping("/users/{userName}/authorityPrivilege")
+  @ApiOperation("Modify authority management privileges of user")
+  public BaseVO upsertUserAuthorityPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      @RequestBody AuthorityPrivilegeDTO authorityPrivilegeDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.upsertAuthorityPrivilege(connection, userName, authorityPrivilegeDTO, "user");
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @PostMapping("/roles/{roleName}/authorityPrivilege")
+  @ApiOperation("Modify authority management privileges of role")
+  public BaseVO upsertRoleAuthorityPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      @RequestBody AuthorityPrivilegeDTO authorityPrivilegeDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.upsertAuthorityPrivilege(connection, roleName, authorityPrivilegeDTO, "role");
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @GetMapping("/users/{userName}/dataPrivilege")
+  @ApiOperation("Get data management privileges of user")
+  public BaseVO<List<DataPrivilegeVO>> getUserDataPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("userName") String userName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(userName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    List<DataPrivilegeVO> dataPrivilegeList =
+        iotDBService.getUserDataPrivilege(connection, userName);
+    return BaseVO.success("Get successfully", dataPrivilegeList);
+  }
+
+  @GetMapping("/roles/{roleName}/dataPrivilege")
+  @ApiOperation("Get data management privileges of role")
+  public BaseVO<List<DataPrivilegeVO>> getRoleDataPrivilege(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      HttpServletRequest request)
+      throws BaseException {
+    checkName(roleName);
+    check(request, serverId);
+    Connection connection = connectionService.getById(serverId);
+    List<DataPrivilegeVO> dataPrivilegeList =
+        iotDBService.getRoleDataPrivilege(connection, roleName);
+    return BaseVO.success("Get successfully", dataPrivilegeList);
+  }
+
+  @PostMapping("/users/{userName}/dataPrivilege")
+  @ApiOperation("Modify data management privileges of user")
   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);
+    checkName(userName);
+    checkPrivilegeInfoDTO(privilegeInfoDTO);
+    Connection connection = connectionService.getById(serverId);
+    iotDBService.upsertDataPrivileges(connection, "user", userName, privilegeInfoDTO);
+    return BaseVO.success("Upsert successfully", null);
+  }
+
+  @PostMapping("/roles/{roleName}/dataPrivilege")
+  @ApiOperation("Modify data management privileges of role")
+  public BaseVO setRolePrivileges(
+      @PathVariable("serverId") Integer serverId,
+      @PathVariable("roleName") String roleName,
+      @RequestBody PrivilegeInfoDTO privilegeInfoDTO,
+      HttpServletRequest request)
+      throws BaseException {
+    check(request, serverId);
+    checkName(roleName);
+    checkPrivilegeInfoDTO(privilegeInfoDTO);
     Connection connection = connectionService.getById(serverId);
-    iotDBService.setUserPrivileges(connection, userName, privilegeInfoDTO);
-    return BaseVO.success("操作成功", null);
+    iotDBService.upsertDataPrivileges(connection, "role", roleName, privilegeInfoDTO);
+    return BaseVO.success("Upsert successfully", null);
   }
 
-  private void pathCheck(PrivilegeInfoDTO privilegeInfoDTO) throws BaseException {
+  private void checkPrivilegeInfoDTO(PrivilegeInfoDTO privilegeInfoDTO) throws BaseException {
     Integer type = privilegeInfoDTO.getType();
     List<String> groupPaths = privilegeInfoDTO.getGroupPaths();
     List<String> devicePaths = privilegeInfoDTO.getDevicePaths();
@@ -748,109 +1112,60 @@ public class IotDBController {
       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);
+  private void check(HttpServletRequest request, Integer serverId) throws BaseException {
+    Integer userId = AuthenticationUtils.getUserId(request);
+    connectionService.check(serverId, userId);
   }
 
-  @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);
+  private void checkParameter(String groupName) throws BaseException {
+    String checkName = StringUtils.removeStart(groupName, "root").toLowerCase();
+    if (!groupName.matches("^root\\.[^ ]+$")
+        || checkName.contains(".root.")
+        || checkName.matches("^[^ ]*\\.root$")) {
+      throw new BaseException(ErrorCode.NO_SUP_CONTAIN_ROOT, ErrorCode.NO_SUP_CONTAIN_ROOT_MSG);
+    }
+    if (checkName.contains(".as.")
+        || checkName.contains(".null.")
+        || checkName.contains(".like.")
+        || checkName.matches("^[^ ]*\\.as$")
+        || checkName.matches("^[^ ]*\\.null$")
+        || checkName.matches("^[^ ]*\\.like$")) {
+      throw new BaseException(ErrorCode.NO_SUP_CONTAIN_WORD, ErrorCode.NO_SUP_CONTAIN_WORD_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("^[^ ]+$")) {
+  private void checkParameter(String groupName, String deviceName) throws BaseException {
+    checkParameter(deviceName);
+    checkParameter(groupName);
+    if (!deviceName.startsWith(groupName)) {
       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)
+  private void checkParameter(String groupName, String deviceName, String timeseriesName)
       throws BaseException {
-    check(request, serverId);
-    Connection connection = connectionService.getById(serverId);
-    iotDBService.setIotDBRole(connection, iotDBRole);
-    return BaseVO.success("创建成功", null);
+    checkParameter(deviceName, timeseriesName);
+    checkParameter(groupName, deviceName);
+    if (StringUtils.removeStart(timeseriesName, deviceName + ".").contains(".")) {
+      throw new BaseException(
+          ErrorCode.MEASUREMENTS_NAME_CONTAIN_DOT, ErrorCode.MEASUREMENTS_NAME_CONTAIN_DOT_MSG);
+    }
   }
 
-  private void check(HttpServletRequest request, Integer serverId) throws BaseException {
-    Integer userId = AuthenticationUtils.getUserId(request);
-    connectionService.check(serverId, userId);
+  private void checkName(String name) throws BaseException {
+    if (name == null || !name.matches("^[^ ]{4,}$")) {
+      throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+    }
   }
 
   private Long switchTime(String ttlUnit) throws BaseException {
-    Long time = 0L;
+    Long time;
     switch (ttlUnit) {
+      case "millisecond":
+        time = 1L;
+        break;
       case "second":
         time = 1000L;
         break;
@@ -887,7 +1202,7 @@ public class IotDBController {
     long minuteTime = 60000L;
     long secondTime = 1000L;
     if (time == 0) {
-      return "milliSecond";
+      return "millisecond";
     }
     if ((time / yearTime != 0) && (time % yearTime == 0)) {
       return "year";
@@ -910,6 +1225,12 @@ public class IotDBController {
     if ((time / secondTime != 0) && (time % secondTime == 0)) {
       return "second";
     }
-    return null;
+    return "millisecond";
+  }
+
+  private void checkTtl(Long ttl, String unit) throws BaseException {
+    if (Long.MAX_VALUE / switchTime(unit) < ttl) {
+      throw new BaseException(ErrorCode.TTL_OVER, ErrorCode.TTL_OVER_MSG);
+    }
   }
 }
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
index b162210..82d2b89 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/controller/QueryController.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/QueryController.java
@@ -42,7 +42,7 @@ import javax.servlet.http.HttpServletRequest;
 import java.util.List;
 
 @RestController
-@Api(value = "查询相关接口")
+@Api(value = "Query related")
 @RequestMapping("/servers/{serverId}")
 public class QueryController {
 
@@ -53,7 +53,7 @@ public class QueryController {
   @Autowired private QueryService queryService;
 
   @PostMapping("/querySql")
-  @ApiOperation("用于查询器查询")
+  @ApiOperation("Execute the query script")
   public BaseVO<List<SqlResultVO>> query(
       @PathVariable("serverId") Integer serverId,
       @RequestBody SearchDTO searchDTO,
@@ -67,11 +67,11 @@ public class QueryController {
     Connection connection = connectionService.getById(serverId);
     Long timestamp = searchDTO.getTimestamp();
     List<SqlResultVO> sqlResultVOList = iotDBService.queryAll(connection, sqls, timestamp);
-    return BaseVO.success("查询成功", sqlResultVOList);
+    return BaseVO.success("Execute the query script successfully", sqlResultVOList);
   }
 
   @PostMapping("/query")
-  @ApiOperation("用于查询脚本保存或编辑")
+  @ApiOperation("Save or update the query script")
   public BaseVO saveQuery(
       @PathVariable("serverId") Integer serverId,
       @RequestBody Query query,
@@ -84,23 +84,23 @@ public class QueryController {
     check(request, serverId);
     if (query.getId() != null) {
       queryService.update(serverId, query);
-      return BaseVO.success("更新成功", null);
+      return BaseVO.success("Update successful", query.getId());
     }
-    queryService.save(serverId, query);
-    return BaseVO.success("保存成功", null);
+    Integer id = queryService.save(serverId, query);
+    return BaseVO.success("Save successful", id);
   }
 
   @GetMapping("/query")
-  @ApiOperation("获取脚本列表")
+  @ApiOperation("Get query scripts")
   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);
+    return BaseVO.success("Get successful", queryVOList);
   }
 
   @DeleteMapping("/query/{queryId}")
-  @ApiOperation("删除脚本")
+  @ApiOperation("Delete the query script")
   public BaseVO deleteQuery(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("queryId") Integer queryId,
@@ -108,11 +108,11 @@ public class QueryController {
       throws BaseException {
     check(request, serverId);
     queryService.deleteQuery(queryId);
-    return BaseVO.success("删除成功", null);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/query/{queryId}")
-  @ApiOperation("获取指定脚本")
+  @ApiOperation("Get the specified query script")
   public BaseVO<Query> getQuery(
       @PathVariable("serverId") Integer serverId,
       @PathVariable("queryId") Integer queryId,
@@ -120,11 +120,11 @@ public class QueryController {
       throws BaseException {
     check(request, serverId);
     Query query = queryService.getQuery(queryId);
-    return BaseVO.success("获取成功", query);
+    return BaseVO.success("Get successfully", query);
   }
 
   @GetMapping("/stop")
-  @ApiOperation("用于查询终止")
+  @ApiOperation("Stop the query")
   public BaseVO query(
       @PathVariable("serverId") Integer serverId,
       @RequestParam("timestamp") Long timestamp,
@@ -132,7 +132,7 @@ public class QueryController {
       throws BaseException {
     check(request, serverId);
     iotDBService.stopQuery(serverId, timestamp);
-    return BaseVO.success("停止成功", null);
+    return BaseVO.success("Stop the query successful", null);
   }
 
   public void check(HttpServletRequest request, Integer serverId) throws BaseException {
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
index ff0e235..b1a7f97 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/controller/UserController.java
@@ -47,7 +47,7 @@ import java.util.Calendar;
 import java.util.List;
 
 @RestController
-@Api(value = "登录相关接口")
+@Api(value = "User related")
 public class UserController {
 
   @Autowired private UserService userService;
@@ -57,7 +57,7 @@ public class UserController {
   private static final Logger logger = LoggerFactory.getLogger(UserController.class);
 
   @PostMapping("/login")
-  @ApiOperation("登录")
+  @ApiOperation("login")
   public BaseVO<ConnectionVO> login(
       @RequestParam("name") String name,
       @RequestParam("password") String password,
@@ -71,27 +71,27 @@ public class UserController {
     List<ConnVO> connVOs = connectionService.getAllConnections(userId);
     ConnectionVO connectionVO = new ConnectionVO(connVOs, userId, name);
     response.addHeader("Authorization", getToken(user));
-    return BaseVO.success("登录成功", connectionVO);
+    return BaseVO.success("Login  successful", connectionVO);
   }
 
   @PostMapping("/save")
-  @ApiOperation("创建用户  (未使用)")
+  @ApiOperation("Create user (not used)")
   public BaseVO save(@RequestBody User user) throws BaseException {
     userService.insert(user);
-    return BaseVO.success("保存成功", null);
+    return BaseVO.success("Save successful", null);
   }
 
   @DeleteMapping("/delete")
-  @ApiOperation("删除用户  (未使用)")
+  @ApiOperation("Delete user (not used)")
   public BaseVO delete(@RequestParam("userId") Integer userId, HttpServletRequest request)
       throws BaseException {
     AuthenticationUtils.userAuthentication(userId, request);
     userService.delete(userId);
-    return BaseVO.success("删除成功", null);
+    return BaseVO.success("Delete successfully", null);
   }
 
   @GetMapping("/get")
-  @ApiOperation("二次登录获取用户信息")
+  @ApiOperation("Get information of user")
   public BaseVO<User> getUser(HttpServletRequest request) {
     String authorization = request.getHeader("Authorization");
     DecodedJWT decode = JWT.decode(authorization);
@@ -102,7 +102,24 @@ public class UserController {
       user.setId(userId);
       user.setName(name);
     }
-    return BaseVO.success("获取成功", user);
+    return BaseVO.success("Get successfully", user);
+  }
+
+  @GetMapping("/")
+  public String welcome() {
+    String str =
+        "<!DOCTYPE html>\n"
+            + "<html lang=\"ch\">\n"
+            + "<head>\n"
+            + "    <meta charset=\"UTF-8\">\n"
+            + "    <title>welcome</title>\n"
+            + "</head>\n"
+            + "<body>\n"
+            + "<h1>You have successfully started IoTDB-Workbench backend application!</h1>\n"
+            + "<h2>For a better experience with IOTDB-Workbench, Please refer to the <a href=\"https://github.com/loveher147/iotdb-admin/blob/main/backend/doc/deploy.md\">deployment documentation</a> for deployment</h2>\n"
+            + "</body>\n"
+            + "</html>";
+    return str;
   }
 
   private String getToken(User user) throws BaseException {
@@ -115,7 +132,7 @@ public class UserController {
               .withClaim("name", user.getName())
               .withExpiresAt(instance.getTime())
               .sign(Algorithm.HMAC256("IOTDB:" + InetAddress.getLocalHost().getHostAddress()));
-      logger.info(user.getName() + "登录成功");
+      logger.info(user.getName() + "login successfully");
       return token;
     } catch (Exception e) {
       logger.info(e.getMessage());
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
deleted file mode 100644
index 750ef37..0000000
--- a/backend/src/main/java/org/apache/iotdb/admin/demo/JDBC.java
+++ /dev/null
@@ -1,152 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 892182d..0000000
--- a/backend/src/main/java/org/apache/iotdb/admin/demo/NativeAPI.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * 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
-     *
-     * <p>TSEncoding编码方式: PLAIN编码:不编码 压缩效率高 空间存储效率低 二阶差分编码(TS_2DIFF):适合单调序列数据 不适合编码波动较大的数据
-     * 游程编码(RLE):比较适合整数值连续出现的序列 GORILLA编码:无损编码,它比较适合编码前后值比较接近的数值序列 定频数据编码(REGULAR):仅适用于整型 允许数据缺失
-     *
-     * <p>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
index 615ac99..22d1242 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/filter/TokenFilter.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/filter/TokenFilter.java
@@ -33,9 +33,7 @@ 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 {
diff --git a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java b/backend/src/main/java/org/apache/iotdb/admin/mapper/RoleMapper.java
similarity index 75%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/mapper/RoleMapper.java
index 9030089..b791a52 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/mapper/RoleMapper.java
@@ -17,17 +17,12 @@
  * under the License.
  */
 
-package org.apache.iotdb.admin.model.vo;
+package org.apache.iotdb.admin.mapper;
 
-import lombok.Data;
+import org.apache.iotdb.admin.model.entity.Role;
 
-import java.io.Serializable;
+import com.baomidou.mybatisplus.core.mapper.BaseMapper;
+import org.springframework.stereotype.Component;
 
-@Data
-public class DeviceVO implements Serializable {
-
-  private String description;
-  private String creator;
-  private String time;
-  private Integer deviceId;
-}
+@Component
+public interface RoleMapper extends BaseMapper<Role> {}
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/AuthorityPrivilegeDTO.java
similarity index 87%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/AuthorityPrivilegeDTO.java
index 9b2246e..4a7ea78 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/AuthorityPrivilegeDTO.java
@@ -25,9 +25,8 @@ import java.io.Serializable;
 import java.util.List;
 
 @Data
-public class CountDTO<T> implements Serializable {
+public class AuthorityPrivilegeDTO implements Serializable {
+  private List<String> privileges;
 
-  private List<T> objects;
-  private Integer totalCount;
-  private Integer totalPage;
+  private List<String> cancelPrivileges;
 }
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
index d17f8ab..3841840 100644
--- 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
@@ -32,24 +32,24 @@ import java.io.Serializable;
 @Data
 public class ConnectionDTO implements Serializable {
 
-  @NotBlank(message = "主机地址不能为空或为null")
+  @NotBlank(message = "The host address cannot be empty or 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 = "主机号输入不合法")
+      message = "The host is invalid")
   private String host;
 
-  @NotNull(message = "端口号不能为null")
-  @Range(min = 0, max = 65535, message = "端口号输入不合法")
+  @NotNull(message = "The port number cannot be null")
+  @Range(min = 0, max = 65535, message = "The host is invalid")
   private Integer port;
 
-  @NotBlank(message = "用户名不能为空或为null")
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "用户名不能包含空格")
+  @NotBlank(message = "The username cannot be empty or null")
+  @Length(min = 4, message = "The username must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The username cannot contain spaces")
   private String username;
 
-  @NotBlank(message = "密码不能为空或为null")
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "密码不能包含空格")
+  @NotBlank(message = "The password cannot be empty or null")
+  @Length(min = 4, message = "The password must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The username cannot contain spaces")
   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
index 9b2246e..f287c90 100644
--- 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
@@ -26,7 +26,6 @@ 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/SearchDTO.java b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DataDeleteDTO.java
similarity index 74%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/DataDeleteDTO.java
index 366dff0..ef7bfb0 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DataDeleteDTO.java
@@ -21,16 +21,18 @@ package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.constraints.NotEmpty;
 
 import java.io.Serializable;
+import java.util.Date;
 import java.util.List;
 
 @Data
-public class SearchDTO implements Serializable {
+public class DataDeleteDTO implements Serializable {
 
-  private List<String> sqls;
+  @NotEmpty(message = "The timestamp list cannot be empty")
+  private List<Date> timestampList;
 
-  @NotNull(message = "不能为null")
-  private Long timestamp;
+  @NotEmpty(message = "The measurement list cannot be empty")
+  private List<String> measurementList;
 }
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/DataQueryDTO.java
similarity index 77%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/DataQueryDTO.java
index 366dff0..f6b3f35 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/SearchDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DataQueryDTO.java
@@ -21,16 +21,19 @@ package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
 
-import javax.validation.constraints.NotNull;
+import javax.validation.constraints.NotEmpty;
 
 import java.io.Serializable;
+import java.util.Date;
 import java.util.List;
 
 @Data
-public class SearchDTO implements Serializable {
+public class DataQueryDTO implements Serializable {
 
-  private List<String> sqls;
+  private Date startTime;
 
-  @NotNull(message = "不能为null")
-  private Long timestamp;
+  private Date endTime;
+
+  @NotEmpty(message = "The measurement list cannot be empty")
+  private List<String> measurementList;
 }
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/DataUpdateDTO.java
similarity index 71%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/DataUpdateDTO.java
index f2364af..c4f71f4 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/DataUpdateDTO.java
@@ -21,22 +21,22 @@ package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
 
+import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
 
 import java.io.Serializable;
+import java.util.Date;
 import java.util.List;
 
 @Data
-public class DeviceInfoDTO implements Serializable {
+public class DataUpdateDTO implements Serializable {
 
-  private List<DeviceDTO> deviceDTOList;
+  @NotNull(message = "The timestamp cannot be null")
+  private Date timestamp;
 
-  @NotNull(message = "设备名不能为null")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
-  private String deviceName;
+  @NotEmpty(message = "The data value list cannot be empty")
+  private List<String> valueList;
 
-  private String description;
-
-  private Integer deviceId;
+  @NotEmpty(message = "The measurement list cannot be empty")
+  private List<String> measurementList;
 }
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
index e26eea3..3d5f99f 100644
--- 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
@@ -21,16 +21,31 @@ package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
 
+import javax.validation.constraints.NotEmpty;
+
 import java.io.Serializable;
+import java.util.List;
 
 @Data
 public class DeviceDTO implements Serializable {
 
+  @NotEmpty(message = "The measurement cannot be empty")
   private String timeseries;
 
+  @NotEmpty(message = "The data type cannot be empty")
   private String dataType;
 
+  @NotEmpty(message = "The encoding cannot be empty")
   private String encoding;
 
   private String description;
+
+  private String alias;
+
+  @NotEmpty(message = "The compression cannot be empty")
+  private String compression;
+
+  private List<List<String>> tags;
+
+  private List<List<String>> attributes;
 }
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
index f2364af..a47413d 100644
--- 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
@@ -21,6 +21,8 @@ package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
 
+import javax.validation.Valid;
+import javax.validation.constraints.NotEmpty;
 import javax.validation.constraints.NotNull;
 import javax.validation.constraints.Pattern;
 
@@ -30,10 +32,12 @@ import java.util.List;
 @Data
 public class DeviceInfoDTO implements Serializable {
 
+  @NotEmpty(message = "The measurement list cannot be empty")
+  @Valid
   private List<DeviceDTO> deviceDTOList;
 
-  @NotNull(message = "设备名不能为null")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @NotNull(message = "The device name cannot be null")
+  @Pattern(regexp = "^[^ ]+$", message = "The device name cannot contain spaces")
   private String deviceName;
 
   private String description;
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
index 3e751b9..c49aa14 100644
--- 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
@@ -29,8 +29,8 @@ import java.io.Serializable;
 @Data
 public class GroupDTO implements Serializable {
 
-  @NotNull(message = "存储组名不能为null")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @NotNull(message = "The storage group name cannot be null")
+  @Pattern(regexp = "^[^ ]+$", message = "The storage group name cannot contain spaces")
   private String groupName;
 
   private String description;
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
index 4a25786..a25a5b5 100644
--- 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
@@ -22,15 +22,18 @@ 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;
-import java.util.List;
 
-/** 传输role信息类 */
 @Data
 public class IotDBRole implements Serializable {
 
-  @Length(min = 4, message = "长度必须大于等于4")
+  private Integer id;
+
+  @Length(min = 4, message = "The username must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The role name cannot contain spaces")
   private String roleName;
 
-  private List<String> privileges;
+  private String description;
 }
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
index d0beb5b..374ecb2 100644
--- 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
@@ -26,19 +26,14 @@ import javax.validation.constraints.Pattern;
 
 import java.io.Serializable;
 
-/** 传输User信息类 */
 @Data
 public class IotDBUser implements Serializable {
 
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @Length(min = 4, message = "The username must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The username cannot contain spaces")
   private String userName;
 
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @Length(min = 4, message = "The password must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The password cannot contain spaces")
   private String password;
-
-  //    private List<String> privileges;
-  //
-  //    private List<String> roles;
 }
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
index 7b2eda7..27048c2 100644
--- 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
@@ -25,7 +25,6 @@ import java.io.Serializable;
 
 @Data
 public class MeasurementDTO implements Serializable {
-
   private String timeseries;
   private String alias;
   private String storagegroup;
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
index 7e55404..646938e 100644
--- 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
@@ -26,8 +26,7 @@ import java.util.List;
 
 @Data
 public class PrivilegeInfoDTO implements Serializable {
-
-  // 0 1 2 3 对应 root、storageGroup、device、timeseries
+  // 0, 1, 2, 3 corresponding to root, storageGroup, device, timeseries
   private Integer type;
   private List<String> groupPaths;
   private List<String> devicePaths;
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/RandomImportDTO.java
similarity index 62%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/RandomImportDTO.java
index f2364af..f037d0f 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/DeviceInfoDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/RandomImportDTO.java
@@ -20,23 +20,25 @@
 package org.apache.iotdb.admin.model.dto;
 
 import lombok.Data;
+import org.hibernate.validator.constraints.Range;
 
+import javax.validation.constraints.Min;
 import javax.validation.constraints.NotNull;
-import javax.validation.constraints.Pattern;
 
 import java.io.Serializable;
-import java.util.List;
+import java.util.Date;
 
 @Data
-public class DeviceInfoDTO implements Serializable {
+public class RandomImportDTO implements Serializable {
 
-  private List<DeviceDTO> deviceDTOList;
+  @NotNull(message = "The start time cannot be null")
+  private Date startTime;
 
-  @NotNull(message = "设备名不能为null")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
-  private String deviceName;
+  @NotNull(message = "The step size cannot be null")
+  @Min(value = 1, message = "The step size must be at least 1ms")
+  private Integer stepSize;
 
-  private String description;
-
-  private Integer deviceId;
+  @NotNull(message = "The data line cannot be null")
+  @Range(min = 1, max = 1000000, message = "The number of data lines is between 1 and 1000000")
+  private Integer totalLine;
 }
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/RoleGrantDTO.java
similarity index 87%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/RoleGrantDTO.java
index 9b2246e..bd6fe87 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/RoleGrantDTO.java
@@ -25,9 +25,9 @@ import java.io.Serializable;
 import java.util.List;
 
 @Data
-public class CountDTO<T> implements Serializable {
+public class RoleGrantDTO implements Serializable {
 
-  private List<T> objects;
-  private Integer totalCount;
-  private Integer totalPage;
+  private List<String> UserList;
+
+  private List<String> cancelUserList;
 }
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
index 366dff0..b9a3dea 100644
--- 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
@@ -31,6 +31,6 @@ public class SearchDTO implements Serializable {
 
   private List<String> sqls;
 
-  @NotNull(message = "不能为null")
+  @NotNull(message = "Timestamp cannot be null")
   private Long timestamp;
 }
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/UserGrantDTO.java
similarity index 87%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/dto/UserGrantDTO.java
index 9b2246e..67c98bf 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/CountDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/dto/UserGrantDTO.java
@@ -25,9 +25,9 @@ import java.io.Serializable;
 import java.util.List;
 
 @Data
-public class CountDTO<T> implements Serializable {
+public class UserGrantDTO implements Serializable {
 
-  private List<T> objects;
-  private Integer totalCount;
-  private Integer totalPage;
+  private List<String> roleList;
+
+  private List<String> cancelRoleList;
 }
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
index 9080433..10eccec 100644
--- 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
@@ -37,32 +37,32 @@ public class Connection implements Serializable {
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotBlank(message = "主机地址不能为空或为null")
+  @NotBlank(message = "The host address cannot be empty or 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 = "主机号输入不合法")
+      message = "The host is invalid")
   private String host;
 
-  @NotNull(message = "端口号不能为null")
-  @Range(min = 0, max = 65535, message = "端口号输入不合法")
+  @NotNull(message = "The port number cannot be null")
+  @Range(min = 0, max = 65535, message = "The host is invalid")
   private Integer port;
 
-  @NotBlank(message = "用户名不能为空或为null")
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "用户名不能包含空格")
+  @NotBlank(message = "The username cannot be empty or null")
+  @Length(min = 4, message = "The username must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The username cannot contain spaces")
   private String username;
 
-  @NotBlank(message = "密码不能为空或为null")
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "密码不能包含空格")
+  @NotBlank(message = "The password cannot be empty or null")
+  @Length(min = 4, message = "The password must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The username cannot contain spaces")
   private String password;
 
-  @NotBlank(message = "连接名不能为空或为null")
-  @Length(min = 3, max = 100, message = "连接名长度必须在3-100之间")
-  @Pattern(regexp = "^[^ ]+$", message = "连接名不能包含空格")
+  @NotBlank(message = "The connection name cannot be empty or null")
+  @Length(min = 3, max = 100, message = "The connection name must be between 3 and 100")
+  @Pattern(regexp = "^[^ ]+$", message = "The connection name cannot contains spaces")
   private String alias;
 
-  @NotNull(message = "用户id不能为null")
+  @NotNull(message = "The user id cannot be 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
index 7ce33e1..8e5d2fe 100644
--- 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
@@ -36,20 +36,20 @@ public class Device implements Serializable {
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotNull(message = "未指定所属主机")
+  @NotNull(message = "The host cannot be null")
   private String host;
 
   private String description;
 
   @NotBlank
-  @Length(min = 4, message = "创建者名长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "创建者名不能包含空格")
+  @Length(min = 4, message = "The creator name must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The creator name cannot contains spaces")
   private String creator;
 
-  @NotNull(message = "未指定创建时间")
+  @NotNull(message = "The create time cannot be null")
   private Long createTime;
 
   @NotBlank
-  @Pattern(regexp = "^[^ ]+$", message = "设备名不能包含空格")
+  @Pattern(regexp = "^[^ ]+$", message = "The device name cannot contains spaces")
   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
index 43f15f2..ae7fe50 100644
--- 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
@@ -33,10 +33,10 @@ public class Measurement implements Serializable {
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotNull(message = "未指定所属主机")
+  @NotNull(message = "The host cannot be null")
   private String host;
 
-  @NotNull(message = "未指定测点名")
+  @NotNull(message = "The measurement name cannot be null")
   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
index f2b7898..e9c741a 100644
--- 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
@@ -33,10 +33,10 @@ public class Query implements Serializable {
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotNull(message = "未指定所属连接id")
+  @NotNull(message = "The connection id cannot be null")
   private Integer connectionId;
 
-  @NotNull(message = "未指定脚本名")
+  @NotNull(message = "The query name cannot be null")
   private String queryName;
 
   private String sqls;
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/Role.java
similarity index 75%
copy from backend/src/main/java/org/apache/iotdb/admin/model/entity/Measurement.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/entity/Role.java
index 43f15f2..17a8bf7 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/entity/Measurement.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/entity/Role.java
@@ -22,22 +22,27 @@ 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.NotNull;
 
 import java.io.Serializable;
 
 @Data
-public class Measurement implements Serializable {
+public class Role implements Serializable {
 
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotNull(message = "未指定所属主机")
+  @NotNull(message = "The role name cannot be null")
+  @Length(min = 4, message = "The role name must contain at least 4 characters")
+  private String name;
+
+  @NotNull(message = "The host cannot be null")
   private String host;
 
-  @NotNull(message = "未指定测点名")
-  private String measurementName;
+  @NotNull(message = "The port cannot be null")
+  private Integer port;
 
   private String description;
 }
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
index 8550ac8..fb72929 100644
--- 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
@@ -36,17 +36,17 @@ public class StorageGroup implements Serializable {
   @TableId(type = IdType.AUTO)
   private Integer id;
 
-  @NotNull(message = "未指定所属主机")
+  @NotNull(message = "The host cannot be null")
   private String host;
 
   private String description;
 
   @NotBlank
-  @Length(min = 4, message = "创建者名长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "创建者名不能包含空格")
+  @Length(min = 4, message = "The creator name must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The creator name cannot contains spaces")
   private String creator;
 
-  @NotNull(message = "未指定创建时间")
+  @NotNull(message = "The create time cannot be null")
   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
index c778fd7..4b82cbd 100644
--- 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
@@ -38,12 +38,12 @@ public class User implements Serializable {
   private Integer id;
 
   @NotBlank
-  @Length(min = 4, message = "长度必须大于等于4")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @Length(min = 4, message = "The account name must contain at least 4 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The account name cannot contain spaces")
   private String name;
 
   @NotBlank
-  @Length(min = 6, message = "长度必须大于等于6")
-  @Pattern(regexp = "^[^ ]+$", message = "不能包含空格")
+  @Length(min = 6, message = "The account password must contain at least 6 characters")
+  @Pattern(regexp = "^[^ ]+$", message = "The account password cannot contain spaces")
   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
index 23eec26..6bfc8df 100644
--- 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
@@ -21,17 +21,15 @@ package org.apache.iotdb.admin.model.vo;
 
 import lombok.Data;
 
-/** 返回信息类 */
+/** Return base class */
 @Data
 public class BaseVO<T> {
 
-  /** 0 表示成功 其他表示错误类型 */
+  /** 0 indicates success and other indicates error types */
   private String code;
 
-  /** 定义出错时候用户可读的信息 */
   private String message;
 
-  /** 这是一个返回数据的通用类型模板 */
   private T data;
 
   public BaseVO() {}
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
index 0f33ac9..6e2debd 100644
--- 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
@@ -25,12 +25,14 @@ import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
 
-/** 展示别名及serverId */
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
 public class ConnVO implements Serializable {
-
   private Integer id;
   private String alias;
+  private String host;
+  private Integer port;
+  private String username;
+  private String password;
 }
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
index ff7df4a..4ee6f87 100644
--- 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
@@ -26,7 +26,6 @@ import lombok.NoArgsConstructor;
 import java.io.Serializable;
 import java.util.List;
 
-/** 展示用户的连接列表 */
 @Data
 @AllArgsConstructor
 @NoArgsConstructor
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/DataCountVO.java
similarity index 83%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/QueryVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/DataCountVO.java
index 0848dbe..cdef28c 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/QueryVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DataCountVO.java
@@ -24,8 +24,9 @@ import lombok.Data;
 import java.io.Serializable;
 
 @Data
-public class QueryVO implements Serializable {
-
-  private Integer id;
-  private String queryName;
+public class DataCountVO implements Serializable {
+  private Integer groupCount;
+  private Integer deviceCount;
+  private Integer measurementCount;
+  private Integer dataCount;
 }
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/DataInfo.java
similarity index 87%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasurementVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/DataInfo.java
index 3606c51..8c58ff9 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasurementVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DataInfo.java
@@ -24,11 +24,10 @@ import lombok.Data;
 import java.io.Serializable;
 
 @Data
-public class MeasurementVO implements Serializable {
-
-  private String timeseries;
+public class DataInfo implements Serializable {
   private String dataType;
-  private String encoding;
-  private String description;
+
   private String newValue;
+
+  private Integer dataCount;
 }
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/DataModelVO.java
similarity index 58%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupInfoVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/DataModelVO.java
index f60f74d..2763728 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/GroupInfoVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DataModelVO.java
@@ -19,18 +19,45 @@
 
 package org.apache.iotdb.admin.model.vo;
 
-import lombok.AllArgsConstructor;
 import lombok.Data;
-import lombok.NoArgsConstructor;
 
 import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.List;
 
 @Data
-@NoArgsConstructor
-@AllArgsConstructor
-public class GroupInfoVO implements Serializable {
+public class DataModelVO implements Serializable {
+  private String name;
+
+  private Boolean isGroup;
+
+  private Boolean isDevice;
+
+  private Boolean isMeasurement;
+
+  private Integer groupCount;
 
-  private String groupName;
   private Integer deviceCount;
-  private String description;
+
+  private Integer measurementCount;
+
+  private DataInfo dataInfo;
+
+  private String path;
+
+  private List<DataModelVO> children;
+
+  public DataModelVO(String name) {
+    this.name = name;
+    this.isGroup = false;
+    this.isDevice = false;
+    this.isMeasurement = false;
+  }
+
+  public List<DataModelVO> initNodeChildren() {
+    if (children == null) {
+      children = new ArrayList<>();
+    }
+    return children;
+  }
 }
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/vo/DataPrivilegeVO.java
similarity index 76%
copy from backend/src/main/java/org/apache/iotdb/admin/model/dto/PrivilegeInfoDTO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/DataPrivilegeVO.java
index 7e55404..52850ba 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/dto/PrivilegeInfoDTO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DataPrivilegeVO.java
@@ -17,7 +17,7 @@
  * under the License.
  */
 
-package org.apache.iotdb.admin.model.dto;
+package org.apache.iotdb.admin.model.vo;
 
 import lombok.Data;
 
@@ -25,16 +25,14 @@ import java.io.Serializable;
 import java.util.List;
 
 @Data
-public class PrivilegeInfoDTO implements Serializable {
-
-  // 0 1 2 3 对应 root、storageGroup、device、timeseries
+public class DataPrivilegeVO implements Serializable {
+  // 0, 1, 2, 3 corresponding to 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;
+  private List<String> allTimeseriesPaths;
+  private List<NodeTreeVO> allDevicePaths;
+  private List<NodeTreeVO> allGroupPaths;
 }
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/DataVO.java
similarity index 86%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/SqlResultVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/DataVO.java
index d8ba158..ef34613 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/SqlResultVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/DataVO.java
@@ -24,12 +24,11 @@ import lombok.Data;
 import java.io.Serializable;
 import java.util.List;
 
-/** sql查询的元数据列表和数据列表 */
 @Data
-public class SqlResultVO implements Serializable {
-
+public class DataVO implements Serializable {
   private List<String> metaDataList;
   private List<List<String>> valueList;
-  private String queryTime;
-  private Long line;
+  private List<String> typeList;
+  private Integer totalCount;
+  private Integer totalPage;
 }
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
index b182eef..ca6d7a7 100644
--- 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
@@ -22,13 +22,14 @@ package org.apache.iotdb.admin.model.vo;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 @Data
 public class DeviceInfo implements Serializable {
-
   private String deviceName;
   private String description;
   private String creator;
   private Integer line;
   private Integer deviceId;
+  private List<String> parents;
 }
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
index 779973a..9fb33f3 100644
--- 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
@@ -26,7 +26,6 @@ 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
index 9030089..8f2b66f 100644
--- 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
@@ -25,7 +25,6 @@ import java.io.Serializable;
 
 @Data
 public class DeviceVO implements Serializable {
-
   private String description;
   private String creator;
   private String time;
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
index f60f74d..512deb7 100644
--- 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
@@ -29,7 +29,6 @@ import java.io.Serializable;
 @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
index 09eeae3..352442b 100644
--- 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
@@ -25,7 +25,6 @@ import java.io.Serializable;
 
 @Data
 public class GroupVO implements Serializable {
-
   private String groupName;
   private String alias;
   private String description;
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/ImportDataVO.java
similarity index 74%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/ImportDataVO.java
index 1c56d63..d618b61 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/ImportDataVO.java
@@ -22,12 +22,18 @@ 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;
+public class ImportDataVO implements Serializable {
   private Integer totalCount;
-  private Integer totalPage;
+
+  private Integer failCount;
+
+  private String fileDownloadUri;
+
+  public ImportDataVO(Integer totalCount, Integer failCount, String fileDownloadUri) {
+    this.totalCount = totalCount;
+    this.failCount = failCount;
+    this.fileDownloadUri = fileDownloadUri;
+  }
 }
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
index 3606c51..a934231 100644
--- 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
@@ -22,13 +22,18 @@ package org.apache.iotdb.admin.model.vo;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 @Data
 public class MeasurementVO implements Serializable {
-
   private String timeseries;
   private String dataType;
   private String encoding;
   private String description;
   private String newValue;
+  private Integer dataCount;
+  private String alias;
+  private String compression;
+  private List<List<String>> tags;
+  private List<List<String>> attributes;
 }
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
index 1c56d63..d46fd4a 100644
--- 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
@@ -26,7 +26,6 @@ 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/MeasuremtnInfoVO.java b/backend/src/main/java/org/apache/iotdb/admin/model/vo/NodeTreeVO.java
similarity index 73%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/NodeTreeVO.java
index 1c56d63..cfa4acc 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/MeasuremtnInfoVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/NodeTreeVO.java
@@ -22,12 +22,23 @@ package org.apache.iotdb.admin.model.vo;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.ArrayList;
 import java.util.List;
 
 @Data
-public class MeasuremtnInfoVO implements Serializable {
+public class NodeTreeVO implements Serializable {
+  private String name;
 
-  private List<MeasurementVO> measurementVOList;
-  private Integer totalCount;
-  private Integer totalPage;
+  private List<NodeTreeVO> children;
+
+  public NodeTreeVO(String name) {
+    this.name = name;
+  }
+
+  public List<NodeTreeVO> initChildren() {
+    if (children == null) {
+      children = new ArrayList<>();
+    }
+    return children;
+  }
 }
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
index 0848dbe..6578d2e 100644
--- 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
@@ -25,7 +25,6 @@ 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
index 696931e..4238b84 100644
--- 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
@@ -24,10 +24,13 @@ import lombok.Data;
 import java.io.Serializable;
 import java.util.Date;
 import java.util.List;
+import java.util.Map;
 
 @Data
 public class RecordVO implements Serializable {
-
   private List<Date> timeList;
-  private List<Long> valueList;
+
+  private List<String> valueList;
+
+  private Map<String, Integer> textCount;
 }
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/RoleVO.java
similarity index 88%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/RoleVO.java
index 9030089..6b683ba 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/DeviceVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/RoleVO.java
@@ -22,12 +22,13 @@ package org.apache.iotdb.admin.model.vo;
 import lombok.Data;
 
 import java.io.Serializable;
+import java.util.List;
 
 @Data
-public class DeviceVO implements Serializable {
-
+public class RoleVO implements Serializable {
   private String description;
-  private String creator;
-  private String time;
-  private Integer deviceId;
+
+  private List<String> userList;
+
+  private Integer id;
 }
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
index d8ba158..4cffeac 100644
--- 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
@@ -24,10 +24,8 @@ 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;
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
index 3303d9e..5dc1766 100644
--- 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
@@ -25,7 +25,6 @@ import java.io.Serializable;
 
 @Data
 public class StorageGroupVO implements Serializable {
-
   private String groupName;
   private Integer groupId;
 }
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/UserRolesVO.java
similarity index 87%
copy from backend/src/main/java/org/apache/iotdb/admin/model/vo/RecordVO.java
copy to backend/src/main/java/org/apache/iotdb/admin/model/vo/UserRolesVO.java
index 696931e..25721c1 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/model/vo/RecordVO.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/model/vo/UserRolesVO.java
@@ -22,12 +22,12 @@ 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 {
+public class UserRolesVO implements Serializable {
 
-  private List<Date> timeList;
-  private List<Long> valueList;
+  private String password;
+
+  private List<String> roleList;
 }
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
index b5829a5..64317c4 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/ConnectionService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/ConnectionService.java
@@ -26,7 +26,6 @@ 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;
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
index d1de1b9..89b4d67 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/DeviceService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/DeviceService.java
@@ -28,7 +28,6 @@ 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;
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java b/backend/src/main/java/org/apache/iotdb/admin/service/FileService.java
similarity index 76%
copy from backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
copy to backend/src/main/java/org/apache/iotdb/admin/service/FileService.java
index fb9c1e2..5a88461 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/FileService.java
@@ -20,13 +20,12 @@
 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 {
+import org.springframework.core.io.Resource;
+import org.springframework.web.multipart.MultipartFile;
 
-  User login(String name, String password) throws BaseException;
+public interface FileService {
+  String storeFile(MultipartFile file, String fileName) throws BaseException;
 
-  void insert(User user) throws BaseException;
-
-  void delete(Integer userId) throws BaseException;
+  Resource loadFileAsResource(String fileName) 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
index 76ee8c5..c08e04a 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/GroupService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/GroupService.java
@@ -27,7 +27,6 @@ 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;
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
index 83c6a4a..70cd585 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/IotDBService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/IotDBService.java
@@ -22,16 +22,20 @@ 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 org.apache.iotdb.admin.model.vo.*;
 
 import java.util.List;
+import java.util.Set;
 
 public interface IotDBService {
+  DataCountVO getDataCount(Connection connection) throws BaseException;
+
+  DataModelVO getDataModel(Connection connection) throws BaseException;
 
   List<String> getAllStorageGroups(Connection connection) throws BaseException;
 
+  List<NodeTreeVO> getGroupsNodeTree(Connection connection) throws BaseException;
+
   void saveStorageGroup(Connection connection, String groupName) throws BaseException;
 
   void deleteStorageGroup(Connection connection, String groupName) throws BaseException;
@@ -48,7 +52,7 @@ public interface IotDBService {
 
   List<String> getIotDBRoleList(Connection connection) throws BaseException;
 
-  IotDBUserVO getIotDBUser(Connection connection, String userName) throws BaseException;
+  RoleVO getIotDBRoleInfo(Connection connection, String roleName) throws BaseException;
 
   void deleteIotDBUser(Connection connection, String userName) throws BaseException;
 
@@ -58,12 +62,36 @@ public interface IotDBService {
 
   void setIotDBRole(Connection connection, IotDBRole iotDBRole) throws BaseException;
 
-  void insertTimeseries(Connection connection, String deviceName, Timeseries timeseries)
+  UserRolesVO getRolesOfUser(Connection connection, String userName) throws BaseException;
+
+  void userGrant(Connection connection, String userName, UserGrantDTO userGrantDTO)
       throws BaseException;
 
-  void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException;
+  void roleGrant(Connection connection, String roleName, RoleGrantDTO roleGrantDTO)
+      throws BaseException;
+
+  Set<String> getUserAuthorityPrivilege(Connection connection, String userName)
+      throws BaseException;
+
+  Set<String> getAllAuthorityPrivilege(Connection connection, String userName) throws BaseException;
+
+  Set<String> getRoleAuthorityPrivilege(Connection connection, String roleName)
+      throws BaseException;
 
-  SqlResultVO showTimeseries(Connection connection, String deviceName) throws BaseException;
+  void upsertAuthorityPrivilege(
+      Connection connection,
+      String userName,
+      AuthorityPrivilegeDTO authorityPrivilegeDTO,
+      String userOrRole)
+      throws BaseException;
+
+  List<DataPrivilegeVO> getUserDataPrivilege(Connection connection, String userName)
+      throws BaseException;
+
+  List<DataPrivilegeVO> getRoleDataPrivilege(Connection connection, String roleName)
+      throws BaseException;
+
+  void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException;
 
   List<Integer> getDevicesCount(Connection connection, List<String> groupNames)
       throws BaseException;
@@ -72,17 +100,16 @@ public interface IotDBService {
 
   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)
+  List<String> deleteTimeseriesByDevice(Connection connection, String deviceName)
       throws BaseException;
 
-  Integer getMeasurementsCount(Connection connection, String deviceName) throws BaseException;
+  void upsertMeasurements(Connection connection, DeviceInfoDTO deviceInfoDTO) throws BaseException;
+
+  Integer getOneDataCount(Connection connection, String deviceName, String measurementName)
+      throws BaseException;
 
   String getLastMeasurementValue(Connection connection, String timeseries) throws BaseException;
 
@@ -90,12 +117,43 @@ public interface IotDBService {
 
   List<String> getDevices(Connection connection, String groupName) throws BaseException;
 
+  List<NodeTreeVO> getDeviceNodeTree(Connection connection, String groupName) throws BaseException;
+
+  NodeTreeVO getDeviceList(Connection connection, String groupName) throws BaseException;
+
+  List<String> getDeviceParents(Connection connection, String groupName, String deviceName)
+      throws BaseException;
+
+  Boolean deviceExist(Connection connection, String groupName, String deviceName)
+      throws BaseException;
+
   List<String> getTimeseries(Connection connection, String deviceName) throws BaseException;
 
-  void setUserPrivileges(Connection connection, String userName, PrivilegeInfoDTO privilegeInfoDTO)
+  DataVO getDataByDevice(
+      Connection connection,
+      String deviceName,
+      Integer pageSize,
+      Integer pageNum,
+      DataQueryDTO dataQueryDTO)
+      throws BaseException;
+
+  void updateDataByDevice(Connection connection, String deviceName, DataUpdateDTO dataUpdateDTO)
+      throws BaseException;
+
+  void deleteDataByDevice(Connection connection, String deviceName, DataDeleteDTO dataDeleteDTO)
+      throws BaseException;
+
+  void randomImport(Connection connection, String deviceName, RandomImportDTO randomImportDTO)
+      throws BaseException;
+
+  String getSqlForExport(String deviceName, DataQueryDTO dataQueryDTO) throws BaseException;
+
+  void upsertDataPrivileges(
+      Connection connection, String userOrRole, String name, PrivilegeInfoDTO privilegeInfoDTO)
       throws BaseException;
 
-  RecordVO getRecords(Connection connection, String deviceName, String timeseriesName)
+  RecordVO getRecords(
+      Connection connection, String deviceName, String timeseriesName, String dataType)
       throws BaseException;
 
   List<SqlResultVO> queryAll(Connection connection, List<String> sqls, Long timestamp)
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
index 1c0e699..c9c7845 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/MeasurementService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/MeasurementService.java
@@ -23,7 +23,6 @@ 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;
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
index eeb8138..67efaf4 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/QueryService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/QueryService.java
@@ -26,8 +26,7 @@ import org.apache.iotdb.admin.model.vo.QueryVO;
 import java.util.List;
 
 public interface QueryService {
-
-  void save(Integer serverId, Query query) throws BaseException;
+  Integer save(Integer serverId, Query query) throws BaseException;
 
   void update(Integer serverId, Query query) 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/RoleService.java
similarity index 69%
copy from backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
copy to backend/src/main/java/org/apache/iotdb/admin/service/RoleService.java
index fb9c1e2..002d61e 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/RoleService.java
@@ -20,13 +20,13 @@
 package org.apache.iotdb.admin.service;
 
 import org.apache.iotdb.admin.common.exception.BaseException;
-import org.apache.iotdb.admin.model.entity.User;
+import org.apache.iotdb.admin.model.dto.IotDBRole;
+import org.apache.iotdb.admin.model.entity.Role;
 
-public interface UserService {
+public interface RoleService {
+  void upsertRoleInfo(String host, Integer port, IotDBRole iotDBRole) throws BaseException;
 
-  User login(String name, String password) throws BaseException;
+  void deleteRoleInfo(String host, Integer port, String roleName) throws BaseException;
 
-  void insert(User user) throws BaseException;
-
-  void delete(Integer userId) throws BaseException;
+  Role getRoleInfo(String host, Integer port, String roleName) 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
index fb9c1e2..449373f 100644
--- a/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/UserService.java
@@ -23,7 +23,6 @@ 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;
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
index 670f0cb..11f036b 100644
--- 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
@@ -47,7 +47,14 @@ public class ConnectionServiceImpl extends ServiceImpl<ConnectionMapper, Connect
     List<Connection> connections = connectionMapper.selectList(queryWrapper);
     List<ConnVO> ConnVOs = new ArrayList();
     for (Connection connection : connections) {
-      ConnVOs.add(new ConnVO(connection.getId(), connection.getAlias()));
+      ConnVOs.add(
+          new ConnVO(
+              connection.getId(),
+              connection.getAlias(),
+              connection.getHost(),
+              connection.getPort(),
+              connection.getUsername(),
+              connection.getPassword()));
     }
     return ConnVOs;
   }
@@ -60,13 +67,10 @@ public class ConnectionServiceImpl extends ServiceImpl<ConnectionMapper, Connect
     queryWrapper.eq("user_id", userId);
     queryWrapper.eq("alias", alias);
     Connection existConnection = connectionMapper.selectOne(queryWrapper);
-    // 别名唯一
+    // Alias are unique
     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);
@@ -116,7 +120,7 @@ public class ConnectionServiceImpl extends ServiceImpl<ConnectionMapper, Connect
     queryWrapper.eq("user_id", userId);
     queryWrapper.eq("alias", alias);
     Connection existConnection = connectionMapper.selectOne(queryWrapper);
-    // 别名唯一
+    // Alias are unique
     if (existConnection != null && !connection.getId().equals(existConnection.getId())) {
       throw new BaseException(ErrorCode.ALIAS_REPEAT, ErrorCode.ALIAS_REPEAT_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
index 0687f5c..7ff9ad3 100644
--- 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
@@ -115,7 +115,7 @@ public class DeviceServiceImpl extends ServiceImpl<DeviceMapper, Device> impleme
     queryWrapper.eq("host", host);
     queryWrapper.eq("device_name", deviceName);
     Device device = deviceMapper.selectOne(queryWrapper);
-    // 非系统创建的设备没有设备信息
+    // Non-system created devices do not have device information
     DeviceVO deviceVO = new DeviceVO();
     if (device != null) {
       deviceVO.setCreator(device.getCreator());
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/FileServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/FileServiceImpl.java
new file mode 100644
index 0000000..0942f55
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/FileServiceImpl.java
@@ -0,0 +1,77 @@
+/*
+ * 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.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.config.FileProperties;
+import org.apache.iotdb.admin.service.FileService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.core.io.Resource;
+import org.springframework.core.io.UrlResource;
+import org.springframework.stereotype.Service;
+import org.springframework.web.multipart.MultipartFile;
+
+import java.io.IOException;
+import java.net.MalformedURLException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.nio.file.StandardCopyOption;
+
+@Service
+public class FileServiceImpl implements FileService {
+
+  private final Path fileStorageLocation;
+
+  @Autowired
+  public FileServiceImpl(FileProperties fileProperties) {
+    this.fileStorageLocation = Paths.get(fileProperties.getTempDir()).toAbsolutePath().normalize();
+  }
+
+  @Override
+  public String storeFile(MultipartFile file, String fileName) throws BaseException {
+    try {
+      Path targetLocation = this.fileStorageLocation.resolve(fileName);
+      Files.copy(file.getInputStream(), targetLocation, StandardCopyOption.REPLACE_EXISTING);
+      String fileFullName = targetLocation.toString();
+      return fileFullName;
+    } catch (IOException ex) {
+      throw new BaseException(ErrorCode.UPLOAD_FILE_FAIL, ErrorCode.UPLOAD_FILE_FAIL_MSG);
+    }
+  }
+
+  @Override
+  public Resource loadFileAsResource(String fileName) throws BaseException {
+    Path filePath;
+    try {
+      filePath = this.fileStorageLocation.resolve(fileName).normalize();
+      Resource resource = new UrlResource(filePath.toUri());
+      if (resource.exists()) {
+        return resource;
+      } else {
+        throw new BaseException(ErrorCode.FILE_NOT_FOUND, ErrorCode.FILE_NOT_FOUND_MSG);
+      }
+    } catch (MalformedURLException ex) {
+      throw new BaseException(ErrorCode.FILE_NOT_FOUND, ErrorCode.FILE_NOT_FOUND_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
index 5ae53be..3a81a14 100644
--- 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
@@ -57,9 +57,6 @@ public class GroupServiceImpl extends ServiceImpl<GroupMapper, StorageGroup>
     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);
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
index 1c56635..803c4f5 100644
--- 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
@@ -34,78 +34,328 @@ 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.apache.commons.lang3.RandomStringUtils;
 import org.apache.commons.lang3.StringUtils;
 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.*;
 import java.util.Date;
 import java.util.concurrent.*;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
 
 @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 Set<String> AUTHORITY_PRIVILEGES = new HashSet<>();
 
-  private static final String NO_NEED_PRIVILEGES = "SET_STORAGE_GROUP";
-
-  private static final List<String> PRIVILEGES = new ArrayList<>();
+  private static final Set<String> DATA_PRIVILEGES = new HashSet<>();
 
   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);
+    AUTHORITY_PRIVILEGES.add("CREATE_USER");
+    AUTHORITY_PRIVILEGES.add("DELETE_USER");
+    AUTHORITY_PRIVILEGES.add("MODIFY_PASSWORD");
+    AUTHORITY_PRIVILEGES.add("LIST_USER");
+    AUTHORITY_PRIVILEGES.add("GRANT_USER_PRIVILEGE");
+    AUTHORITY_PRIVILEGES.add("REVOKE_USER_PRIVILEGE");
+    AUTHORITY_PRIVILEGES.add("GRANT_USER_ROLE");
+    AUTHORITY_PRIVILEGES.add("REVOKE_USER_ROLE");
+    AUTHORITY_PRIVILEGES.add("CREATE_ROLE");
+    AUTHORITY_PRIVILEGES.add("DELETE_ROLE");
+    AUTHORITY_PRIVILEGES.add("LIST_ROLE");
+    AUTHORITY_PRIVILEGES.add("GRANT_ROLE_PRIVILEGE");
+    AUTHORITY_PRIVILEGES.add("REVOKE_ROLE_PRIVILEGE");
+    AUTHORITY_PRIVILEGES.add("CREATE_FUNCTION");
+    AUTHORITY_PRIVILEGES.add("DROP_FUNCTION");
+    AUTHORITY_PRIVILEGES.add("CREATE_TRIGGER");
+    AUTHORITY_PRIVILEGES.add("DROP_TRIGGER");
+    AUTHORITY_PRIVILEGES.add("START_TRIGGER");
+    AUTHORITY_PRIVILEGES.add("STOP_TRIGGER");
   }
 
   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");
+    DATA_PRIVILEGES.add("SET_STORAGE_GROUP");
+    DATA_PRIVILEGES.add("CREATE_TIMESERIES");
+    DATA_PRIVILEGES.add("INSERT_TIMESERIES");
+    DATA_PRIVILEGES.add("READ_TIMESERIES");
+    DATA_PRIVILEGES.add("DELETE_TIMESERIES");
+  }
+
+  @Override
+  public DataCountVO getDataCount(Connection connection) throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String groupCountStr = executeQueryOneValue(sessionPool, "count storage group");
+      int groupCount = Integer.parseInt(groupCountStr);
+      String deviceCountStr = executeQueryOneValue(sessionPool, "count devices");
+      int deviceCount = Integer.parseInt(deviceCountStr);
+      String measurementCountStr = executeQueryOneValue(sessionPool, "count timeseries");
+      int measurementCount = Integer.parseInt(measurementCountStr);
+      List<String> dataCountList = executeQueryOneLine(sessionPool, "select count(*) from root");
+      int dataCount = 0;
+      for (String dataCountStr : dataCountList) {
+        dataCount += Integer.parseInt(dataCountStr);
+      }
+      DataCountVO dataCountVO = new DataCountVO();
+      dataCountVO.setGroupCount(groupCount);
+      dataCountVO.setDeviceCount(deviceCount);
+      dataCountVO.setMeasurementCount(measurementCount);
+      dataCountVO.setDataCount(dataCount);
+      return dataCountVO;
+    } catch (NumberFormatException e) {
+      throw new BaseException(ErrorCode.GET_DATA_COUNT_FAIL, ErrorCode.GET_DATA_COUNT_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public DataModelVO getDataModel(Connection connection) throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      DataModelVO root = new DataModelVO("root");
+      assembleDataModel(root, "root", sessionPool);
+      root.setGroupCount(getGroupCount(sessionPool));
+      root.setPath("root");
+      return root;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private void assembleDataModel(DataModelVO node, String prefixPath, SessionPool sessionPool)
+      throws BaseException {
+    Set<String> childrenNode = getChildrenNode(prefixPath, sessionPool);
+    if (childrenNode == null) {
+      return;
+    }
+    for (String child : childrenNode) {
+      DataModelVO childNode = new DataModelVO(child);
+      assembleDataModel(childNode, prefixPath + "." + child, sessionPool);
+      setNodeInfo(childNode, sessionPool, prefixPath + "." + child);
+      node.initNodeChildren().add(childNode);
+    }
+  }
+
+  private Set<String> getChildrenNode(String prefixPath, SessionPool sessionPool)
+      throws BaseException {
+    String sql = "show storage group " + prefixPath;
+    List<String> children = executeQueryOneColumn(sessionPool, sql);
+    if (children.size() == 0 || (children.size() == 1 && children.get(0).equals(prefixPath))) {
+      sql = "show timeseries " + prefixPath;
+      children = executeQueryOneColumn(sessionPool, sql);
+      if (children.size() == 0 || (children.size() == 1 && children.get(0).equals(prefixPath))) {
+        return null;
+      }
+    }
+    Set<String> childrenNode = new HashSet<>();
+    for (String child : children) {
+      child = StringUtils.removeStart(child, prefixPath + ".").split("\\.")[0];
+      childrenNode.add(child);
+    }
+    return childrenNode;
+  }
+
+  private Integer getGroupCount(SessionPool sessionPool) throws BaseException {
+    String sql = "count storage group";
+    String value = executeQueryOneValue(sessionPool, sql);
+    Integer count = Integer.valueOf(value);
+    return count;
+  }
+
+  private Integer getDeviceCount(SessionPool sessionPool, String groupName) throws BaseException {
+    String sql = "count devices " + groupName;
+    String value = executeQueryOneValue(sessionPool, sql);
+    Integer count = Integer.valueOf(value);
+    return count;
+  }
+
+  private Integer getMeasurementsCount(SessionPool sessionPool, String deviceName)
+      throws BaseException {
+    String sql = "count timeseries " + deviceName;
+    String value = executeQueryOneValue(sessionPool, sql);
+    Integer count = Integer.valueOf(value);
+    return count;
+  }
+
+  private boolean isGroup(SessionPool sessionPool, String path) throws BaseException {
+    String sql = "show storage group " + path;
+    List<String> groups = executeQueryOneColumn(sessionPool, sql);
+    boolean isGroup = false;
+    for (String group : groups) {
+      if (group.equals(path)) {
+        isGroup = true;
+        break;
+      }
+    }
+    return isGroup;
+  }
+
+  private boolean isDevice(SessionPool sessionPool, String path) throws BaseException {
+    String sql = "show devices " + path;
+    List<String> devices = executeQueryOneColumn(sessionPool, sql);
+    boolean isDevice = false;
+    for (String device : devices) {
+      if (device.equals(path)) {
+        isDevice = true;
+        break;
+      }
+    }
+    return isDevice;
+  }
+
+  private boolean isMeasurement(SessionPool sessionPool, String path) throws BaseException {
+    String sql = "show timeseries " + path;
+    List<String> measurements = executeQueryOneColumn(sessionPool, sql);
+    boolean isMeasurement = false;
+    for (String measurement : measurements) {
+      if (measurement.equals(path)) {
+        isMeasurement = true;
+        break;
+      }
+    }
+    return isMeasurement;
+  }
+
+  private void setNodeInfo(DataModelVO dataModelVO, SessionPool sessionPool, String path)
+      throws BaseException {
+    dataModelVO.setPath(path);
+    if (isGroup(sessionPool, path)) {
+      dataModelVO.setDeviceCount(getDeviceCount(sessionPool, path));
+      dataModelVO.setIsGroup(true);
+    }
+    if (isDevice(sessionPool, path)) {
+      dataModelVO.setMeasurementCount(getMeasurementsCount(sessionPool, path));
+      dataModelVO.setIsDevice(true);
+      return;
+    }
+    if (isMeasurement(sessionPool, path)) {
+      DataInfo dataInfo = new DataInfo();
+      dataInfo.setNewValue(getLastValue(sessionPool, path));
+      dataInfo.setDataCount(getOneDataCount(sessionPool, path));
+      dataInfo.setDataType(getDataType(sessionPool, path));
+      dataModelVO.setDataInfo(dataInfo);
+      dataModelVO.setIsMeasurement(true);
+    }
+  }
+
+  private String getLastValue(SessionPool sessionPool, String timeseries) throws BaseException {
+    int index = timeseries.lastIndexOf(".");
+    String sql =
+        "select last_value("
+            + timeseries.substring(index + 1)
+            + ") from "
+            + timeseries.substring(0, index);
+    String value = executeQueryOneValue(sessionPool, sql);
+    return value;
+  }
+
+  private Integer getOneDataCount(SessionPool sessionPool, String timeseries) throws BaseException {
+    int index = timeseries.lastIndexOf(".");
+    String sql = "select count(*) from " + timeseries.substring(0, index);
+    String countStr = executeQueryOneLine(sessionPool, sql, "count(" + timeseries + ")");
+    return Integer.parseInt(countStr);
+  }
+
+  private String getDataType(SessionPool sessionPool, String timeseries) throws BaseException {
+    String sql = "show timeseries " + timeseries;
+    String dataType = executeQueryOneLine(sessionPool, sql, "dataType");
+    return dataType;
   }
 
   @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;
+    List<String> groups;
+    try {
+      String sql = "show storage group";
+      groups = executeQueryOneColumn(sessionPool, sql);
+      return groups;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<NodeTreeVO> getGroupsNodeTree(Connection connection) throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      return getGroupsNodeTree(sessionPool);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private List<NodeTreeVO> getGroupsNodeTree(SessionPool sessionPool) throws BaseException {
+    Set<String> firstLevelNodes = getChildrenNode("root", "storage group", sessionPool);
+    if (firstLevelNodes == null || firstLevelNodes.size() == 0) {
+      return null;
+    }
+    List<NodeTreeVO> groupNodeVOList = new ArrayList<>();
+    for (String firstLevelNodeName : firstLevelNodes) {
+      NodeTreeVO firstLevelNode = new NodeTreeVO(firstLevelNodeName);
+      groupNodeVOList.add(firstLevelNode);
+      assembleNodeTree(firstLevelNode, firstLevelNodeName, "storage group", sessionPool);
+    }
+    return groupNodeVOList;
+  }
+
+  private void assembleNodeTree(
+      NodeTreeVO node, String prefixPath, String type, SessionPool sessionPool)
+      throws BaseException {
+    Set<String> childrenNode = getChildrenNode(prefixPath, type, sessionPool);
+    if (childrenNode == null) {
+      return;
+    }
+    for (String child : childrenNode) {
+      NodeTreeVO childNode = new NodeTreeVO(child);
+      assembleNodeTree(childNode, child, type, sessionPool);
+      node.initChildren().add(childNode);
+    }
+  }
+
+  private Set<String> getChildrenNode(String prefixPath, String type, SessionPool sessionPool)
+      throws BaseException {
+    String sql = "show " + type + " " + prefixPath;
+    List<String> children = executeQueryOneColumn(sessionPool, sql);
+    if (children.size() == 0 || (children.size() == 1 && children.get(0).equals(prefixPath))) {
+      return null;
+    }
+    Set<String> childrenNode = new HashSet<>();
+    for (String child : children) {
+      if (child.equals(prefixPath)) {
+        continue;
+      }
+      child = prefixPath + "." + StringUtils.removeStart(child, prefixPath + ".").split("\\.")[0];
+      childrenNode.add(child);
+    }
+    return childrenNode;
   }
 
   @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);
       }
+      // 300 indicates that the storage group is repeated or there is already a storage group on its
+      // front or back path
       if (e.getStatusCode() == 300) {
         throw new BaseException(ErrorCode.SET_GROUP_FAIL, ErrorCode.SET_GROUP_FAIL_MSG);
       }
@@ -114,15 +364,12 @@ public class IotDBServiceImpl implements IotDBService {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.SET_GROUP_FAIL, ErrorCode.SET_GROUP_FAIL_MSG);
     } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
-      }
+      closeSessionPool(sessionPool);
     }
   }
 
   @Override
   public void deleteStorageGroup(Connection connection, String groupName) throws BaseException {
-    paramValid(groupName);
     SessionPool sessionPool = getSessionPool(connection);
     try {
       sessionPool.deleteStorageGroup(groupName);
@@ -136,9 +383,7 @@ public class IotDBServiceImpl implements IotDBService {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.DELETE_GROUP_FAIL, ErrorCode.DELETE_GROUP_FAIL_MSG);
     } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
-      }
+      closeSessionPool(sessionPool);
     }
   }
 
@@ -146,7 +391,6 @@ public class IotDBServiceImpl implements IotDBService {
   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;
@@ -161,7 +405,6 @@ public class IotDBServiceImpl implements IotDBService {
           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 {
@@ -193,12 +436,8 @@ public class IotDBServiceImpl implements IotDBService {
       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();
-      }
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
     }
   }
 
@@ -206,7 +445,6 @@ public class IotDBServiceImpl implements IotDBService {
   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;
@@ -219,9 +457,11 @@ public class IotDBServiceImpl implements IotDBService {
         while (sessionDataSetWrapper.hasNext()) {
           RowRecord rowRecord = sessionDataSetWrapper.next();
           List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+          String measurementName = fields.get(0).toString();
+          if (StringUtils.removeStart(measurementName, deviceName + ".").contains(".")) {
+            continue;
+          }
           if (keyword != null || "".equals(keyword)) {
-            String measurementName = fields.get(0).toString();
-            measurementName = StringUtils.removeStart(measurementName, deviceName + ".");
             if (measurementName.contains(keyword)) {
               count++;
             } else {
@@ -270,125 +510,94 @@ public class IotDBServiceImpl implements IotDBService {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
     } finally {
-      if (sessionDataSetWrapper != null) {
-        sessionDataSetWrapper.close();
-      }
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
     }
   }
 
   @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;
+    List<String> users;
+    try {
+      String sql = "list user";
+      users = executeQueryOneColumn(sessionPool, sql);
+      return users;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
   }
 
   @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;
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "list role";
+      List<String> roles = executeQueryOneColumn(sessionPool, sql);
+      sessionPool.close();
+      return roles;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
   }
 
   @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);
+  public RoleVO getIotDBRoleInfo(Connection connection, String roleName) throws BaseException {
+    SessionPool sessionPool = null;
+    RoleVO roleVO = new RoleVO();
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "LIST ALL USER OF ROLE " + roleName;
+      List<String> users = executeQueryOneColumn(sessionPool, sql);
+      roleVO.setUserList(users);
+      return roleVO;
+    } catch (BaseException e) {
+      throw new BaseException(ErrorCode.ROLE_GET_USERS_FAIL, ErrorCode.ROLE_GET_USERS_FAIL_MSG);
     } finally {
-      if (sessionpool != null) {
-        sessionpool.close();
-      }
+      closeSessionPool(sessionPool);
     }
-    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);
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_DELETE_USER, ErrorCode.NO_PRI_DELETE_USER_MSG);
+      } else {
+        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();
-      }
+      closeSessionPool(sessionPool);
     }
   }
 
   @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);
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_DELETE_ROLE, ErrorCode.NO_PRI_DELETE_ROLE_MSG);
+      } else {
+        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();
-      }
+      closeSessionPool(sessionPool);
     }
   }
 
@@ -402,29 +611,19 @@ public class IotDBServiceImpl implements IotDBService {
       sessionPool.executeNonQueryStatement(sql);
     } catch (StatementExecutionException e) {
       logger.error(e.getMessage());
-      throw new BaseException(ErrorCode.SET_DB_USER_FAIL, ErrorCode.SET_DB_USER_FAIL_MSG);
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_CREATE_USER, ErrorCode.NO_PRI_CREATE_USER_MSG);
+      } else if (e.getMessage().contains("already exists")) {
+        throw new BaseException(ErrorCode.USER_NAME_EXISTS, ErrorCode.USER_NAME_EXISTS_MSG);
+      } else {
+        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();
-      }
+      closeSessionPool(sessionPool);
     }
-    //        // 用户角色
-    //        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
@@ -434,176 +633,673 @@ public class IotDBServiceImpl implements IotDBService {
     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);
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_CREATE_ROLE, ErrorCode.NO_PRI_CREATE_ROLE_MSG);
+      } else if (e.getMessage().contains("already exists")) {
+        throw new BaseException(ErrorCode.ROLE_NAME_EXISTS, ErrorCode.ROLE_NAME_EXISTS_MSG);
+      } else {
+        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);
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
-      }
+      closeSessionPool(sessionPool);
     }
   }
 
-  //    @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 {
+  public UserRolesVO getRolesOfUser(Connection connection, String userName) throws BaseException {
     SessionPool sessionPool = getSessionPool(connection);
+    UserRolesVO userRolesVO = new UserRolesVO();
+    if (userName.equals(connection.getUsername())) {
+      userRolesVO.setPassword(connection.getPassword());
+    } else {
+      userRolesVO.setPassword(null);
+    }
+    String sql = "list all role of user " + userName;
     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();
+      List<String> roleList = executeQueryOneColumn(sessionPool, sql);
+      userRolesVO.setRoleList(roleList);
+      return userRolesVO;
+    } catch (BaseException e) {
+      if (e.getErrorCode().equals(ErrorCode.NO_PRI_DO_THIS)) {
+        throw new BaseException(ErrorCode.NO_PRI_LIST_ROLE, ErrorCode.NO_PRI_LIST_ROLE_MSG);
+      } else {
+        throw e;
       }
+    } finally {
+      closeSessionPool(sessionPool);
     }
   }
 
   @Override
-  public void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException {
+  public void userGrant(Connection connection, String userName, UserGrantDTO userGrantDTO)
+      throws BaseException {
     SessionPool sessionPool = getSessionPool(connection);
+    List<String> roleList = userGrantDTO.getRoleList();
+    List<String> cancelRoleList = userGrantDTO.getCancelRoleList();
     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);
+      if (cancelRoleList != null && cancelRoleList.size() != 0) {
+        for (String cancelRole : cancelRoleList) {
+          revokeRole(sessionPool, userName, cancelRole);
+        }
       }
-      throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
-    } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
+      if (roleList != null && roleList.size() != 0) {
+        for (String garntRole : roleList) {
+          grantRole(sessionPool, userName, garntRole);
+        }
       }
+    } finally {
+      closeSessionPool(sessionPool);
     }
   }
 
   @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)
+  public void roleGrant(Connection connection, String roleName, RoleGrantDTO roleGrantDTO)
       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;
+    List<String> userList = roleGrantDTO.getUserList();
+    List<String> cancelUserList = roleGrantDTO.getCancelUserList();
+    try {
+      if (cancelUserList != null && cancelUserList.size() != 0) {
+        for (String cancelUser : cancelUserList) {
+          revokeRole(sessionPool, cancelUser, roleName);
+        }
+      }
+      if (userList != null && userList.size() != 0) {
+        for (String garntUser : userList) {
+          grantRole(sessionPool, garntUser, roleName);
+        }
       }
-      Integer count = Integer.valueOf(value);
-      devicesCount.add(count);
+    } finally {
+      closeSessionPool(sessionPool);
     }
-    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;
+  private void revokeRole(SessionPool sessionPool, String userName, String roleName)
+      throws BaseException {
+    String sql = "revoke " + roleName + " from " + userName;
     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.NO_PRI_REVOKE_USER_ROLE, ErrorCode.NO_PRI_REVOKE_USER_ROLE_MSG);
+      } else {
+        throw new BaseException(ErrorCode.REVOKE_ROLE, ErrorCode.REVOKE_ROLE_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();
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     }
   }
 
-  @Override
-  public void cancelGroupTtl(Connection connection, String groupName) throws BaseException {
-    SessionPool sessionPool = getSessionPool(connection);
-    String sql = "unset ttl to " + groupName;
+  private void grantRole(SessionPool sessionPool, String userName, String roleName)
+      throws BaseException {
+    String sql = "grant " + roleName + " to " + userName;
     try {
       sessionPool.executeNonQueryStatement(sql);
     } catch (StatementExecutionException e) {
       logger.error(e.getMessage());
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(
+            ErrorCode.NO_PRI_GRANT_USER_ROLE, ErrorCode.NO_PRI_GRANT_USER_ROLE_MSG);
+      } else {
+        throw new BaseException(ErrorCode.GRANT_ROLE, ErrorCode.GRANT_ROLE_MSG);
+      }
     } 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;
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     }
-    Integer count = Integer.valueOf(value);
-    return count;
   }
 
   @Override
-  public List<Integer> getTimeseriesCount(Connection connection, List<String> deviceNames)
+  public Set<String> getUserAuthorityPrivilege(Connection connection, String userName)
       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 sessionPool = null;
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      if ("root".equals(userName)) {
+        return AUTHORITY_PRIVILEGES;
+      }
+      Set<String> privileges = new HashSet<>();
+      List<String> rowInfos = new ArrayList<>();
+      sessionPool = getSessionPool(connection);
+      String sql = "list user privileges " + userName;
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      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 (!"".equals(field.toString())) {
+              break;
+            }
+          } else {
+            rowInfos.add(field.toString());
+          }
+        }
+      }
+      privileges = switchRowInfosToAuthorityPrivileges(rowInfos);
+      return privileges;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(
+          ErrorCode.GET_USER_PRIVILEGE_FAIL, ErrorCode.GET_USER_PRIVILEGE_FAIL_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
     }
-    sessionPool.close();
-    return lines;
   }
 
   @Override
-  public void deleteTimeseriesByDevice(Connection connection, String deviceName)
+  public Set<String> getAllAuthorityPrivilege(Connection connection, String userName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      if ("root".equals(userName)) {
+        return AUTHORITY_PRIVILEGES;
+      }
+      Set<String> privileges = new HashSet<>();
+      List<String> rowInfos = new ArrayList<>();
+      sessionPool = getSessionPool(connection);
+      String sql = "list user privileges " + userName;
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      while (sessionDataSetWrapper.hasNext()) {
+        RowRecord next = sessionDataSetWrapper.next();
+        List<org.apache.iotdb.tsfile.read.common.Field> fields = next.getFields();
+        rowInfos.add(fields.get(1).toString());
+      }
+      privileges = switchRowInfosToAuthorityPrivileges(rowInfos);
+      return privileges;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(
+          ErrorCode.GET_USER_PRIVILEGE_FAIL, ErrorCode.GET_USER_PRIVILEGE_FAIL_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public Set<String> getRoleAuthorityPrivilege(Connection connection, String roleName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      Set<String> privileges = new HashSet<>();
+      sessionPool = getSessionPool(connection);
+      String sql = "list role privileges " + roleName;
+      List<String> rowInfos = executeQueryOneColumn(sessionPool, sql);
+      privileges = switchRowInfosToAuthorityPrivileges(rowInfos);
+      return privileges;
+    } catch (BaseException e) {
+      if (e.getErrorCode().equals(ErrorCode.NO_PRI_DO_THIS)) {
+        throw new BaseException(ErrorCode.NO_PRI_LIST_ROLE, ErrorCode.NO_PRI_LIST_ROLE_MSG);
+      } else {
+        throw new BaseException(
+            ErrorCode.GET_ROLE_PRIVILEGE_FAIL, ErrorCode.GET_ROLE_PRIVILEGE_FAIL_MSG);
+      }
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private Set<String> switchRowInfosToAuthorityPrivileges(List<String> rowInfos) {
+    Set<String> authorityPrivileges = new HashSet<>();
+    for (String rowInfo : rowInfos) {
+      String[] split = rowInfo.split("\\s:\\s");
+      String[] privileges = split[1].split("\\s");
+      for (String privilege : privileges) {
+        if (AUTHORITY_PRIVILEGES.contains(privilege)) {
+          authorityPrivileges.add(privilege);
+        }
+      }
+    }
+    return authorityPrivileges;
+  }
+
+  @Override
+  public void upsertAuthorityPrivilege(
+      Connection connection,
+      String userName,
+      AuthorityPrivilegeDTO authorityPrivilegeDTO,
+      String userOrRole)
       throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      List<String> cancelPrivileges = authorityPrivilegeDTO.getCancelPrivileges();
+      if (cancelPrivileges != null) {
+        checkAuthorityPrivilege(cancelPrivileges);
+        for (String cancelPrivilege : cancelPrivileges) {
+          upsertAuthorityPrivilege(sessionPool, "revoke", userOrRole, userName, cancelPrivilege);
+        }
+      }
+      List<String> privileges = authorityPrivilegeDTO.getPrivileges();
+      if (privileges != null) {
+        checkAuthorityPrivilege(privileges);
+        for (String privilege : privileges) {
+          upsertAuthorityPrivilege(sessionPool, "grant", userOrRole, userName, privilege);
+        }
+      }
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private void upsertAuthorityPrivilege(
+      SessionPool sessionPool,
+      String operationType,
+      String userOrRole,
+      String name,
+      String privilegesStr)
+      throws BaseException {
+    String sql =
+        operationType
+            + " "
+            + userOrRole
+            + " "
+            + name
+            + " privileges '"
+            + privilegesStr
+            + "' on root";
+    try {
+      sessionPool.executeNonQueryStatement(sql);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(
+            ErrorCode.NO_PRI_GRANT_PRIVILEGE, ErrorCode.NO_PRI_GRANT_PRIVILEGE_MSG);
+      }
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    }
+  }
+
+  private void checkAuthorityPrivilege(List<String> privileges) throws BaseException {
+    for (String privilege : privileges) {
+      if (!AUTHORITY_PRIVILEGES.contains(privilege)) {
+        throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+      }
+    }
+  }
+
+  @Override
+  public List<DataPrivilegeVO> getUserDataPrivilege(Connection connection, String userName)
+      throws BaseException {
+    if ("root".equalsIgnoreCase(userName)) {
+      DataPrivilegeVO dataPrivilegeVO = new DataPrivilegeVO();
+      dataPrivilegeVO.setType(0);
+      dataPrivilegeVO.setPrivileges(new ArrayList<>(DATA_PRIVILEGES));
+      return Arrays.asList(dataPrivilegeVO);
+    }
+    SessionPool sessionPool = null;
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      List<String> rowInfos = new ArrayList<>();
+      sessionPool = getSessionPool(connection);
+      String sql = "list user privileges " + userName;
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      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 (!"".equals(field.toString())) {
+              break;
+            }
+          } else {
+            rowInfos.add(field.toString());
+          }
+        }
+      }
+      // rowInfos form: "path : privilege1 privilege2 privilege3"
+      List<DataPrivilegeVO> dataPrivilegeList =
+          switchRowInfosToDataPrivileges(rowInfos, sessionPool);
+      return dataPrivilegeList;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(
+          ErrorCode.GET_USER_PRIVILEGE_FAIL, ErrorCode.GET_USER_PRIVILEGE_FAIL_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<DataPrivilegeVO> getRoleDataPrivilege(Connection connection, String roleName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "list role privileges " + roleName;
+      List<String> rowInfos = executeQueryOneColumn(sessionPool, sql);
+
+      // rowInfos form: "path : privilege1 privilege2 privilege3"
+      List<DataPrivilegeVO> dataPrivilegeList =
+          switchRowInfosToDataPrivileges(rowInfos, sessionPool);
+      return dataPrivilegeList;
+    } catch (BaseException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(
+          ErrorCode.GET_ROLE_PRIVILEGE_FAIL, ErrorCode.GET_ROLE_PRIVILEGE_FAIL_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private List<DataPrivilegeVO> switchRowInfosToDataPrivileges(
+      List<String> rowInfos, SessionPool sessionPool) throws BaseException {
+    if (rowInfos == null || rowInfos.size() == 0) {
+      return null;
+    }
+    List<String> paths = new ArrayList<>();
+    List<List<String>> privilegesList = new ArrayList<>();
+    List<DataPrivilegeVO> dataPrivilegeList = new ArrayList<>();
+    for (String rowInfo : rowInfos) {
+      String[] split = rowInfo.split("\\s:\\s");
+      String[] allPrivileges = split[1].split("\\s");
+      String path = split[0];
+      if ("root".equals(path)) {
+        handleRootPrivileges(allPrivileges, dataPrivilegeList);
+        continue;
+      }
+
+      List<String> privileges = new ArrayList<>();
+      for (String privilege : allPrivileges) {
+        if (DATA_PRIVILEGES.contains(privilege)) {
+          privileges.add(privilege);
+        }
+      }
+      privilegesList.add(privileges);
+      paths.add(path);
+    }
+
+    // Map form: {"privilege1 privilege2 privilege3..." : ["path1","path2"]} path1,path2 have the
+    // same privileges.
+    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 < paths.size(); i++) {
+      String path = paths.get(i);
+      String privilegesStr = String.join(" ", privilegesList.get(i));
+      int type = findType(sessionPool, path);
+      if (type == 1) {
+        if (privilegeOne.containsKey(privilegesStr)) {
+          List<String> pathList = privilegeOne.get(privilegesStr);
+          pathList.add(path);
+          continue;
+        }
+        ArrayList<String> newPaths = new ArrayList();
+        newPaths.add(path);
+        privilegeOne.put(privilegesStr, newPaths);
+        continue;
+      }
+      if (type == 2) {
+        if (privilegeTwo.containsKey(privilegesStr)) {
+          List<String> pathList = privilegeTwo.get(privilegesStr);
+          pathList.add(path);
+          continue;
+        }
+        ArrayList<String> newStr = new ArrayList();
+        newStr.add(path);
+        privilegeTwo.put(privilegesStr, newStr);
+        continue;
+      }
+      if (type == 3) {
+        if (privilegeThree.containsKey(privilegesStr)) {
+          List<String> pathList = privilegeThree.get(privilegesStr);
+          pathList.add(path);
+          continue;
+        }
+        ArrayList<String> newStr = new ArrayList();
+        newStr.add(path);
+        privilegeThree.put(privilegesStr, newStr);
+      }
+    }
+
+    Set<String> oneKeys = privilegeOne.keySet();
+    Set<String> twoKeys = privilegeTwo.keySet();
+    Set<String> threeKeys = privilegeThree.keySet();
+    List<String> allGroupPaths = executeQueryOneColumn(sessionPool, "show storage group");
+    List<String> allDevicePaths = executeQueryOneColumn(sessionPool, "show devices");
+
+    for (String oneKey : oneKeys) {
+      DataPrivilegeVO dataPrivilegeVO = new DataPrivilegeVO();
+      List<String> groupPaths = privilegeOne.get(oneKey);
+      List<String> privilegesOne = Arrays.asList(oneKey.split(" "));
+
+      dataPrivilegeVO.setType(1);
+      dataPrivilegeVO.setPrivileges(privilegesOne);
+      dataPrivilegeVO.setGroupPaths(groupPaths);
+      dataPrivilegeVO.setAllGroupPaths(getGroupsNodeTree(sessionPool));
+      dataPrivilegeList.add(dataPrivilegeVO);
+    }
+    for (String twoKey : twoKeys) {
+      List<String> privilegesTwo = Arrays.asList(twoKey.split(" "));
+      List<String> pathsTwo = privilegeTwo.get(twoKey);
+
+      Map<String, List<String>> groupPathsToDevicePaths = new HashMap<>();
+      for (String path : pathsTwo) {
+        String groupPath = getSupPath(path, allGroupPaths);
+        if (!groupPathsToDevicePaths.containsKey(groupPath)) {
+          groupPathsToDevicePaths.put(groupPath, Stream.of(path).collect(Collectors.toList()));
+        } else {
+          groupPathsToDevicePaths.get(groupPath).add(path);
+        }
+      }
+      for (Map.Entry<String, List<String>> entry : groupPathsToDevicePaths.entrySet()) {
+        DataPrivilegeVO dataPrivilegeVO = new DataPrivilegeVO();
+        String groupName = entry.getKey();
+        dataPrivilegeVO.setType(2);
+        dataPrivilegeVO.setPrivileges(privilegesTwo);
+        dataPrivilegeVO.setGroupPaths(Arrays.asList(groupName));
+        dataPrivilegeVO.setDevicePaths(entry.getValue());
+        dataPrivilegeVO.setAllDevicePaths(getDeviceNodeTree(sessionPool, groupName));
+        dataPrivilegeVO.setAllGroupPaths(switchListToNodeList(allGroupPaths));
+        dataPrivilegeList.add(dataPrivilegeVO);
+      }
+    }
+    for (String threeKey : threeKeys) {
+      List<String> privilegesThree = Arrays.asList(threeKey.split(" "));
+      List<String> pathsThree = privilegeThree.get(threeKey);
+
+      Map<String, List<String>> devicePathsTotimeseriesPaths = new HashMap<>();
+      for (String path : pathsThree) {
+        String devicePath = getSupPath(path, allDevicePaths);
+        if (!devicePathsTotimeseriesPaths.containsKey(devicePath)) {
+          devicePathsTotimeseriesPaths.put(
+              devicePath, Stream.of(path).collect(Collectors.toList()));
+        } else {
+          devicePathsTotimeseriesPaths.get(devicePath).add(path);
+        }
+      }
+      for (Map.Entry<String, List<String>> entry : devicePathsTotimeseriesPaths.entrySet()) {
+        DataPrivilegeVO dataPrivilegeVO = new DataPrivilegeVO();
+        dataPrivilegeVO.setType(3);
+        dataPrivilegeVO.setPrivileges(privilegesThree);
+        String device = entry.getKey();
+        String group = getSupPath(device, allGroupPaths);
+        dataPrivilegeVO.setGroupPaths(Arrays.asList(group));
+        dataPrivilegeVO.setDevicePaths(Arrays.asList(device));
+        dataPrivilegeVO.setTimeseriesPaths(entry.getValue());
+        dataPrivilegeVO.setAllGroupPaths(switchListToNodeList(allGroupPaths));
+        String sql = "show devices " + group;
+        List<String> devicePathsOfGroup = executeQueryOneColumn(sessionPool, sql);
+        dataPrivilegeVO.setAllDevicePaths(switchListToNodeList(devicePathsOfGroup));
+        sql = "show timeseries " + device;
+        dataPrivilegeVO.setAllTimeseriesPaths(executeQueryOneColumn(sessionPool, sql));
+        dataPrivilegeList.add(dataPrivilegeVO);
+      }
+    }
+    return dataPrivilegeList;
+  }
+
+  private String getSupPath(String path, List<String> allSupPath) throws BaseException {
+    for (String supPath : allSupPath) {
+      String checkPath = StringUtils.removeStart(path, supPath);
+      if (path.contains(supPath) && checkPath.startsWith(".") || checkPath.equals("")) {
+        return supPath;
+      }
+    }
+    throw new BaseException(
+        ErrorCode.GET_DATA_PRIVILEGE_FAIL, ErrorCode.GET_DATA_PRIVILEGE_FAIL_MSG);
+  }
+
+  private List<NodeTreeVO> switchListToNodeList(List<String> list) {
+    List<NodeTreeVO> nodeList = new ArrayList<>();
+    for (String s : list) {
+      nodeList.add(new NodeTreeVO(s));
+    }
+    return nodeList;
+  }
+
+  private void handleRootPrivileges(
+      String[] allPrivileges, List<DataPrivilegeVO> dataPrivilegeList) {
+    Set<String> rootPrivilegesSet = new HashSet<>();
+    for (String privilege : allPrivileges) {
+      if (DATA_PRIVILEGES.contains(privilege)) {
+        rootPrivilegesSet.add(privilege);
+      }
+    }
+    if (rootPrivilegesSet.size() > 0) {
+      DataPrivilegeVO dataPrivilegeVO = new DataPrivilegeVO();
+      dataPrivilegeVO.setPrivileges(new ArrayList<String>(rootPrivilegesSet));
+      dataPrivilegeVO.setType(0);
+      dataPrivilegeList.add(dataPrivilegeVO);
+    }
+  }
+
+  @Override
+  public void deleteTimeseries(Connection connection, String timeseriesName) throws BaseException {
     SessionPool sessionPool = getSessionPool(connection);
-    String sql = "delete timeseries " + deviceName + ".*";
+    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 {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<Integer> getDevicesCount(Connection connection, List<String> groupNames)
+      throws BaseException {
+    SessionPool sessionPool = getSessionPool(connection);
+    List<Integer> devicesCount = new ArrayList<>();
+    try {
+      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);
+      }
+      return devicesCount;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @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 {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @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 {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<Integer> getTimeseriesCount(Connection connection, List<String> deviceNames)
+      throws BaseException {
+    SessionPool sessionPool = getSessionPool(connection);
+    List<Integer> lines = new ArrayList<>();
+    try {
+      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);
+      }
+      return lines;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<String> deleteTimeseriesByDevice(Connection connection, String deviceName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      List<String> timeseriesList = getTimeseries(connection, deviceName);
+      for (String timeseries : timeseriesList) {
+        String sql = "delete timeseries " + timeseries;
+        sessionPool.executeNonQueryStatement(sql);
+      }
+      return timeseriesList;
     } catch (StatementExecutionException e) {
       logger.error(e.getMessage());
       if (e.getStatusCode() == 602) {
@@ -614,56 +1310,281 @@ public class IotDBServiceImpl implements IotDBService {
     } catch (IoTDBConnectionException e) {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.DELETE_TS_FAIL, ErrorCode.DELETE_TS_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
     }
   }
 
   @Override
-  public void createDeviceWithMeasurements(Connection connection, DeviceInfoDTO deviceInfoDTO)
+  public void upsertMeasurements(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);
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String deviceName = deviceInfoDTO.getDeviceName();
+      checkDevicePath(sessionPool, deviceName);
+      String sql = "show timeseries " + deviceName;
+      List<String> existMeasurements = executeQueryOneColumn(sessionPool, sql);
+      for (DeviceDTO deviceDTO : deviceInfoDTO.getDeviceDTOList()) {
+        String timeseries = deviceDTO.getTimeseries();
+        checkTags(deviceDTO.getTags());
+        checkTags(deviceDTO.getAttributes());
+        if (existMeasurements.contains(timeseries)) {
+          upsertMeasurementAlias(sessionPool, timeseries, deviceDTO.getAlias());
+          upsertMeasurementTags(sessionPool, deviceDTO);
+          upsertMeasurementAttributes(sessionPool, deviceDTO);
+        } else {
+          createMeasurement(sessionPool, deviceDTO);
+        }
+      }
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private void createMeasurement(SessionPool sessionPool, DeviceDTO deviceDTO)
+      throws BaseException {
+    String measurement = deviceDTO.getTimeseries();
+    try {
+      TSDataType type = handleTypeStr(deviceDTO.getDataType());
+      TSEncoding encoding = handleEncodingStr(deviceDTO.getEncoding());
+      CompressionType compressionType = handleCompressionStr(deviceDTO.getCompression());
+      String alias = deviceDTO.getAlias();
+      if (alias == null || "null".equals(alias) || StringUtils.isBlank(alias)) {
+        alias = null;
+      }
+      Map<String, String> tags = handleTagsList(deviceDTO.getTags());
+      Map<String, String> attributes = handleTagsList(deviceDTO.getAttributes());
+      sessionPool.createTimeseries(
+          measurement, type, encoding, compressionType, null, tags, attributes, alias);
     } catch (IoTDBConnectionException e) {
       logger.error(e.getMessage());
-      throw new BaseException(ErrorCode.INSERT_DEV_FAIL, ErrorCode.INSERT_DEV_FAIL_MSG);
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
       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);
+      if (e.getMessage().contains("already exist")) {
+        throw new BaseException(
+            ErrorCode.MEASUREMENT_ALREADY_EXIST,
+            measurement + ErrorCode.MEASUREMENT_ALREADY_EXIST_MSG);
       }
-    } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
+      throw new BaseException(ErrorCode.INSERT_TS_FAIL, measurement + ErrorCode.INSERT_TS_FAIL_MSG);
+    }
+  }
+
+  private Map<String, String> handleTagsList(List<List<String>> tags) throws BaseException {
+    if (tags != null && tags.size() > 0) {
+      Map<String, String> result = new HashMap<>();
+      for (List<String> tag : tags) {
+        result.put(tag.get(0), tag.get(1));
       }
+      return result;
+    } else {
+      return null;
+    }
+  }
+
+  private Map<String, String> handleTagsString(String tags) throws BaseException {
+    if (!"null".equals(tags)) {
+      String patternStr = "\"([^\"]+)\":\"([^\"]+)\"";
+      Pattern pattern = Pattern.compile(patternStr);
+      Matcher matcher = pattern.matcher(tags);
+      Map<String, String> result = new HashMap<>();
+      while (matcher.find()) {
+        result.put(matcher.group(1), matcher.group(2));
+      }
+      return result;
+    } else {
+      return null;
+    }
+  }
+
+  private void checkDevicePath(SessionPool sessionPool, String deviceName) throws BaseException {
+    String sql = "show timeseries " + deviceName;
+    List<String> measurements = executeQueryOneColumn(sessionPool, sql);
+    if (measurements.size() > 0 && measurements.get(0).equals(deviceName)) {
+      throw new BaseException(
+          ErrorCode.MEASUREMENT_NAME_EQUALS_DEVICE, ErrorCode.MEASUREMENT_NAME_EQUALS_DEVICE_MSG);
+    }
+  }
+
+  private void checkTags(List<List<String>> tags) throws BaseException {
+    if (tags != null && tags.size() > 0) {
+      for (List<String> tag : tags) {
+        if (tag.size() != 2) {
+          throw new BaseException(ErrorCode.WRONG_DB_PARAM, ErrorCode.WRONG_DB_PARAM_MSG);
+        }
+        String key = tag.get(0);
+        String value = tag.get(1);
+        checkKey(key);
+        checkValue(value);
+      }
+    }
+  }
+
+  private void checkKey(String key) throws BaseException {
+    if (key != null) {
+      checkValue(key);
+      if (key.matches("^\\d+$")) {
+        throw new BaseException(ErrorCode.NO_SUP_ALL_DIGIT, ErrorCode.NO_SUP_ALL_DIGIT_MSG);
+      }
+    }
+  }
+
+  private void checkValue(String value) throws BaseException {
+    if (value != null) {
+      if (value.matches("^as$") || value.matches("^null$") || value.matches("^like$")) {
+        throw new BaseException(ErrorCode.NO_SUP_WORD, ErrorCode.NO_SUP_WORD_MSG);
+      }
+    }
+  }
+
+  private void upsertMeasurementAlias(SessionPool sessionPool, String timeseries, String alias)
+      throws BaseException {
+    if (alias == null || "null".equals(alias) || StringUtils.isBlank(alias)) {
+      return;
+    }
+    if (alias.matches("^as$") || alias.matches("^\\d+$") || alias.matches("^like$")) {
+      throw new BaseException(ErrorCode.NO_SUP_ALIAS_WORD, ErrorCode.NO_SUP_ALIAS_WORD_MSG);
+    }
+    String existAlias = executeQueryOneLine(sessionPool, "show timeseries " + timeseries, "alias");
+    if (alias.equals(existAlias)) {
+      return;
+    }
+    try {
+      String sql = "alter timeseries " + timeseries + " upsert alias=" + alias;
+      sessionPool.executeNonQueryStatement(sql);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      if (e.getMessage().contains("No permissions")) {
+        throw new BaseException(
+            ErrorCode.NO_PRI_ALTER_MEASUREMENT, ErrorCode.NO_PRI_ALTER_MEASUREMENT_MSG);
+      }
+      throw new BaseException(ErrorCode.UPSERT_ALIAS_FAIL, ErrorCode.UPSERT_ALIAS_FAIL_MSG);
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    }
+  }
+
+  private void upsertMeasurementTags(SessionPool sessionPool, DeviceDTO deviceDTO)
+      throws BaseException {
+    try {
+      String tags =
+          executeQueryOneLine(sessionPool, "show timeseries " + deviceDTO.getTimeseries(), "tags");
+      Map<String, String> existTags = handleTagsString(tags);
+      List<List<String>> newTags = deviceDTO.getTags();
+      Map<String, String> addTags = handleTagsList(newTags);
+
+      if (addTags == null && existTags == null) {
+        return;
+      }
+      if (addTags != null && addTags.equals(existTags)) {
+        return;
+      }
+
+      if (existTags != null) {
+        String sql =
+            "alter timeseries "
+                + deviceDTO.getTimeseries()
+                + " drop "
+                + String.join(",", existTags.keySet());
+        sessionPool.executeNonQueryStatement(sql);
+      }
+      if (newTags != null) {
+        for (List<String> newTag : newTags) {
+          String sql =
+              "alter timeseries "
+                  + deviceDTO.getTimeseries()
+                  + " add tags "
+                  + newTag.get(0)
+                  + "="
+                  + newTag.get(1);
+          sessionPool.executeNonQueryStatement(sql);
+        }
+      }
+    } catch (BaseException | StatementExecutionException e) {
+      logger.error(e.getMessage());
+      if (e.getMessage().contains("No permissions")) {
+        throw new BaseException(
+            ErrorCode.NO_PRI_ALTER_MEASUREMENT, ErrorCode.NO_PRI_ALTER_MEASUREMENT_MSG);
+      }
+      throw new BaseException(ErrorCode.UPSERT_TAGS_FAIL, ErrorCode.UPSERT_TAGS_FAIL_MSG);
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    }
+  }
+
+  private void upsertMeasurementAttributes(SessionPool sessionPool, DeviceDTO deviceDTO)
+      throws BaseException {
+    try {
+      String attributes =
+          executeQueryOneLine(
+              sessionPool, "show timeseries " + deviceDTO.getTimeseries(), "attributes");
+      Map<String, String> existAttributes = handleTagsString(attributes);
+      List<List<String>> newAttributes = deviceDTO.getAttributes();
+      Map<String, String> addAttributes = handleTagsList(newAttributes);
+
+      if (addAttributes == null && existAttributes == null) {
+        return;
+      }
+      if (addAttributes != null && addAttributes.equals(existAttributes)) {
+        return;
+      }
+
+      if (existAttributes != null) {
+        String sql =
+            "alter timeseries "
+                + deviceDTO.getTimeseries()
+                + " drop "
+                + String.join(",", existAttributes.keySet());
+        sessionPool.executeNonQueryStatement(sql);
+      }
+      if (newAttributes != null) {
+        for (List<String> newAttribute : newAttributes) {
+          String sql =
+              "alter timeseries "
+                  + deviceDTO.getTimeseries()
+                  + " add attributes "
+                  + newAttribute.get(0)
+                  + "="
+                  + newAttribute.get(1);
+          sessionPool.executeNonQueryStatement(sql);
+        }
+      }
+    } catch (BaseException | StatementExecutionException e) {
+      logger.error(e.getMessage());
+      if (e.getMessage().contains("No permissions")) {
+        throw new BaseException(
+            ErrorCode.NO_PRI_ALTER_MEASUREMENT, ErrorCode.NO_PRI_ALTER_MEASUREMENT_MSG);
+      }
+      throw new BaseException(
+          ErrorCode.UPSERT_ATTRIBUTES_FAIL, ErrorCode.UPSERT_ATTRIBUTES_FAIL_MSG);
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     }
   }
 
   @Override
-  public Integer getMeasurementsCount(Connection connection, String deviceName)
+  public Integer getOneDataCount(Connection connection, String deviceName, String measurementName)
       throws BaseException {
-    SessionPool sessionPool = getSessionPool(connection);
-    String sql = "count timeseries " + deviceName;
-    String valueStr = executeQueryOneValue(sessionPool, sql);
-    return Integer.valueOf(valueStr);
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "select count(*) from " + deviceName;
+      String countStr = executeQueryOneLine(sessionPool, sql, "count(" + measurementName + ")");
+      return Integer.parseInt(countStr);
+    } catch (BaseException e) {
+      throw new BaseException(
+          ErrorCode.GET_MEASUREMENT_DATA_COUNT_FAIL, ErrorCode.GET_MEASUREMENT_DATA_COUNT_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
   }
 
   @Override
@@ -679,33 +1600,169 @@ public class IotDBServiceImpl implements IotDBService {
     String value;
     try {
       value = executeQueryOneValue(sessionPool, sql);
+      return value;
     } finally {
-      sessionPool.close();
+      closeSessionPool(sessionPool);
     }
-    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;
+    try {
+      String sql = "show ttl on " + groupName;
+      String queryField = "ttl";
+      String ttl = executeQueryOneLine(sessionPool, sql, queryField);
+      return ttl;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
   }
 
   @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;
+    try {
+      String sql = "show devices " + groupName;
+      List<String> devicesName = executeQueryOneColumn(sessionPool, sql);
+      return devicesName;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<NodeTreeVO> getDeviceNodeTree(Connection connection, String groupName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      return getDeviceNodeTree(sessionPool, groupName);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private List<NodeTreeVO> getDeviceNodeTree(SessionPool sessionPool, String groupName)
+      throws BaseException {
+    Set<String> firstLevelNodes = getChildrenNode(groupName, "devices", sessionPool);
+    if (firstLevelNodes == null || firstLevelNodes.size() == 0) {
+      return null;
+    }
+    List<NodeTreeVO> groupNodeVOList = new ArrayList<>();
+    for (String firstLevelNodeName : firstLevelNodes) {
+      NodeTreeVO firstLevelNode = new NodeTreeVO(firstLevelNodeName);
+      groupNodeVOList.add(firstLevelNode);
+      assembleNodeTree(firstLevelNode, firstLevelNodeName, "devices", sessionPool);
+    }
+    return groupNodeVOList;
+  }
+
+  @Override
+  public NodeTreeVO getDeviceList(Connection connection, String groupName) throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "show devices " + groupName;
+      List<String> devices = executeQueryOneColumn(sessionPool, sql);
+      String ancestryName = null;
+      if (devices.size() == 0) {
+        return null;
+      } else if (groupName.equals(devices.get(0))) {
+        ancestryName = groupName;
+      }
+      NodeTreeVO ancestry = new NodeTreeVO(ancestryName);
+      assembleDeviceList(ancestry, groupName, sessionPool);
+      return ancestry;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public List<String> getDeviceParents(Connection connection, String groupName, String deviceName)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    try {
+      sessionPool = getSessionPool(connection);
+      String sql = "show devices " + groupName;
+      List<String> devices = executeQueryOneColumn(sessionPool, sql);
+      List<String> parents =
+          devices.stream()
+              .filter(d -> deviceName.startsWith(d))
+              .filter(d -> StringUtils.removeStart(deviceName, d).startsWith("."))
+              .sorted()
+              .collect(Collectors.toList());
+      parents.add(deviceName);
+      return parents;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private void assembleDeviceList(NodeTreeVO node, String deviceName, SessionPool sessionPool)
+      throws BaseException {
+    List<String> descendants = findDescendants(deviceName, sessionPool);
+    if (descendants.size() == 0) {
+      return;
+    }
+    List<String> children = findChildren(descendants);
+    for (String child : children) {
+      NodeTreeVO childNode = new NodeTreeVO(child);
+      node.initChildren().add(childNode);
+      assembleDeviceList(childNode, child, sessionPool);
+    }
+  }
+
+  private List<String> findChildren(List<String> descendants) {
+    List<String> children = new ArrayList<>();
+    for (int i = 0; i < descendants.size(); i++) {
+      int tag = 0;
+      for (int j = 0; j < descendants.size(); j++) {
+        if (!descendants.get(i).equals(descendants.get(j))
+            && descendants.get(i).contains(descendants.get(j))
+            && StringUtils.removeStart(descendants.get(i), descendants.get(j)).startsWith(".")) {
+          tag++;
+        }
+      }
+      if (tag == 0) {
+        children.add(descendants.get(i));
+      }
+    }
+    return children;
+  }
+
+  private List<String> findDescendants(String deviceName, SessionPool sessionPool)
+      throws BaseException {
+    List<String> descendants = executeQueryOneColumn(sessionPool, "show devices " + deviceName);
+    if (descendants.size() != 0 && deviceName.equals(descendants.get(0))) {
+      descendants.remove(0);
+    }
+    return descendants;
+  }
+
+  @Override
+  public Boolean deviceExist(Connection connection, String groupName, String deviceName)
+      throws BaseException {
+    SessionPool sessionPool = getSessionPool(connection);
+    try {
+      String sql = "show devices " + groupName;
+      List<String> devices = executeQueryOneColumn(sessionPool, sql);
+      Boolean isExist = false;
+      for (String device : devices) {
+        if (deviceName.equals(device)) {
+          isExist = true;
+          break;
+        }
+      }
+      return isExist;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
   }
 
   @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);
@@ -725,32 +1782,358 @@ public class IotDBServiceImpl implements IotDBService {
     List<List<String>> valueList = sqlResultVO.getValueList();
     List<String> timeseries = new ArrayList<>();
     for (List<String> list : valueList) {
+      String measurementName = list.get(0);
+      if (StringUtils.removeStart(measurementName, deviceName + ".").contains(".")) {
+        continue;
+      }
       timeseries.add(list.get(index));
     }
     return timeseries;
   }
 
   @Override
-  public void setUserPrivileges(
-      Connection connection, String userName, PrivilegeInfoDTO privilegeInfoDTO)
+  public DataVO getDataByDevice(
+      Connection connection,
+      String deviceName,
+      Integer pageSize,
+      Integer pageNum,
+      DataQueryDTO dataQueryDTO)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    List<String> measurementList = dataQueryDTO.getMeasurementList();
+    List<String> newMeasurementList = new ArrayList<>();
+    for (String measurement : measurementList) {
+      newMeasurementList.add(StringUtils.removeStart(measurement, deviceName + "."));
+    }
+
+    String basicSql = "select " + String.join(",", newMeasurementList) + " from " + deviceName;
+    String whereClause = getWhereClause(dataQueryDTO);
+    String limitClause = " limit " + pageSize + " offset " + (pageNum - 1) * pageSize;
+    String sql = basicSql + whereClause + limitClause;
+    try {
+      sessionPool = getSessionPool(connection);
+      DataVO dataVO = getDataBySql(sql, sessionPool);
+      Integer totalLine = getDataLineBySql(basicSql + whereClause, deviceName, sessionPool);
+      dataVO.setTotalCount(totalLine);
+      int totalPage = (totalLine + pageSize - 1) / pageSize;
+      dataVO.setTotalPage(totalPage);
+      return dataVO;
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private String getWhereClause(DataQueryDTO dataQueryDTO) {
+    Long startTime = null;
+    if (dataQueryDTO.getStartTime() != null) {
+      startTime = dataQueryDTO.getStartTime().getTime();
+    }
+    Long endTime = null;
+    if (dataQueryDTO.getEndTime() != null) {
+      endTime = dataQueryDTO.getEndTime().getTime();
+    }
+
+    String whereClause = "";
+    if (startTime != null && endTime != null) {
+      whereClause = " where time >= " + startTime + " and time <= " + endTime;
+    } else if (startTime == null && endTime != null) {
+      whereClause = " where time <= " + endTime;
+    } else if (startTime != null && endTime == null) {
+      whereClause = " where time >= " + startTime;
+    }
+    return whereClause;
+  }
+
+  private DataVO getDataBySql(String sql, SessionPool sessionPool) throws BaseException {
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    DataVO dataVO = new DataVO();
+    List<List<String>> valueList = new ArrayList<>();
+    try {
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      List<String> columnTypes = sessionDataSetWrapper.getColumnTypes();
+      dataVO.setTypeList(columnTypes);
+      List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+      dataVO.setMetaDataList(columnNames);
+      if ("Time".equals(columnNames.get(0))) {
+        while (sessionDataSetWrapper.hasNext()) {
+          List<String> lineValueList = new ArrayList<>();
+          RowRecord rowRecord = sessionDataSetWrapper.next();
+          long timestamp = rowRecord.getTimestamp();
+          SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss.SSS");
+          Date date = new Date(timestamp);
+          String timeStr = simpleDateFormat.format(date);
+          lineValueList.add(timeStr);
+          for (org.apache.iotdb.tsfile.read.common.Field field : rowRecord.getFields()) {
+            lineValueList.add(field.toString());
+          }
+          valueList.add(lineValueList);
+        }
+      } else {
+        while (sessionDataSetWrapper.hasNext()) {
+          List<String> lineValueList = new ArrayList<>();
+          RowRecord rowRecord = sessionDataSetWrapper.next();
+          for (org.apache.iotdb.tsfile.read.common.Field field : rowRecord.getFields()) {
+            lineValueList.add(field.toString());
+          }
+          valueList.add(lineValueList);
+        }
+      }
+      dataVO.setValueList(valueList);
+      return dataVO;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_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);
+      } else {
+        throw new BaseException(ErrorCode.GET_DATA_FAIL, ErrorCode.GET_DATA_FAIL_MSG);
+      }
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+    }
+  }
+
+  private Integer getDataLineBySql(String sql, String deviceName, SessionPool sessionPool)
+      throws BaseException {
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      int lineCount = 0;
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      while (sessionDataSetWrapper.hasNext()) {
+        lineCount++;
+      }
+      return lineCount;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_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);
+      } else {
+        throw new BaseException(ErrorCode.GET_DATA_FAIL, ErrorCode.GET_DATA_FAIL_MSG);
+      }
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+    }
+  }
+
+  @Override
+  public void updateDataByDevice(
+      Connection connection, String deviceName, DataUpdateDTO dataUpdateDTO) throws BaseException {
+    SessionPool sessionPool = null;
+    long timestamp = dataUpdateDTO.getTimestamp().getTime();
+    List<String> measurementList = dataUpdateDTO.getMeasurementList();
+    List<String> valueList = dataUpdateDTO.getValueList();
+    List<String> newMeasurementList = new ArrayList<>();
+    for (String measurement : measurementList) {
+      newMeasurementList.add(StringUtils.removeStart(measurement, deviceName + "."));
+    }
+    try {
+      sessionPool = getSessionPool(connection);
+      sessionPool.insertRecord(deviceName, timestamp, newMeasurementList, valueList);
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_INSERT_DATA, ErrorCode.NO_PRI_INSERT_DATA_MSG);
+      }
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.UPDATE_DATA_FAIL, ErrorCode.UPDATE_DATA_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public void deleteDataByDevice(
+      Connection connection, String deviceName, DataDeleteDTO dataDeleteDTO) throws BaseException {
+    SessionPool sessionPool = null;
+    List<Date> timestampList = dataDeleteDTO.getTimestampList();
+    List<String> timestampStrList = new ArrayList<>();
+    for (Date date : timestampList) {
+      timestampStrList.add(Long.toString(date.getTime()));
+    }
+    List<String> measurementList = dataDeleteDTO.getMeasurementList();
+    try {
+      sessionPool = getSessionPool(connection);
+      for (String measurement : measurementList) {
+        for (String timestamp : timestampStrList) {
+          String sql = "delete from " + measurement + " where time=" + timestamp;
+          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_DATA_FAIL, ErrorCode.DELETE_DATA_FAIL_MSG);
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  @Override
+  public void randomImport(
+      Connection connection, String deviceName, RandomImportDTO randomImportDTO)
+      throws BaseException {
+    SessionPool sessionPool = null;
+    int totalLine = randomImportDTO.getTotalLine();
+    int stepSize = randomImportDTO.getStepSize();
+    Long startTime = randomImportDTO.getStartTime().getTime();
+
+    List<Long> times = new ArrayList<>(totalLine);
+    List<List<String>> measurementsList = new ArrayList<>(totalLine);
+    List<List<Object>> valuesList = new ArrayList<>(totalLine);
+    List<List<TSDataType>> typesList = new ArrayList<>(totalLine);
+    try {
+      sessionPool = getSessionPool(connection);
+      SessionDataSetWrapper sessionDataSetWrapper =
+          sessionPool.executeQueryStatement("show timeseries " + deviceName);
+      List<String> columnNames = sessionDataSetWrapper.getColumnNames();
+      sessionDataSetWrapper.getColumnTypes();
+      int timeseriesIndex = -1;
+      int dataTypeIndex = -1;
+      if (columnNames != null) {
+        for (int i = 0; i < columnNames.size(); i++) {
+          if ("timeseries".equalsIgnoreCase(columnNames.get(i))) {
+            timeseriesIndex = i;
+          }
+          if ("dataType".equalsIgnoreCase(columnNames.get(i))) {
+            dataTypeIndex = i;
+          }
+        }
+      }
+      if (timeseriesIndex == -1 || dataTypeIndex == -1) {
+        logger.error(ErrorCode.RANDOM_IMPORT_DATA_FAIL_MSG);
+        throw new BaseException(
+            ErrorCode.RANDOM_IMPORT_DATA_FAIL, ErrorCode.RANDOM_IMPORT_DATA_FAIL_MSG);
+      }
+
+      List<String> measurements = new ArrayList<>();
+      List<String> typesStr = new ArrayList<>();
+      while (sessionDataSetWrapper.hasNext()) {
+        RowRecord next = sessionDataSetWrapper.next();
+        String timeseries = next.getFields().get(timeseriesIndex).toString();
+        timeseries = StringUtils.removeStart(timeseries, deviceName + ".");
+        if (timeseries.contains(".")) {
+          continue;
+        }
+        measurements.add(timeseries);
+        String dataType = next.getFields().get(dataTypeIndex).toString();
+        typesStr.add(dataType);
+      }
+      if (measurements.size() == 0) {
+        logger.error(ErrorCode.NO_MEASUREMENT_MSG);
+        throw new BaseException(ErrorCode.NO_MEASUREMENT, ErrorCode.NO_MEASUREMENT_MSG);
+      }
+
+      List<TSDataType> types = handleTypeStr(typesStr);
+      List<String> devices = new ArrayList<>(totalLine);
+      for (int i = 0; i < totalLine; i++) {
+        typesList.add(types);
+        measurementsList.add(measurements);
+        devices.add(deviceName);
+
+        List<Object> values = createRandomData(typesStr);
+        valuesList.add(values);
+
+        times.add(stepSize * i + startTime);
+      }
+
+      sessionPool.insertRecords(devices, times, measurementsList, typesList, valuesList);
+
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      System.out.println(e.getStatusCode());
+      if (e.getMessage().contains("No permissions")) {
+        throw new BaseException(ErrorCode.NO_PRI_INSERT_DATA, ErrorCode.NO_PRI_INSERT_DATA_MSG);
+      }
+      throw new BaseException(
+          ErrorCode.RANDOM_IMPORT_DATA_FAIL, ErrorCode.RANDOM_IMPORT_DATA_FAIL_MSG);
+    } finally {
+      closeSessionPool(sessionPool);
+    }
+  }
+
+  private List<Object> createRandomData(List<String> types) throws BaseException {
+    Random random = new Random();
+    List<Object> values = new ArrayList<>();
+    for (String type : types) {
+      switch (type) {
+        case "BOOLEAN":
+          values.add(random.nextBoolean());
+          break;
+        case "INT32":
+          values.add(random.nextInt());
+          break;
+        case "INT64":
+          values.add(random.nextLong());
+          break;
+        case "FLOAT":
+          values.add(random.nextFloat());
+          break;
+        case "DOUBLE":
+          values.add(random.nextDouble());
+          break;
+        case "TEXT":
+          values.add(RandomStringUtils.randomAlphabetic(5));
+          break;
+        default:
+          throw new BaseException(ErrorCode.DB_DATATYPE_WRONG, ErrorCode.DB_DATATYPE_WRONG_MSG);
+      }
+    }
+    return values;
+  }
+
+  @Override
+  public String getSqlForExport(String deviceName, DataQueryDTO dataQueryDTO) throws BaseException {
+    List<String> measurementList = dataQueryDTO.getMeasurementList();
+    List<String> newMeasurementList = new ArrayList<>();
+    for (String measurement : measurementList) {
+      newMeasurementList.add(StringUtils.removeStart(measurement, deviceName + "."));
+    }
+    String whereClause = getWhereClause(dataQueryDTO);
+    String sql =
+        "select " + String.join(",", newMeasurementList) + " from " + deviceName + whereClause;
+    return sql;
+  }
+
+  @Override
+  public void upsertDataPrivileges(
+      Connection connection, String userOrRole, String name, PrivilegeInfoDTO privilegeInfoDTO)
       throws BaseException {
     SessionPool sessionPool = getSessionPool(connection);
-    // 授权
+    // grant
     List<String> privileges = privilegeInfoDTO.getPrivileges();
     if (notNullAndNotZero(privileges)) {
-      grantOrRevoke("grant", privileges, userName, privilegeInfoDTO, sessionPool);
+      grantOrRevoke("grant", userOrRole, privileges, name, privilegeInfoDTO, sessionPool);
     }
-    // 取消授权
+    // revoke
     List<String> cancelPrivileges = privilegeInfoDTO.getCancelPrivileges();
     if (notNullAndNotZero(cancelPrivileges)) {
-      grantOrRevoke("revoke", cancelPrivileges, userName, privilegeInfoDTO, sessionPool);
+      grantOrRevoke("revoke", userOrRole, cancelPrivileges, name, privilegeInfoDTO, sessionPool);
     }
-    cancelPathPrivileges(userName, privilegeInfoDTO, sessionPool);
+    cancelPathPrivileges(name, userOrRole, privilegeInfoDTO, sessionPool);
     sessionPool.close();
   }
 
   private void cancelPathPrivileges(
-      String userName, PrivilegeInfoDTO privilegeInfoDTO, SessionPool sessionPool) {
+      String name, String userOrRole, PrivilegeInfoDTO privilegeInfoDTO, SessionPool sessionPool)
+      throws BaseException {
     Integer type = privilegeInfoDTO.getType();
     List<String> delDevicePaths = privilegeInfoDTO.getDelDevicePaths();
     List<String> delGroupPaths = privilegeInfoDTO.getDelGroupPaths();
@@ -758,79 +2141,23 @@ public class IotDBServiceImpl implements IotDBService {
     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());
-              }
-            }
+          for (String privilege : DATA_PRIVILEGES) {
+            grantOrRevokePaths("revoke", userOrRole, name, privilege, delGroupPaths, sessionPool);
           }
         }
         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());
-              }
-            }
+          for (String privilege : DATA_PRIVILEGES) {
+            grantOrRevokePaths("revoke", userOrRole, name, privilege, delDevicePaths, sessionPool);
           }
         }
         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());
-              }
-            }
+          for (String privilege : DATA_PRIVILEGES) {
+            grantOrRevokePaths(
+                "revoke", userOrRole, name, privilege, delTimeseriesPaths, sessionPool);
           }
         }
         break;
@@ -838,41 +2165,58 @@ public class IotDBServiceImpl implements IotDBService {
   }
 
   @Override
-  public RecordVO getRecords(Connection connection, String deviceName, String timeseriesName)
+  public RecordVO getRecords(
+      Connection connection, String deviceName, String timeseriesName, String dataType)
       throws BaseException {
-    SessionPool sessionPool = getSessionPool(connection);
+    SessionPool sessionPool = null;
+    SessionDataSetWrapper sessionDataSetWrapper = null;
     RecordVO recordVO = new RecordVO();
     List<Date> timeList = new ArrayList<>();
-    List<Long> valueList = new ArrayList<>();
+    List<String> valueList = new ArrayList<>();
+    Map<String, Integer> textCount = new HashMap<>();
     String sql =
-        "select time,"
-            + timeseriesName
+        "select "
+            + StringUtils.removeStart(timeseriesName, deviceName + ".")
             + " 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()) {
+      sessionPool = getSessionPool(connection);
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      while (sessionDataSetWrapper.hasNext()) {
+        if ("TEXT".equals(dataType)) {
+          RowRecord next = sessionDataSetWrapper.next();
+          String text = next.getFields().get(0).toString();
+          if (textCount.containsKey(text)) {
+            textCount.put(text, textCount.get(text) + 1);
+          } else {
+            textCount.put(text, 1);
+          }
+        } else if (StringUtils.equalsAny(
+            dataType, "INT32", "INT64", "BOOLEAN", "FLOAT", "DOUBLE")) {
           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);
+          valueList.add(fields.get(0).toString());
+        } else {
+          throw new BaseException(ErrorCode.DB_DATATYPE_WRONG, ErrorCode.DB_DATATYPE_WRONG_MSG);
         }
       }
+      recordVO.setTimeList(timeList);
+      recordVO.setValueList(valueList);
+      recordVO.setTextCount(textCount);
+      return recordVO;
     } 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);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+      closeSessionPool(sessionPool);
     }
-    recordVO.setTimeList(timeList);
-    recordVO.setValueList(valueList);
-    return recordVO;
   }
 
   @Override
@@ -887,42 +2231,25 @@ public class IotDBServiceImpl implements IotDBService {
       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);
+        if (StringUtils.isBlank(sql)) {
           continue;
         }
-        if ("select".equalsIgnoreCase(judge)) {
-          SqlResultVO sqlResultVO = executeQuery(sessionPool, sql, false, id_plus_timestamp, true);
+        String judge = sql.toLowerCase();
+        if (judge.startsWith("show")
+            || judge.startsWith("count")
+            || judge.startsWith("list")
+            || judge.startsWith("select")) {
+          SqlResultVO sqlResultVO = executeQuery(sessionPool, sql, id_plus_timestamp);
           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);
-              }
-            }
+        }
+        try {
+          if (QUERY_STOP.get(id_plus_timestamp)) {
             long start = System.currentTimeMillis();
             sessionPool.executeNonQueryStatement(sql);
             long end = System.currentTimeMillis();
-            double time = (end - start + 0.0d) / 1000;
-            String queryTime = time + "s";
+            long time = end - start;
+            String queryTime = time + "ms";
             SqlResultVO sqlResultVO = new SqlResultVO();
             sqlResultVO.setQueryTime(queryTime);
             sqlResultVO.setLine(0L);
@@ -932,18 +2259,19 @@ public class IotDBServiceImpl implements IotDBService {
           logger.error(e.getMessage());
           throw new BaseException(
               ErrorCode.SQL_EP,
-              ErrorCode.SQL_EP_MSG + ":" + sql + "执行出错,错误信息[" + e.getMessage() + "]");
+              ErrorCode.SQL_EP_MSG
+                  + ":["
+                  + sql
+                  + "]statement execution error, error message:["
+                  + e.getMessage()
+                  + "]");
         } catch (IoTDBConnectionException e) {
           logger.error(e.getMessage());
-          throw new BaseException(
-              ErrorCode.SQL_EP,
-              ErrorCode.SQL_EP_MSG + ":" + sql + "执行出错,错误信息[" + e.getMessage() + "]");
+          throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
         }
       }
     } finally {
-      if (sessionPool != null) {
-        sessionPool.close();
-      }
+      closeSessionPool(sessionPool);
     }
     QUERY_STOP.remove(id_plus_timestamp);
     return results;
@@ -962,6 +2290,8 @@ public class IotDBServiceImpl implements IotDBService {
       throw new BaseException(ErrorCode.UPDATE_PWD_FAIL, ErrorCode.UPDATE_PWD_FAIL_MSG);
     } catch (IoTDBConnectionException e) {
       e.printStackTrace();
+    } finally {
+      closeSessionPool(sessionPool);
     }
   }
 
@@ -976,118 +2306,71 @@ public class IotDBServiceImpl implements IotDBService {
   }
 
   private void grantOrRevoke(
-      String word,
+      String grantOrRevoke,
+      String userOrRole,
       List<String> privileges,
-      String userName,
+      String name,
       PrivilegeInfoDTO privilegesInfo,
       SessionPool sessionPool)
       throws BaseException {
     Integer type = privilegesInfo.getType();
-    //        String privilegesStr = String.join("','", privileges); 一起存会有bug
-    for (String privilegesStr : privileges) {
+    for (String privilege : privileges) {
       if (type == 0) {
-        String sql = word + " user " + userName + " privileges '" + privilegesStr + "' on root";
+        grantOrRevokePaths(
+            grantOrRevoke, userOrRole, name, privilege, Arrays.asList("root"), sessionPool);
+      } else if (type == 1) {
+        List<String> groupPaths = privilegesInfo.getGroupPaths();
+        grantOrRevokePaths(grantOrRevoke, userOrRole, name, privilege, groupPaths, sessionPool);
+      } else if (type == 2) {
+        List<String> devicePaths = privilegesInfo.getDevicePaths();
+        grantOrRevokePaths(grantOrRevoke, userOrRole, name, privilege, devicePaths, sessionPool);
+      } else if (type == 3) {
+        List<String> timeseriesPaths = privilegesInfo.getTimeseriesPaths();
+        grantOrRevokePaths(
+            grantOrRevoke, userOrRole, name, privilege, timeseriesPaths, sessionPool);
+      } else {
+        throw new BaseException(ErrorCode.NO_TYPE, ErrorCode.NO_TYPE_MSG);
+      }
+    }
+  }
+
+  private void grantOrRevokePaths(
+      String grantOrRevoke,
+      String userOrRole,
+      String name,
+      String privilege,
+      List<String> paths,
+      SessionPool sessionPool)
+      throws BaseException {
+    if (notNullAndNotZero(paths)) {
+      for (String groupPath : paths) {
+        String sql =
+            grantOrRevoke
+                + " "
+                + userOrRole
+                + " "
+                + name
+                + " privileges '"
+                + privilege
+                + "' on "
+                + groupPath;
         try {
           sessionPool.executeNonQueryStatement(sql);
         } catch (StatementExecutionException e) {
           logger.error(e.getMessage());
+          if (e.getStatusCode() == 602) {
+            throw new BaseException(
+                ErrorCode.NO_PRI_GRANT_PRIVILEGE, ErrorCode.NO_PRI_GRANT_PRIVILEGE_MSG);
+          }
         } catch (IoTDBConnectionException e) {
           logger.error(e.getMessage());
+          throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
         }
-        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 */
+  /** Determines that the list is not empty and has a length greater than 0 */
   private boolean notNullAndNotZero(List list) {
     if (list != null && list.size() > 0) {
       return true;
@@ -1095,10 +2378,36 @@ public class IotDBServiceImpl implements IotDBService {
     return false;
   }
 
+  private List<String> executeQueryOneLine(SessionPool sessionPool, String sql)
+      throws BaseException {
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    try {
+      List<String> valueList = new ArrayList<>();
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      if (sessionDataSetWrapper.hasNext()) {
+        RowRecord rowRecord = sessionDataSetWrapper.next();
+        List<org.apache.iotdb.tsfile.read.common.Field> fields = rowRecord.getFields();
+        for (org.apache.iotdb.tsfile.read.common.Field field : fields) {
+          valueList.add(field.toString());
+        }
+      }
+      return valueList;
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
+    }
+  }
+
   private String executeQueryOneLine(SessionPool sessionPool, String sql, String queryField)
       throws BaseException {
+    SessionDataSetWrapper sessionDataSetWrapper = null;
     try {
-      SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
       List<String> columnNames = sessionDataSetWrapper.getColumnNames();
       int index = -1;
       for (int i = 0; i < columnNames.size(); i++) {
@@ -1122,21 +2431,24 @@ public class IotDBServiceImpl implements IotDBService {
     } catch (StatementExecutionException e) {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
+    } finally {
+      closeResultSet(sessionDataSetWrapper);
     }
-    throw new BaseException(ErrorCode.NO_GROUP, ErrorCode.NO_GROUP_MSG);
+    throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
   }
 
   private SqlResultVO executeQuery(SessionPool sessionPool, String sql, Boolean closePool)
       throws BaseException {
     SqlResultVO sqlResultVO = new SqlResultVO();
     List<List<String>> valuelist = new ArrayList<>();
+    SessionDataSetWrapper sessionDataSetWrapper = null;
     try {
-      SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      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()) {
@@ -1153,7 +2465,9 @@ public class IotDBServiceImpl implements IotDBService {
         String queryTime = time + "s";
         sqlResultVO.setQueryTime(queryTime);
         sqlResultVO.setLine(count);
+        sqlResultVO.setValueList(valuelist);
       }
+      return sqlResultVO;
     } catch (IoTDBConnectionException e) {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
@@ -1161,26 +2475,28 @@ public class IotDBServiceImpl implements IotDBService {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.SQL_EP, ErrorCode.SQL_EP_MSG);
     } finally {
+      closeResultSet(sessionDataSetWrapper);
       if (sessionPool != null && closePool) {
         sessionPool.close();
       }
     }
-    sqlResultVO.setValueList(valuelist);
-    return sqlResultVO;
   }
 
-  private SqlResultVO executeQuery(
-      SessionPool sessionPool, String sql, Boolean closePool, String notStopKey, boolean timeFlag)
+  private SqlResultVO executeQuery(SessionPool sessionPool, String sql, String notStopKey)
       throws BaseException {
     SqlResultVO sqlResultVO = new SqlResultVO();
     List<List<String>> valuelist = new ArrayList<>();
+    SessionDataSetWrapper sessionDataSetWrapper = null;
+    boolean timeFlag = false;
     try {
-      SessionDataSetWrapper sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
+      sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
       long start = System.currentTimeMillis();
       List<String> columnNames = sessionDataSetWrapper.getColumnNames();
       sqlResultVO.setMetaDataList(columnNames);
+      if ("Time".equals(columnNames.get(0))) {
+        timeFlag = true;
+      }
       int batchSize = sessionDataSetWrapper.getBatchSize();
-      // 记录行数
       long count = 0;
       if (batchSize > 0) {
         while (sessionDataSetWrapper.hasNext() && QUERY_STOP.get(notStopKey)) {
@@ -1200,25 +2516,26 @@ public class IotDBServiceImpl implements IotDBService {
           valuelist.add(strList);
         }
         long end = System.currentTimeMillis();
-        double time = (end - start + 0.0d) / 1000;
-        String queryTime = time + "s";
+        long time = end - start;
+        String queryTime = time + "ms";
         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);
+      throw new BaseException(
+          ErrorCode.SQL_EP,
+          ErrorCode.SQL_EP_MSG
+              + ":["
+              + sql
+              + "]statement execution error, error message:["
+              + e.getMessage()
+              + "]");
+    } catch (IoTDBConnectionException e) {
+      logger.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
     } finally {
-      if (sessionPool != null && closePool) {
-        sessionPool.close();
-      }
+      closeResultSet(sessionDataSetWrapper);
     }
     sqlResultVO.setValueList(valuelist);
     return sqlResultVO;
@@ -1271,9 +2588,7 @@ public class IotDBServiceImpl implements IotDBService {
       logger.error(e.getMessage());
       throw new BaseException(ErrorCode.GET_MSM_FAIL, ErrorCode.GET_MSM_FAIL_MSG);
     } finally {
-      if (sessionDataSetWrapper != null) {
-        sessionDataSetWrapper.close();
-      }
+      closeResultSet(sessionDataSetWrapper);
     }
   }
 
@@ -1305,9 +2620,7 @@ public class IotDBServiceImpl implements IotDBService {
       throw new BaseException(
           ErrorCode.GET_SQL_ONE_VALUE_FAIL, ErrorCode.GET_SQL_ONE_VALUE_FAIL_MSG);
     } finally {
-      if (sessionDataSetWrapper != null) {
-        sessionDataSetWrapper.close();
-      }
+      closeResultSet(sessionDataSetWrapper);
     }
   }
 
@@ -1344,18 +2657,17 @@ public class IotDBServiceImpl implements IotDBService {
       throw new BaseException(
           ErrorCode.GET_SQL_ONE_COLUMN_FAIL, ErrorCode.GET_SQL_ONE_COLUMN_FAIL_MSG);
     } finally {
-      if (sessionDataSetWrapper != null) {
-        sessionDataSetWrapper.close();
-      }
+      closeResultSet(sessionDataSetWrapper);
     }
   }
 
   private List<String> executeQueryOneColumn(SessionPool sessionPool, String sql)
       throws BaseException {
     SessionDataSetWrapper sessionDataSetWrapper = null;
+    ExecutorService service = null;
     try {
       Callable call = () -> sessionPool.executeQueryStatement(sql);
-      ExecutorService service = Executors.newFixedThreadPool(1);
+      service = Executors.newFixedThreadPool(1);
       Future submit = service.submit(call);
       sessionDataSetWrapper = (SessionDataSetWrapper) submit.get(60, TimeUnit.SECONDS);
       int batchSize = sessionDataSetWrapper.getBatchSize();
@@ -1370,12 +2682,15 @@ public class IotDBServiceImpl implements IotDBService {
       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);
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_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);
+      if (e.getStatusCode() == 602) {
+        throw new BaseException(ErrorCode.NO_PRI_DO_THIS, ErrorCode.NO_PRI_DO_THIS_MSG);
+      } else {
+        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);
@@ -1389,303 +2704,14 @@ public class IotDBServiceImpl implements IotDBService {
       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;
-      }
+      service.shutdown();
+      closeResultSet(sessionDataSetWrapper);
     }
-    return pathVO;
   }
 
-  private int findType(SessionPool sessionPool, String s) throws BaseException {
-    // 主要用于判断s路径是否已经不存在 iotdb存在已删除路径的权限还会展示出来的问题
-    String sql = "count timeseries " + s;
+  private int findType(SessionPool sessionPool, String path) throws BaseException {
+    // Check whether the path does not exist
+    String sql = "count timeseries " + path;
     SessionDataSetWrapper sessionDataSetWrapper = null;
     try {
       sessionDataSetWrapper = sessionPool.executeQueryStatement(sql);
@@ -1700,24 +2726,20 @@ public class IotDBServiceImpl implements IotDBService {
         sessionDataSetWrapper.close();
       }
     }
-    sql = "count storage group " + s;
+    sql = "count storage group " + path;
     Integer isGroup = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
-    if (isGroup == 1) {
+    if (isGroup >= 1) {
       return 1;
     }
-    // 无效路径 既不是root 也不是存储组 不展示到页面
-    if (isGroup > 1) {
-      return -1;
-    }
-    sql = "count devices " + s;
+    sql = "count devices " + path;
     Integer isDevices = Integer.valueOf(executeQueryOneValue(sessionPool, sql));
-    if (isDevices == 1) {
+    if (isDevices >= 1) {
       return 2;
     }
     return 3;
   }
 
-  private List<TSEncoding> handleEncodingStr(List<String> encoding) {
+  private List<TSEncoding> handleEncodingStr(List<String> encoding) throws BaseException {
     List<TSEncoding> list = new ArrayList<>();
     for (String s : encoding) {
       switch (s) {
@@ -1748,51 +2770,119 @@ public class IotDBServiceImpl implements IotDBService {
         case "GORILLA":
           list.add(TSEncoding.GORILLA);
           break;
+        default:
+          throw new BaseException(ErrorCode.DB_ENCODING_WRONG, ErrorCode.DB_ENCODING_WRONG_MSG);
       }
     }
     return list;
   }
 
-  private List<Object> handleValueStr(List<String> values, List<TSDataType> types)
+  private TSEncoding handleEncodingStr(String encoding) throws BaseException {
+    TSEncoding tsEncoding;
+    switch (encoding) {
+      case "PLAIN":
+        tsEncoding = TSEncoding.PLAIN;
+        break;
+      case "PLAIN_DICTIONARY":
+        tsEncoding = TSEncoding.PLAIN_DICTIONARY;
+        break;
+      case "RLE":
+        tsEncoding = TSEncoding.RLE;
+        break;
+      case "DIFF":
+        tsEncoding = TSEncoding.DIFF;
+        break;
+      case "TS_2DIFF":
+        tsEncoding = TSEncoding.TS_2DIFF;
+        break;
+      case "BITMAP":
+        tsEncoding = TSEncoding.BITMAP;
+        break;
+      case "GORILLA_V1":
+        tsEncoding = TSEncoding.GORILLA_V1;
+        break;
+      case "REGULAR":
+        tsEncoding = TSEncoding.REGULAR;
+        break;
+      case "GORILLA":
+        tsEncoding = TSEncoding.GORILLA;
+        break;
+      default:
+        throw new BaseException(ErrorCode.DB_ENCODING_WRONG, ErrorCode.DB_ENCODING_WRONG_MSG);
+    }
+    return tsEncoding;
+  }
+
+  private List<CompressionType> handleCompressionStr(List<String> compression)
       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<CompressionType> list = new ArrayList<>();
+    for (String s : compression) {
+      switch (s) {
+        case "UNCOMPRESSED":
+          list.add(CompressionType.UNCOMPRESSED);
+          break;
+        case "SNAPPY":
+          list.add(CompressionType.SNAPPY);
+          break;
+        case "GZIP":
+          list.add(CompressionType.GZIP);
+          break;
+        case "LZ4":
+          list.add(CompressionType.LZ4);
+          break;
+        case "LZO":
+          list.add(CompressionType.LZO);
+          break;
+        case "PLA":
+          list.add(CompressionType.PLA);
+          break;
+        case "PAA":
+          list.add(CompressionType.PAA);
+          break;
+        case "SDT":
+          list.add(CompressionType.SDT);
+          break;
+        default:
+          throw new BaseException(
+              ErrorCode.DB_COMPRESSION_WRONG, ErrorCode.DB_COMPRESSION_WRONG_MSG);
       }
-      list.add(values.get(i));
     }
     return list;
   }
 
+  private CompressionType handleCompressionStr(String compression) throws BaseException {
+    CompressionType compressionType;
+    switch (compression) {
+      case "UNCOMPRESSED":
+        compressionType = CompressionType.UNCOMPRESSED;
+        break;
+      case "SNAPPY":
+        compressionType = CompressionType.SNAPPY;
+        break;
+      case "GZIP":
+        compressionType = CompressionType.GZIP;
+        break;
+      case "LZ4":
+        compressionType = CompressionType.LZ4;
+        break;
+      case "LZO":
+        compressionType = CompressionType.LZO;
+        break;
+      case "PLA":
+        compressionType = CompressionType.PLA;
+        break;
+      case "PAA":
+        compressionType = CompressionType.PAA;
+        break;
+      case "SDT":
+        compressionType = CompressionType.SDT;
+        break;
+      default:
+        throw new BaseException(ErrorCode.DB_COMPRESSION_WRONG, ErrorCode.DB_COMPRESSION_WRONG_MSG);
+    }
+    return compressionType;
+  }
+
   private List<TSDataType> handleTypeStr(List<String> types) throws BaseException {
     List<TSDataType> list = new ArrayList<>();
     for (String type : types) {
@@ -1824,21 +2914,31 @@ public class IotDBServiceImpl implements IotDBService {
     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);
+  private TSDataType handleTypeStr(String type) throws BaseException {
+    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);
     }
-    return conn;
+    return tsDataType;
   }
 
   public static SessionPool getSessionPool(Connection connection) throws BaseException {
@@ -1854,114 +2954,16 @@ public class IotDBServiceImpl implements IotDBService {
     }
     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);
+
+  private void closeSessionPool(SessionPool sessionPool) {
+    if (sessionPool != null) {
+      sessionPool.close();
     }
   }
 
-  /**
-   * 防止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);
-      }
+  private void closeResultSet(SessionDataSetWrapper sessionDataSetWrapper) {
+    if (sessionDataSetWrapper != null) {
+      sessionDataSetWrapper.close();
     }
   }
 }
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
index 4cc0ba2..1a4a252 100644
--- 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
@@ -125,7 +125,7 @@ public class MeasurementServiceImpl extends ServiceImpl<MeasurementMapper, Measu
       queryWrapper.eq("host", host);
       queryWrapper.eq("measurement_name", measurements.get(i));
       Measurement existMeasurement = measurementMapper.selectOne(queryWrapper);
-      // 未创建的测点
+      // Uncreated measurement
       if (existMeasurement == null) {
         Measurement mea = new Measurement();
         mea.setDescription(descriptions.get(i));
@@ -138,7 +138,7 @@ public class MeasurementServiceImpl extends ServiceImpl<MeasurementMapper, Measu
         }
         continue;
       }
-      // 已创建的测点更新描述
+      // Updated description of created measurement
       existMeasurement.setDescription(descriptions.get(i));
       int flag = measurementMapper.updateById(existMeasurement);
       if (flag <= 0) {
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
index a8b9490..ad09160 100644
--- 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
@@ -41,7 +41,7 @@ public class QueryServiceImpl extends ServiceImpl<QueryMapper, Query> implements
   @Autowired private QueryMapper queryMapper;
 
   @Override
-  public void save(Integer serverId, Query inputQuery) throws BaseException {
+  public Integer save(Integer serverId, Query inputQuery) throws BaseException {
     QueryWrapper queryWrapper = new QueryWrapper();
     queryWrapper.eq("connection_id", serverId);
     queryWrapper.eq("query_name", inputQuery.getQueryName());
@@ -52,7 +52,7 @@ public class QueryServiceImpl extends ServiceImpl<QueryMapper, Query> implements
       newQuery.setQueryName(inputQuery.getQueryName());
       newQuery.setSqls(inputQuery.getSqls());
       queryMapper.insert(newQuery);
-      return;
+      return queryMapper.selectOne(queryWrapper).getId();
     }
     throw new BaseException(ErrorCode.QUERY_EXIST, ErrorCode.QUERY_EXIST_MSG);
   }
diff --git a/backend/src/main/java/org/apache/iotdb/admin/service/impl/RoleServiceImpl.java b/backend/src/main/java/org/apache/iotdb/admin/service/impl/RoleServiceImpl.java
new file mode 100644
index 0000000..bca73bd
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/service/impl/RoleServiceImpl.java
@@ -0,0 +1,99 @@
+/*
+ * 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.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.mapper.RoleMapper;
+import org.apache.iotdb.admin.model.dto.IotDBRole;
+import org.apache.iotdb.admin.model.entity.Role;
+import org.apache.iotdb.admin.service.RoleService;
+
+import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
+import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Service;
+
+@Slf4j
+@Service
+public class RoleServiceImpl extends ServiceImpl<RoleMapper, Role> implements RoleService {
+
+  @Autowired private RoleMapper roleMapper;
+
+  @Override
+  public void upsertRoleInfo(String host, Integer port, IotDBRole iotDBRole) throws BaseException {
+    QueryWrapper<Role> wrapper = new QueryWrapper<>();
+    wrapper.eq("host", host);
+    wrapper.eq("port", port);
+    wrapper.eq("name", iotDBRole.getRoleName());
+    try {
+      Role role = roleMapper.selectOne(wrapper);
+      int flag = 0;
+      if (role == null) {
+        role = new Role();
+        role.setDescription(iotDBRole.getDescription());
+        role.setHost(host);
+        role.setPort(port);
+        role.setName(iotDBRole.getRoleName());
+        flag = roleMapper.insert(role);
+      } else {
+        role.setDescription(iotDBRole.getDescription());
+        flag = roleMapper.updateById(role);
+      }
+      if (flag == 0) {
+        throw new BaseException(
+            ErrorCode.UPSERT_ROLE_INFO_FAIL, ErrorCode.UPSERT_ROLE_INFO_FAIL_MSG);
+      }
+    } catch (Exception e) {
+      log.error(e.getMessage());
+      throw new BaseException(ErrorCode.UPSERT_ROLE_INFO_FAIL, ErrorCode.UPSERT_ROLE_INFO_FAIL_MSG);
+    }
+  }
+
+  @Override
+  public void deleteRoleInfo(String host, Integer port, String roleName) throws BaseException {
+    QueryWrapper<Role> wrapper = new QueryWrapper<>();
+    wrapper.eq("host", host);
+    wrapper.eq("port", port);
+    wrapper.eq("name", roleName);
+    try {
+      roleMapper.delete(wrapper);
+    } catch (Exception e) {
+      log.error(e.getMessage());
+      throw new BaseException(ErrorCode.DELETE_ROLE_INFO_FAIL, ErrorCode.DELETE_ROLE_INFO_FAIL_MSG);
+    }
+  }
+
+  @Override
+  public Role getRoleInfo(String host, Integer port, String roleName) throws BaseException {
+    QueryWrapper<Role> wrapper = new QueryWrapper<>();
+    wrapper.eq("host", host);
+    wrapper.eq("port", port);
+    wrapper.eq("name", roleName);
+    try {
+      Role role = roleMapper.selectOne(wrapper);
+      return role;
+    } catch (Exception e) {
+      log.error(e.getMessage());
+      throw new BaseException(ErrorCode.GET_ROLE_INFO_FAIL, ErrorCode.GET_ROLE_INFO_FAIL_MSG);
+    }
+  }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/tool/ExportCsv.java b/backend/src/main/java/org/apache/iotdb/admin/tool/ExportCsv.java
new file mode 100644
index 0000000..a31431f
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/tool/ExportCsv.java
@@ -0,0 +1,214 @@
+/*
+ * 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.tool;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.config.FileProperties;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.RpcUtils;
+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.TSDataType;
+import org.apache.iotdb.tsfile.read.common.Field;
+import org.apache.iotdb.tsfile.read.common.RowRecord;
+
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.BufferedWriter;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.time.ZoneId;
+import java.time.ZonedDateTime;
+import java.time.format.DateTimeFormatter;
+import java.util.List;
+
+@Slf4j
+@Component
+public class ExportCsv {
+
+  private final Path fileStorageLocation;
+
+  @Autowired
+  public ExportCsv(FileProperties fileProperties) {
+    this.fileStorageLocation = Paths.get(fileProperties.getTempDir()).toAbsolutePath().normalize();
+  }
+
+  private static final String TARGET_FILE = "dump";
+
+  public String exportCsv(
+      String host, Integer port, String username, String password, String sql, String timeZone)
+      throws BaseException {
+    Session session = null;
+    try {
+      session = new Session(host, port, username, password);
+      session.open(false);
+
+      if (timeZone != null) {
+        session.setTimeZone(timeZone);
+      }
+      ZoneId zoneId = ZoneId.of(session.getTimeZone());
+
+      return dumpResult(sql, session, zoneId);
+    } catch (IoTDBConnectionException e) {
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      throw new BaseException(
+          ErrorCode.IMPORT_CSV_FAIL, ErrorCode.IMPORT_CSV_FAIL_MSG + e.getMessage());
+    } finally {
+      if (session != null) {
+        try {
+          session.close();
+        } catch (IoTDBConnectionException e) {
+          throw new BaseException(ErrorCode.CLOSE_DBCONN_FAIL, ErrorCode.CLOSE_DBCONN_FAIL_MSG);
+        }
+      }
+    }
+  }
+
+  private String dumpResult(String sql, Session session, ZoneId zoneId) throws BaseException {
+    final String fileName = TARGET_FILE + System.currentTimeMillis() + ".csv";
+    final String path = fileStorageLocation.resolve(fileName).toString();
+    File tf = new File(path);
+    try {
+      if (!tf.exists() && !tf.createNewFile()) {
+        throw new BaseException(ErrorCode.CREATE_FILE_FAIL, ErrorCode.CREATE_FILE_FAIL_MSG);
+      }
+    } catch (IOException | BaseException e) {
+      throw new BaseException(ErrorCode.CREATE_FILE_FAIL, ErrorCode.CREATE_FILE_FAIL_MSG);
+    }
+    log.info("Start exporting data from SQL statement:" + sql);
+    try (BufferedWriter bw = new BufferedWriter(new FileWriter(tf))) {
+      SessionDataSet sessionDataSet = session.executeQueryStatement(sql);
+      long startTime = System.currentTimeMillis();
+      // write data in csv file
+      List<String> columnNames = sessionDataSet.getColumnNames();
+      writeMetadata(bw, columnNames);
+      boolean isDataType = false;
+      if ("Time".equals(columnNames.get(0))) {
+        isDataType = true;
+      }
+      int line = writeResultSet(sessionDataSet, bw, zoneId, isDataType);
+      String runTime = System.currentTimeMillis() - startTime + "ms";
+      log.info("Export " + line + " line data from SQL:" + sql + ". Time consuming:" + runTime);
+      return fileName;
+    } catch (IoTDBConnectionException e) {
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (IOException e) {
+      throw new BaseException(ErrorCode.FILE_IO_FAIL, ErrorCode.FILE_IO_FAIL_MSG + e.getMessage());
+    } catch (StatementExecutionException e) {
+      throw new BaseException(
+          ErrorCode.EXPORT_CSV_FAIL, ErrorCode.EXPORT_CSV_FAIL_MSG + e.getMessage());
+    }
+  }
+
+  private void writeMetadata(BufferedWriter bw, List<String> columnNames) throws IOException {
+    for (int i = 0; i < columnNames.size() - 1; i++) {
+      bw.write(columnNames.get(i) + ",");
+    }
+    bw.write(columnNames.get(columnNames.size() - 1) + "\n");
+  }
+
+  private int writeResultSet(
+      SessionDataSet rs, BufferedWriter bw, ZoneId zoneId, boolean isDataType)
+      throws IOException, StatementExecutionException, IoTDBConnectionException {
+    int line = 0;
+    if (isDataType) {
+      while (rs.hasNext()) {
+        RowRecord rowRecord = rs.next();
+        List<Field> fields = rowRecord.getFields();
+        writeTime(rowRecord.getTimestamp(), bw, zoneId);
+        writeValue(fields, bw);
+        line++;
+      }
+    } else {
+      while (rs.hasNext()) {
+        RowRecord rowRecord = rs.next();
+        List<Field> fields = rowRecord.getFields();
+        writeValue(fields, bw);
+        line++;
+      }
+    }
+    return line;
+  }
+
+  private void writeTime(Long time, BufferedWriter bw, ZoneId zoneId) throws IOException {
+    ZonedDateTime dateTime;
+    String timestampPrecision = "ms";
+    String str =
+        RpcUtils.parseLongToDateWithPrecision(
+            DateTimeFormatter.ISO_OFFSET_DATE_TIME, time, zoneId, timestampPrecision);
+    bw.write(str + ",");
+  }
+
+  @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning
+  private void writeValue(List<Field> fields, BufferedWriter bw) throws IOException {
+    for (int j = 0; j < fields.size() - 1; j++) {
+      String value = fields.get(j).getStringValue();
+      if ("null".equalsIgnoreCase(value)) {
+        bw.write(",");
+      } else {
+        if (fields.get(j).getDataType() == TSDataType.TEXT) {
+          int location = value.indexOf("\"");
+          if (location > -1) {
+            if (location == 0 || value.charAt(location - 1) != '\\') {
+              bw.write("\"" + value.replace("\"", "\\\"") + "\",");
+            } else {
+              bw.write("\"" + value + "\",");
+            }
+          } else if (value.contains(",")) {
+            bw.write("\"" + value + "\",");
+          } else {
+            bw.write(value + ",");
+          }
+        } else {
+          bw.write(value + ",");
+        }
+      }
+    }
+    String lastValue = fields.get(fields.size() - 1).getStringValue();
+    if ("null".equalsIgnoreCase(lastValue)) {
+      bw.write("\n");
+    } else {
+      if (fields.get(fields.size() - 1).getDataType() == TSDataType.TEXT) {
+        int location = lastValue.indexOf("\"");
+        if (location > -1) {
+          if (location == 0 || lastValue.charAt(location - 1) != '\\') {
+            bw.write("\"" + lastValue.replace("\"", "\\\"") + "\"\n");
+          } else {
+            bw.write("\"" + lastValue + "\"\n");
+          }
+        } else if (lastValue.contains(",")) {
+          bw.write("\"" + lastValue + "\"\n");
+        } else {
+          bw.write(lastValue + "\n");
+        }
+      } else {
+        bw.write(lastValue + "\n");
+      }
+    }
+  }
+}
diff --git a/backend/src/main/java/org/apache/iotdb/admin/tool/ImportCsv.java b/backend/src/main/java/org/apache/iotdb/admin/tool/ImportCsv.java
new file mode 100644
index 0000000..368e49e
--- /dev/null
+++ b/backend/src/main/java/org/apache/iotdb/admin/tool/ImportCsv.java
@@ -0,0 +1,388 @@
+/*
+ * 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.tool;
+
+import org.apache.iotdb.admin.common.exception.BaseException;
+import org.apache.iotdb.admin.common.exception.ErrorCode;
+import org.apache.iotdb.admin.config.FileProperties;
+import org.apache.iotdb.admin.model.vo.ImportDataVO;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+import org.apache.iotdb.session.Session;
+import org.apache.iotdb.tsfile.common.constant.TsFileConstant;
+
+import lombok.extern.slf4j.Slf4j;
+import org.apache.commons.lang3.StringUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import java.io.*;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.text.SimpleDateFormat;
+import java.util.*;
+
+@Slf4j
+@Component
+public class ImportCsv {
+
+  private static final String[] STRING_TIME_FORMAT =
+      new String[] {
+        "yyyy-MM-dd'T'HH:mm:ss.SSSZ",
+        "yyyy/MM/dd HH:mm:ss.SSS",
+        "yyyy-MM-dd HH:mm:ss.SSS",
+        "yyyy.MM.dd HH:mm:ss.SSS",
+        "yyyy/MM/dd'T'HH:mm:ss.SSS",
+        "yyyy-MM-dd'T'HH:mm:ss.SSS",
+        "yyyy-MM-dd'T'HH:mm:ss.SSS",
+        "yyyy.MM.dd'T'HH:mm:ss.SSS",
+        "yyyy-MM-dd HH:mm:ss.SSSZZ",
+        "yyyy/MM/dd HH:mm:ss.SSSZZ",
+        "yyyy.MM.dd HH:mm:ss.SSSZZ",
+        "yyyy-MM-dd'T'HH:mm:ss.SSSZZ",
+        "yyyy/MM/dd'T'HH:mm:ss.SSSZZ",
+        "yyyy-MM-dd HH:mm:ss",
+        "yyyy/MM/dd HH:mm:ss",
+        "yyyy.MM.dd HH:mm:ss",
+        "yyyy-MM-dd'T'HH:mm:ss",
+        "yyyy/MM/dd'T'HH:mm:ss",
+        "yyyy.MM.dd'T'HH:mm:ss",
+        "yyyy-MM-dd HH:mm:ssZZ",
+        "yyyy/MM/dd HH:mm:ssZZ",
+        "yyyy.MM.dd HH:mm:ssZZ",
+        "yyyy-MM-dd'T'HH:mm:ssZZ",
+        "yyyy/MM/dd'T'HH:mm:ssZZ",
+        "yyyy.MM.dd'T'HH:mm:ssZZ",
+      };
+
+  private final Path fileStorageLocation;
+
+  @Autowired
+  public ImportCsv(FileProperties fileProperties) {
+    this.fileStorageLocation = Paths.get(fileProperties.getTempDir()).toAbsolutePath().normalize();
+  }
+
+  public ImportDataVO importCsv(
+      String host, Integer port, String username, String password, String filename, String timeZone)
+      throws BaseException {
+    Session session = null;
+    try {
+      session = new Session(host, port, username, password, false);
+      session.open(false);
+      if (timeZone != null) {
+        session.setTimeZone(timeZone);
+      }
+
+      File file = new File(filename);
+      if (file.isFile()) {
+        return loadDataFromCSV(file, session);
+      } else {
+        throw new BaseException(ErrorCode.UPLOAD_FILE_FAIL, ErrorCode.UPLOAD_FILE_FAIL_MSG);
+      }
+    } catch (IoTDBConnectionException e) {
+      throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+    } catch (StatementExecutionException e) {
+      throw new BaseException(
+          ErrorCode.IMPORT_CSV_FAIL, ErrorCode.IMPORT_CSV_FAIL_MSG + e.getMessage());
+    } finally {
+      if (session != null) {
+        try {
+          session.close();
+        } catch (IoTDBConnectionException e) {
+          throw new BaseException(ErrorCode.CLOSE_DBCONN_FAIL, ErrorCode.CLOSE_DBCONN_FAIL_MSG);
+        }
+      }
+    }
+  }
+
+  @SuppressWarnings("squid:S1135")
+  private ImportDataVO loadDataFromCSV(File file, Session session) throws BaseException {
+    log.info("Start import data from file:" + file.getName());
+    String errorFileName = "error" + System.currentTimeMillis() + ".txt";
+    File errorFile = new File(this.fileStorageLocation.resolve(errorFileName).toString());
+
+    try (BufferedReader br =
+            new BufferedReader(
+                new InputStreamReader(new FileInputStream(file), StandardCharsets.UTF_8));
+        BufferedWriter bw = new BufferedWriter(new FileWriter(errorFile))) {
+      String header = br.readLine();
+      String[] cols = splitCsvLine(header);
+      if (cols.length <= 1) {
+        throw new BaseException(
+            ErrorCode.FILE_FIRST_LINE_ILLEGAL, ErrorCode.FILE_FIRST_LINE_ILLEGAL_MSG);
+      }
+      for (int i = 1; i < cols.length; i++) {
+        if (!cols[i].startsWith("root.") || StringUtils.countMatches(cols[i], ".") < 2) {
+          throw new BaseException(
+              ErrorCode.FILE_FIRST_LINE_ILLEGAL, ErrorCode.FILE_FIRST_LINE_ILLEGAL_MSG);
+        }
+      }
+
+      List<String> devices = new ArrayList<>();
+      List<Long> times = new ArrayList<>();
+      List<List<String>> measurementsList = new ArrayList<>();
+      List<List<String>> valuesList = new ArrayList<>();
+      Map<String, List<Integer>> devicesToPositions = new HashMap<>();
+      Map<String, List<String>> devicesToMeasurements = new HashMap<>();
+
+      for (int i = 1; i < cols.length; i++) {
+        splitColToDeviceAndMeasurement(cols[i], devicesToPositions, devicesToMeasurements, i);
+      }
+
+      SimpleDateFormat timeFormatter = null;
+      boolean useFormatter = false;
+
+      int lineNumber = 0;
+      List<String> insertErrorInfo = new ArrayList<>();
+      String line;
+      while ((line = br.readLine()) != null) {
+        cols = splitCsvLine(line);
+        lineNumber++;
+        if (lineNumber == 1) {
+          timeFormatter = formatterInit(cols[0]);
+          useFormatter = (timeFormatter != null);
+        }
+        for (Map.Entry<String, List<Integer>> deviceToPositions : devicesToPositions.entrySet()) {
+          List<String> values = new ArrayList<>();
+          for (int position : deviceToPositions.getValue()) {
+            values.add(cols[position]);
+          }
+          boolean isAllBlank = true;
+          for (String value : values) {
+            if (value != null && !"".equals(value)) {
+              isAllBlank = false;
+              break;
+            }
+          }
+          if (isAllBlank) {
+            continue;
+          }
+          valuesList.add(values);
+
+          String device = deviceToPositions.getKey();
+          devices.add(device);
+
+          times.add(parseTime(cols[0], useFormatter, timeFormatter));
+
+          measurementsList.add(devicesToMeasurements.get(device));
+        }
+        if (lineNumber % 10000 == 0) {
+          try {
+            session.insertRecords(devices, times, measurementsList, valuesList);
+          } catch (StatementExecutionException e) {
+            if (e.getMessage().contains("failed to insert measurements")) {
+              insertErrorInfo.addAll(
+                  Arrays.asList(
+                      StringUtils.splitByWholeSeparator(
+                          e.getMessage(),
+                          "org.apache.iotdb.db.exception.StorageEngineException: ")));
+            } else {
+              throw new BaseException(
+                  ErrorCode.IMPORT_CSV_FAIL, ErrorCode.IMPORT_CSV_FAIL_MSG + e.getMessage());
+            }
+          } catch (IoTDBConnectionException e) {
+            throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+          }
+          devices = new ArrayList<>();
+          times = new ArrayList<>();
+          measurementsList = new ArrayList<>();
+          valuesList = new ArrayList<>();
+        }
+      }
+      try {
+        if (lineNumber % 10000 != 0) {
+          session.insertRecords(devices, times, measurementsList, valuesList);
+        }
+      } catch (StatementExecutionException e) {
+        if (e.getMessage().contains("failed to insert measurements")) {
+          insertErrorInfo.addAll(
+              Arrays.asList(
+                  StringUtils.splitByWholeSeparator(
+                      e.getMessage(), "org.apache.iotdb.db.exception.StorageEngineException: ")));
+        } else {
+          throw new BaseException(
+              ErrorCode.IMPORT_CSV_FAIL, ErrorCode.IMPORT_CSV_FAIL_MSG + e.getMessage());
+        }
+      } catch (IoTDBConnectionException e) {
+        throw new BaseException(ErrorCode.GET_SESSION_FAIL, ErrorCode.GET_SESSION_FAIL_MSG);
+      }
+
+      for (String s : insertErrorInfo) {
+        bw.write(s + "\n");
+      }
+      int errorCount = insertErrorInfo.size();
+      String fileDownloadUri = null;
+      if (errorCount > 0) {
+        fileDownloadUri = "/downloadFile/" + errorFileName;
+      }
+      Integer totalCount = lineNumber * (cols.length - 1);
+      return new ImportDataVO(totalCount, errorCount, fileDownloadUri);
+    } catch (FileNotFoundException e) {
+      throw new BaseException(ErrorCode.UPLOAD_FILE_FAIL, ErrorCode.UPLOAD_FILE_FAIL_MSG);
+    } catch (IOException e) {
+      throw new BaseException(ErrorCode.FILE_IO_FAIL, ErrorCode.FILE_IO_FAIL_MSG + e.getMessage());
+    } catch (ArrayIndexOutOfBoundsException e) {
+      throw new BaseException(ErrorCode.FILE_FORMAT_ILLEGAL, ErrorCode.FILE_FORMAT_ILLEGAL_MSG);
+    }
+  }
+
+  private long parseTime(String str, boolean useFormatter, SimpleDateFormat timeFormatter)
+      throws BaseException {
+    try {
+      if (useFormatter) {
+        return timeFormatter.parse(str).getTime();
+      } else {
+        return Long.parseLong(str);
+      }
+    } catch (Exception e) {
+      throw new BaseException(ErrorCode.FILE_TIME_ILLEGAL, ErrorCode.FILE_TIME_ILLEGAL_MSG);
+    }
+  }
+
+  private SimpleDateFormat formatterInit(String time) {
+
+    try {
+      Long.parseLong(time);
+      return null;
+    } catch (Exception ignored) {
+      // do nothing
+    }
+
+    for (String timeFormat : STRING_TIME_FORMAT) {
+      SimpleDateFormat format = new SimpleDateFormat(timeFormat);
+      try {
+        format.parse(time).getTime();
+        return format;
+      } catch (java.text.ParseException ignored) {
+        // do nothing
+      }
+    }
+    return null;
+  }
+
+  private void splitColToDeviceAndMeasurement(
+      String col,
+      Map<String, List<Integer>> devicesToPositions,
+      Map<String, List<String>> devicesToMeasurements,
+      int position)
+      throws BaseException {
+    if (col.length() > 0) {
+      if (col.charAt(col.length() - 1) == TsFileConstant.DOUBLE_QUOTE) {
+        int endIndex = col.lastIndexOf('"', col.length() - 2);
+        // if a double quotes with escape character
+        while (endIndex != -1 && col.charAt(endIndex - 1) == '\\') {
+          endIndex = col.lastIndexOf('"', endIndex - 2);
+        }
+        if (endIndex != -1 && (endIndex == 0 || col.charAt(endIndex - 1) == '.')) {
+          putDeviceAndMeasurement(
+              col.substring(0, endIndex - 1),
+              col.substring(endIndex),
+              devicesToPositions,
+              devicesToMeasurements,
+              position);
+        } else {
+          throw new BaseException(
+              ErrorCode.FILE_FIRST_LINE_ILLEGAL, ErrorCode.FILE_FIRST_LINE_ILLEGAL_MSG);
+        }
+      } else if (col.charAt(col.length() - 1) != TsFileConstant.DOUBLE_QUOTE
+          && col.charAt(col.length() - 1) != TsFileConstant.PATH_SEPARATOR_CHAR) {
+        int endIndex = col.lastIndexOf(TsFileConstant.PATH_SEPARATOR_CHAR);
+        if (endIndex < 0) {
+          putDeviceAndMeasurement("", col, devicesToPositions, devicesToMeasurements, position);
+        } else {
+          putDeviceAndMeasurement(
+              col.substring(0, endIndex),
+              col.substring(endIndex + 1),
+              devicesToPositions,
+              devicesToMeasurements,
+              position);
+        }
+      } else {
+        throw new BaseException(
+            ErrorCode.FILE_FIRST_LINE_ILLEGAL, ErrorCode.FILE_FIRST_LINE_ILLEGAL_MSG);
+      }
+    } else {
+      putDeviceAndMeasurement("", col, devicesToPositions, devicesToMeasurements, position);
+    }
+  }
+
+  private void putDeviceAndMeasurement(
+      String device,
+      String measurement,
+      Map<String, List<Integer>> devicesToPositions,
+      Map<String, List<String>> devicesToMeasurements,
+      int position) {
+    if (devicesToMeasurements.get(device) == null && devicesToPositions.get(device) == null) {
+      List<String> measurements = new ArrayList<>();
+      measurements.add(measurement);
+      devicesToMeasurements.put(device, measurements);
+      List<Integer> positions = new ArrayList<>();
+      positions.add(position);
+      devicesToPositions.put(device, positions);
+    } else {
+      devicesToMeasurements.get(device).add(measurement);
+      devicesToPositions.get(device).add(position);
+    }
+  }
+
+  private String[] splitCsvLine(String path) throws BaseException {
+    List<String> nodes = new ArrayList<>();
+    int startIndex = 0;
+    for (int i = 0; i < path.length(); i++) {
+      if (path.charAt(i) == ',') {
+        nodes.add(path.substring(startIndex, i));
+        startIndex = i + 1;
+      } else if (path.charAt(i) == '"') {
+        int[] result = nextNode(path, nodes, '"', startIndex, i);
+        startIndex = result[0];
+        i = result[1];
+      } else if (path.charAt(i) == '\'') {
+        int[] result = nextNode(path, nodes, '\'', startIndex, i);
+        startIndex = result[0];
+        i = result[1];
+      }
+    }
+    if (path.charAt(path.length() - 1) == ',') {
+      nodes.add("");
+    }
+    if (startIndex <= path.length() - 1) {
+      nodes.add(path.substring(startIndex));
+    }
+    return nodes.toArray(new String[0]);
+  }
+
+  private int[] nextNode(String path, List<String> nodes, char enclose, int startIndex, int i)
+      throws BaseException {
+    int endIndex = path.indexOf(enclose, i + 1);
+    // if a double quotes with escape character
+    while (endIndex != -1 && path.charAt(endIndex - 1) == '\\') {
+      endIndex = path.indexOf(enclose, endIndex + 1);
+    }
+    if (endIndex != -1 && (endIndex == path.length() - 1 || path.charAt(endIndex + 1) == ',')) {
+      nodes.add(path.substring(startIndex + 1, endIndex));
+      i = endIndex + 1;
+      startIndex = endIndex + 2;
+      return new int[] {startIndex, i};
+    } else {
+      throw new BaseException(ErrorCode.FILE_LINE_ILLEGAL, ErrorCode.FILE_LINE_ILLEGAL_MSG + path);
+    }
+  }
+}
diff --git a/backend/src/main/resources/application-dev.properties b/backend/src/main/resources/application-dev.properties
index 4a14685..b547fb9 100644
--- a/backend/src/main/resources/application-dev.properties
+++ b/backend/src/main/resources/application-dev.properties
@@ -17,14 +17,23 @@
 # under the License.
 #
 
-# 指定日志配置文件的位置
+# Designate the log configuration file
 logging.config=classpath:log4j2.xml
 
-# 配置端口号和上下文根
+# Set port and context path
 server.port=8080
 server.servlet.context-path=/api
 
-# 指定数据源和连接驱动
-# 如下配置数据源的方式会导致项目重新打包后数据丢失,仅为了开发时方便测试,实际部署项目时请参考application-prod.properties文件配置
+# The following data source configuration method will cause data loss after the project is repackaged.
+# To facilitate testing during development, refer to the application-prod.properties file for configuration during actual project deployment
 spring.datasource.url=jdbc:sqlite::resource:sqlite/iotdb.db
-spring.datasource.driver-class-name=org.sqlite.JDBC
\ No newline at end of file
+spring.datasource.driver-class-name=org.sqlite.JDBC
+
+# Enable the multipart uploading function
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.file-size-threshold=2KB
+spring.servlet.multipart.max-file-size=200MB
+spring.servlet.multipart.max-request-size=215MB
+
+# All files generated during CSV import and export are stored in this folder
+file.temp-dir=./tempFile
\ No newline at end of file
diff --git a/backend/src/main/resources/application-prod.properties b/backend/src/main/resources/application-prod.properties
index b6b57f8..e830534 100644
--- a/backend/src/main/resources/application-prod.properties
+++ b/backend/src/main/resources/application-prod.properties
@@ -17,14 +17,19 @@
 # under the License.
 #
 
-# 指定日志配置文件的位置
 logging.config=classpath:log4j2-prod.xml
 
-# 配置端口号和上下文根
-server.port=8081
+server.port=9089
 server.servlet.context-path=/api
 
-# 指定数据源和连接驱动
-# 请将backend/src/main/resources/sqlite下的iotdb.db文件复制一份到你的服务器上,并将以下路径修改为你的iotdb.db文件路径
+# Please make a copy of the iotdb.db file in the backend/src/main/resources/sqlite folder to your server and change the path below to your iotdb.db file path
 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
+spring.datasource.driver-class-name=org.sqlite.JDBC
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.file-size-threshold=2KB
+spring.servlet.multipart.max-file-size=200MB
+spring.servlet.multipart.max-request-size=215MB
+
+# All files generated during CSV import and export are stored in this folder
+file.temp-dir=./tempFile
\ No newline at end of file
diff --git a/backend/src/main/resources/application-test.properties b/backend/src/main/resources/application-test.properties
index 2d959b0..7cd752d 100644
--- a/backend/src/main/resources/application-test.properties
+++ b/backend/src/main/resources/application-test.properties
@@ -23,4 +23,11 @@ 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
+spring.datasource.driver-class-name=org.sqlite.JDBC
+
+spring.servlet.multipart.enabled=true
+spring.servlet.multipart.file-size-threshold=2KB
+spring.servlet.multipart.max-file-size=200MB
+spring.servlet.multipart.max-request-size=215MB
+
+file.temp-dir=./tempFile
\ No newline at end of file
diff --git a/backend/src/main/resources/application.properties b/backend/src/main/resources/application.properties
index 5aa2fca..e9e7335 100644
--- a/backend/src/main/resources/application.properties
+++ b/backend/src/main/resources/application.properties
@@ -17,5 +17,5 @@
 # under the License.
 #
 
-# 指定配置文件。dev、prod、test分别表示开发、生产、测试环境
+# Designate the configuration file
 spring.profiles.active=dev
\ No newline at end of file
diff --git a/backend/src/main/resources/banner.txt b/backend/src/main/resources/banner.txt
new file mode 100644
index 0000000..14108eb
--- /dev/null
+++ b/backend/src/main/resources/banner.txt
@@ -0,0 +1,8 @@
+ ██          ██████████ ███████   ██████         ██       ██                 ██     ██                               ██
+░██         ░░░░░██░░░ ░██░░░░██ ░█░░░░██       ░██      ░██                ░██    ░██                              ░██
+░██  ██████     ░██    ░██    ░██░█   ░██       ░██   █  ░██  ██████  ██████░██  ██░██       █████  ███████   █████ ░██
+░██ ██░░░░██    ░██    ░██    ░██░██████   █████░██  ███ ░██ ██░░░░██░░██░░█░██ ██ ░██████  ██░░░██░░██░░░██ ██░░░██░██████
+░██░██   ░██    ░██    ░██    ░██░█░░░░ ██░░░░░ ░██ ██░██░██░██   ░██ ░██ ░ ░████  ░██░░░██░███████ ░██  ░██░██  ░░ ░██░░░██
+░██░██   ░██    ░██    ░██    ██ ░█    ░██      ░████ ░░████░██   ░██ ░██   ░██░██ ░██  ░██░██░░░░  ░██  ░██░██   ██░██  ░██
+░██░░██████     ░██    ░███████  ░███████       ░██░   ░░░██░░██████ ░███   ░██░░██░██████ ░░██████ ███  ░██░░█████ ░██  ░██
+░░  ░░░░░░      ░░     ░░░░░░░   ░░░░░░░        ░░       ░░  ░░░░░░  ░░░    ░░  ░░ ░░░░░    ░░░░░░ ░░░   ░░  ░░░░░  ░░   ░░
diff --git a/backend/src/main/resources/file/template.csv b/backend/src/main/resources/file/template.csv
new file mode 100644
index 0000000..19f0233
--- /dev/null
+++ b/backend/src/main/resources/file/template.csv
@@ -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.
+
+-->
+
+Time,root.group1.dev.s1,root.group1.dev.s2,root.group2.dev.s
+1,100,150,300
+3,200,300,320
+10,300,,400
+(Before importing data from this file, delete the license comments and the following contents.)
+CSV file format:
+    The file is split with ",", and the first column is "Time" on the first line, followed by the measurement name.
+    The first column from the second row is the timestamp, followed by the imported data.
+    If you do not need to import data for certain measurement at certain timestamps, do not enter them. Refer to line 4 of this file.
+    The timestamp format can be number, yyyy-MM-dd'T'HH:mm:ss, yyyy-MM-dd HH:mm:ss, yyyy-MM-dd'T'HH:mm:ss.SSS and so on.
+    The timestamp format and column number of each row must be the same.
+    Note:fields containing , should be escaped by \.
+You can use the export CSV tool to export data to get more templates.
\ No newline at end of file
diff --git a/backend/src/main/resources/log4j2-prod.xml b/backend/src/main/resources/log4j2-prod.xml
index 3a0f519..9bea303 100644
--- a/backend/src/main/resources/log4j2-prod.xml
+++ b/backend/src/main/resources/log4j2-prod.xml
@@ -21,7 +21,6 @@
 <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>
@@ -101,7 +100,7 @@
     </appenders>
 
     <loggers>
-        <!--level日志级别: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
+        <!--level: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
         <Root level="${log.root.level}">
             <AppenderRef ref="STDOUT"/>
             <AppenderRef ref="ROLLING_INFO"/>
diff --git a/backend/src/main/resources/log4j2.xml b/backend/src/main/resources/log4j2.xml
index 21772ee..c4660f6 100644
--- a/backend/src/main/resources/log4j2.xml
+++ b/backend/src/main/resources/log4j2.xml
@@ -21,7 +21,6 @@
 <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>
@@ -101,7 +100,7 @@
     </appenders>
 
     <loggers>
-        <!--level日志级别: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
+        <!--level: ALL < TRACE < DEBUG < INFO < WARN < ERROR < FATAL < OFF -->
         <Root level="${log.root.level}">
             <AppenderRef ref="STDOUT"/>
             <AppenderRef ref="ROLLING_INFO"/>
diff --git a/backend/src/main/resources/sqlite/iotdb.db b/backend/src/main/resources/sqlite/iotdb.db
index 5a23664..9700849 100644
Binary files a/backend/src/main/resources/sqlite/iotdb.db and b/backend/src/main/resources/sqlite/iotdb.db differ
diff --git a/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java b/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java
deleted file mode 100644
index 882ff68..0000000
--- a/backend/src/test/java/org/apache/iotdb/admin/DemoJDBC.java
+++ /dev/null
@@ -1,38 +0,0 @@
-/*
- * 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
index adb49fa..cd9d2e8 100644
--- a/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
@@ -38,7 +38,6 @@ import java.util.Calendar;
 
 @SpringBootTest
 class ConnectionControllerTest {
-
   private MockMvc mvc;
 
   @Autowired private WebApplicationContext wac;
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
index adb51de..2686573 100644
--- a/backend/src/test/java/org/apache/iotdb/admin/controller/IotDBControllerTest.java
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/IotDBControllerTest.java
@@ -40,7 +40,6 @@ import java.util.Calendar;
 @SpringBootTest
 @TestMethodOrder(MethodOrderer.OrderAnnotation.class)
 class IotDBControllerTest {
-
   private MockMvc mvc;
   @Autowired private WebApplicationContext wac;
 
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
index f392b35..7b1ba85 100644
--- a/backend/src/test/java/org/apache/iotdb/admin/controller/QueryControllerTest.java
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/QueryControllerTest.java
@@ -36,8 +36,6 @@ import org.springframework.web.context.WebApplicationContext;
 import java.net.InetAddress;
 import java.util.Calendar;
 
-import static org.junit.jupiter.api.Assertions.*;
-
 @SpringBootTest
 class QueryControllerTest {
 
diff --git a/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java b/backend/src/test/java/org/apache/iotdb/admin/controller/UserControllerTest.java
similarity index 59%
copy from backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
copy to backend/src/test/java/org/apache/iotdb/admin/controller/UserControllerTest.java
index adb49fa..574aa0c 100644
--- a/backend/src/test/java/org/apache/iotdb/admin/controller/ConnectionControllerTest.java
+++ b/backend/src/test/java/org/apache/iotdb/admin/controller/UserControllerTest.java
@@ -24,20 +24,18 @@ 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 {
+class UserControllerTest {
 
   private MockMvc mvc;
 
@@ -45,57 +43,23 @@ class ConnectionControllerTest {
 
   private String token = getToken();
 
-  @Transactional
-  @Rollback
   @Test
-  void saveOrUpdateConnection() throws Exception {
+  void login() 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());
-  }
... 16287 lines suppressed ...