Java轻量架构下Apache IoTDB时序数据库实战:从传感器数据到SQL查询
简介本资源为基于Java轻量式架构的Apache IoTDB物联网时序数据管理与分析设计源码面向工业物联网开发者、时序数据库学习者及大数据分析工程师用于解决大规模设备时序数据的高效存储、快速读取与复杂分析问题。压缩包共2000个文件约39.56MB以1873个Java源文件为核心辅以XML配置、Shell脚本、Markdown文档、properties与yaml配置等覆盖核心引擎、测试用例、构建配置与项目说明等模块。已有495人学习下载适合具备一定Java与数据库基础、希望深入理解时序数据库实现原理的读者。源码完整呈现了Apache IoTDB在数据存储格式、索引结构与查询处理上的设计思路并包含与Hadoop、Spark、Flink等大数据平台整合的相关代码可帮助读者掌握轻量级时序数据管理系统的架构组织、模块划分与工程构建方式为二次开发、性能调优及物联网数据分析方案落地提供可参考的实践基础。1. 从一堆传感器到一条 SQLJava 轻量架构下 Apache IoTDB 到底解决什么问题工厂车间里 2000 个振动传感器每秒上报一次数据一天就是 1.7 亿条记录。用 MySQL 存三个月后单表查询开始卡用 Hadoop 全家桶运维成本比设备还贵。这个矛盾在物联网项目里反复出现——数据量是时序的、写入是并发的、查询却往往只需要最近几小时或某个设备的趋势。Apache IoTDB 就是为这个场景设计的时序数据库原生树形元数据模型、列式存储、内置降采样和对齐查询单机就能扛住千万级点位写入。而「基于 Java 轻量式架构」的意思是用 Spring Boot 这类轻量容器把 IoTDB 的 Java 原生接口包一层不引入 Kafka、Flink 全套流处理让中小规模物联网项目在 2 核 4G 的边缘服务器上也能跑起来。这套方案适合做物联网毕业设计、课程设计案例源码也适合真实产线里做设备数据采集与分析的团队。源码层面核心就是三件事Session 连接池管理、树形路径建模、以及查询结果的降采样与分页。2. 轻量架构选型为什么用 Java 原生 Session 而不是 JDBC 或 REST2.1 IoTDB 三种接入方式的真实差异IoTDB 对外提供三种 Java 侧接入方式JDBC 驱动、REST API、原生 Session。很多教程一上来就讲 JDBC因为大家熟悉但在物联网高频写入场景下JDBC 的 SQL 解析开销和连接管理会成为瓶颈。原生 Session 走的是 Thrift RPC批量写入时可以把多条数据攒成一个 Batch 一次发送吞吐量比逐条 JDBC insert 高一个数量级。REST API 适合跨语言或前端直连但每次请求都要走 HTTP 序列化延迟敏感场景不推荐。接入方式典型吞吐适用场景轻量架构建议原生 Session最高批量写入可达百万点/秒设备直连、边缘采集首选JDBC中等受 SQL 解析限制已有 SQL 生态、报表工具仅查询侧REST API较低HTTP 开销明显跨语言、前端可视化非核心链路轻量式架构的核心判断是写入走 Session查询走 Session 或 JDBC 都行但不要为了「统一」而全部用 JDBC。我一般会在 Spring Boot 里配一个 SessionPool写入和查询共用避免连接数爆炸。2.2 用 Maven 引入 IoTDB 并建立第一个 Session先确认 Java 环境。JDK 8 或 11 都可以IoTDB 的 Java 客户端对 8 兼容良好。Maven 依赖只需要一个核心包不要引一堆用不上的模块。!-- pom.xml 片段只引 session 核心包避免拉入整个 server -- dependency groupIdorg.apache.iotdb/groupId artifactIdiotdb-session/artifactId version1.3.0/version !-- 按实际服务端版本对齐客户端与服务端大版本需一致 -- /dependency版本对齐是血泪经验客户端和服务端大版本不一致时Thrift 接口可能对不上报的错往往是「连接被重置」这种玄学信息排查半天才发现是版本问题。建议客户端版本与服务端保持同一 minor 版本。2.3 建立 SessionPool 而不是单 Session单 Session 不是线程安全的多线程写入会串数据。正确做法是用 SessionPool它内部维护多个连接按需分配。// SessionPool 初始化轻量架构下连接数不用太大 private SessionPool pool; PostConstruct public void init() throws Exception { pool new SessionPool.Builder() .host(127.0.0.1) // IoTDB 服务端地址 .port(6667) // 默认 RPC 端口 .user(root) .password(root) .maxSize(8) // 连接池上限2 核机器 8 足够 .build(); pool.open(false); // false 表示不自动建 Session由池管理 }参数说明maxSize不是越大越好。每个 Session 底层是一条 TCP 连接加 Thrift 缓冲8 个连接在 2 核 4G 机器上已经能跑满写入带宽。设成 50 反而会因为线程切换和内存占用拖慢整体。open(false)是让池自己管理生命周期不要手动再 open 单个 Session。3. 树形路径建模设备测点怎么映射成 IoTDB 的存储组与时间序列3.1 从设备台账到 root.工厂.车间.设备.测点IoTDB 的元数据是树形结构路径用点分隔。一个典型的映射是root.{集团}.{车间}.{设备类型}.{设备编号}.{测点}。比如root.hangzhou.workshop01.motor.m001.temperature。这个路径不是随便起的它决定了后续查询的粒度和存储组的划分。存储组Storage Group是 IoTDB 的物理隔离单位同一存储组内的数据共享 WAL 和文件管理。常见做法是按「工厂车间」设存储组设备作为路径中间节点。这样查询某个车间所有设备时前缀匹配就能命中不用全表扫。-- 创建存储组按车间粒度避免存储组过多导致文件句柄耗尽 CREATE STORAGE GROUP root.hangzhou.workshop01; CREATE STORAGE GROUP root.hangzhou.workshop02; -- 创建时间序列指定编码和压缩温度用 GORILLA状态用 PLAIN CREATE TIMESERIES root.hangzhou.workshop01.motor.m001.temperature WITH DATATYPEFLOAT, ENCODINGGORILLA, COMPRESSORSNAPPY; CREATE TIMESERIES root.hangzhou.workshop01.motor.m001.status WITH DATATYPEINT32, ENCODINGPLAIN, COMPRESSORSNAPPY;编码选择直接影响存储和查询效率。GORILLA 适合浮点且变化平缓的温度、压力PLAIN 适合状态码这种随机跳变的值。压缩器统一用 SNAPPY在 CPU 和压缩比之间平衡最好。不要用 GZIP写入时 CPU 会成为瓶颈。3.2 用 Java 代码自动注册时间序列实际项目里设备是动态接入的不可能手动建序列。常见做法是设备首次上报时检查路径是否存在不存在则自动创建。// 自动注册时间序列先判断再创建避免重复建报错 public void registerIfAbsent(String devicePath, String measurement, TSDataType type) { String fullPath devicePath . measurement; try { if (!pool.checkTimeseriesExists(fullPath)) { // 根据数据类型选编码浮点用 GORILLA整型用 PLAIN TSEncoding encoding (type TSDataType.FLOAT || type TSDataType.DOUBLE) ? TSEncoding.GORILLA : TSEncoding.PLAIN; pool.createTimeseries(fullPath, type, encoding, Compressor.SNAPPY); } } catch (Exception e) { // 并发场景下可能两个线程同时判断为不存在捕获已存在异常即可 log.warn(timeseries may already exist: {}, fullPath); } }逻辑说明checkTimeseriesExists和createTimeseries之间存在竞态多设备并发首次接入时会撞车。捕获异常而不是加锁是因为建序列本身是低频操作加锁反而影响写入主链路。参数上devicePath建议在应用层做规范化统一小写、去掉特殊字符否则路径里带空格或中文会在查询时带来转义麻烦。3.3 批量写入攒批比逐条快在哪Session 提供insertRecords和insertTablet两种批量接口。insertTablet是列式批量写入适合同一设备多测点、多时间点的场景性能最好。// insertTablet一次写入一个设备多个测点的批量数据 public void writeBatch(String devicePath, ListString measurements, ListTSDataType types, long[] timestamps, Object[] values) throws Exception { Tablet tablet new Tablet(devicePath, measurements, types, timestamps.length); for (int row 0; row timestamps.length; row) { tablet.addTimestamp(row, timestamps[row]); for (int col 0; col measurements.size(); col) { // values 按行优先排列这里按列取值写入 tablet.addValue(row, measurements.get(col), values[col * timestamps.length row]); } } pool.insertTablet(tablet); }参数说明Tablet构造时指定行数内部预分配数组避免写入过程中扩容。timestamps必须递增IoTDB 对乱序数据有容忍但会触发乱序合并影响写入性能。如果设备时钟不同步导致时间戳乱序建议在应用层先按时间排序再攒批。批量大小控制在 1000 到 5000 行之间太小网络往返多太大内存占用高且失败重传代价大。4. 查询与分析降采样、对齐查询和分页在 Java 里怎么写4.1 降采样查询别把原始点全捞回应用层物联网查询最常见的需求是「最近 24 小时温度趋势」。如果每秒一个点24 小时就是 86400 个点全捞回 Java 再画图前端渲染和网络传输都是浪费。IoTDB 支持在 SQL 层做降采样用GROUP BY时间区间加聚合函数。-- 每 5 分钟取一次平均温度24 小时只有 288 个点 SELECT AVG(temperature) FROM root.hangzhou.workshop01.motor.m001 WHERE time now() - 24h GROUP BY ([now() - 24h, now()), 5m);Java 侧用Session.executeQueryStatement执行结果集按行遍历。注意GROUP BY的时间区间是左闭右开边界点归属要清楚。如果某个区间没有数据IoTDB 默认不返回该行前端画图时会出现断点。需要补零的话在应用层按时间轴对齐填充。4.2 对齐查询多测点同一时间戳合并成一行设备有温度、湿度、压力多个测点如果分别查询再在 Java 里按时间戳 join代码量大且容易错。IoTDB 的对齐查询Align by device 或按时间对齐可以一次返回多列。-- 对齐查询同一设备多测点按时间戳对齐输出 SELECT temperature, humidity, pressure FROM root.hangzhou.workshop01.motor.m001 WHERE time now() - 1h ALIGN BY DEVICE;ALIGN BY DEVICE会把同一设备的多测点结果按时间戳合并缺失的测点补 null。Java 侧遍历时用ResultSet的getColumnNames动态取列不要硬编码列顺序否则加测点就要改代码。4.3 分页与流式读取避免 OOM 的两种做法查询大量历史数据时一次性executeQueryStatement会把所有结果缓存在客户端数据量大直接 OOM。两种做法一是用LIMIT和OFFSET分页二是用SessionDataSet的迭代器流式读取。// 流式读取hasNext 逐行取不在客户端全量缓存 public void streamQuery(String sql, int batchSize) throws Exception { try (SessionDataSet dataSet pool.executeQueryStatement(sql)) { int count 0; while (dataSet.hasNext()) { RowRecord row dataSet.next(); // 处理单行比如写入下游或做实时计算 processRow(row); if (count % batchSize 0) { // 每 batchSize 行做一次批量落库或发送控制内存 flush(); } } } }参数说明batchSize根据下游处理能力定写数据库一般 500 到 1000发消息队列可以到 2000。try-with-resources确保SessionDataSet关闭否则连接池里的连接会被占满后续查询拿不到连接表现为「查询卡死」——这又是一个不看日志很难定位的坑。5. 避坑与排查Java 接 IoTDB 最常见的 5 个翻车现场5.1 现象写入报「Connection reset」原因客户端服务端版本不一致解决对齐版本这个错误信息极具误导性看起来像网络问题实际八成是 Thrift 接口版本不匹配。IoTDB 客户端和服务端的 RPC 接口在不同 minor 版本间可能有字段增减。排查方法先看服务端日志有没有收到请求如果服务端完全没日志就是客户端发出去的包服务端解析不了。解决就是查服务端版本把iotdb-session依赖改成同一 minor 版本。别用「最新版客户端连旧版服务端」这种组合。5.2 现象查询越来越慢最后超时原因SessionDataSet 没关闭解决try-with-resources前面提过executeQueryStatement返回的SessionDataSet持有底层连接资源。如果代码里只取数据不关闭连接池的maxSize很快被占满后续查询全部阻塞。更隐蔽的是有些框架的异常处理会吞掉 close 调用。统一用 try-with-resources或者在 finally 里显式 close。排查时看连接池活跃连接数如果一直等于 maxSize 且不下降基本就是这个原因。5.3 现象时间戳乱序导致写入变慢原因设备时钟不同步解决应用层排序或开乱序合并IoTDB 对乱序数据有容忍度但乱序写入会触发磁盘上的乱序合并写入吞吐明显下降。现象是写入延迟从毫秒级涨到秒级磁盘 IO 升高。根因通常是设备时钟不同步或者网络延迟导致到达顺序乱。解决分两层应用层在攒批前按时间戳排序成本低如果乱序不可避免在 IoTDB 配置里调大乱序合并的窗口但这是用查询性能换写入性能要权衡。5.4 现象存储组建太多服务端启动慢原因按设备建存储组解决按车间或产线建有人图省事每个设备建一个存储组几百个设备就是几百个存储组。IoTDB 每个存储组对应一组文件句柄和 WAL数量多了之后服务端启动要逐个恢复启动时间从秒级变成分钟级。正确做法是按车间或产线建存储组设备作为路径中间节点。已经建多了的话需要迁移数据并删除多余存储组没有后悔药只能提前规划好。5.5 现象GROUP BY 查询结果比预期少原因空区间不返回解决应用层补零降采样查询时如果某个时间区间没有数据IoTDB 不返回该行。前端画折线图时缺失区间会直接连成直线看起来像数据没断实际是断的。这个坑在设备停机场景下特别明显。解决是在 Java 侧拿到结果后按查询时间范围和降采样间隔生成完整时间轴缺失区间填 null 或上一个有效值。别指望 SQL 层补零IoTDB 没这个语义。6. 进阶技巧用 Java 策略模式封装多设备查询与一个验证方法设备类型多了之后查询逻辑会分叉温度设备查降采样状态设备查最新值报警设备查阈值区间。如果写一堆 if-else代码很快失控。我一般用策略模式每种设备类型对应一个查询策略Spring 启动时自动注册。// 查询策略接口不同设备类型实现不同的 SQL 组装逻辑 public interface QueryStrategy { String buildSql(String devicePath, long startTime, long endTime); boolean supports(String deviceType); } // 温度设备降采样平均 Component public class TemperatureQueryStrategy implements QueryStrategy { Override public String buildSql(String devicePath, long startTime, long endTime) { return String.format( SELECT AVG(temperature) FROM %s WHERE time %d AND time %d GROUP BY ([%d, %d), 5m), devicePath, startTime, endTime, startTime, endTime); } Override public boolean supports(String deviceType) { return temperature.equals(deviceType); } } // 状态设备取最新值 Component public class StatusQueryStrategy implements QueryStrategy { Override public String buildSql(String devicePath, long startTime, long endTime) { return String.format( SELECT LAST(status) FROM %s WHERE time %d AND time %d, devicePath, startTime, endTime); } Override public boolean supports(String deviceType) { return status.equals(deviceType); } }逻辑说明supports方法让策略自描述适用范围新增设备类型时只加一个实现类不改调用方。调用侧注入ListQueryStrategy遍历找到 supports 为 true 的策略。参数上startTime和endTime用毫秒时间戳避免字符串拼接时区问题。SQL 里的路径要做白名单校验防止注入——虽然 IoTDB 路径语法有限但设备编号来自外部输入时仍要过滤特殊字符。验证方法写完策略后用一个已知数据集做回归。比如造 24 小时每分钟一个点的温度数据用降采样策略查预期返回 288 个点每个点是 5 分钟平均。如果返回数量不对先查时间区间边界再查 GROUP BY 间隔是否写错单位5m是 5 分钟5s是 5 秒别混。这个验证不用等真实设备用insertTablet批量造数据就行几分钟能跑完。我自己的习惯是每加一个查询策略先写一个最小验证用例用造的数据跑通再接真实设备。这样出问题时能确定是策略逻辑错还是数据问题省掉大量在真实设备上反复试的时间。希望帮到你。本文还有配套的精品资源点击获取

