|
|
|
|
|
|
90
|
DRUID_PASSWORD=...
|
90
|
DRUID_PASSWORD=...
|
|
91
|
```
|
91
|
```
|
|
92
|
|
92
|
|
|
93
|
-Spring Boot config uses `${ENV_NAME:default}` syntax for all sensitive values.
|
|
|
|
|
|
93
|
+Spring Boot config uses `${ENV_NAME:default}` syntax for non-sensitive defaults only. **MySQL and Druid passwords have no fallback defaults** — missing env vars will cause startup failures.
|
|
94
|
|
94
|
|
|
95
|
## IoT Data Flow
|
95
|
## IoT Data Flow
|
|
96
|
|
96
|
|
|
|
|
|
|
|
103
|
├─→ MySQL (sys_controller, sys_device tables)
|
103
|
├─→ MySQL (sys_controller, sys_device tables)
|
|
104
|
└─→ TDengine (time-series telemetry tables)
|
104
|
└─→ TDengine (time-series telemetry tables)
|
|
105
|
|
105
|
|
|
106
|
-VehicleSyncTask (@Scheduled every 30s)
|
|
|
|
|
|
106
|
+VehicleSyncTask (@Scheduled every 30s, Redis distributed lock)
|
|
107
|
↓ reads Redis DSB:* keys
|
107
|
↓ reads Redis DSB:* keys
|
|
108
|
├─→ syncs to sysrealtime (MySQL)
|
108
|
├─→ syncs to sysrealtime (MySQL)
|
|
109
|
├─→ updates vehicle GPS in sys_car (MySQL)
|
109
|
├─→ updates vehicle GPS in sys_car (MySQL)
|
|
110
|
├─→ updates sys_indicators KPIs (MySQL)
|
110
|
├─→ updates sys_indicators KPIs (MySQL)
|
|
111
|
- └─→ triggers external webhook
|
|
|
|
|
|
111
|
+ └─→ triggers external webhook (URL from `iot.mqtt.vehicle-trigger-url` config)
|
|
112
|
```
|
112
|
```
|
|
113
|
|
113
|
|
|
114
|
## MQTT Consumers
|
114
|
## MQTT Consumers
|
|
115
|
|
115
|
|
|
116
|
-All MQTT consumers extend `AbstractMqttConsumer` which provides:
|
|
|
|
117
|
-- Connection management (reconnect, keepalive)
|
|
|
|
118
|
-- `checkServerAvailability()` with retry limits
|
|
|
|
|
|
116
|
+Two base classes handle MQTT connections:
|
|
|
|
117
|
+
|
|
|
|
118
|
+**`AbstractMqttConsumer`** (single-topic consumers):
|
|
|
|
119
|
+- Connection management with `synchronized` reconnect/disconnect
|
|
|
|
120
|
+- Broken-state MqttClient detection and recreation on reconnect
|
|
119
|
- Graceful shutdown via `@PreDestroy`
|
121
|
- Graceful shutdown via `@PreDestroy`
|
|
120
|
|
122
|
|
|
|
|
123
|
+**`AbstractDynamicMqttConsumer`** (dynamic multi-topic consumers):
|
|
|
|
124
|
+- Incremental topic subscription refresh (add/remove only changed topics)
|
|
|
|
125
|
+- Batch subscribe with retry logic
|
|
|
|
126
|
+- Connection health checks before subscribe
|
|
|
|
127
|
+
|
|
121
|
Implementations:
|
128
|
Implementations:
|
|
122
|
-- `MqttGenericConsumer` — General telemetry ingestion
|
|
|
|
123
|
-- `MqttStatusConsumer` — Device status messages
|
|
|
|
124
|
-- `MqttFaultConsumer` — Fault/alarm messages
|
|
|
|
|
|
129
|
+- `MqttGenericConsumer` — General telemetry ingestion (single-topic)
|
|
|
|
130
|
+- `MqttStatusConsumer` — Device status messages (single-topic)
|
|
|
|
131
|
+- `MqttFaultConsumer` — Fault/alarm messages (single-topic)
|
|
|
|
132
|
+- `MqttDynamicConsumer` — Dynamic topic subscription (extends AbstractDynamicMqttConsumer)
|
|
|
|
133
|
+- `MqttChargeStationConsumer` — Charge station telemetry (extends AbstractDynamicMqttConsumer)
|
|
125
|
|
134
|
|
|
126
|
## Deployment
|
135
|
## Deployment
|
|
127
|
|
136
|
|
|
|
|
|
|
|
148
|
- Password max retry: 5 attempts, lock time: 10 minutes
|
157
|
- Password max retry: 5 attempts, lock time: 10 minutes
|
|
149
|
- XSS filtering enabled
|
158
|
- XSS filtering enabled
|
|
150
|
- SQL injection prevention: field whitelist + parameterized queries in TDengineService
|
159
|
- SQL injection prevention: field whitelist + parameterized queries in TDengineService
|
|
151
|
-- Table name validation: regex `^[a-zA-Z_][a-zA-Z0-9_]*$` in SysrealtimeService
|
|
|
|
|
|
160
|
+- Table name validation: regex `^[a-zA-Z_][a-zA-Z0-9_]*$` in SysControllerService, SysFaultService, SysAlarmService
|
|
|
|
161
|
+- Input validation at MQTT consumer boundaries (null/empty checks on controllerId, path, timestamp, deviceId)
|
|
|
|
162
|
+- No hardcoded password fallbacks in config files — env vars required at startup
|
|
152
|
|
163
|
|
|
153
|
## API Response Format
|
164
|
## API Response Format
|
|
154
|
|
165
|
|
|
|
|
|
|
|
184
|
- **MyBatis mappers are Java interfaces** with XML mapping files in `src/main/resources/mapper/`
|
195
|
- **MyBatis mappers are Java interfaces** with XML mapping files in `src/main/resources/mapper/`
|
|
185
|
- **Service naming**: Custom IoT services often use concrete classes directly (no `I` prefix)
|
196
|
- **Service naming**: Custom IoT services often use concrete classes directly (no `I` prefix)
|
|
186
|
- **TDengine SQL**: Built with string concatenation but protected by field whitelist (`ALLOWED_COLUMNS`) and `escapeValue()`
|
197
|
- **TDengine SQL**: Built with string concatenation but protected by field whitelist (`ALLOWED_COLUMNS`) and `escapeValue()`
|
|
187
|
-- **No distributed locks**: `VehicleSyncTask` scheduled tasks may duplicate in clustered environments
|
|
|
|
|
|
198
|
+- **Distributed locks**: `VehicleSyncTask` uses Redis `SET NX` for per-method distributed locking (30s delay, 60s TTL)
|
|
|
|
199
|
+- **TDengine cache bounds**: `stableColumnCache` capped at 1000 entries to prevent unbounded growth
|
|
188
|
- **Alibaba Maven mirror** (`https://maven.aliyun.com/repository/public`) configured in root `pom.xml`
|
200
|
- **Alibaba Maven mirror** (`https://maven.aliyun.com/repository/public`) configured in root `pom.xml`
|