物联网平台ThingsBoard开发环境构建记:从零到一的全过程与踩坑实录

前言

最近因项目需要,我们准备基于ThingsBoard开发一套医院后勤管理系统。ThingsBoard作为一款开源物联网平台,功能强大,但它的开发环境搭建并不像官方文档描述的那么“丝滑”。从源码编译到数据库初始化,再到服务启动,我们踩了不少坑。本文详细记录了整个构建过程以及遇到的七个典型问题及其解决方案,希望能为同样准备上手ThingsBoard的开发者提供一份避坑指南。

一、环境准备

在开始之前,请确保以下软件已正确安装:

组件推荐版本备注
JDKOpenJDK 17ThingsBoard 4.3.x 要求 JDK 17
Maven3.6+用于构建后端
Node.js18.x 或 20.x用于前端编译
Yarn1.22.x前端包管理器
PostgreSQL13+需要创建两个数据库
Git最新版克隆源码
Docker (可选)20.10+用于快速启动数据库

注意:Windows 用户强烈建议使用 WSL2 + Ubuntu 环境,可避免许多路径和脚本兼容性问题。本文的踩坑经历基于原生 Windows 环境,因此更具参考价值。

二、源码获取与编译

2.1 克隆代码

git clone https://github.com/thingsboard/thingsboard.git
cd thingsboard

2.2 配置Maven仓库镜像(关键!)

踩坑1:gradle-maven-plugin 1.0.12 找不到

编译一开始就遇到:

Plugin org.thingsboard:gradle-maven-plugin:1.0.12 or one of its dependencies could not be resolved

这个插件是 ThingsBoard 自定义的,默认 Maven 中央仓库中没有,阿里云镜像也没有。

踩坑2:org.thingsboard.langchain4j:langchain4j-bom:1.8.0-TB 找不到

同样,这个依赖也不在公共仓库中。

解决办法:在 Maven 的 settings.xml 中增加 ThingsBoard 官方仓库的镜像,让 Maven 能够从 ThingsBoard 自己的仓库中下载这些构件。

编辑你使用的 settings.xml(全局路径如 I:\apache-maven-3.9.9\conf\settings.xml,用户级路径如 C:\Users\<用户名>\.m2\settings.xml),在 <mirrors> 标签内添加:

<mirror>
    <id>thingsboard-repo</id>
    <mirrorOf>*</mirrorOf>
    <name>thingsboard-repo</name>
    <url>https://repo.thingsboard.io/artifactory/libs-release-public</url>
</mirror>

注意<mirrorOf>*</mirrorOf> 会拦截所有仓库请求,将其重定向到 ThingsBoard 仓库。如果担心其他依赖下载变慢,可以只镜像特定的仓库 ID,但为了简单,这里用 * 也没问题,因为 ThingsBoard 仓库本身也代理了大量公共依赖。

添加后保存,重新执行编译命令即可正常下载这些专属依赖。

2.3 编译

mvn clean install -DskipTests

编译后为三个操作系统打包:

  • redhat linux : thingsboard.rpm
  • debian: thingsboard.deb
  • windows: thingsboard-windows.zip

我使用rocky linux,并没有采用thingsboard.rpm,而是把bin, conf, control, data目录,还有两个jar包:thingsboard-4.3.1.1.jar,thingsboard-4.3.1.1-boot.jar使用7zip打包为thingsboard-linux.7z

上传到操作系统,使用如下命令解压:

7z x thingsboard-linux.7z -o/feng/thingsboard

踩坑3:gradle-maven-plugin 下载 gradle-7.3.3-bin.zip 卡死

编译过程中,edqs 模块需要执行 gradle-maven-plugin,该插件会尝试从 https://services.gradle.org/distributions/ 下载 gradle-7.3.3-bin.zip。由于网络原因,下载非常缓慢甚至卡死。

解决方法

  1. 手动下载 gradle-7.3.3-bin.zip(可从腾讯云镜像或 Gradle 官网获取)。
  2. 放入 Gradle Wrapper 缓存目录:C:\Users\<用户名>\.gradle\wrapper\dists\gradle-7.3.3-bin\ 下的某个子目录中(如 6a41zxkdtcxs8rphpq6y0069z),并删除原有的 .part 临时文件。
  3. 重新编译,插件会直接使用本地缓存,跳过网络下载。

踩坑4:winsw-2.0.1-bin.exe 下载失败

编译 edqs 模块时,日志显示:

Could not find artifact com.sun.winsw:winsw:exe:bin:2.0.1

winsw 是一个用于将 Java 程序包装为 Windows 服务的工具,它的二进制文件同样不在公共仓库中。