相关新闻

小波变换+平行注意力:多源遥感分类融合新方案

小波变换+平行注意力:多源遥感分类融合新方案

简介:这份资源对应北京航空航天大学学报2023年论文《基于小波变换与平行注意力的多源遥感图像分类》的开源代码,面向遥感图像处理、机器学习及深度学习方向的研究者与工程师,可用于土地利用分类、环境监测、灾害预警等场景。压缩包共56个文件…

2026/9/26 1:57:25 阅读更多 →
柔性开断点(SOP)在配电网电压控制中的应用与实践

柔性开断点(SOP)在配电网电压控制中的应用与实践

1. 项目背景与核心价值在新能源占比快速提升的现代配电网中,电压波动与无功功率失衡问题日益突出。传统配电网采用机械式开关进行拓扑调整,响应速度慢且操作次数有限。柔性开断点(Soft Open Point, SOP)作为一种基于电力电子技术的…

2026/9/25 3:52:25 阅读更多 →
无监督SAR图像配准:无需标注的稠密位移估计实战指南

无监督SAR图像配准:无需标注的稠密位移估计实战指南

简介:无监督SAR图像配准的Python实现方案,内含完整项目源码与说明文档,主要面向计算机视觉、遥感图像处理方向的在校生与研发人员,尤其适合作为课程大作业、毕业设计或初期项目立项的参考。资源共75个文件,以37个Pytho…

