Files

135 lines
5.8 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# iot-util 项目开发规范
## 本地测试
- **规则**: 不进行本地启动测试,由用户自行在 IDEA 中运行验证。
- **约束**: 严禁使用任何方式启动或停止本地 Java 进程。
---
## 项目概述
IoT 设备管理工具,对接中国移动 OneNET 平台(iot-api.heclouds.com),提供产品详情、设备列表、设备属性、物模型、数据点等查询功能,并附带 Web 管理界面。
- **框架**: Solon 3.10.5
- **认证**: Sa-Token 1.44.0(登录鉴权)+ HMAC-SHA1IoT 平台鉴权)
- **HTTP 客户端**: OkHttp 4.12.0
- **模板引擎**: FreeMarker
- **JSON**: Jacksonsolon-serialization-jackson 3.10.5
- **端口**: 8081app.yml 配置)
---
## 目录结构
```
src/main/java/com/yixiong/iot/
├── App.java # 启动类
├── config/
│ └── IotProperties.java # IoT 配置属性(对应 app.yml iot.* 节点)
├── controller/
│ ├── AuthController.java # 登录/登出页面路由
│ ├── PageController.java # 主页路由(注入 defaultProductId 到模板)
│ ├── ProductController.java # GET /product/detail
│ ├── DeviceController.java # GET /device/list|detail|event-log|datapoints
│ ├── ThingModelController.java # GET|POST /thingmodel/*
│ └── GlobalExceptionFilter.java # 全局异常过滤,统一返回 JSON
├── service/
│ ├── ProductService.java
│ ├── DeviceService.java
│ └── ThingModelService.java
├── model/
│ ├── IotResponse.java # 通用响应包装(code/msg/requestId/data
│ ├── OldIotResponse.java # 旧版响应(errno/error/data,已备用)
│ ├── ProductDetailData.java
│ ├── DeviceItem.java # 设备列表项 & 设备详情复用
│ ├── DeviceListData.java
│ ├── DeviceEventItem.java
│ ├── DeviceEventListData.java
│ ├── DevicePropertyItem.java # 设备属性最新数据
│ ├── PropertyHistoryData.java # 属性历史包装(data.list
│ ├── PropertyHistoryItem.java
│ ├── DatapointData.java # 数据点(含内部类 DatapointStream/DatapointItem
│ └── ThingModelData.java # 物模型(含内部类 Property/Event/Service
└── util/
├── IotHttpClient.java # OkHttp 封装,HMAC 鉴权,正常响应 DEBUG 日志
└── IotTokenUtil.java # HMAC-SHA1 Token 生成
src/main/resources/
├── app.yml
└── templates/
├── login.ftl # 登录页
└── index.ftl # 主页(产品详情 + 设备列表 Tab,多个弹窗)
```
---
## API 路由一览
| 方法 | 路径 | 说明 |
|------|------|------|
| GET | `/` | 主页(需登录) |
| GET | `/auth/login` | 登录页 |
| POST | `/auth/doLogin` | 登录处理 |
| GET | `/auth/logout` | 登出 |
| GET | `/product/detail?product_id=` | 产品详情 |
| GET | `/device/list` | 设备列表(product_id 取配置默认值) |
| GET | `/device/detail?device_name=` | 设备详情(product_id 取配置默认值) |
| GET | `/device/event-log` | 设备事件记录 |
| GET | `/device/datapoints` | 设备历史数据点 |
| GET | `/thingmodel/query-thing-model` | 产品物模型(product_id 取配置默认值) |
| GET | `/thingmodel/query-device-property?device_name=` | 设备属性最新数据 |
| POST | `/thingmodel/query-device-property-detail` | 设备属性详情(下发命令) |
| GET | `/thingmodel/query-property-history` | 设备属性历史记录(data 为 Object,结构不固定) |
---
## 配置说明(app.yml
```yaml
iot:
auth:
version: "2022-05-01"
resource-name: "userid/459810" # IoT 平台用户 ID
access-key: "..." # HMAC 密钥(Base64
signature-method: "sha1"
expiration-seconds: 3600
http:
base-url: "https://iot-api.heclouds.com" # 新版 APIHMAC 鉴权)
default-product-id: "VGi8wC99jO" # 默认产品 ID,多数接口使用此值
old-base-url: "https://api.heclouds.com" # 旧版 APIapi-key 鉴权,备用)
api-key: "..." # 旧版 Master Key
auth:
username: admin
password: ... # 登录密码
```
---
## 关键设计决策
### IoT 平台鉴权
- 新版接口(`iot-api.heclouds.com`)使用 HMAC-SHA1 Token,放在 `Authorization` 请求头
- Token 格式:`version=...&res=...&et=...&method=sha1&sign=...`(查询字符串格式)
- 每次请求实时生成 Token,避免过期
### HTTP 客户端
- `IotHttpClient.execute()` 不对非 2xx 状态码抛异常,始终返回响应体
- 正常响应打 DEBUG 日志,非 2xx 打 WARN,网络异常打 ERROR
- 全局日志级别 WARN,框架 INFO 日志屏蔽
### 响应反序列化
- 各 Service 使用独立 `ObjectMapper`,配置 `SNAKE_CASE` 命名策略 + 忽略未知字段
- 属性历史接口(`/thingmodel/query-property-history`)的 `data` 结构不固定,反序列化为 `Object` 透传
### 前端页面
- 纯原生 HTML/CSS/JS + FreeMarker,无第三方 UI 框架
- 主页两个 Tab:产品详情、设备列表;页面加载后自动触发两个查询
- 设备列表每行操作按钮:详情、数据点、事件记录、属性(均以弹窗展示)
- 属性弹窗支持二级跳转:属性列表 → 历史记录弹窗
- 产品详情页有"物模型"按钮,展示属性/事件/服务功能点
### 已知注意事项
- `DeviceDetailData.java``OldIotResponse.java` 为旧版 API 遗留,当前设备详情已改用新版接口(`/device/detail`),这两个类暂未删除
- `ThingModelData.ThingModelService` 内部类与 Spring 的 `@Service` 无关,是物模型的服务功能点 DTO