Commit 1f8576f6432fe5201497d2c3704de809d7185307
1 parent
9e776924
修改:IOT 根据属性列表,自动生成属性上报事件和属性设置、获取服务
Showing
22 changed files
with
662 additions
and
171 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/IotThinkModelFunctionController.http
| @@ -5,46 +5,140 @@ tenant-id: {{adminTenentId}} | @@ -5,46 +5,140 @@ tenant-id: {{adminTenentId}} | ||
| 5 | Authorization: Bearer {{token}} | 5 | Authorization: Bearer {{token}} |
| 6 | 6 | ||
| 7 | { | 7 | { |
| 8 | - "productId": 1, | ||
| 9 | - "productKey": "123456", | 8 | + "productId": 1002, |
| 9 | + "productKey": "smart-sensor-002", | ||
| 10 | "properties": [ | 10 | "properties": [ |
| 11 | { | 11 | { |
| 12 | - "identifier": "CurrentTemperature", | ||
| 13 | - "name": "当前温度", | 12 | + "identifier": "Temperature", |
| 13 | + "name": "温度", | ||
| 14 | "accessMode": "r", | 14 | "accessMode": "r", |
| 15 | "required": true, | 15 | "required": true, |
| 16 | "dataType": { | 16 | "dataType": { |
| 17 | "type": "float", | 17 | "type": "float", |
| 18 | "specs": { | 18 | "specs": { |
| 19 | - "min": "-40", | ||
| 20 | - "max": "120", | ||
| 21 | - "unit": "°C", | ||
| 22 | - "unitName": "摄氏度", | ||
| 23 | - "step": "0.1" | 19 | + "min": -40.0, |
| 20 | + "max": 125.0, | ||
| 21 | + "step": 0.1, | ||
| 22 | + "unit": "℃" | ||
| 24 | } | 23 | } |
| 25 | - } | 24 | + }, |
| 25 | + "description": "当前温度值" | ||
| 26 | }, | 26 | }, |
| 27 | { | 27 | { |
| 28 | - "identifier": "CurrentHumidity", | ||
| 29 | - "name": "当前湿度", | 28 | + "identifier": "Humidity", |
| 29 | + "name": "湿度", | ||
| 30 | "accessMode": "r", | 30 | "accessMode": "r", |
| 31 | "required": true, | 31 | "required": true, |
| 32 | "dataType": { | 32 | "dataType": { |
| 33 | "type": "float", | 33 | "type": "float", |
| 34 | "specs": { | 34 | "specs": { |
| 35 | - "min": "0", | ||
| 36 | - "max": "100", | ||
| 37 | - "unit": "%", | ||
| 38 | - "unitName": "百分比", | ||
| 39 | - "step": "0.1" | 35 | + "min": 0.0, |
| 36 | + "max": 100.0, | ||
| 37 | + "step": 0.1, | ||
| 38 | + "unit": "%" | ||
| 40 | } | 39 | } |
| 41 | - } | 40 | + }, |
| 41 | + "description": "当前湿度值" | ||
| 42 | + }, | ||
| 43 | + { | ||
| 44 | + "identifier": "GeoLocation", | ||
| 45 | + "name": "地理位置", | ||
| 46 | + "accessMode": "r", | ||
| 47 | + "required": false, | ||
| 48 | + "dataType": { | ||
| 49 | + "type": "struct", | ||
| 50 | + "specs": [ | ||
| 51 | + { | ||
| 52 | + "identifier": "Longitude", | ||
| 53 | + "name": "经度", | ||
| 54 | + "dataType": { | ||
| 55 | + "type": "double", | ||
| 56 | + "specs": { | ||
| 57 | + "min": -180.0, | ||
| 58 | + "max": 180.0, | ||
| 59 | + "step": 0.000001, | ||
| 60 | + "unit": "°" | ||
| 61 | + } | ||
| 62 | + }, | ||
| 63 | + "description": "设备所在位置的经度" | ||
| 64 | + }, | ||
| 65 | + { | ||
| 66 | + "identifier": "Latitude", | ||
| 67 | + "name": "纬度", | ||
| 68 | + "dataType": { | ||
| 69 | + "type": "double", | ||
| 70 | + "specs": { | ||
| 71 | + "min": -90.0, | ||
| 72 | + "max": 90.0, | ||
| 73 | + "step": 0.000001, | ||
| 74 | + "unit": "°" | ||
| 75 | + } | ||
| 76 | + }, | ||
| 77 | + "description": "设备所在位置的纬度" | ||
| 78 | + } | ||
| 79 | + ] | ||
| 80 | + }, | ||
| 81 | + "description": "设备的地理位置信息" | ||
| 82 | + } | ||
| 83 | + ], | ||
| 84 | + "services": [ | ||
| 85 | + { | ||
| 86 | + "identifier": "Reboot", | ||
| 87 | + "name": "重启设备", | ||
| 88 | + "callType": "async", | ||
| 89 | + "inputData": [], | ||
| 90 | + "description": "远程重启设备", | ||
| 91 | + "method": "thing.service.reboot" | ||
| 92 | + }, | ||
| 93 | + { | ||
| 94 | + "identifier": "SetThreshold", | ||
| 95 | + "name": "设置温度阈值", | ||
| 96 | + "callType": "sync", | ||
| 97 | + "inputData": [ | ||
| 98 | + { | ||
| 99 | + "identifier": "Threshold", | ||
| 100 | + "name": "阈值", | ||
| 101 | + "dataType": { | ||
| 102 | + "type": "float", | ||
| 103 | + "specs": { | ||
| 104 | + "min": -40.0, | ||
| 105 | + "max": 125.0, | ||
| 106 | + "step": 0.1, | ||
| 107 | + "unit": "℃" | ||
| 108 | + } | ||
| 109 | + }, | ||
| 110 | + "description": "报警温度阈值" | ||
| 111 | + } | ||
| 112 | + ], | ||
| 113 | + "description": "设置设备的温度报警阈值", | ||
| 114 | + "method": "thing.service.setThreshold" | ||
| 42 | } | 115 | } |
| 43 | ], | 116 | ], |
| 44 | - "services": "{}", | ||
| 45 | - "events": "{}" | 117 | + "events": [ |
| 118 | + { | ||
| 119 | + "identifier": "HighTemperatureAlert", | ||
| 120 | + "name": "高温报警", | ||
| 121 | + "type": "alert", | ||
| 122 | + "outputData": [ | ||
| 123 | + { | ||
| 124 | + "identifier": "CurrentTemperature", | ||
| 125 | + "name": "当前温度", | ||
| 126 | + "dataType": { | ||
| 127 | + "type": "float", | ||
| 128 | + "specs": { | ||
| 129 | + "unit": "℃" | ||
| 130 | + } | ||
| 131 | + }, | ||
| 132 | + "description": "触发报警时的温度值" | ||
| 133 | + } | ||
| 134 | + ], | ||
| 135 | + "description": "当温度超过阈值时触发高温报警事件", | ||
| 136 | + "method": "thing.event.highTemperatureAlert" | ||
| 137 | + } | ||
| 138 | + ] | ||
| 46 | } | 139 | } |
| 47 | 140 | ||
| 141 | + | ||
| 48 | ### 请求 /iot/think-model-function/update 接口 => 成功 | 142 | ### 请求 /iot/think-model-function/update 接口 => 成功 |
| 49 | PUT {{baseUrl}}/iot/think-model-function/update | 143 | PUT {{baseUrl}}/iot/think-model-function/update |
| 50 | Content-Type: application/json | 144 | Content-Type: application/json |
| @@ -53,46 +147,137 @@ Authorization: Bearer {{token}} | @@ -53,46 +147,137 @@ Authorization: Bearer {{token}} | ||
| 53 | 147 | ||
| 54 | { | 148 | { |
| 55 | "id": 1, | 149 | "id": 1, |
| 56 | - "productId": 1, | ||
| 57 | - "productKey": "123456", | 150 | + "productId": 1001, |
| 151 | + "productKey": "smart-sensor-001", | ||
| 58 | "properties": [ | 152 | "properties": [ |
| 59 | { | 153 | { |
| 60 | - "identifier": "CurrentTemperature", | ||
| 61 | - "name": "当前温度", | 154 | + "identifier": "Temperature", |
| 155 | + "name": "温度", | ||
| 62 | "accessMode": "r", | 156 | "accessMode": "r", |
| 63 | "required": true, | 157 | "required": true, |
| 64 | "dataType": { | 158 | "dataType": { |
| 65 | "type": "float", | 159 | "type": "float", |
| 66 | "specs": { | 160 | "specs": { |
| 67 | - "min": "-40", | ||
| 68 | - "max": "130", | ||
| 69 | - "unit": "°C", | ||
| 70 | - "unitName": "摄氏度", | ||
| 71 | - "step": "0.1" | 161 | + "min": -40.0, |
| 162 | + "max": 125.0, | ||
| 163 | + "step": 0.1, | ||
| 164 | + "unit": "℃" | ||
| 72 | } | 165 | } |
| 73 | - } | 166 | + }, |
| 167 | + "description": "当前温度值" | ||
| 74 | }, | 168 | }, |
| 75 | { | 169 | { |
| 76 | - "identifier": "CurrentHumidity", | ||
| 77 | - "name": "当前湿度", | 170 | + "identifier": "Humidity", |
| 171 | + "name": "湿度", | ||
| 78 | "accessMode": "r", | 172 | "accessMode": "r", |
| 79 | "required": true, | 173 | "required": true, |
| 80 | "dataType": { | 174 | "dataType": { |
| 81 | "type": "float", | 175 | "type": "float", |
| 82 | "specs": { | 176 | "specs": { |
| 83 | - "min": "0", | ||
| 84 | - "max": "100", | ||
| 85 | - "unit": "%", | ||
| 86 | - "unitName": "百分比", | ||
| 87 | - "step": "0.1" | 177 | + "min": 0.0, |
| 178 | + "max": 100.0, | ||
| 179 | + "step": 0.1, | ||
| 180 | + "unit": "%" | ||
| 88 | } | 181 | } |
| 89 | - } | 182 | + }, |
| 183 | + "description": "当前湿度值" | ||
| 184 | + }, | ||
| 185 | + { | ||
| 186 | + "identifier": "GeoLocation", | ||
| 187 | + "name": "地理位置", | ||
| 188 | + "accessMode": "r", | ||
| 189 | + "required": false, | ||
| 190 | + "dataType": { | ||
| 191 | + "type": "struct", | ||
| 192 | + "specs": [ | ||
| 193 | + { | ||
| 194 | + "identifier": "Longitude", | ||
| 195 | + "name": "经度", | ||
| 196 | + "dataType": { | ||
| 197 | + "type": "double", | ||
| 198 | + "specs": { | ||
| 199 | + "min": -180.0, | ||
| 200 | + "max": 180.0, | ||
| 201 | + "step": 0.000001, | ||
| 202 | + "unit": "°" | ||
| 203 | + } | ||
| 204 | + }, | ||
| 205 | + "description": "设备所在位置的经度" | ||
| 206 | + }, | ||
| 207 | + { | ||
| 208 | + "identifier": "Latitude", | ||
| 209 | + "name": "纬度", | ||
| 210 | + "dataType": { | ||
| 211 | + "type": "double", | ||
| 212 | + "specs": { | ||
| 213 | + "min": -90.0, | ||
| 214 | + "max": 90.0, | ||
| 215 | + "step": 0.000001, | ||
| 216 | + "unit": "°" | ||
| 217 | + } | ||
| 218 | + }, | ||
| 219 | + "description": "设备所在位置的纬度" | ||
| 220 | + } | ||
| 221 | + ] | ||
| 222 | + }, | ||
| 223 | + "description": "设备的地理位置信息" | ||
| 224 | + } | ||
| 225 | + ], | ||
| 226 | + "services": [ | ||
| 227 | + { | ||
| 228 | + "identifier": "Reboot", | ||
| 229 | + "name": "重启设备", | ||
| 230 | + "callType": "async", | ||
| 231 | + "inputData": [], | ||
| 232 | + "description": "远程重启设备" | ||
| 233 | + }, | ||
| 234 | + { | ||
| 235 | + "identifier": "SetThreshold", | ||
| 236 | + "name": "设置温度阈值", | ||
| 237 | + "callType": "sync", | ||
| 238 | + "inputData": [ | ||
| 239 | + { | ||
| 240 | + "identifier": "Threshold", | ||
| 241 | + "name": "阈值", | ||
| 242 | + "dataType": { | ||
| 243 | + "type": "float", | ||
| 244 | + "specs": { | ||
| 245 | + "min": -40.0, | ||
| 246 | + "max": 125.0, | ||
| 247 | + "step": 0.1, | ||
| 248 | + "unit": "℃" | ||
| 249 | + } | ||
| 250 | + }, | ||
| 251 | + "description": "报警温度阈值" | ||
| 252 | + } | ||
| 253 | + ], | ||
| 254 | + "description": "设置设备的温度报警阈值" | ||
| 90 | } | 255 | } |
| 91 | ], | 256 | ], |
| 92 | - "services": "{}", | ||
| 93 | - "events": "{}" | 257 | + "events": [ |
| 258 | + { | ||
| 259 | + "identifier": "HighTemperatureAlert", | ||
| 260 | + "name": "高温报警", | ||
| 261 | + "type": "alert", | ||
| 262 | + "outputData": [ | ||
| 263 | + { | ||
| 264 | + "identifier": "CurrentTemperature", | ||
| 265 | + "name": "当前温度", | ||
| 266 | + "dataType": { | ||
| 267 | + "type": "float", | ||
| 268 | + "specs": { | ||
| 269 | + "unit": "℃" | ||
| 270 | + } | ||
| 271 | + }, | ||
| 272 | + "description": "触发报警时的温度值" | ||
| 273 | + } | ||
| 274 | + ], | ||
| 275 | + "description": "当温度超过阈值时触发高温报警事件" | ||
| 276 | + } | ||
| 277 | + ] | ||
| 94 | } | 278 | } |
| 95 | 279 | ||
| 280 | + | ||
| 96 | ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 | 281 | ### 请求 /iot/think-model-function/get-by-product-key 接口 => 成功 |
| 97 | GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 | 282 | GET {{baseUrl}}/iot/think-model-function/get-by-product-key?productKey=123456 |
| 98 | tenant-id: {{adminTenentId}} | 283 | tenant-id: {{adminTenentId}} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArgument.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +@Data | ||
| 6 | +public class ThingModelArgument { | ||
| 7 | + private String identifier; | ||
| 8 | + private String name; | ||
| 9 | + private ThingModelDataType dataType; | ||
| 10 | + private String direction; // 用于区分输入或输出参数,"input" 或 "output" | ||
| 11 | + private String description; | ||
| 12 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArraySpecs.java
0 → 100644
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelArrayType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelArrayType extends ThingModelDataType { | ||
| 9 | + private ThingModelArraySpecs specs; | ||
| 10 | +} | ||
| 11 | + |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelBoolType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelBoolType extends ThingModelDataType { | ||
| 9 | + // Bool 类型一般不需要额外的 specs | ||
| 10 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDataType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import com.fasterxml.jackson.annotation.JsonSubTypes; | ||
| 4 | +import com.fasterxml.jackson.annotation.JsonTypeInfo; | ||
| 5 | +import lombok.Data; | ||
| 6 | + | ||
| 7 | +@Data | ||
| 8 | +@JsonTypeInfo(use = JsonTypeInfo.Id.NAME, property = "type", visible = true) | ||
| 9 | +@JsonSubTypes({ | ||
| 10 | + @JsonSubTypes.Type(value = ThingModelIntType.class, name = "int"), | ||
| 11 | + @JsonSubTypes.Type(value = ThingModelFloatType.class, name = "float"), | ||
| 12 | + @JsonSubTypes.Type(value = ThingModelDoubleType.class, name = "double"), | ||
| 13 | + @JsonSubTypes.Type(value = ThingModelTextType.class, name = "text"), | ||
| 14 | + @JsonSubTypes.Type(value = ThingModelDateType.class, name = "date"), | ||
| 15 | + @JsonSubTypes.Type(value = ThingModelBoolType.class, name = "bool"), | ||
| 16 | + @JsonSubTypes.Type(value = ThingModelEnumType.class, name = "enum"), | ||
| 17 | + @JsonSubTypes.Type(value = ThingModelStructType.class, name = "struct"), | ||
| 18 | + @JsonSubTypes.Type(value = ThingModelArrayType.class, name = "array") | ||
| 19 | +}) | ||
| 20 | +public abstract class ThingModelDataType { | ||
| 21 | + private String type; | ||
| 22 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDateType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelDateType extends ThingModelDataType { | ||
| 9 | + // Date 类型一般不需要额外的 specs | ||
| 10 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelDoubleType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelDoubleType extends ThingModelDataType { | ||
| 9 | + private ThingModelDoubleSpecs specs; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +@Data | ||
| 13 | +class ThingModelDoubleSpecs { | ||
| 14 | + private Double min; | ||
| 15 | + private Double max; | ||
| 16 | + private Double step; | ||
| 17 | + private String unit; | ||
| 18 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEnumType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | +import java.util.Map; | ||
| 6 | + | ||
| 7 | +@Data | ||
| 8 | +@EqualsAndHashCode(callSuper = true) | ||
| 9 | +public class ThingModelEnumType extends ThingModelDataType { | ||
| 10 | + private Map<String, String> specs; // 枚举值和描述的键值对 | ||
| 11 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelEvent.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import java.util.List; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +public class ThingModelEvent { | ||
| 8 | + private String identifier; | ||
| 9 | + private String name; | ||
| 10 | + private String type; // "info"、"alert"、"error" | ||
| 11 | + private List<ThingModelArgument> outputData; | ||
| 12 | + private String description; | ||
| 13 | + private String method; | ||
| 14 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelFloatType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelFloatType extends ThingModelDataType { | ||
| 9 | + private ThingModelFloatSpecs specs; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +@Data | ||
| 13 | +class ThingModelFloatSpecs { | ||
| 14 | + private Float min; | ||
| 15 | + private Float max; | ||
| 16 | + private Float step; | ||
| 17 | + private String unit; | ||
| 18 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelIntType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelIntType extends ThingModelDataType { | ||
| 9 | + private ThingModelIntSpecs specs; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +@Data | ||
| 13 | +class ThingModelIntSpecs { | ||
| 14 | + private Integer min; | ||
| 15 | + private Integer max; | ||
| 16 | + private Integer step; | ||
| 17 | + private String unit; | ||
| 18 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelProperty.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +@Data | ||
| 6 | +public class ThingModelProperty { | ||
| 7 | + private String identifier; | ||
| 8 | + private String name; | ||
| 9 | + private String accessMode; // "rw"、"r"、"w" | ||
| 10 | + private boolean required; | ||
| 11 | + private ThingModelDataType dataType; | ||
| 12 | + private String description; | ||
| 13 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelService.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import java.util.List; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +public class ThingModelService { | ||
| 8 | + private String identifier; | ||
| 9 | + private String name; | ||
| 10 | + private String callType; // "sync"、"async" | ||
| 11 | + private List<ThingModelArgument> inputData; | ||
| 12 | + private List<ThingModelArgument> outputData; | ||
| 13 | + private String description; | ||
| 14 | + private String method; | ||
| 15 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructField.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | + | ||
| 5 | +@Data | ||
| 6 | +public class ThingModelStructField { | ||
| 7 | + private String identifier; | ||
| 8 | + private String name; | ||
| 9 | + private ThingModelDataType dataType; | ||
| 10 | + private String description; | ||
| 11 | +} | ||
| 0 | \ No newline at end of file | 12 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelStructType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | +import java.util.List; | ||
| 6 | + | ||
| 7 | +@Data | ||
| 8 | +@EqualsAndHashCode(callSuper = true) | ||
| 9 | +public class ThingModelStructType extends ThingModelDataType { | ||
| 10 | + private List<ThingModelStructField> specs; | ||
| 11 | +} | ||
| 12 | + | ||
| 13 | + |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/thingModel/ThingModelTextType.java
0 → 100644
| 1 | +package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel; | ||
| 2 | + | ||
| 3 | +import lombok.Data; | ||
| 4 | +import lombok.EqualsAndHashCode; | ||
| 5 | + | ||
| 6 | +@Data | ||
| 7 | +@EqualsAndHashCode(callSuper = true) | ||
| 8 | +public class ThingModelTextType extends ThingModelDataType { | ||
| 9 | + private ThingModelTextSpecs specs; | ||
| 10 | +} | ||
| 11 | + | ||
| 12 | +@Data | ||
| 13 | +class ThingModelTextSpecs { | ||
| 14 | + private Integer length; // 最大长度 | ||
| 15 | +} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThingModelProperty.java deleted
| 1 | -package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; | ||
| 2 | - | ||
| 3 | -import io.swagger.v3.oas.annotations.media.Schema; | ||
| 4 | -import lombok.Data; | ||
| 5 | - | ||
| 6 | -import java.util.List; | ||
| 7 | - | ||
| 8 | -@Schema(description = "管理后台 - IoT 产品物模型属性") | ||
| 9 | -@Data | ||
| 10 | -public class IotThingModelProperty { | ||
| 11 | - | ||
| 12 | - @Schema(description = "属性标识符") | ||
| 13 | - private String identifier; | ||
| 14 | - | ||
| 15 | - @Schema(description = "属性名称") | ||
| 16 | - private String name; | ||
| 17 | - | ||
| 18 | - @Schema(description = "访问模式 (r/rw)") | ||
| 19 | - private String accessMode; | ||
| 20 | - | ||
| 21 | - @Schema(description = "是否必需") | ||
| 22 | - private boolean required; | ||
| 23 | - | ||
| 24 | - @Schema(description = "数据类型") | ||
| 25 | - private DataType dataType; | ||
| 26 | - | ||
| 27 | - @Schema(description = "数据类型") | ||
| 28 | - @Data | ||
| 29 | - public static class DataType { | ||
| 30 | - | ||
| 31 | - @Schema(description = "数据类型(float, double, struct, enum等)") | ||
| 32 | - private String type; | ||
| 33 | - | ||
| 34 | - @Schema(description = "单一类型的规格(适用于float, double等)") | ||
| 35 | - private Specs specs; | ||
| 36 | - | ||
| 37 | - @Schema(description = "结构体字段(适用于struct类型)") | ||
| 38 | - private List<StructField> structSpecs; | ||
| 39 | - | ||
| 40 | - @Schema(description = "规格") | ||
| 41 | - @Data | ||
| 42 | - public static class Specs { | ||
| 43 | - | ||
| 44 | - @Schema(description = "最小值") | ||
| 45 | - private String min; | ||
| 46 | - | ||
| 47 | - @Schema(description = "最大值") | ||
| 48 | - private String max; | ||
| 49 | - | ||
| 50 | - @Schema(description = "单位符号") | ||
| 51 | - private String unit; | ||
| 52 | - | ||
| 53 | - @Schema(description = "单位名称") | ||
| 54 | - private String unitName; | ||
| 55 | - | ||
| 56 | - @Schema(description = "步进值") | ||
| 57 | - private String step; | ||
| 58 | - } | ||
| 59 | - | ||
| 60 | - @Schema(description = "结构体字段") | ||
| 61 | - @Data | ||
| 62 | - public static class StructField { | ||
| 63 | - | ||
| 64 | - @Schema(description = "字段标识符") | ||
| 65 | - private String identifier; | ||
| 66 | - | ||
| 67 | - @Schema(description = "字段名称") | ||
| 68 | - private String name; | ||
| 69 | - | ||
| 70 | - @Schema(description = "字段的数据类型") | ||
| 71 | - private DataType dataType; | ||
| 72 | - } | ||
| 73 | - } | ||
| 74 | - | ||
| 75 | - @Schema(description = "枚举规格") | ||
| 76 | - @Data | ||
| 77 | - public static class EnumSpecs { | ||
| 78 | - | ||
| 79 | - @Schema(description = "枚举值") | ||
| 80 | - private int value; | ||
| 81 | - | ||
| 82 | - @Schema(description = "枚举名称") | ||
| 83 | - private String name; | ||
| 84 | - | ||
| 85 | - public EnumSpecs(int value, String name) { | ||
| 86 | - this.value = value; | ||
| 87 | - this.name = name; | ||
| 88 | - } | ||
| 89 | - } | ||
| 90 | -} |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionRespVO.java
| 1 | package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; | 1 | package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; | ||
| 3 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; | 6 | import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; |
| 4 | import com.alibaba.excel.annotation.ExcelProperty; | 7 | import com.alibaba.excel.annotation.ExcelProperty; |
| 5 | import io.swagger.v3.oas.annotations.media.Schema; | 8 | import io.swagger.v3.oas.annotations.media.Schema; |
| @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO { | @@ -23,15 +26,15 @@ public class IotThinkModelFunctionRespVO { | ||
| 23 | 26 | ||
| 24 | @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) | 27 | @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) |
| 25 | @ExcelProperty("属性列表") | 28 | @ExcelProperty("属性列表") |
| 26 | - private List<IotThingModelProperty> properties; | 29 | + private List<ThingModelProperty> properties; |
| 27 | 30 | ||
| 28 | @Schema(description = "服务列表") | 31 | @Schema(description = "服务列表") |
| 29 | @ExcelProperty("服务列表") | 32 | @ExcelProperty("服务列表") |
| 30 | - private String services; | 33 | + private List<ThingModelService> services; |
| 31 | 34 | ||
| 32 | @Schema(description = "事件列表") | 35 | @Schema(description = "事件列表") |
| 33 | @ExcelProperty("事件列表") | 36 | @ExcelProperty("事件列表") |
| 34 | - private String events; | 37 | + private List<ThingModelEvent> events; |
| 35 | 38 | ||
| 36 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) | 39 | @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED) |
| 37 | @ExcelProperty("创建时间") | 40 | @ExcelProperty("创建时间") |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thinkmodelfunction/vo/IotThinkModelFunctionSaveReqVO.java
| 1 | package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; | 1 | package cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo; |
| 2 | 2 | ||
| 3 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; | ||
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; | ||
| 3 | import io.swagger.v3.oas.annotations.media.Schema; | 6 | import io.swagger.v3.oas.annotations.media.Schema; |
| 4 | -import lombok.*; | ||
| 5 | -import java.util.*; | ||
| 6 | -import jakarta.validation.constraints.*; | 7 | +import jakarta.validation.constraints.NotEmpty; |
| 8 | +import jakarta.validation.constraints.NotNull; | ||
| 9 | +import lombok.Data; | ||
| 10 | + | ||
| 11 | +import java.util.List; | ||
| 7 | 12 | ||
| 8 | @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") | 13 | @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO") |
| 9 | @Data | 14 | @Data |
| @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO { | @@ -22,12 +27,12 @@ public class IotThinkModelFunctionSaveReqVO { | ||
| 22 | 27 | ||
| 23 | @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) | 28 | @Schema(description = "属性列表", requiredMode = Schema.RequiredMode.REQUIRED) |
| 24 | @NotEmpty(message = "属性列表不能为空") | 29 | @NotEmpty(message = "属性列表不能为空") |
| 25 | - private List<IotThingModelProperty> properties; | 30 | + private List<ThingModelProperty> properties; |
| 26 | 31 | ||
| 27 | @Schema(description = "服务列表") | 32 | @Schema(description = "服务列表") |
| 28 | - private String services; | 33 | + private List<ThingModelService> services; |
| 29 | 34 | ||
| 30 | @Schema(description = "事件列表") | 35 | @Schema(description = "事件列表") |
| 31 | - private String events; | 36 | + private List<ThingModelEvent> events; |
| 32 | 37 | ||
| 33 | } | 38 | } |
| 34 | \ No newline at end of file | 39 | \ No newline at end of file |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/convert/thinkmodelfunction/IotThinkModelFunctionConvert.java
| 1 | package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; | 1 | package cn.iocoder.yudao.module.iot.convert.thinkmodelfunction; |
| 2 | 2 | ||
| 3 | import cn.hutool.json.JSONUtil; | 3 | import cn.hutool.json.JSONUtil; |
| 4 | -import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThingModelProperty; | 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelEvent; |
| 5 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelProperty; | ||
| 6 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.ThingModelService; | ||
| 5 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; | 7 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionRespVO; |
| 6 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; | 8 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; |
| 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | 9 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; |
| 8 | -import org.mapstruct.AfterMapping; | ||
| 9 | import org.mapstruct.Mapper; | 10 | import org.mapstruct.Mapper; |
| 10 | import org.mapstruct.Mapping; | 11 | import org.mapstruct.Mapping; |
| 11 | -import org.mapstruct.MappingTarget; | ||
| 12 | import org.mapstruct.factory.Mappers; | 12 | import org.mapstruct.factory.Mappers; |
| 13 | 13 | ||
| 14 | +import java.util.ArrayList; | ||
| 14 | import java.util.List; | 15 | import java.util.List; |
| 15 | 16 | ||
| 16 | @Mapper | 17 | @Mapper |
| @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert { | @@ -18,34 +19,43 @@ public interface IotThinkModelFunctionConvert { | ||
| 18 | 19 | ||
| 19 | IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); | 20 | IotThinkModelFunctionConvert INSTANCE = Mappers.getMapper(IotThinkModelFunctionConvert.class); |
| 20 | 21 | ||
| 21 | - // 将 SaveReqVO 转换为 DO | ||
| 22 | - @Mapping(target = "properties", ignore = true) | 22 | + // 将 SaveReqVO 转换为 DO 对象,处理 properties, services, events 字段 |
| 23 | + @Mapping(target = "properties", expression = "java(convertPropertiesToJson(bean.getProperties()))") | ||
| 24 | + @Mapping(target = "services", expression = "java(convertServicesToJson(bean.getServices()))") | ||
| 25 | + @Mapping(target = "events", expression = "java(convertEventsToJson(bean.getEvents()))") | ||
| 23 | IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); | 26 | IotThinkModelFunctionDO convert(IotThinkModelFunctionSaveReqVO bean); |
| 24 | 27 | ||
| 25 | - // 将 DO 转换为 RespVO | ||
| 26 | - @Mapping(target = "properties", ignore = true) | 28 | + default String convertPropertiesToJson(List<ThingModelProperty> properties) { |
| 29 | + return properties != null ? JSONUtil.toJsonStr(properties) : "[]"; | ||
| 30 | + } | ||
| 31 | + | ||
| 32 | + default String convertServicesToJson(List<ThingModelService> services) { | ||
| 33 | + return services != null ? JSONUtil.toJsonStr(services) : "[]"; | ||
| 34 | + } | ||
| 35 | + | ||
| 36 | + default String convertEventsToJson(List<ThingModelEvent> events) { | ||
| 37 | + return events != null ? JSONUtil.toJsonStr(events) : "[]"; | ||
| 38 | + } | ||
| 39 | + | ||
| 40 | + // 将 DO 转换为 RespVO 对象,处理 properties, services, events 字段 | ||
| 41 | + @Mapping(target = "properties", expression = "java(convertJsonToProperties(bean.getProperties()))") | ||
| 42 | + @Mapping(target = "services", expression = "java(convertJsonToServices(bean.getServices()))") | ||
| 43 | + @Mapping(target = "events", expression = "java(convertJsonToEvents(bean.getEvents()))") | ||
| 27 | IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); | 44 | IotThinkModelFunctionRespVO convert(IotThinkModelFunctionDO bean); |
| 28 | 45 | ||
| 29 | - // 处理 properties 字段的转换,从 VO 到 DO | ||
| 30 | - @AfterMapping | ||
| 31 | - default void convertPropertiesToDO(IotThinkModelFunctionSaveReqVO source, @MappingTarget IotThinkModelFunctionDO target) { | ||
| 32 | - target.setProperties(JSONUtil.toJsonStr(source.getProperties())); | 46 | + default List<ThingModelProperty> convertJsonToProperties(String propertiesJson) { |
| 47 | + return propertiesJson != null ? JSONUtil.toList(propertiesJson, ThingModelProperty.class) : new ArrayList<>(); | ||
| 33 | } | 48 | } |
| 34 | 49 | ||
| 35 | - // 处理 properties 字段的转换,从 DO 到 VO | ||
| 36 | - @AfterMapping | ||
| 37 | - default void convertPropertiesToVO(IotThinkModelFunctionDO source, @MappingTarget IotThinkModelFunctionRespVO target) { | ||
| 38 | - target.setProperties(JSONUtil.toList(source.getProperties(), IotThingModelProperty.class)); | 50 | + default List<ThingModelService> convertJsonToServices(String servicesJson) { |
| 51 | + return servicesJson != null ? JSONUtil.toList(servicesJson, ThingModelService.class) : new ArrayList<>(); | ||
| 52 | + } | ||
| 53 | + | ||
| 54 | + default List<ThingModelEvent> convertJsonToEvents(String eventsJson) { | ||
| 55 | + return eventsJson != null ? JSONUtil.toList(eventsJson, ThingModelEvent.class) : new ArrayList<>(); | ||
| 39 | } | 56 | } |
| 40 | 57 | ||
| 41 | // 批量转换 DO 列表到 RespVO 列表 | 58 | // 批量转换 DO 列表到 RespVO 列表 |
| 42 | List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list); | 59 | List<IotThinkModelFunctionRespVO> convertList(List<IotThinkModelFunctionDO> list); |
| 43 | - | ||
| 44 | - // 批量转换处理 properties 字段 | ||
| 45 | - @AfterMapping | ||
| 46 | - default void convertPropertiesListToVO(List<IotThinkModelFunctionDO> sourceList, @MappingTarget List<IotThinkModelFunctionRespVO> targetList) { | ||
| 47 | - for (int i = 0; i < sourceList.size(); i++) { | ||
| 48 | - convertPropertiesToVO(sourceList.get(i), targetList.get(i)); | ||
| 49 | - } | ||
| 50 | - } | ||
| 51 | } | 60 | } |
| 61 | + |
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thinkmodelfunction/IotThinkModelFunctionServiceImpl.java
| 1 | package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; | 1 | package cn.iocoder.yudao.module.iot.service.thinkmodelfunction; |
| 2 | 2 | ||
| 3 | -import cn.iocoder.yudao.framework.common.exception.ServiceException; | 3 | +import cn.hutool.json.JSONUtil; |
| 4 | +import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.thingModel.*; | ||
| 4 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; | 5 | import cn.iocoder.yudao.module.iot.controller.admin.thinkmodelfunction.vo.IotThinkModelFunctionSaveReqVO; |
| 5 | import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; | 6 | import cn.iocoder.yudao.module.iot.convert.thinkmodelfunction.IotThinkModelFunctionConvert; |
| 6 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; | 7 | import cn.iocoder.yudao.module.iot.dal.dataobject.thinkmodelfunction.IotThinkModelFunctionDO; |
| @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j; | @@ -10,6 +11,10 @@ import lombok.extern.slf4j.Slf4j; | ||
| 10 | import org.springframework.stereotype.Service; | 11 | import org.springframework.stereotype.Service; |
| 11 | import org.springframework.validation.annotation.Validated; | 12 | import org.springframework.validation.annotation.Validated; |
| 12 | 13 | ||
| 14 | +import java.util.ArrayList; | ||
| 15 | +import java.util.Collections; | ||
| 16 | +import java.util.List; | ||
| 17 | + | ||
| 13 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; | 18 | import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; |
| 14 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; | 19 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY; |
| 15 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; | 20 | import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.THINK_MODEL_FUNCTION_NOT_EXISTS; |
| @@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -27,10 +32,13 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 27 | log.info("创建物模型,参数:{}", createReqVO); | 32 | log.info("创建物模型,参数:{}", createReqVO); |
| 28 | // 验证 ProductKey 对应的产品物模型是否已存在 | 33 | // 验证 ProductKey 对应的产品物模型是否已存在 |
| 29 | validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); | 34 | validateThinkModelFunctionNotExistsByProductKey(createReqVO.getProductKey()); |
| 30 | - // 插入 | 35 | + // 转换请求对象为数据对象 |
| 31 | IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); | 36 | IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(createReqVO); |
| 37 | + // 自动生成属性上报事件和属性设置、获取服务 | ||
| 38 | + generateDefaultEventsAndServices(createReqVO, thinkModelFunction); | ||
| 39 | + // 插入数据库 | ||
| 32 | thinkModelFunctionMapper.insert(thinkModelFunction); | 40 | thinkModelFunctionMapper.insert(thinkModelFunction); |
| 33 | - // 返回 | 41 | + // 返回生成的 ID |
| 34 | return thinkModelFunction.getId(); | 42 | return thinkModelFunction.getId(); |
| 35 | } | 43 | } |
| 36 | 44 | ||
| @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -43,9 +51,9 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 43 | @Override | 51 | @Override |
| 44 | public void deleteThinkModelFunction(Long id) { | 52 | public void deleteThinkModelFunction(Long id) { |
| 45 | log.info("删除物模型,id:{}", id); | 53 | log.info("删除物模型,id:{}", id); |
| 46 | - // 校验存在 | 54 | + // 校验物模型是否存在 |
| 47 | validateThinkModelFunctionExists(id); | 55 | validateThinkModelFunctionExists(id); |
| 48 | - // 删除 | 56 | + // 删除物模型 |
| 49 | thinkModelFunctionMapper.deleteById(id); | 57 | thinkModelFunctionMapper.deleteById(id); |
| 50 | } | 58 | } |
| 51 | 59 | ||
| @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -68,12 +76,15 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 68 | @Override | 76 | @Override |
| 69 | public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { | 77 | public void updateThinkModelFunction(IotThinkModelFunctionSaveReqVO updateReqVO) { |
| 70 | log.info("更新物模型,参数:{}", updateReqVO); | 78 | log.info("更新物模型,参数:{}", updateReqVO); |
| 71 | - // 校验存在 | 79 | + // 校验物模型是否存在 |
| 72 | validateThinkModelFunctionExists(updateReqVO.getId()); | 80 | validateThinkModelFunctionExists(updateReqVO.getId()); |
| 73 | - // 校验 productKey 是否重复 | 81 | + // 校验 ProductKey 是否唯一 |
| 74 | validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); | 82 | validateProductKeyUnique(updateReqVO.getId(), updateReqVO.getProductKey()); |
| 75 | - // 更新 | 83 | + // 转换请求对象为数据对象 |
| 76 | IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); | 84 | IotThinkModelFunctionDO thinkModelFunction = IotThinkModelFunctionConvert.INSTANCE.convert(updateReqVO); |
| 85 | + // 自动生成或更新属性上报事件和属性设置、获取服务 | ||
| 86 | + generateDefaultEventsAndServices(updateReqVO, thinkModelFunction); | ||
| 87 | + // 更新数据库 | ||
| 77 | thinkModelFunctionMapper.updateById(thinkModelFunction); | 88 | thinkModelFunctionMapper.updateById(thinkModelFunction); |
| 78 | } | 89 | } |
| 79 | 90 | ||
| @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | @@ -83,4 +94,151 @@ public class IotThinkModelFunctionServiceImpl implements IotThinkModelFunctionSe | ||
| 83 | throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); | 94 | throw exception(THINK_MODEL_FUNCTION_EXISTS_BY_PRODUCT_KEY); |
| 84 | } | 95 | } |
| 85 | } | 96 | } |
| 86 | -} | ||
| 87 | \ No newline at end of file | 97 | \ No newline at end of file |
| 98 | + | ||
| 99 | + /** | ||
| 100 | + * @ TODO 还要再优化 | ||
| 101 | + * 根据属性列表,自动生成属性上报事件和属性设置、获取服务 | ||
| 102 | + */ | ||
| 103 | + private void generateDefaultEventsAndServices(IotThinkModelFunctionSaveReqVO reqVO, IotThinkModelFunctionDO thinkModelFunction) { | ||
| 104 | + // 获取属性列表 | ||
| 105 | + List<ThingModelProperty> properties = reqVO.getProperties(); | ||
| 106 | + if (properties == null) { | ||
| 107 | + properties = new ArrayList<>(); | ||
| 108 | + } | ||
| 109 | + | ||
| 110 | + // 生成属性上报事件 | ||
| 111 | + List<ThingModelEvent> events = reqVO.getEvents() != null ? new ArrayList<>(reqVO.getEvents()) : new ArrayList<>(); | ||
| 112 | + ThingModelEvent propertyPostEvent = generatePropertyPostEvent(properties); | ||
| 113 | + events.add(propertyPostEvent); | ||
| 114 | + | ||
| 115 | + // 生成属性设置和获取服务 | ||
| 116 | + List<ThingModelService> services = reqVO.getServices() != null ? new ArrayList<>(reqVO.getServices()) : new ArrayList<>(); | ||
| 117 | + ThingModelService propertySetService = generatePropertySetService(properties); | ||
| 118 | + if (propertySetService != null) { | ||
| 119 | + services.add(propertySetService); | ||
| 120 | + } | ||
| 121 | + ThingModelService propertyGetService = generatePropertyGetService(properties); | ||
| 122 | + if (propertyGetService != null) { | ||
| 123 | + services.add(propertyGetService); | ||
| 124 | + } | ||
| 125 | + | ||
| 126 | + // 更新 thinkModelFunction 对象的 events 和 services 字段 | ||
| 127 | + thinkModelFunction.setEvents(JSONUtil.toJsonStr(events)); | ||
| 128 | + thinkModelFunction.setServices(JSONUtil.toJsonStr(services)); | ||
| 129 | + } | ||
| 130 | + | ||
| 131 | + /** | ||
| 132 | + * 生成属性上报事件 | ||
| 133 | + */ | ||
| 134 | + private ThingModelEvent generatePropertyPostEvent(List<ThingModelProperty> properties) { | ||
| 135 | + ThingModelEvent event = new ThingModelEvent(); | ||
| 136 | + event.setIdentifier("post"); | ||
| 137 | + event.setName("属性上报"); | ||
| 138 | + event.setType("info"); | ||
| 139 | + event.setDescription("属性上报事件"); | ||
| 140 | + event.setMethod("thing.event.property.post"); | ||
| 141 | + | ||
| 142 | + // 将属性列表转换为事件的输出参数 | ||
| 143 | + List<ThingModelArgument> outputData = new ArrayList<>(); | ||
| 144 | + for (ThingModelProperty property : properties) { | ||
| 145 | + ThingModelArgument arg = new ThingModelArgument(); | ||
| 146 | + arg.setIdentifier(property.getIdentifier()); | ||
| 147 | + arg.setName(property.getName()); | ||
| 148 | + arg.setDataType(property.getDataType()); | ||
| 149 | + arg.setDescription(property.getDescription()); | ||
| 150 | + arg.setDirection("output"); // 设置为输出参数 | ||
| 151 | + outputData.add(arg); | ||
| 152 | + } | ||
| 153 | + event.setOutputData(outputData); | ||
| 154 | + | ||
| 155 | + return event; | ||
| 156 | + } | ||
| 157 | + | ||
| 158 | + /** | ||
| 159 | + * 生成属性设置服务 | ||
| 160 | + */ | ||
| 161 | + private ThingModelService generatePropertySetService(List<ThingModelProperty> properties) { | ||
| 162 | + List<ThingModelArgument> inputData = new ArrayList<>(); | ||
| 163 | + for (ThingModelProperty property : properties) { | ||
| 164 | + if ("w".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { | ||
| 165 | + ThingModelArgument arg = new ThingModelArgument(); | ||
| 166 | + arg.setIdentifier(property.getIdentifier()); | ||
| 167 | + arg.setName(property.getName()); | ||
| 168 | + arg.setDataType(property.getDataType()); | ||
| 169 | + arg.setDescription(property.getDescription()); | ||
| 170 | + arg.setDirection("input"); // 设置为输入参数 | ||
| 171 | + inputData.add(arg); | ||
| 172 | + } | ||
| 173 | + } | ||
| 174 | + if (inputData.isEmpty()) { | ||
| 175 | + // 如果没有可写属性,不生成属性设置服务 | ||
| 176 | + return null; | ||
| 177 | + } | ||
| 178 | + | ||
| 179 | + ThingModelService service = new ThingModelService(); | ||
| 180 | + service.setIdentifier("set"); | ||
| 181 | + service.setName("属性设置"); | ||
| 182 | + service.setCallType("async"); | ||
| 183 | + service.setDescription("属性设置服务"); | ||
| 184 | + service.setMethod("thing.service.property.set"); | ||
| 185 | + service.setInputData(inputData); | ||
| 186 | + // 属性设置服务一般不需要输出参数 | ||
| 187 | + service.setOutputData(new ArrayList<>()); | ||
| 188 | + | ||
| 189 | + return service; | ||
| 190 | + } | ||
| 191 | + | ||
| 192 | + /** | ||
| 193 | + * 生成属性获取服务 | ||
| 194 | + */ | ||
| 195 | + private ThingModelService generatePropertyGetService(List<ThingModelProperty> properties) { | ||
| 196 | + List<ThingModelArgument> outputData = new ArrayList<>(); | ||
| 197 | + for (ThingModelProperty property : properties) { | ||
| 198 | + if ("r".equals(property.getAccessMode()) || "rw".equals(property.getAccessMode())) { | ||
| 199 | + ThingModelArgument arg = new ThingModelArgument(); | ||
| 200 | + arg.setIdentifier(property.getIdentifier()); | ||
| 201 | + arg.setName(property.getName()); | ||
| 202 | + arg.setDataType(property.getDataType()); | ||
| 203 | + arg.setDescription(property.getDescription()); | ||
| 204 | + arg.setDirection("output"); // 设置为输出参数 | ||
| 205 | + outputData.add(arg); | ||
| 206 | + } | ||
| 207 | + } | ||
| 208 | + if (outputData.isEmpty()) { | ||
| 209 | + // 如果没有可读属性,不生成属性获取服务 | ||
| 210 | + return null; | ||
| 211 | + } | ||
| 212 | + | ||
| 213 | + ThingModelService service = new ThingModelService(); | ||
| 214 | + service.setIdentifier("get"); | ||
| 215 | + service.setName("属性获取"); | ||
| 216 | + service.setCallType("async"); | ||
| 217 | + service.setDescription("属性获取服务"); | ||
| 218 | + service.setMethod("thing.service.property.get"); | ||
| 219 | + | ||
| 220 | + // 定义输入参数:属性标识符列表 | ||
| 221 | + ThingModelArgument inputArg = new ThingModelArgument(); | ||
| 222 | + inputArg.setIdentifier("properties"); | ||
| 223 | + inputArg.setName("属性标识符列表"); | ||
| 224 | + inputArg.setDescription("需要获取的属性标识符列表"); | ||
| 225 | + inputArg.setDirection("input"); // 设置为输入参数 | ||
| 226 | + | ||
| 227 | + // 创建数组类型,元素类型为文本类型(字符串) | ||
| 228 | + ThingModelArrayType arrayType = new ThingModelArrayType(); | ||
| 229 | + arrayType.setType("array"); | ||
| 230 | + ThingModelArraySpecs arraySpecs = new ThingModelArraySpecs(); | ||
| 231 | + // 不指定数组长度,size 可以为 0 或者省略 | ||
| 232 | + ThingModelTextType textType = new ThingModelTextType(); | ||
| 233 | + textType.setType("text"); | ||
| 234 | + // 如果有需要,可以设置 TextType 的 specs,如长度限制 | ||
| 235 | + arraySpecs.setItem(textType); | ||
| 236 | + arrayType.setSpecs(arraySpecs); | ||
| 237 | + | ||
| 238 | + inputArg.setDataType(arrayType); | ||
| 239 | + | ||
| 240 | + service.setInputData(Collections.singletonList(inputArg)); | ||
| 241 | + service.setOutputData(outputData); | ||
| 242 | + | ||
| 243 | + return service; | ||
| 244 | + } | ||
| 245 | +} |