2026/9/25 6:43:17 阅读更多 →

最新新闻

OpenClaw 给了每个人“数字分身”,但企业更需要可靠的 AI 员工:用 TaoToken 统一 Key 打通 Agent 配置

OpenClaw 给了每个人“数字分身”,但企业更需要可靠的 AI 员工:用 TaoToken 统一 Key 打通 Agent 配置

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

2026/9/26 13:02:09 阅读更多 →
GLM-5.3本地部署实战:量化、vLLM推理与生产级API集成

GLM-5.3本地部署实战:量化、vLLM推理与生产级API集成

1. 项目概述:为什么是GLM-5.3,又为什么必须本地跑?最近在几个技术群和开源社区里,几乎每天都能看到“GLM-5.3 本地部署”被反复刷屏。不是因为某个新功能发布会,也不是厂商营销推波助澜,而是真实的一线开发…

2026/9/26 13:02:09 阅读更多 →
从0到1搭建AI Agent平台:从Function Calling到业务落地

从0到1搭建AI Agent平台:从Function Calling到业务落地

最近被问得最多的问题,就是AI Agent到底怎么落地。不是那种PPT层面的"我们规划了Agent战略",而是真正动手,从零搭一个能用的Agent平台出来。我自己从最早接触大模型API到现在,前后折腾了大半年,从只会调接口…

