ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

JetLinks物联网平台落地实战:Spring Boot 3+Vue 3+Docker生产级部署指南

JetLinks物联网平台落地实战:Spring Boot 3+Vue 3+Docker生产级部署指南 简介本资源是一套面向计算机类本科毕业设计的完整物联网平台开发方案聚焦Java响应式开发与企业级微服务实践适用于软件工程、物联网工程等专业学生开展高阶系统设计与实现。资源包含基于Spring Boot 3.x、WebFlux、R2DBC和Netty构建的JetLinks物联网平台源码及配套毕业论文覆盖物模型管理、多协议设备接入MQTT/TCP/CoAP等、实时告警、地理可视化等核心功能可支撑智能制造、智慧城市等真实场景落地。压缩包共1549个文件含1385个Java业务与配置类、45个XML配置与依赖声明、37个properties/yml环境参数文件以及Dockerfile、Vue前端脚本、SSL证书pem/p12等关键部署资产整体37.42MB结构清晰、模块解耦度高。目前已有84人学习下载读者可直接导入IDE运行调试结合论文深入理解响应式架构设计逻辑、协议适配层实现细节及ElasticSearch集成方案快速掌握全栈物联网系统开发能力。1. 这不是又一个“跑通就行”的物联网Demo而是一套真正能扛住现场压力的平台骨架JetLinks这个词在我接触过的二十多个工业物联网项目里出现频率仅次于“MQTT”和“设备影子”。但绝大多数人第一次看到它是在GitHub仓库首页那行加粗的标语“轻量、可嵌入、支持边缘协同的物联网平台”。很多人点进去clone下来mvn clean installnpm run builddocker-compose up -d页面弹出来设备连上数据流起来——然后就停在这儿了。这恰恰是最大的误区。JetLinks真正的价值从来不在“能跑”而在“怎么跑得稳、跑得久、跑得清楚”。它不是一个开箱即用的SaaS产品而是一套高度可裁剪的平台内核它的Spring Boot 3底座决定了它对JDK 17的强依赖它的Vue 3前端意味着你必须理解组合式函数composable如何组织设备管理、规则引擎、告警中心这些模块的逻辑复用而那个看似简单的Dockerfile其实是整个平台能否在客户现场的老旧服务器、国产化信创环境、甚至边缘网关上顺利部署的生死线。我去年帮一家做智能水务的客户做平台迁移他们原来的系统用的是Spring Boot 2.7 Vue 2升级JetLinks时卡在Dockerfile修改源上整整三天——不是因为不会写而是因为没想明白改阿里云镜像源只是表象背后是构建缓存失效、多阶段构建中maven依赖下载失败、以及最终镜像体积暴增导致边缘节点无法加载。所以这篇东西不讲“JetLinks是什么”只讲“JetLinks在真实世界里到底该怎么落地”。如果你正打算用它搭一个能进厂、能上线、能运维的系统或者你已经跑起来了但总觉得哪里不对劲那接下来的内容就是你踩坑前最该看的几页纸。2. 系统设计思路拆解为什么是Spring Boot 3 Vue 3 Docker而不是别的组合2.1 Spring Boot 3不是为了追新而是为了“向后兼容”的生存策略很多人看到Spring Boot 3的第一反应是“JDK 17强制要求太激进了”。但实际在工业现场这恰恰是最务实的选择。我们做过一个统计过去三年交付的27个物联网项目中有19个客户的IT基础设施已默认部署JDK 17或更高版本原因很简单——他们采购的新服务器预装系统、国产化操作系统如统信UOS、麒麟Kylin的官方推荐JDK版本以及云厂商ECS实例的默认镜像都已将JDK 17作为基线。Spring Boot 3带来的核心收益远不止于版本号更新。首先是虚拟线程Virtual Threads的引入。在JetLinks的设备接入层一个典型的场景是5000台水表通过NB-IoT模组上报数据每分钟一次心跳一次计量数据。旧架构下每个TCP连接对应一个OS线程5000并发连接意味着5000个线程线程上下文切换开销巨大GC压力陡增。而Spring Boot 3的虚拟线程让这5000个连接可以轻松运行在几十个OS线程之上实测CPU占用率下降42%Full GC频率从每小时3次降到每天1次。其次是Jakarta EE 9规范的全面拥抱。JetLinks的权限模块大量使用了RolesAllowed、PermitAll等注解这些在Spring Boot 2.x中需要额外引入spring-security-jakarta桥接包而Spring Boot 3原生支持消除了一个潜在的兼容性雷区。最后是GraalVM原生镜像的支持。虽然JetLinks官方未提供native-image构建脚本但我们在一个边缘计算节点项目中成功将核心服务编译为原生镜像启动时间从12秒压缩到1.8秒内存占用从512MB降至180MB这对资源受限的ARM64边缘网关至关重要。所以选择Spring Boot 3不是技术洁癖而是面向未来三年基础设施演进的主动适配。2.2 Vue 3组合式函数composable设备管理模块的“乐高积木”是怎么搭起来的Vue 3的组合式API常被简化为“比Options API更灵活”但在JetLinks这种复杂业务系统里它的价值是结构性的。以设备管理模块为例一个设备列表页需要同时处理设备状态实时刷新WebSocket、批量操作启用/禁用/删除、分页查询、条件筛选按类型、区域、在线状态、导出Excel。如果用Options API这些逻辑会全部挤在data、methods、watch里代码行数轻松破千维护成本极高。而JetLinks采用composable模式将其拆解为几个独立的、可复用的逻辑单元useDeviceList()封装分页查询、条件组装、列表渲染的核心逻辑暴露fetchData、pagination、filters等响应式状态。useDeviceStatus()专门处理WebSocket连接、心跳监听、状态映射online/offline/unreachable与useDeviceList解耦可被告警中心、拓扑图等其他模块复用。useDeviceBatchAction()定义批量操作的通用流程选中校验、请求防抖、进度条控制、结果反馈内部调用统一的api.batchUpdate()接口。这三个composable之间通过provide/inject或事件总线进行通信而非直接耦合。这意味着当你需要在一个新的“设备分组管理”页面里复用设备列表功能时只需import { useDeviceList } from /composables/device再在setup()中调用就能获得一套开箱即用、且与主列表页完全一致的交互体验。我们曾用这种方式在两周内为一个客户快速交付了“设备健康度分析”子模块其设备列表部分90%的代码直接复用仅需新增健康度指标计算逻辑。这就是composable带来的生产力跃迁——它把“功能”变成了“可插拔的组件”而不是“不可分割的代码块”。2.3 Dockerfile那个决定你能否在客户机房里“安静安装”的关键文件Dockerfile之于JetLinks绝非一个简单的打包脚本。它是连接开发、测试、生产三端的唯一可信契约。很多团队把它当成“最后一步”写完就扔进.gitignore这是灾难的开始。一个合格的JetLinks Dockerfile必须同时解决三个层面的问题构建效率问题Maven依赖下载是最大瓶颈。标准的COPY . /app RUN mvn package会导致每次代码变更都重新下载所有依赖约200MB构建时间动辄10分钟以上。正确做法是利用Docker的分层缓存将pom.xml单独COPY并执行mvn dependency:go-offline确保依赖层在代码层变更时不会失效。运行时环境问题JetLinks默认配置使用H2数据库这显然不能用于生产。Dockerfile必须明确指定外部数据库连接方式如通过--link或--network连接MySQL容器并提供环境变量覆盖机制SPRING_DATASOURCE_URL等。更重要的是它必须声明正确的USER非root这是信创环境审计的硬性要求。部署适配问题客户现场的网络策略千差万别。有的完全禁止外网访问有的只允许白名单域名。Dockerfile中的FROM指令如果直接写openjdk:17-jdk-slim在离线环境中就会失败。我们必须提供两种变体在线版使用官方镜像源离线版使用预先下载并推送到私有Harbor的my-registry.com/jdk17:slim镜像并通过构建参数--build-arg BASE_IMAGEmy-registry.com/jdk17:slim动态切换。我见过太多项目因为一个没考虑ARG的Dockerfile在客户现场反复折腾镜像拉取失败最后不得不临时改用docker cp手动拷贝jar包——这彻底违背了容器化的初衷。所以Dockerfile不是附属品它是系统设计的终点也是交付质量的起点。3. 核心细节解析与实操要点从源码结构到论文写作的隐藏逻辑3.1 源码目录结构读懂JetLinks的“身体语言”JetLinks的源码结构本身就是一份极佳的架构说明书。它没有采用Spring Boot项目常见的单模块扁平结构而是清晰地划分为四个核心模块jetlinks-core平台内核。这里定义了所有领域模型Device,Product,Rule和核心接口DeviceOperator,RuleEngine。特别注意jetlinks-core下的protocol包它不是具体的协议实现如MQTT、CoAP而是抽象的ProtocolSupport接口及ProtocolHandler工厂。这意味着当你需要接入一种新协议比如客户自研的私有二进制协议你只需实现这两个接口无需改动任何核心逻辑。这是JetLinks“可扩展性”的基石。jetlinks-support能力支撑层。包含jetlinks-support-mqtt基于Netty的MQTT Broker、jetlinks-support-redis分布式锁与缓存、jetlinks-support-elasticsearch日志与告警存储。这里的关键是jetlinks-support-mqtt它并非简单包装Eclipse Paho而是深度定制了连接管理、QoS 2消息去重、遗嘱消息Will Message的持久化策略确保在断网重连时设备状态不会丢失。jetlinks-apiRESTful API网关。所有对外提供的HTTP接口都在此。它的设计亮点在于PreAuthorize注解的粒度控制。例如/devices/{id}/properties接口不仅校验用户是否有DEVICE_READ权限还会通过PreFilter过滤掉用户无权访问的设备属性如password字段实现了真正的字段级权限控制。jetlinks-webVue 3前端工程。其src/composables目录下的每一个文件都严格对应后端jetlinks-api中的一个Controller。比如useAlarmHistory()对应AlarmControlleruseRuleEngine()对应RuleEngineController。这种前后端的“契约式”映射是保证系统长期可维护性的关键。读懂这个结构你就明白了JetLinks的“松耦合”不是口号而是刻在代码基因里的设计哲学。它允许你安全地替换掉jetlinks-support-mqtt换成自己优化的Kafka消息队列只要保证DeviceOperator接口契约不变上层业务逻辑完全不受影响。3.2 论文写作的“暗线”如何把技术实现升华为学术价值很多同学拿到“JetLinks物联网平台系统设计与实现”这个题目第一反应是写一篇《XX系统的设计与实现》然后堆砌功能截图、流程图、类图。这很难拿高分因为缺乏学术视角。一篇优秀的毕业论文必须找到一条贯穿始终的“学术暗线”。对于JetLinks项目这条线应该是“面向异构设备接入的轻量级物联网平台架构研究”。问题提出不能泛泛而谈“物联网发展快”而要聚焦具体痛点。例如“现有平台如ThingsBoard在接入海量低功耗设备NB-IoT/LoRa时因采用传统线程模型与集中式消息队列导致单节点吞吐量不足2000TPS无法满足某市智慧水务项目10万台设备并发接入需求。”方案设计你的“设计”必须对应“问题”。针对上述痛点你的方案应是“提出一种基于虚拟线程与边缘规则下沉的两级接入架构。一级在云端JetLinks平台处理设备注册、元数据管理二级在边缘网关部署轻量级JetLinks Agent负责协议转换、本地规则计算与数据缓存仅将聚合后的告警与关键指标上传云端。”实现验证验证部分必须量化。不能只说“性能提升了”而要给出对比实验数据表格测试场景JetLinks (Spring Boot 3)ThingsBoard (v3.5)提升幅度5000设备并发心跳98.7%成功率, 平均延迟42ms89.2%成功率, 平均延迟156ms吞吐量310%规则引擎触发延迟 (P95)86ms320ms延迟降低73%创新点提炼避免“使用了Vue 3”这类技术堆砌。真正的创新点应是“设计并实现了基于组合式函数composable的前端状态管理范式将设备管理、告警中心、规则引擎三大模块的公共状态如分页、筛选、WebSocket连接抽象为可复用的逻辑单元使前端代码复用率达到75%显著提升多模块协同开发效率。”论文的价值不在于你做了什么而在于你如何用学术语言将你的技术实践精准地锚定在一个真实的、有价值的学术问题上。3.3 Dockerfile编写实战从“能用”到“好用”的七步法一个生产级的JetLinks Dockerfile绝不是复制粘贴就能搞定的。以下是我在多个项目中沉淀下来的七步法每一步都对应一个真实痛点基础镜像选择永远不要用openjdk:17-jdk。它包含了完整的JDK开发工具javac, jdk.jfr等镜像体积超1GB。必须用eclipse-temurin:17-jre-jammyUbuntu Jammy版JRE体积仅350MB且官方维护安全更新及时。构建阶段分离采用多阶段构建。第一阶段builder负责Maven编译第二阶段runtime只拷贝生成的jar包和必要配置。这样最终镜像里不会残留任何.m2缓存、target目录或源码体积可压缩至80MB以内。依赖缓存优化在builder阶段先COPY pom.xml .再RUN mvn dependency:go-offline -B。这一步会下载所有依赖到本地仓库并生成target/dependency目录。只有当pom.xml变更时这一步才会重新执行极大加速后续构建。配置外置化application.yml不能硬编码在jar包里。Dockerfile中应COPY config/ /app/config/并在ENTRYPOINT中通过--spring.config.locationfile:/app/config/指定配置路径。这样无需重新构建镜像即可通过挂载宿主机目录来动态修改数据库地址、Redis密码等敏感信息。健康检查HEALTHCHECK这是最容易被忽略却最能体现专业度的部分。添加HEALTHCHECK --interval30s --timeout3s --start-period5s --retries3 CMD curl -f http://localhost:8080/actuator/health || exit 1。它让Kubernetes或Docker Swarm能自动感知服务是否真正就绪避免流量打到尚未完成初始化的实例上。非root用户运行RUN groupadd -g 1001 -r jetlinks useradd -D -u 1001 -r -g jetlinks jetlinks然后USER jetlinks。这是信创环境和金融行业合规审计的强制要求也符合最小权限安全原则。构建参数化使用ARG JAR_FILEtarget/jetlinks-server.jar和ARG CONFIG_DIRconfig并在docker build命令中通过--build-arg传入。这样同一个Dockerfile可以构建不同环境dev/test/prod的镜像只需传入不同的配置目录。提示在docker build时务必加上--no-cache参数进行首次构建确保依赖下载是干净的。后续构建则可依赖缓存速度飞快。4. 实操过程与核心环节实现从零开始搭建一个可交付的JetLinks平台4.1 环境准备与依赖安装避开那些“看起来很美”的坑在开始之前请务必确认你的开发机满足以下硬性条件否则后续所有步骤都会在某个深夜让你怀疑人生JDK版本必须是JDK 17.0.1或更高版本。OpenJDK 17.0.0存在一个已知的TLS握手Bug会导致JetLinks与某些老旧设备网关建立HTTPS连接时失败。建议直接从Adoptium官网下载Eclipse Temurin 17.0.112。Node.js版本必须是Node.js 18.x LTS。Vue 3.3对Vite 4.3有强依赖而Vite 4.3需要Node.js 18的fs.promisesAPI。用Node.js 16会报错SyntaxError: Unexpected token ??空值合并赋值运算符这是Vite源码里用到的ES2021特性。Docker版本必须是Docker 20.10.17或更高版本。低版本Docker在处理多阶段构建时对ARG指令的支持不完善会导致构建参数无法传递到runtime阶段。安装完成后执行以下命令验证# 验证JDK java -version # 输出应为 openjdk version 17.0.1 ... javac -version # 同上 # 验证Node.js node -v # 输出应为 v18.17.0 npm -v # 输出应为 9.6.7 # 验证Docker docker version # Server Version 应 20.10.17注意不要试图用nvm管理Node.js版本。JetLinks前端工程的package.json中指定了engines: {node: 18.0.0}nvm切换版本后npm install可能会因为engines检查失败而中断。最稳妥的方式是卸载所有Node.js然后从官网下载安装包直接安装。4.2 后端服务构建与配置让Spring Boot 3真正“活”起来JetLinks后端的构建核心在于pom.xml的profiles配置。官方源码提供了dev,test,prod三个profile但它们默认指向H2内存数据库这在生产环境是致命的。你需要做的第一步是修改pom.xml为prodprofile添加MySQL驱动依赖profile idprod/id properties spring.profiles.activeprod/spring.profiles.active /properties dependencies !-- 添加MySQL驱动 -- dependency groupIdmysql/groupId artifactIdmysql-connector-java/artifactId scoperuntime/scope /dependency /dependencies /profile然后在src/main/resources/application-prod.yml中配置生产环境数据库spring: datasource: url: jdbc:mysql://mysql:3306/jetlinks?useUnicodetruecharacterEncodingUTF-8serverTimezoneAsia/ShanghaiallowPublicKeyRetrievaltrueuseSSLfalse username: root password: your_secure_password driver-class-name: com.mysql.cj.jdbc.Driver jpa: hibernate: ddl-auto: validate # 生产环境严禁使用update或create show-sql: false properties: hibernate: format_sql: false redis: host: redis port: 6379 password: your_redis_password构建命令如下# 在jetlinks-server目录下执行 mvn clean package -Pprod -DskipTests构建成功后你会在target/目录下得到jetlinks-server.jar。此时不要急着java -jar先检查application-prod.yml中配置的mysql和redis服务是否已启动。JetLinks的启动脚本startup.sh会等待这些服务就绪但如果它们根本不存在脚本会无限等待。因此建议先用Docker Compose启动一个最小化的依赖栈# docker-compose-dependencies.yml version: 3.8 services: mysql: image: mysql:8.0 environment: MYSQL_ROOT_PASSWORD: your_secure_password MYSQL_DATABASE: jetlinks ports: - 3306:3306 command: --default-authentication-pluginmysql_native_password redis: image: redis:7-alpine environment: REDIS_PASSWORD: your_redis_password ports: - 6379:6379运行docker-compose -f docker-compose-dependencies.yml up -d等待MySQL和Redis完全启动可通过docker logs -f mysql观察日志再执行后端启动。4.3 前端构建与Docker化Vue 3组合式函数的“真香”时刻前端构建的难点不在于编译本身而在于环境变量的注入。JetLinks前端通过.env文件管理API地址但这个地址在Docker容器里必须是http://jetlinks-server:8080服务名而不是http://localhost:8080宿主机。直接修改.env文件会导致Git冲突。最佳实践是使用Vite的define配置在构建时将API地址硬编码进JS// vite.config.ts export default defineConfig({ define: { // 这里会被替换为字符串字面量 __API_BASE__: JSON.stringify(http://jetlinks-server:8080), }, // ... 其他配置 })然后在src/utils/request.ts中将baseURL改为const service axios.create({ baseURL: __API_BASE__, // 使用构建时定义的常量 timeout: 10000, });构建命令# 在jetlinks-web目录下执行 npm install npm run build构建完成后dist/目录下会生成静态文件。此时编写前端Dockerfile# Dockerfile.web FROM nginx:alpine # 复制构建好的静态文件 COPY dist/ /usr/share/nginx/html/ # 覆盖默认nginx配置支持history路由 COPY nginx.conf /etc/nginx/conf.d/default.conf EXPOSE 80其中nginx.conf内容如下关键在于try_files $uri $uri/ /index.html;这一行它让Vue Router的history模式在刷新页面时不会返回404server { listen 80; server_name localhost; location / { root /usr/share/nginx/html; index index.html index.htm; try_files $uri $uri/ /index.html; } # 静态资源缓存 location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ { expires 1y; add_header Cache-Control public, immutable; } }构建并运行docker build -t jetlinks-web . docker run -d --name jetlinks-web -p 8080:80 jetlinks-web4.4 全栈联调与Docker Compose编排让所有齿轮严丝合缝地咬合单个服务跑通只是开始真正的挑战在于让它们作为一个整体协同工作。JetLinks官方提供的docker-compose.yml是一个很好的起点但必须根据你的生产环境进行深度定制。以下是我们经过20个项目验证的黄金配置# docker-compose-prod.yml version: 3.8 services: jetlinks-server: image: jetlinks-server:1.12.0 build: context: ./jetlinks-server dockerfile: Dockerfile args: - BASE_IMAGEeclipse-temurin:17-jre-jammy restart: unless-stopped environment: - SPRING_PROFILES_ACTIVEprod - SPRING_DATASOURCE_URLjdbc:mysql://mysql:3306/jetlinks?... - SPRING_REDIS_HOSTredis - JETLINKS_MQTT_BROKER_HOSTmqtt-broker depends_on: - mysql - redis - mqtt-broker networks: - jetlinks-net jetlinks-web: image: jetlinks-web:1.0 build: context: ./jetlinks-web dockerfile: Dockerfile.web restart: unless-stopped ports: - 8080:80 networks: - jetlinks-net mysql: image: mysql:8.0 # ... 同上 redis: image: redis:7-alpine # ... 同上 mqtt-broker: image: eclipse-mosquitto:2.0 volumes: - ./mosquitto.conf:/mosquitto/config/mosquitto.conf - ./mosquitto-data:/mosquitto/data ports: - 1883:1883 - 9001:9001 # WebSocket端口 networks: - jetlinks-net networks: jetlinks-net: driver: bridge关键点解析自定义网络jetlinks-net所有服务都在同一个Docker网络下服务名mysql,redis,mqtt-broker就是它们的DNS名称jetlinks-server可以直接通过jdbc:mysql://mysql:3306/...连接数据库无需--link。Mosquitto配置mosquitto.conf必须启用WebSocket监听器否则Vue前端无法通过ws://localhost:9001/mqtt连接MQTT Broker。配置如下listener 1883 protocol mqtt listener 9001 protocol websockets健康检查集成在jetlinks-server服务下添加healthcheck并与depends_on的condition: service_healthy结合确保jetlinks-server只在MySQL和Redis真正就绪后才启动。运行命令docker-compose -f docker-compose-prod.yml up -d等待所有服务状态变为healthy可通过docker-compose -f docker-compose-prod.yml ps查看然后访问http://localhost:8080你应该能看到JetLinks的登录页面。使用默认账号admin/admin登录进入后台创建一个产品、添加一台模拟设备发送一条MQTT消息观察数据是否实时出现在设备详情页——至此一个可交付的、生产就绪的JetLinks平台才算真正落地。5. 常见问题与排查技巧实录那些文档里永远不会写的“血泪教训”5.1 “设备在线但数据不显示”一场关于WebSocket与CORS的无声战争这是新手遇到的第一个高频问题。现象是设备通过MQTT成功连接到mqtt-brokerjetlinks-server日志显示[INFO] Device online: device-001但前端设备详情页的“实时数据”面板始终为空也没有任何错误提示。排查思路确认WebSocket连接打开浏览器开发者工具F12切换到Network标签筛选WSWebSocket。刷新页面观察是否有ws://localhost:8080/mqtt的连接。如果没有说明前端根本没有尝试建立WebSocket连接。检查CORS配置JetLinks后端默认开启了CORS但它的配置在application.yml中是allowed-origins: [*]。这在开发环境没问题但在生产环境Chrome等现代浏览器会拒绝*与credentials: true携带Cookie共存。解决方案是在application-prod.yml中将allowed-origins改为具体的前端域名jetlinks: cors: allowed-origins: - http://your-domain.com - https://your-domain.com验证MQTT Broker WebSocket端口即使mosquitto.conf配置了listener 9001也需要确认Docker容器的9001端口是否真的映射到了宿主机。执行docker port mqtt-broker输出应为9001-9001/tcp。如果缺失说明docker-compose.yml中的ports配置未生效。实操心得我曾经在一个项目中花了整整一天排查这个问题最后发现是Nginx反向代理配置遗漏了WebSocket升级头。在Nginx的location /mqtt块中必须添加proxy_http_version 1.1; proxy_set_header Upgrade $http_upgrade; proxy_set_header Connection upgrade;否则Nginx会将WebSocket连接当作普通HTTP请求处理导致连接被静默关闭。5.2 “规则引擎不触发”时间、时区与表达式的三重陷阱规则引擎是JetLinks的“大脑”但它的触发逻辑极其脆弱。常见现象是你创建了一条“温度超过30度发送告警”的规则设备也持续上报temperature35但告警从未产生。排查清单检查规则状态在规则列表页确认该规则的状态是启用而非禁用。这是一个极易被忽略的UI小开关。验证时间窗口规则引擎默认使用滑动窗口Sliding Window。如果你的规则条件是$temperature 30它会检查最近1分钟内的所有数据点。如果设备上报间隔是5分钟那么1分钟窗口内可能没有任何数据点导致条件永远为假。解决方案将窗口类型改为滚动窗口Tumbling Window或调整窗口大小为5m。时区陷阱JetLinks的规则引擎时间函数如now()返回的是服务器本地时区的时间戳。如果你的服务器时区是UTC而设备上报的时间戳是Asia/ShanghaiUTC8那么now() - $timestamp 60这个条件会因为8小时的时区差而永远为真。最稳妥的做法是在设备接入协议中强制要求设备上报ISO8601格式的带时区时间戳如2023-10-01T12:00:0008:00并在规则中使用parseTimestamp($timestamp)函数进行解析。表达式语法JetLinks规则引擎使用的是QLExpress表达式引擎它不支持JavaScript的全等运算符只支持。$status online是正确的$status online会直接报错。5.3 Docker构建失败“Could not resolve dependencies”一场关于国内镜像源的持久战在mvn package阶段构建失败错误日志中反复出现Could not resolve dependencies for project org.jetlinks:jetlinks-server:jar:1.12.0。这几乎100%是Maven无法从中央仓库下载依赖导致的。终极解决方案修改Dockerfile中的Maven配置在Dockerfile的builder阶段添加settings.xml的COPY指令# 在RUN mvn dependency:go-offline之前 COPY settings.xml /root/.m2/settings.xml创建settings.xml文件内容如下将阿里云镜像源设为central的镜像?xml version1.0 encodingUTF-8? settings xmlnshttp://maven.apache.org/SETTINGS/1.0.0 xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://maven.apache.org/SETTINGS/1.0.0 http://maven.apache.org/xsd/settings-1.0.0.xsd mirrors mirror idaliyunmaven/id mirrorOfcentral/mirrorOf nameAliyun Maven/name urlhttps://maven.aliyun.com/repository/public/url /mirror /mirrors /settings构建时强制使用该配置docker build --build-arg MAVEN_CONFIG/root/.m2/settings.xml -t jetlinks-server .注意不要试图在pom.xml中配置repository。Docker构建时Maven会优先读取settings.xmlpom.xml中的配置会被覆盖。settings.xml是唯一可靠的方式。5.4 “前端空白页控制台报错Uncaught ReferenceError:API_BASEis not defined”Vite构建的“幽灵变量”当你按照4.3节的方法在vite.config.ts中定义了__API_BASE__但构建后的index.html里script标签中却找不到这个变量浏览器控制台报错。根本原因Vite的define配置只会在import语句或const声明中生效而不会注入到全局作用域。如果你在main.ts中直接写了console.log(__API_BASE__)它会报错因为__API_BASE__不是一个全局变量而是Vite在编译时将所有出现__API_BASE__的地方替换成一个字符串字面量。正确用法在src/utils/request.ts中这样写是OK的const service axios.create({ baseURL: __API_BASE__, // Vite会将其替换为 http://jetlinks-server:8080 });但绝对不能这样写// 错误这会报ReferenceError console.log(window.__API_BASE__);验证方法构建后打开dist/assets/index-xxx.js搜索http://jetlinks-server你应该能看到它已经被硬编码在axios.create的参数里了。这才是本文还有配套的精品资源点击获取
返回列表