解决方法

  1. 手动下载 winsw-2.0.1-bin.exe(可从 Jenkins 仓库获取:https://repo.jenkins-ci.org/releases/com/sun/winsw/winsw/2.0.1/winsw-2.0.1-bin.exe)。
  2. 使用 Maven 命令将其安装到本地仓库:
    mvn install:install-file -Dfile=winsw-2.0.1-bin.exe -DgroupId=com.sun.winsw -DartifactId=winsw -Dversion=2.0.1 -Dpackaging=exe -Dclassifier=bin
    
  3. 重新编译,依赖解析成功。

2.4 前端说明

其实编译时前端也一块儿编译了。这里说明一下ThingsBoard 的前端,它分为两部分:ui-ngx(主 UI)和 msa/web-ui(微服务版本的 UI 包装)。后者在编译时会使用 pkg 工具将 Node.js 应用打包成可执行文件。

踩坑5:frontend-maven-plugin 自动添加代理参数

执行 mvn install 时,日志显示:

Found proxies: [netbeans-default-proxy{protocol='http', host='127.0.0.1', port=4780}]
Running 'yarn run build:prod --https-proxy=http://127.0.0.1:4780 --proxy=http://127.0.0.1:4780'
Error: Unknown arguments: https-proxy, proxy

这是因为 Maven Settings 中激活了一个名为 netbeans-default-proxy 的代理(通常由 NetBeans IDE 自动添加),导致 frontend-maven-plugin 将代理参数传递给 yarn,而 Angular CLI 不识别这些参数。

解决方法
编辑 ~/.m2/settings.xml,找到 <proxies> 标签,将 netbeans-default-proxy<active>true</active> 改为 <active>false</active>,或直接删除该 proxy 块。保存后重新编译,代理参数不再出现。

踩坑6:pkg 打包时下载 Node 二进制文件失败

编译 msa/web-ui 模块时,执行 yarn run pkg 会调用 pkg-fetch 下载 Node.js 的预编译二进制文件(例如 node-v22.17.1-win-x64node-v22.17.1-linux-x64)。由于网络原因,下载经常失败,报错类似:

Error! Network error during fetch: request to https://github.com/yao-pkg/pkg-fetch/releases/download/v3.5/node-v22.17.1-linux-x64 failed

解决方法

  1. 手动从 GitHub Releases 下载所需的二进制文件:
    • node-v22.17.1-win-x64
    • node-v22.17.1-linux-x64
      下载地址:https://github.com/yao-pkg/pkg-fetch/releases/tag/v3.5(根据日志中的 tag 版本选择)
  2. 设置环境变量 PKG_CACHE_PATH,指向一个你创建的缓存目录,例如:
    set PKG_CACHE_PATH=C:\Users\<用户名>\.pkg-cache
    
  3. 在该缓存目录下创建版本子目录,如 v3.5,然后将下载的文件放入其中,并重命名为:
    • fetched-v22.17.1-win-x64
    • fetched-v22.17.1-linux-x64
  4. 重新编译 msa/web-ui,pkg 会直接从缓存中读取,不再尝试网络下载。

注意:pkg 在打包时会同时需要 Windows 和 Linux 的二进制(因为目标平台包括两者),因此两个文件都需要准备。

三、数据库初始化

3.1 准备 PostgreSQL

首先确保 PostgreSQL 服务已启动,并创建两个数据库:

CREATE DATABASE thingsboard;
CREATE DATABASE thingsboard_events;

3.2 执行初始化脚本

官方文档给出的linux命令是:

cd bin/install
./install_dev_db.sh

实际上install_dev_db.sh脚本使用了这个配置文件:conf/thingsboard.yml,其中有个错误:

value_bytes_size: "${SECURITY_API_KEY_VALUE_PREFIX:64}"

应该改为:

value_bytes_size: "${SECURITY_API_KEY_VALUE_BYTES_SIZE:64}"

thingsboard.yml包含了上百个环境变量,最好在install_dev_db.sh脚本中设置环境变量而不必再profile文件中设置环境变量:

#!/bin/bash

BASE=/feng/thingsboard
jarfile="${BASE}/thingsboard-4.3.1.1-boot.jar"
installDir=${BASE}/data
loadDemo=true
upgrade=false

# 错误处理
error_exit() {
    echo -e "\033[31m[ERROR] $1\033[0m" >&2
    exit 1
}

# 检查 JAR 文件
if [ ! -f "$jarfile" ]; then
    error_exit "JAR file not found: $jarfile"
fi

# 环境变量
export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@"
export LOADER_PATH="${BASE}/conf,${BASE}/extensions"
export SQL_DATA_FOLDER="${SQL_DATA_FOLDER:-/tmp}"
export SPRING_MVC_ASYNC_REQUEST_TIMEOUT="300000"
export SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE="50MB"
export SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE="50MB"
export SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING="last"
export SPRING_JPA_DIALECT="org.thingsboard.server.dao.ThingsboardPostgreSQLDialect"
export JAVAX_PERSISTENCE_QUERY_TIMEOUT="300000"
export SPRING_DRIVER_CLASS_NAME="org.postgresql.Driver"
export SPRING_DATASOURCE_URL="jdbc:postgresql://8.141.5.220:15432/thingsboard?connectTimeout=30&socketTimeout=30"
export SPRING_DATASOURCE_USERNAME="postgres"
export SPRING_DATASOURCE_PASSWORD="123456"
export SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD="0"
export SPRING_DATASOURCE_MAXIMUM_POOL_SIZE="16"
export SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS="false"

export SPRING_DEDICATED_EVENTS_DATASOURCE_ENABLED="false"
export SPRING_EVENTS_DATASOURCE_DRIVER_CLASS_NAME="org.postgresql.Driver"
export SPRING_EVENTS_DATASOURCE_URL="jdbc:postgresql://8.141.5.220:15432/thingsboard_events?connectTimeout=30&socketTimeout=30"
export SPRING_EVENTS_DATASOURCE_USERNAME="postgres"
export SPRING_EVENTS_DATASOURCE_PASSWORD="123456"
export SPRING_EVENTS_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD="0"
export SPRING_EVENTS_DATASOURCE_MAXIMUM_POOL_SIZE="4"
export SPRING_EVENTS_DATASOURCE_HIKARI_REGISTER_MBEANS="false"

# 确保运行用户
if [ "$EUID" -eq 0 ]; then
    run_user="thingsboard"
    if ! id "thingsboard" &>/dev/null; then
        useradd -m -s /bin/bash thingsboard
    fi
    # 创建日志目录并授权
    mkdir -p /var/log/thingsboard
    chown -R "$run_user":"$run_user" /var/log/thingsboard
    mkdir -p "$installDir"
    chown -R "$run_user":"$run_user" "$installDir"
    mkdir -p "${BASE}/logs" 2>/dev/null
    chown -R "$run_user":"$run_user" "$BASE" 2>/dev/null || true
else
    run_user="$USER"
fi

echo "Using system user: $run_user"
echo "Database URL: $SPRING_DATASOURCE_URL"
echo "Starting ThingsBoard database installation..."

# 使用 su 切换用户,执行 java -cp 并指定正确的 Launcher 类
su -s /bin/bash - "$run_user" <<EOF
export JAVA_OPTS="$JAVA_OPTS"
export LOADER_PATH="$LOADER_PATH"
export SQL_DATA_FOLDER="$SQL_DATA_FOLDER"
export SPRING_MVC_ASYNC_REQUEST_TIMEOUT="$SPRING_MVC_ASYNC_REQUEST_TIMEOUT"
export SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE="$SPRING_SERVLET_MULTIPART_MAX_FILE_SIZE"
export SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE="$SPRING_SERVLET_MULTIPART_MAX_REQUEST_SIZE"
export SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING="$SPRING_JPA_PROPERTIES_HIBERNATE_ORDER_BY_DEFAULT_NULL_ORDERING"
export SPRING_JPA_DIALECT="$SPRING_JPA_DIALECT"
export JAVAX_PERSISTENCE_QUERY_TIMEOUT="$JAVAX_PERSISTENCE_QUERY_TIMEOUT"
export SPRING_DRIVER_CLASS_NAME="$SPRING_DRIVER_CLASS_NAME"
export SPRING_DATASOURCE_URL="$SPRING_DATASOURCE_URL"
export SPRING_DATASOURCE_USERNAME="$SPRING_DATASOURCE_USERNAME"
export SPRING_DATASOURCE_PASSWORD="$SPRING_DATASOURCE_PASSWORD"
export SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD="$SPRING_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD"
export SPRING_DATASOURCE_MAXIMUM_POOL_SIZE="$SPRING_DATASOURCE_MAXIMUM_POOL_SIZE"
export SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS="$SPRING_DATASOURCE_HIKARI_REGISTER_MBEANS"
export SPRING_DEDICATED_EVENTS_DATASOURCE_ENABLED="$SPRING_DEDICATED_EVENTS_DATASOURCE_ENABLED"
export SPRING_EVENTS_DATASOURCE_DRIVER_CLASS_NAME="$SPRING_EVENTS_DATASOURCE_DRIVER_CLASS_NAME"
export SPRING_EVENTS_DATASOURCE_URL="$SPRING_EVENTS_DATASOURCE_URL"
export SPRING_EVENTS_DATASOURCE_USERNAME="$SPRING_EVENTS_DATASOURCE_USERNAME"
export SPRING_EVENTS_DATASOURCE_PASSWORD="$SPRING_EVENTS_DATASOURCE_PASSWORD"
export SPRING_EVENTS_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD="$SPRING_EVENTS_DATASOURCE_HIKARI_LEAK_DETECTION_THRESHOLD"
export SPRING_EVENTS_DATASOURCE_MAXIMUM_POOL_SIZE="$SPRING_EVENTS_DATASOURCE_MAXIMUM_POOL_SIZE"
export SPRING_EVENTS_DATASOURCE_HIKARI_REGISTER_MBEANS="$SPRING_EVENTS_DATASOURCE_HIKARI_REGISTER_MBEANS"

# 使用 -cp 和正确的 PropertiesLauncher 类(包含 launch 路径)
java -cp "$jarfile" \
    -Dloader.main=org.thingsboard.server.ThingsboardInstallApplication \
    -Dinstall.data_dir="$installDir" \
    -Dinstall.load_demo=$loadDemo \
    -Dspring.jpa.hibernate.ddl-auto=none \
    -Dinstall.upgrade=$upgrade \
    -Djava.net.preferIPv4Stack=true \
    org.springframework.boot.loader.launch.PropertiesLauncher
EOF

exit_code=$?
if [ $exit_code -ne 0 ]; then
    echo -e "\033[31mThingsBoard DB installation failed with exit code $exit_code!\033[0m"
    if [ -f /var/log/thingsboard/thingsboard.log ]; then
        echo "Last 50 lines of /var/log/thingsboard/thingsboard.log:"
        tail -50 /var/log/thingsboard/thingsboard.log
    fi
    exit $exit_code
else
    echo -e "\033[32mThingsBoard DB installation completed successfully.\033[0m"
fi

执行后的效果为:

[root@iZ2ze6qcuxrmhddeb4m9xuZ thingsboard]# rm -f /var/log/thingsboard/thingsboard.log
[root@iZ2ze6qcuxrmhddeb4m9xuZ thingsboard]# bash bin/install/install_dev_db.sh 
Using system user: thingsboard
Database URL: jdbc:postgresql://8.141.5.220:15432/thingsboard?connectTimeout=30&socketTimeout=30
Starting ThingsBoard database installation...
Last login: Mon May 11 13:00:10 CST 2026
  _____ _     _                 ____                      _
 |_   _| |__ (_)_ __   __ _ ___| __ )  ___   __ _ _ __ __| |
   | | | '_ \| | '_ \ / _` / __|  _ \ / _ \ / _` | '__/ _` |
   | | | | | | | | | | (_| \__ \ |_) | (_) | (_| | | | (_| |
   |_| |_| |_|_|_| |_|\__, |___/____/ \___/ \__,_|_|  \__,_|
                      |___/

 ===========================================================
 :: ThingsBoard ::       (v4.3.1.1)
 ===========================================================

ThingsBoard DB installation completed successfully.
[root@iZ2ze6qcuxrmhddeb4m9xuZ thingsboard]# cat /var/log/thingsboard/thingsboard.log
2026-05-11 13:02:38,823 [background-preinit] INFO  o.h.validator.internal.util.Version - HV000001: Hibernate Validator 8.0.3.Final
2026-05-11 13:02:39,131 [main] INFO  o.t.s.ThingsboardInstallApplication - Starting ThingsboardInstallApplication v4.3.1.1 using Java 17.0.14 with PID 4113505 (/feng/thingsboard/thingsboard-4.3.1.1-boot.jar started by thingsboard in /home/thingsboard)
2026-05-11 13:02:39,132 [main] INFO  o.t.s.ThingsboardInstallApplication - The following 1 profile is active: "install"
2026-05-11 13:02:44,338 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2026-05-11 13:02:44,339 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in LAZY mode.
2026-05-11 13:02:44,671 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 309 ms. Found 7 JPA repository interfaces.
2026-05-11 13:02:44,677 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2026-05-11 13:02:44,677 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in LAZY mode.
2026-05-11 13:02:45,191 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 510 ms. Found 58 JPA repository interfaces.
2026-05-11 13:02:45,196 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2026-05-11 13:02:45,196 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in LAZY mode.
2026-05-11 13:02:45,217 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 16 ms. Found 1 JPA repository interface.
2026-05-11 13:02:45,225 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Multiple Spring Data modules found, entering strict repository configuration mode
2026-05-11 13:02:45,225 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Bootstrapping Spring Data JPA repositories in LAZY mode.
2026-05-11 13:02:45,243 [main] INFO  o.s.d.r.c.RepositoryConfigurationDelegate - Finished Spring Data repository scanning in 14 ms. Found 1 JPA repository interface.
2026-05-11 13:02:47,121 [main] INFO  o.s.i.c.DefaultConfiguringBeanFactoryPostProcessor - No bean named 'errorChannel' has been explicitly defined. Therefore, a default PublishSubscribeChannel will be created.
2026-05-11 13:02:47,149 [main] INFO  o.s.i.c.DefaultConfiguringBeanFactoryPostProcessor - No bean named 'integrationHeaderChannelRegistry' has been explicitly defined. Therefore, a default DefaultHeaderChannelRegistry will be created.
2026-05-11 13:02:49,366 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat initialized with port 8080 (http)
2026-05-11 13:02:49,395 [main] INFO  o.a.coyote.http11.Http11NioProtocol - The ["http-nio-0.0.0.0-8080"] connector has been configured to support HTTP upgrade to [h2c]
2026-05-11 13:02:49,396 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Initializing ProtocolHandler ["http-nio-0.0.0.0-8080"]
2026-05-11 13:02:49,400 [main] INFO  o.a.catalina.core.StandardService - Starting service [Tomcat]
2026-05-11 13:02:49,401 [main] INFO  o.a.catalina.core.StandardEngine - Starting Servlet engine: [Apache Tomcat/10.1.52]
2026-05-11 13:02:49,529 [main] INFO  o.a.c.c.C.[Tomcat].[localhost].[/] - Initializing Spring embedded WebApplicationContext
2026-05-11 13:02:49,530 [main] INFO  o.s.b.w.s.c.ServletWebServerApplicationContext - Root WebApplicationContext: initialization completed in 10251 ms
2026-05-11 13:02:50,710 [main] INFO  o.h.jpa.internal.util.LogHelper - HHH000204: Processing PersistenceUnitInfo [name: default]
2026-05-11 13:02:51,014 [main] INFO  org.hibernate.Version - HHH000412: Hibernate ORM core version 6.6.44.Final
2026-05-11 13:02:51,128 [main] INFO  o.h.c.i.RegionFactoryInitiator - HHH000026: Second-level cache disabled
2026-05-11 13:02:51,497 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Starting...
2026-05-11 13:02:52,416 [main] INFO  com.zaxxer.hikari.pool.HikariPool - HikariPool-1 - Added connection org.postgresql.jdbc.PgConnection@14ca4b4d
2026-05-11 13:02:52,423 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Start completed.
2026-05-11 13:02:52,742 [main] INFO  o.hibernate.orm.connections.pooling - HHH10001005: Database info:
        Database JDBC URL [Connecting through datasource 'HikariDataSource (HikariPool-1)']
        Database driver: undefined/unknown
        Database version: 12.0
        Autocommit mode: undefined/unknown
        Isolation level: undefined/unknown
        Minimum pool size: undefined/unknown
        Maximum pool size: undefined/unknown
2026-05-11 13:02:54,442 [main] INFO  o.s.o.j.p.SpringPersistenceUnitInfo - No LoadTimeWeaver setup: ignoring JPA class transformer
2026-05-11 13:03:01,020 [main] INFO  o.h.e.t.j.p.i.JtaPlatformInitiator - HHH000489: No JTA platform available (set 'hibernate.transaction.jta.platform' to enable JTA platform integration)
2026-05-11 13:03:01,049 [main] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Initialized JPA EntityManagerFactory for persistence unit 'default'
2026-05-11 13:03:04,868 [main] INFO  o.t.s.d.a.CachedAttributesService - Going to use directExecutor for the local cache type caffeine
2026-05-11 13:03:05,908 [main] INFO  o.t.s.d.s.NamedParameterJdbcTemplateConfiguration - Set jdbcTemplate query timeout [30] second(s)
2026-05-11 13:03:06,934 [main] INFO  o.s.b.a.w.s.WelcomePageHandlerMapping - Adding welcome page: class path resource [public/index.html]
2026-05-11 13:03:10,555 [main] INFO  o.s.b.a.e.web.EndpointLinksResolver - Exposing 1 endpoint beneath base path '/actuator'
2026-05-11 13:03:11,474 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - Adding {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2026-05-11 13:03:11,475 [main] INFO  o.s.i.c.PublishSubscribeChannel - Channel 'application.errorChannel' has 1 subscriber(s).
2026-05-11 13:03:11,482 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - started bean '_org.springframework.integration.errorLogger'
2026-05-11 13:03:11,544 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Starting ProtocolHandler ["http-nio-0.0.0.0-8080"]
2026-05-11 13:03:11,568 [main] INFO  o.s.b.w.e.tomcat.TomcatWebServer - Tomcat started on port 8080 (http) with context path '/'
2026-05-11 13:03:11,630 [main] INFO  o.t.s.ThingsboardInstallApplication - Started ThingsboardInstallApplication in 34.404 seconds (process running for 36.787)
2026-05-11 13:03:11,706 [main] INFO  o.t.s.i.ThingsboardInstallService - Starting ThingsBoard Installation...
2026-05-11 13:03:11,707 [main] INFO  o.t.s.i.ThingsboardInstallService - Installing DataBase schema for entities...
2026-05-11 13:03:11,707 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Installing SQL DataBase schema part: schema-entities.sql
2026-05-11 13:03:12,061 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Installing SQL DataBase schema indexes part: schema-entities-idx.sql
2026-05-11 13:03:12,187 [main] INFO  o.t.s.s.i.SqlEntityDatabaseSchemaService - Installing SQL DataBase schema PostgreSQL specific indexes part: schema-entities-idx-psql-addon.sql
2026-05-11 13:03:12,292 [main] INFO  o.t.s.s.i.SqlEntityDatabaseSchemaService - Installing SQL DataBase schema views: schema-views.sql
2026-05-11 13:03:12,370 [main] INFO  o.t.s.s.i.SqlEntityDatabaseSchemaService - Installing SQL DataBase schema functions: schema-functions.sql
2026-05-11 13:03:12,484 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Successfully executed query: DROP VIEW IF EXISTS device_info_view CASCADE;
2026-05-11 13:03:17,538 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Successfully executed query: CREATE OR REPLACE VIEW device_info_view AS SELECT * FROM device_info_active_attribute_view;
2026-05-11 13:03:22,541 [main] INFO  o.t.s.i.ThingsboardInstallService - Installing DataBase schema for timeseries...
2026-05-11 13:03:22,542 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Installing SQL DataBase schema part: schema-ts-psql.sql
2026-05-11 13:03:22,667 [main] INFO  o.t.s.s.i.SqlAbstractDatabaseSchemaService - Successfully executed query: CREATE TABLE IF NOT EXISTS ts_kv_indefinite PARTITION OF ts_kv DEFAULT;
2026-05-11 13:03:27,671 [main] INFO  o.t.s.i.ThingsboardInstallService - Loading system data...
2026-05-11 13:03:28,320 [main] INFO  o.s.d.j.r.query.QueryEnhancerFactory - Hibernate is in classpath; If applicable, HQL parser will be used.
2026-05-11 13:03:32,160 [main] INFO  c.d.oss.driver.api.core.uuid.Uuids - PID obtained through native call to getpid(): 4113505
2026-05-11 13:03:34,834 [main] INFO  org.owasp.validator.html.Policy - Attempting to load AntiSamy policy from an input stream.
2026-05-11 13:03:35,102 [main] WARN  org.owasp.validator.html.Policy - The directive "noopenerAndNoreferrerAnchors" is enabled by default, but disabled in this policy. It is recommended to leave it enabled to prevent reverse tabnabbing attacks.
2026-05-11 13:03:36,353 [main] INFO  o.t.s.s.i.DefaultSystemDataLoaderService - Creating JWT admin settings...
2026-05-11 13:03:36,368 [main] INFO  o.t.s.s.s.a.j.s.DefaultJwtSettingsService - Saving new JWT admin settings. From this moment, the JWT parameters from YAML and ENV will be ignored
2026-05-11 13:03:36,409 [main] INFO  o.t.s.service.install.InstallScripts - Loading system widgets
2026-05-11 13:04:30,801 [main] INFO  o.t.s.service.install.InstallScripts - Loading system SCADA symbols
2026-05-11 13:05:01,007 [main] INFO  o.t.s.s.i.DefaultSystemDataLoaderService - Creating default notification configs for system admin
2026-05-11 13:05:01,372 [main] INFO  o.t.s.s.i.DefaultSystemDataLoaderService - Creating default notification configs for all tenants
2026-05-11 13:05:09,923 [main] INFO  o.t.s.service.install.InstallScripts - Loading system images and resources...
2026-05-11 13:05:10,001 [main] INFO  o.t.s.d.resource.BaseResourceService - Creating system resource gateway-management-extension.js
2026-05-11 13:05:11,821 [main] INFO  o.t.s.d.resource.BaseResourceService - Creating system resource gateways_dashboard.json
2026-05-11 13:05:11,855 [main] INFO  o.t.s.i.ThingsboardInstallService - Loading demo data...
2026-05-11 13:05:14,901 [sql-log-1-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - Queue-1 [TS] queueSize [0] totalAdded [17] totalSaved [17] totalFailed [0]
2026-05-11 13:05:14,938 [sql-log-1-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - Queue-1 [TS Latest] queueSize [0] totalAdded [17] totalSaved [17] totalFailed [0]
2026-05-11 13:05:15,836 [main] INFO  o.t.s.i.ThingsboardInstallService - Installation finished successfully!
2026-05-11 13:05:15,849 [main] INFO  o.s.b.w.e.tomcat.GracefulShutdown - Commencing graceful shutdown. Waiting for active requests to complete
2026-05-11 13:05:15,851 [tomcat-shutdown] INFO  o.a.coyote.http11.Http11NioProtocol - Pausing ProtocolHandler ["http-nio-0.0.0.0-8080"]
2026-05-11 13:05:15,857 [tomcat-shutdown] INFO  o.s.b.w.e.tomcat.GracefulShutdown - Graceful shutdown complete
2026-05-11 13:05:15,858 [main] INFO  o.a.coyote.http11.Http11NioProtocol - Stopping ProtocolHandler ["http-nio-0.0.0.0-8080"]
2026-05-11 13:05:15,900 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - Removing {logging-channel-adapter:_org.springframework.integration.errorLogger} as a subscriber to the 'errorChannel' channel
2026-05-11 13:05:15,900 [main] INFO  o.s.i.c.PublishSubscribeChannel - Channel 'application.errorChannel' has 0 subscriber(s).
2026-05-11 13:05:15,901 [main] INFO  o.s.i.endpoint.EventDrivenConsumer - stopped bean '_org.springframework.integration.errorLogger'
2026-05-11 13:05:15,931 [sql-queue-0-attributes-6-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling was interrupted
2026-05-11 13:05:15,932 [sql-queue-0-attributes-6-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling completed
2026-05-11 13:05:15,932 [sql-queue-1-attributes-7-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling was interrupted
2026-05-11 13:05:15,932 [sql-queue-1-attributes-7-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling completed
2026-05-11 13:05:15,932 [sql-queue-2-attributes-8-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling was interrupted
2026-05-11 13:05:15,932 [sql-queue-2-attributes-8-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Attributes] Queue polling completed
2026-05-11 13:05:15,932 [sql-queue-1-ts latest-13-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling was interrupted
2026-05-11 13:05:15,932 [sql-queue-1-ts latest-13-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling completed
2026-05-11 13:05:15,933 [sql-queue-1-ts-10-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling was interrupted
2026-05-11 13:05:15,933 [sql-queue-1-ts-10-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling completed
2026-05-11 13:05:15,933 [sql-queue-2-ts latest-14-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling was interrupted
2026-05-11 13:05:15,933 [sql-queue-2-ts latest-14-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling completed
2026-05-11 13:05:15,933 [sql-queue-0-ts-9-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling was interrupted
2026-05-11 13:05:15,933 [sql-queue-0-ts-9-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling completed
2026-05-11 13:05:15,934 [sql-queue-2-ts-11-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling was interrupted
2026-05-11 13:05:15,934 [sql-queue-2-ts-11-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS] Queue polling completed
2026-05-11 13:05:15,934 [sql-queue-0-ts latest-12-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling was interrupted
2026-05-11 13:05:15,934 [sql-queue-0-ts latest-12-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [TS Latest] Queue polling completed
2026-05-11 13:05:15,938 [sql-queue-0-events-3-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling was interrupted
2026-05-11 13:05:15,938 [sql-queue-0-events-3-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling completed
2026-05-11 13:05:15,938 [sql-queue-1-events-4-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling was interrupted
2026-05-11 13:05:15,938 [sql-queue-1-events-4-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling completed
2026-05-11 13:05:15,938 [sql-queue-2-events-5-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling was interrupted
2026-05-11 13:05:15,939 [sql-queue-2-events-5-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Events] Queue polling completed
2026-05-11 13:05:15,939 [sql-queue-0-edge events-2-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Edge Events] Queue polling was interrupted
2026-05-11 13:05:15,939 [sql-queue-0-edge events-2-thread-1] INFO  o.t.s.dao.sql.TbSqlBlockingQueue - [Edge Events] Queue polling completed
2026-05-11 13:05:15,941 [main] INFO  o.s.o.j.LocalContainerEntityManagerFactoryBean - Closing JPA EntityManagerFactory for persistence unit 'default'
2026-05-11 13:05:15,946 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown initiated...
2026-05-11 13:05:16,002 [main] INFO  com.zaxxer.hikari.HikariDataSource - HikariPool-1 - Shutdown completed.

在 Windows 环境下,正确的路径是:

cd windows\install
install_dev_db.bat

踩坑7:数据库连接拒绝

执行 install_dev_db.bat 后,出现如下错误:

org.postgresql.util.PSQLException: Connection to localhost:5432 refused.

这是因为 install_dev_db.bat 默认读取的是 conf\thingsboard.yml 中的数据库配置,而不是windows\conf\thingsboard.ymlconf\thingsboard.yml 文件中的连接信息可能与你本地环境不符(例如密码不是 postgres),需要修改。

尝试直接修改配置文件:编辑 conf\thingsboard.yml,将数据库 URL、用户名、密码改为正确的值。但这样会污染打包后的配置,且每次重新编译都会被覆盖。

最佳解决方案:使用环境变量

ThingsBoard 的配置文件中大量使用了 ${SPRING_DATASOURCE_URL:...} 这种占位符,我们可以通过设置环境变量来覆盖默认值,无需修改任何配置文件。

在 Windows 下,通过系统环境变量或命令行临时设置:

set SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard
set SPRING_DATASOURCE_USERNAME=postgres
set SPRING_DATASOURCE_PASSWORD=your_password
set SPRING_EVENTS_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard_events
set SPRING_EVENTS_DATASOURCE_USERNAME=postgres
set SPRING_EVENTS_DATASOURCE_PASSWORD=your_password

设置完成后,再次运行 install_dev_db.bat,初始化成功。

踩坑8:数据库不存在

即使连接成功,仍可能遇到:

FATAL: database "thingsboard" does not exist

这是因为初始化脚本不会自动创建数据库,需要手动创建。按照 3.1 节中的 SQL 语句提前创建好 thingsboardthingsboard_events 即可。

四、启动服务

4.1 启动后端

方式一:使用 Maven 插件(开发调试推荐)

cd application
mvn spring-boot:run

方式二:运行打包后的 JAR

cd application/target
java -jar thingsboard-4.3.1.1-boot.jar

上面提到thingsboard.yml定义了上百个环境变量,尤其是数据库配置使用了通用的SPRING配置,这会影响其他spring程序,所以,应该直接编写一个启动脚本,在脚本中独立定义重要环境变量。

LINUX下startup.sh的全部代码为:

#!/usr/bin/env bash
# 注意:脚本文件应保存为 UTF-8 编码(无需 BOM),并在 Linux 下运行

# ========== 可配置变量 ==========
SERVICE_NAME="thingsboard-4.3.1.1-boot"
JAR_PATH="${SERVICE_NAME}.jar"
# JVM 参数(数组)
JVM_ARGS=(
    '-Dfile.encoding=UTF-8'
    '-Xmx256m'
    '-Xms128m'
)
# ================================

# ---------- 终端设置----------
# 设置窗口标题(部分终端支持,如 xterm、gnome-terminal 等)
echo -ne "\033]0;${SERVICE_NAME}\007"

# 设置前景色(绿色)和背景色(黑色)
if command -v tput >/dev/null 2>&1; then
    tput setaf 2   # 绿色前景
    tput setab 0   # 黑色背景
    tput clear
else
    echo -ne "\033[32;40m"  # 绿字黑底
    clear
fi

# 调整终端窗口大小(部分终端支持,可忽略错误)
if command -v resize >/dev/null 2>&1; then
    resize -s 50 200 2>/dev/null || true
fi

# ---------- 环境变量----------
export HTTP_BIND_ADDRESS="0.0.0.0"
export HTTP_BIND_PORT="8080"

# Redis
export REDIS_HOST="8.141.5.220"
export REDIS_PORT="6379"
export REDIS_DB="0"
export REDIS_PASSWORD=""
export REDIS_USERNAME=""

# Updates
export UPDATES_ENABLED="true"

# CORS
export TB_CORS_ALLOWED_ORIGIN_PATTERNS="*"
export TB_CORS_ALLOWED_METHODS="*"
export TB_CORS_ALLOWED_HEADERS="*"
export TB_CORS_MAX_AGE="1800"
export TB_CORS_ALLOW_CREDENTIALS="true"

# Spring
export SPRING_MVC_ASYNC_REQUEST_TIMEOUT="30000"
export SPRING_JPA_DIALECT="org.thingsboard.server.dao.ThingsboardPostgreSQLDialect"
export JAVAX_PERSISTENCE_QUERY_TIMEOUT="30000"
export SPRING_DRIVER_CLASS_NAME="org.postgresql.Driver"
export SPRING_DATASOURCE_URL="jdbc:postgresql://8.141.5.220:15432/thingsboard"
export SPRING_DATASOURCE_USERNAME="postgres"
export SPRING_DATASOURCE_PASSWORD="123456"
export SPRING_EVENTS_DATASOURCE_DRIVER_CLASS_NAME="org.postgresql.Driver"
export SPRING_EVENTS_DATASOURCE_URL="jdbc:postgresql://8.141.5.220:15432/thingsboard_events"
export SPRING_EVENTS_DATASOURCE_USERNAME="postgres"
export SPRING_EVENTS_DATASOURCE_PASSWORD="123456"

# Transport
export HTTP_ENABLED="true"
export HTTP_REQUEST_TIMEOUT="60000"
export HTTP_MAX_REQUEST_TIMEOUT="300000"
export HTTP_TRANSPORT_MAX_PAYLOAD_SIZE_LIMIT_CONFIGURATION="/api/v1/*/rpc/**=65536;/api/v1/**=52428800"
export MQTT_ENABLED="true"
export MQTT_BIND_ADDRESS="0.0.0.0"
export MQTT_BIND_PORT="1883"

# 关闭网关仪表盘同步
export TB_GATEWAY_DASHBOARD_SYNC_ENABLED="false"

# Device connectivity
export DEVICE_CONNECTIVITY_HTTP_ENABLED="true"
export DEVICE_CONNECTIVITY_HTTP_HOST=""
export DEVICE_CONNECTIVITY_HTTP_PORT="2080"
export DEVICE_CONNECTIVITY_HTTPS_ENABLED="false"
export DEVICE_CONNECTIVITY_HTTPS_HOST=""
export DEVICE_CONNECTIVITY_HTTPS_PORT="443"
export DEVICE_CONNECTIVITY_MQTT_ENABLED="true"
export DEVICE_CONNECTIVITY_MQTT_HOST=""
export DEVICE_CONNECTIVITY_MQTT_PORT="1883"
export DEVICE_CONNECTIVITY_MQTTS_ENABLED="false"
export DEVICE_CONNECTIVITY_MQTTS_HOST=""
export DEVICE_CONNECTIVITY_MQTTS_PORT="8883"
export DEVICE_CONNECTIVITY_MQTTS_CA_ROOT_CERT="cafile.pem"

# MQTT Client
export TB_MQTT_CLIENT_RETRANSMISSION_MAX_ATTEMPTS="3"
export TB_MQTT_CLIENT_RETRANSMISSION_INITIAL_DELAY_MILLIS="5000"
export TB_MQTT_CLIENT_RETRANSMISSION_JITTER_FACTOR="0.15"

# ---------- 检查 Java 环境 ----------
if ! command -v java &> /dev/null; then
    echo -e "\033[31m错误:未找到 Java 运行环境,请先安装 JDK 或 JRE。\033[0m"
    exit 1
fi

# ---------- 检查 JAR 文件 ----------
if [ ! -f "$JAR_PATH" ]; then
    echo -e "\033[31m错误:找不到 $JAR_PATH 文件。\033[0m"
    exit 1
fi

# ---------- 后台启动应用 ----------
LOG_FILE="${SERVICE_NAME}.log"
echo -e "\033[32m后台启动 $SERVICE_NAME 应用,日志输出到 $LOG_FILE ...\033[0m"
nohup java "${JVM_ARGS[@]}" -jar "$JAR_PATH" > "$LOG_FILE" 2>&1 &
echo $! > "${SERVICE_NAME}.pid"
echo -e "\033[32m$SERVICE_NAME 已启动,PID=$(cat ${SERVICE_NAME}.pid),日志文件: $(pwd)/${LOG_FILE},请立即使用tail -f $(pwd)/${LOG_FILE} 查看启动日志\033[0m"

启动后的效果:

[root@iZ2ze6qcuxrmhddeb4m9xuZ thingsboard]# sh startup.sh
后台启动 thingsboard-4.3.1.1-boot 应用,日志输出到 thingsboard-4.3.1.1-boot.log ...
thingsboard-4.3.1.1-boot 已启动,PID=259581,日志文件: /feng/thingsboard/thingsboard-4.3.1.1-boot.log,请立即使用tail -f /feng/thingsboard/thingsboard-4.3.1.1-boot.log 查看启动日志
[root@iZ2ze6qcuxrmhddeb4m9xuZ thingsboard]# tail -f /feng/thingsboard/thingsboard-4.3.1.1-boot.log
 ===========================================================
 :: ThingsBoard ::       (v4.3.1.1)
 ===========================================================

2026-05-11T15:01:44.213+08:00  INFO 259581 --- [           main] o.t.server.ThingsboardServerApplication  : Starting ThingsboardServerApplication v4.3.1.1 using Java 17.0.14 with PID 259581 (/feng/thingsboard/thingsboard-4.3.1.1-boot.jar started by root in /feng/thingsboard)
2026-05-11T15:01:44.228+08:00  INFO 259581 --- [           main] o.t.server.ThingsboardServerApplication  : No active profile set, falling back to 1 default profile: "default"
2026-05-11T15:01:45.552+08:00  WARN 259581 --- [           main] o.s.c.annotation.AnnotationTypeMapping   : Support for convention-based annotation attribute overrides is deprecated and will be removed in Spring Framework 7.0. Please annotate the following attributes in @org.thingsboard.server.config.annotations.ApiOperation with appropriate @AliasFor declarations: [hidden, requestBody, responses]
......

检查进程:

ps -aux | grep things

检查端口:

netstat -nltp | grep 8080

WINDOWS下的启动脚本startup.ps1的全部代码为:

<#
注意文件编码要设置为 UTF-8 BOM,否则会显示中文乱码
#>

# ========== 可配置变量 ==========
$serviceName = "thingsboard-4.3.1.1-boot"           # 服务名称(用于标题、提示和 JAR 文件名)
$jarPath = "target\$serviceName.jar" # JAR 文件路径
$jvmArgs = @(                        # JVM 参数数组(易修改)
    '-Dfile.encoding=UTF-8',
    '-Xmx256m',
    '-Xms128m'
)
# ================================

# 设置控制台编码为 UTF-8
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = New-Object System.Text.UTF8Encoding

# 设置窗口标题
$Host.UI.RawUI.WindowTitle = $serviceName

# 设置缓冲区大小(宽度200,高度2000)
$Host.UI.RawUI.BufferSize = New-Object Management.Automation.Host.Size(200, 2000)

# 设置窗口大小(宽度200,高度50,可根据屏幕调整)
$Host.UI.RawUI.WindowSize = New-Object Management.Automation.Host.Size(200, 50)

# 设置颜色(黑底绿字)
$Host.UI.RawUI.ForegroundColor = "Green"
$Host.UI.RawUI.BackgroundColor = "Black"
Clear-Host

# 检查 Java 环境
java -version 2>&1 | Out-Null
if ($LASTEXITCODE -ne 0) {
    Write-Host "未找到 Java 运行环境,请先安装 JDK 或 JRE。"
    Write-Host "按任意键继续..." -NoNewline
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    exit 1
}

# 检查目标 JAR 文件是否存在
if (-not (Test-Path $jarPath)) {
    Write-Host "错误:找不到 $jarPath 文件。"
    Write-Host "按任意键继续..." -NoNewline
    $null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    exit 1
}

# ---------- 添加数据库连接环境变量 ----------
$env:SPRING_DATASOURCE_URL = "jdbc:postgresql://localhost:5432/thingsboard"
$env:SPRING_DATASOURCE_USERNAME = "postgres"
$env:SPRING_DATASOURCE_PASSWORD = "123456"
$env:SPRING_EVENTS_DATASOURCE_URL = "jdbc:postgresql://localhost:5432/thingsboard_events"
$env:SPRING_EVENTS_DATASOURCE_USERNAME = "postgres"
$env:SPRING_EVENTS_DATASOURCE_PASSWORD = "123456"
$env:REDIS_PASSWORD = "123456"
$env:REDIS_HOST = "localhost"
$env:REDIS_PORT = "6379"
# -----------------------------------------

# 启动应用(使用展开的 JVM 参数)
Write-Host "启动 $serviceName 应用..."
java $jvmArgs -jar $jarPath

# 暂停
Write-Host "按任意键继续..." -NoNewline
$null = $Host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")

踩坑9:启动时仍然连接数据库失败

执行 mvn spring-boot:run 时,发现它读取的是 application\src\main\resources\thingsboard.yml,而不是 target 目录下的配置文件。而源码中的 thingsboard.yml 同样使用了环境变量占位符,但此时我们之前设置的环境变量可能已经失效(例如在新的命令行窗口中)。

解决方法:在启动命令前重新设置环境变量,或者将环境变量持久化到系统变量中。也可以直接在 IDEA 的运行配置中填入环境变量。

为方便起见,我们编写一个启动脚本 start-thingsboard.bat

@echo off
set SPRING_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard
set SPRING_DATASOURCE_USERNAME=postgres
set SPRING_DATASOURCE_PASSWORD=your_password
set SPRING_EVENTS_DATASOURCE_URL=jdbc:postgresql://localhost:5432/thingsboard_events
set SPRING_EVENTS_DATASOURCE_USERNAME=postgres
set SPRING_EVENTS_DATASOURCE_PASSWORD=your_password
cd application
mvn spring-boot:run

在这里插入图片描述

每次启动时执行该脚本即可。

4.2 启动前端(可选)

如果你想单独调试前端,可以运行:

cd ui-ngx
yarn start

前端开发服务器默认运行在 http://localhost:4200,会自动代理 API 请求到 http://localhost:8080

五、验证安装

后端启动成功后,访问 http://localhost:8080,使用默认账号登录:

  • 系统管理员:sysadmin@thingsboard.org / sysadmin
  • 租户管理员:tenant@thingsboard.org / tenant

如果能看到仪表板页面,恭喜你,ThingsBoard 开发环境已经搭建完成!
在这里插入图片描述

六、总结与建议

踩坑汇总

问题原因解决方案
gradle-maven-plugin 或 langchain4j-bom 找不到依赖在 ThingsBoard 私有仓库,公共镜像没有在 settings.xml 中添加 thingsboard-repo 镜像
gradle-7.3.3-bin.zip 下载卡死网络访问国外 Gradle 分发服务器慢手动下载并放入 Gradle 缓存目录
winsw-2.0.1-bin.exe 下载失败依赖不在公共仓库手动下载并用 mvn install:install-file 安装
frontend-maven-plugin 自动添加代理参数Maven Settings 中存在激活的代理禁用或删除 settings.xml 中的代理配置
pkg 打包时下载 Node 二进制失败网络问题,GitHub 访问慢设置 PKG_CACHE_PATH,手动下载并重命名文件放入缓存
数据库初始化连接拒绝配置文件中的数据库连接信息不正确使用环境变量覆盖配置
数据库不存在初始化脚本不会自动创建数据库手动创建 thingsboard 和 thingsboard_events
mvn spring-boot:run 连接失败未传递环境变量在启动命令前设置环境变量

开发环境最佳实践

  1. 优先配置 ThingsBoard 仓库镜像:编译前就在 settings.xml 中加上 ThingsBoard 官方镜像,避免后续大量依赖缺失。

  2. 手动处理外部二进制依赖:对于 winswpkg-fetch 这类网络依赖,提前下载并放置到正确位置,可以节省大量时间。

  3. 使用环境变量而非修改配置文件:ThingsBoard 的设计非常灵活,几乎所有配置都支持环境变量覆盖。这样既能保持源码干净,又能适应不同环境。

  4. 为 Windows 环境准备脚本:将常用的环境变量设置、编译、启动命令封装成 .bat 脚本,避免重复输入。

  5. 善用 Maven 排除模块:如果某些模块(如 edqsmsa/web-ui)编译特别困难,可以用 -pl '!edqs' -pl '!msa/web-ui' 跳过,不影响核心功能。

  6. 保持 JDK 和 Node 版本一致:ThingsBoard 4.3.x 要求 JDK 17 和 Node 18+,版本不匹配会导致各种奇怪错误。

  7. 遇到问题时查看官方社区:ThingsBoard 的 GitHub Issues 和 Stack Overflow 上有大量现成答案,善用搜索。

下一步计划

搭建好开发环境后,我们将基于 ThingsBoard 进行二次开发,实现:

  • 物联中台(设备接入、设备管理)
  • 数据中台(多源数据汇聚、统一 API)
  • 维修管理、资产管理、医废管理等业务模块

后续我会继续分享定制开发过程中的经验,欢迎关注。

最后:如果你在搭建过程中遇到其他问题,欢迎在评论区留言交流。如果觉得本文有帮助,别忘了点赞、收藏、分享!

Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