2026/9/26 13:02:09 阅读更多 →
老旧管网非开挖检测:声波+AI的真实精度解析

老旧管网非开挖检测:声波+AI的真实精度解析

1. 这不是“听个响”,而是把地下管网变成一张会说话的活地图你有没有见过这样的场景:市政人员蹲在井盖边,手里捏着一个巴掌大的探头,往管道口一塞,几秒钟后平板上就跳出“DN300铸铁管,距井口4.2米处存在环向…

2026/9/26 13:02:09 阅读更多 →
鸿蒙状态管理深度解析:LocalStorage与AppStorage选型与实战

鸿蒙状态管理深度解析:LocalStorage与AppStorage选型与实战

1. 状态管理怎么分层:LocalStorage和AppStorage到底解决了什么问题写鸿蒙UI,不管你是刚入门的新手,还是已经做过几个完整项目的老手,都会碰到一个绕不开的问题:多个组件、多个页面之间的数据,到底怎么共享、…

2026/9/26 13:02:09 阅读更多 →
AI重构Obsidian知识库:从四千条乱笔记到可检索资产

AI重构Obsidian知识库:从四千条乱笔记到可检索资产

1. 先别急着整理:几千条笔记乱成一团,根子不在懒而在系统设计 说个我自己的真实场景:上个月我想用Obsidian找几条关于"项目复盘"的资料,搜索框敲下去,直接跳出两百多条结果,其中几十条标题都是&q…

2026/9/26 13:01:09 阅读更多 →

日新闻

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

数据库课后习题答案别硬背:当测试用例集刷,效率翻倍

简介:万常选版《数据库原理与设计》课后习题答案资源,覆盖第2至6章及第9章,适合正在学习关系模型、数据库建模、关系数据理论与模式求精的本科生、自学者作为复习与自测材料。压缩包共7个文件,含3个doc参考答案、2个sql示例脚本、…

2026/9/26 0:00:25 阅读更多 →
学校官网模拟全流程实践:从页面布局到后端接口与部署

学校官网模拟全流程实践:从页面布局到后端接口与部署

如果你正在找一门 Web 大作业的题目,或者刚开始接触 Web 前端开发想做点能拿来展示的东西,“学校官网模拟”几乎是最稳的选择。题目看着简单,但要把导航、新闻列表、轮播 Banner、二级页面、后台数据都串起来,其实已经把前端布局、…

2026/9/26 0:00:25 阅读更多 →
超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

超级玛丽游戏源码C++:从零搭建横版跳跃游戏工程

简介:这是一份面向游戏开发初学者与C进阶学习者的超级玛丽(超级马里奥)游戏源码,基于C面向对象编程实现,适合想通过经典项目理解游戏主循环、角色类设计、地图关卡加载与物理碰撞检测的读者参考。压缩包共49个文件&…

2026/9/26 0:00:25 阅读更多 →

周新闻

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

Flutter for OpenHarmony游戏卡片渐变背景实战:从原理到性能优化

直接铺开项目本身吧。这几个月我一直在折腾一件事:用Flutter给OpenHarmony做一款游戏集合类的App,说白了就是把若干小游戏塞进一个壳里,用统一入口分发。这个方向本身不算新鲜,真正让我花了不少心思的,是首页那堆游戏卡…

2026/9/25 19:27:14 阅读更多 →
Word表格编号全攻略:从列表编号到题注交叉引用

Word表格编号全攻略:从列表编号到题注交叉引用

写Word文档,最让人头疼的往往是那些“看起来不起眼”的小问题。比如表格编号这事:今天在表后面多加了两个空白行,明天给客户交稿前发现整个章节的编号全部错位,光是挨个改序号就能耗掉大半个下午。我前阵子帮人整理一份上百页的技…

2026/9/25 11:15:26 阅读更多 →
从第一个站到第二个站:独立开发者的静态网站选型与落地实践

从第一个站到第二个站:独立开发者的静态网站选型与落地实践

1. 项目概述1.1 核心需求解析做独立开发者这几年,说实话,第一个网站上线的那天晚上我兴奋得没睡着。但等它跑了半年,流量惨淡、功能臃肿、代码自己都懒得看第二遍之后,我才慢慢琢磨明白一个道理:第一个网站是练手&…

2026/9/25 20:29:09 阅读更多 →

月新闻

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能

持续集成 流水线自动化与 声明式交付 实践:原型怎样变成可用功能分类:[AI/大模型]细分主题:AI 增强型 CI/CD 流水线自动化与 GitOps 实践:Agent 工作流、工具调用与任务拆解:从原型到生产的验收清单很多团队在尝试用大…

2026/9/25 20:29:43 阅读更多 →
容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场

容器编排 生产环境运维与排障实战:复盘记录怎样真正派上用场分类:[工程技术]细分主题:Kubernetes 生产环境运维与排障实战:可复制的项目复盘模板与决策记录大部分团队的事故复盘报告,最后都变成了躺在 Confluence 或钉…

2026/9/25 20:29:31 阅读更多 →
容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步

容器 容器化技术与镜像安全管理:核心链路应该先拆哪一步分类:[工程技术]细分主题:Docker 容器化技术与镜像安全管理:核心链路的逐步实现与关键代码取舍面对一个积累了五六年历史包袱的单体架构应用(包含 Web 接口、后台…

2026/9/25 19:27:26 阅读更多 →