Bladeren bron

!1223 【代码优化】IoT: 物模型
Merge pull request !1223 from puhui999/iot

芋道源码 6 maanden geleden
bovenliggende
commit
88ec5269d9
14 gewijzigde bestanden met toevoegingen van 148 en 56 verwijderingen
  1. 11 2
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java
  2. 11 2
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java
  3. 12 2
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java
  4. 11 2
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java
  5. 11 2
      yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java
  6. 10 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java
  7. 13 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java
  8. 13 3
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java
  9. 11 1
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java
  10. 3 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java
  11. 3 4
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java
  12. 6 7
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java
  13. 9 6
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java
  14. 24 19
      yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java

+ 11 - 2
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotDataSpecsDataTypeEnum.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.iot.enums.thingmodel;
 
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-// TODO @puhui999:加个 ArrayValuable
+import java.util.Arrays;
+
 /**
  * IoT 数据定义的数据类型枚举类
  *
@@ -11,7 +13,7 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
-public enum IotDataSpecsDataTypeEnum {
+public enum IotDataSpecsDataTypeEnum implements ArrayValuable<String> {
 
     INT("int"),
     FLOAT("float"),
@@ -23,6 +25,13 @@ public enum IotDataSpecsDataTypeEnum {
     STRUCT("struct"),
     ARRAY("array");
 
+    public static final String[] ARRAYS = Arrays.stream(values()).map(IotDataSpecsDataTypeEnum::getDataType).toArray(String[]::new);
+
     private final String dataType;
 
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
 }

+ 11 - 2
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelAccessModeEnum.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.iot.enums.thingmodel;
 
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-// TODO @puhui999:加个 ArrayValuable
+import java.util.Arrays;
+
 /**
  * IOT 产品物模型属性读取类型枚举
  *
@@ -11,11 +13,18 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
-public enum IotThingModelAccessModeEnum {
+public enum IotThingModelAccessModeEnum implements ArrayValuable<String> {
 
     READ_ONLY("r"),
     READ_WRITE("rw");
 
+    public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelAccessModeEnum::getMode).toArray(String[]::new);
+
     private final String mode;
 
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
 }

+ 12 - 2
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelParamDirectionEnum.java

@@ -1,9 +1,12 @@
 package cn.iocoder.yudao.module.iot.enums.thingmodel;
 
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-// TODO @puhui999:加个 ArrayValuable
+import java.util.Arrays;
+
+
 /**
  * IOT 产品物模型参数是输入参数还是输出参数枚举
  *
@@ -11,11 +14,18 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
-public enum IotThingModelParamDirectionEnum {
+public enum IotThingModelParamDirectionEnum implements ArrayValuable<String> {
 
     INPUT("input"), // 输入参数
     OUTPUT("output"); // 输出参数
 
+    public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelParamDirectionEnum::getDirection).toArray(String[]::new);
+
     private final String direction;
 
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
 }

+ 11 - 2
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceCallTypeEnum.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.iot.enums.thingmodel;
 
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-// TODO @puhui999:加个 ArrayValuable
+import java.util.Arrays;
+
 /**
  * IOT 产品物模型服务调用方式枚举
  *
@@ -11,11 +13,18 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
-public enum IotThingModelServiceCallTypeEnum {
+public enum IotThingModelServiceCallTypeEnum implements ArrayValuable<String> {
 
     ASYNC("async"), // 异步调用
     SYNC("sync"); // 同步调用
 
+    public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceCallTypeEnum::getType).toArray(String[]::new);
+
     private final String type;
 
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
 }

+ 11 - 2
yudao-module-iot/yudao-module-iot-api/src/main/java/cn/iocoder/yudao/module/iot/enums/thingmodel/IotThingModelServiceEventTypeEnum.java

@@ -1,9 +1,11 @@
 package cn.iocoder.yudao.module.iot.enums.thingmodel;
 
+import cn.iocoder.yudao.framework.common.core.ArrayValuable;
 import lombok.AllArgsConstructor;
 import lombok.Getter;
 
-// TODO @puhui999:加个 ArrayValuable
+import java.util.Arrays;
+
 /**
  * IOT 产品物模型事件类型枚举
  *
@@ -11,12 +13,19 @@ import lombok.Getter;
  */
 @AllArgsConstructor
 @Getter
-public enum IotThingModelServiceEventTypeEnum {
+public enum IotThingModelServiceEventTypeEnum implements ArrayValuable<String> {
 
     INFO("info"), // 信息
     ALERT("alert"), // 告警
     ERROR("error"); // 故障
 
+    public static final String[] ARRAYS = Arrays.stream(values()).map(IotThingModelServiceEventTypeEnum::getType).toArray(String[]::new);
+
     private final String type;
 
+    @Override
+    public String[] array() {
+        return ARRAYS;
+    }
+
 }

+ 10 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelEvent.java

@@ -1,11 +1,14 @@
 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceEventTypeEnum;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Pattern;
 import lombok.Data;
 
 import java.util.List;
 
-// TODO @puhui999:必要的参数校验
 /**
  * 物模型中的事件
  *
@@ -17,10 +20,13 @@ public class ThingModelEvent {
     /**
      * 事件标识符
      */
+    @NotEmpty(message = "事件标识符不能为空")
+    @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "事件标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符")
     private String identifier;
     /**
      * 事件名称
      */
+    @NotEmpty(message = "事件名称不能为空")
     private String name;
     /**
      * 是否是标准品类的必选事件
@@ -31,12 +37,15 @@ public class ThingModelEvent {
      *
      * 枚举 {@link IotThingModelServiceEventTypeEnum}
      */
+    @NotEmpty(message = "事件类型不能为空")
+    @InEnum(IotThingModelServiceEventTypeEnum.class)
     private String type;
     /**
      * 事件的输出参数
      *
      * 输出参数定义事件调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。
      */
+    @Valid
     private List<ThingModelParam> outputParams;
     /**
      * 标识设备需要执行的具体操作

+ 13 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelParam.java

@@ -1,12 +1,15 @@
 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs;
+import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelParamDirectionEnum;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Pattern;
 import lombok.Data;
 
 import java.util.List;
 
-// TODO @puhui999:必要的参数校验
 /**
  * IOT 产品物模型中的参数
  *
@@ -18,16 +21,21 @@ public class ThingModelParam {
     /**
      * 参数标识符
      */
+    @NotEmpty(message = "参数标识符不能为空")
+    @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "参数标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符")
     private String identifier;
     /**
      * 参数名称
      */
+    @NotEmpty(message = "参数名称不能为空")
     private String name;
     /**
      * 用于区分输入或输出参数
      *
      * 枚举 {@link IotThingModelParamDirectionEnum}
      */
+    @NotEmpty(message = "参数方向不能为空")
+    @InEnum(IotThingModelParamDirectionEnum.class)
     private String direction;
     /**
      * 参数的序号。从 0 开始排序,且不能重复。
@@ -37,7 +45,11 @@ public class ThingModelParam {
     private Integer paraOrder;
     /**
      * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致
+     *
+     * 枚举 {@link IotDataSpecsDataTypeEnum}
      */
+    @NotEmpty(message = "数据类型不能为空")
+    @InEnum(IotDataSpecsDataTypeEnum.class)
     private String dataType;
     /**
      * 参数值的数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中

+ 13 - 3
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelProperty.java

@@ -1,12 +1,15 @@
 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.dataType.ThingModelDataSpecs;
+import cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelAccessModeEnum;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Pattern;
 import lombok.Data;
 
 import java.util.List;
 
-// TODO @puhui999:必要的参数校验
 /**
  * 物模型中的属性
  *
@@ -20,26 +23,33 @@ public class ThingModelProperty {
     /**
      * 属性标识符
      */
+    @NotEmpty(message = "属性标识符不能为空")
+    @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "属性标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符")
     private String identifier;
     /**
      * 属性名称
      */
+    @NotEmpty(message = "属性名称不能为空")
     private String name;
     /**
      * 云端可以对该属性进行的操作类型
      *
      * 枚举 {@link IotThingModelAccessModeEnum}
      */
+    @NotEmpty(message = "操作类型不能为空")
+    @InEnum(IotThingModelAccessModeEnum.class)
     private String accessMode;
     /**
      * 是否是标准品类的必选服务
      */
     private Boolean required;
     /**
-     * 数据类型,与 dataSpecs 的 dataType 保持一致
+     * 参数值的数据类型,与 dataSpecs 的 dataType 保持一致
      *
-     * 枚举 {@link cn.iocoder.yudao.module.iot.enums.thingmodel.IotDataSpecsDataTypeEnum}
+     * 枚举 {@link IotDataSpecsDataTypeEnum}
      */
+    @NotEmpty(message = "数据类型不能为空")
+    @InEnum(IotDataSpecsDataTypeEnum.class)
     private String dataType;
     /**
      * 数据类型(dataType)为非列表型(int、float、double、text、date、array)的数据规范存储在 dataSpecs 中

+ 11 - 1
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/model/ThingModelService.java

@@ -1,11 +1,14 @@
 package cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model;
 
+import cn.iocoder.yudao.framework.common.validation.InEnum;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelServiceCallTypeEnum;
+import jakarta.validation.Valid;
+import jakarta.validation.constraints.NotEmpty;
+import jakarta.validation.constraints.Pattern;
 import lombok.Data;
 
 import java.util.List;
 
-// TODO @puhui999:必要的参数校验
 /**
  * 物模型中的服务
  *
@@ -17,10 +20,13 @@ public class ThingModelService {
     /**
      * 服务标识符
      */
+    @NotEmpty(message = "服务标识符不能为空")
+    @Pattern(regexp = "^[a-zA-Z][a-zA-Z0-9_]{0,31}$", message = "服务标识符只能由字母、数字和下划线组成,必须以字母开头,长度不超过32个字符")
     private String identifier;
     /**
      * 服务名称
      */
+    @NotEmpty(message = "服务名称不能为空")
     private String name;
     /**
      * 是否是标准品类的必选服务
@@ -31,18 +37,22 @@ public class ThingModelService {
      *
      * 枚举 {@link IotThingModelServiceCallTypeEnum}
      */
+    @NotEmpty(message = "调用类型不能为空")
+    @InEnum(IotThingModelServiceCallTypeEnum.class)
     private String callType;
     /**
      * 服务的输入参数
      *
      * 输入参数定义服务调用时所需提供的信息,用于控制设备行为或执行特定任务
      */
+    @Valid
     private List<ThingModelParam> inputParams;
     /**
      * 服务的输出参数
      *
      * 输出参数定义服务调用后返回的结果或反馈信息,用于确认操作结果或提供额外的信息。
      */
+    @Valid
     private List<ThingModelParam> outputParams;
     /**
      * 标识设备需要执行的具体操作

+ 3 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelListReqVO.java

@@ -6,19 +6,18 @@ import io.swagger.v3.oas.annotations.media.Schema;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-// TODO @puhui999:部分字段,可以用 cursor 加上 example
 @Schema(description = "管理后台 - IoT 产品物模型 List Request VO")
 @Data
 public class IotThingModelListReqVO {
 
-    @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     @NotNull(message = "产品编号不能为空")
     private Long productId;
 
-    @Schema(description = "功能标识")
+    @Schema(description = "功能标识", example = "temperature")
     private String identifier;
 
-    @Schema(description = "功能名称", example = "张三")
+    @Schema(description = "功能名称", example = "温度")
     private String name;
 
     @Schema(description = "功能类型", example = "1")

+ 3 - 4
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelPageReqVO.java

@@ -9,21 +9,20 @@ import lombok.Data;
 import lombok.EqualsAndHashCode;
 import lombok.ToString;
 
-// TODO @puhui999:部分字段,可以用 cursor 加上 example
 @Schema(description = "管理后台 - IoT 产品物模型分页 Request VO")
 @Data
 @EqualsAndHashCode(callSuper = true)
 @ToString(callSuper = true)
 public class IotThingModelPageReqVO extends PageParam {
 
-    @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     @NotNull(message = "产品编号不能为空")
     private Long productId;
 
-    @Schema(description = "功能标识")
+    @Schema(description = "功能标识", example = "temperature")
     private String identifier;
 
-    @Schema(description = "功能名称", example = "张三")
+    @Schema(description = "功能名称", example = "温度")
     private String name;
 
     @Schema(description = "功能类型", example = "1")

+ 6 - 7
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelRespVO.java

@@ -10,7 +10,6 @@ import lombok.Data;
 
 import java.time.LocalDateTime;
 
-// TODO @puhui999:部分字段,可以用 cursor 加上 example
 @Schema(description = "管理后台 - IoT 产品物模型 Response VO")
 @Data
 @ExcelIgnoreUnannotated
@@ -20,23 +19,23 @@ public class IotThingModelRespVO {
     @ExcelProperty("产品ID")
     private Long id;
 
-    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
     private Long productId;
 
-    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_sensor")
     @ExcelProperty("产品标识")
     private String productKey;
 
-    @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature")
     private String identifier;
 
-    @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温度")
     private String name;
 
-    @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "测量当前环境温度")
     private String description;
 
-    @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     private Integer type;
 
     @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)

+ 9 - 6
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/thingmodel/vo/IotThingModelSaveReqVO.java

@@ -6,11 +6,11 @@ import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelP
 import cn.iocoder.yudao.module.iot.controller.admin.thingmodel.model.ThingModelService;
 import cn.iocoder.yudao.module.iot.enums.thingmodel.IotThingModelTypeEnum;
 import io.swagger.v3.oas.annotations.media.Schema;
+import jakarta.validation.Valid;
 import jakarta.validation.constraints.NotEmpty;
 import jakarta.validation.constraints.NotNull;
 import lombok.Data;
 
-// TODO @puhui999:部分字段,可以用 cursor 加上 example
 @Schema(description = "管理后台 - IoT 产品物模型新增/修改 Request VO")
 @Data
 public class IotThingModelSaveReqVO {
@@ -22,33 +22,36 @@ public class IotThingModelSaveReqVO {
     @NotNull(message = "产品ID不能为空")
     private Long productId;
 
-    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temperature_001")
     @NotEmpty(message = "产品标识不能为空")
     private String productKey;
 
-    @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "temp_monitor")
     @NotEmpty(message = "功能标识不能为空")
     private String identifier;
 
-    @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "温度监测器")
     @NotEmpty(message = "功能名称不能为空")
     private String name;
 
-    @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能描述", requiredMode = Schema.RequiredMode.REQUIRED, example = "用于监测环境温度的传感器")
     private String description;
 
-    @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Schema(description = "功能类型", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
     @NotNull(message = "功能类型不能为空")
     @InEnum(IotThingModelTypeEnum.class)
     private Integer type;
 
     @Schema(description = "属性", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
     private ThingModelProperty property;
 
     @Schema(description = "服务", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
     private ThingModelService service;
 
     @Schema(description = "事件", requiredMode = Schema.RequiredMode.REQUIRED)
+    @Valid
     private ThingModelEvent event;
 
 }

+ 24 - 19
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/thingmodel/IotThingModelServiceImpl.java

@@ -55,7 +55,7 @@ public class IotThingModelServiceImpl implements IotThingModelService {
     @Transactional(rollbackFor = Exception.class)
     public Long createThingModel(IotThingModelSaveReqVO createReqVO) {
         // 1.1 校验功能标识符在同一产品下是否唯一
-        validateIdentifierUnique(createReqVO.getProductId(), createReqVO.getIdentifier());
+        validateIdentifierUnique(null, createReqVO.getProductId(), createReqVO.getIdentifier());
         // 1.2 功能名称在同一产品下是否唯一
         validateNameUnique(createReqVO.getProductId(), createReqVO.getName());
         // 1.3 校验产品状态,发布状态下,不允许新增功能
@@ -81,7 +81,7 @@ public class IotThingModelServiceImpl implements IotThingModelService {
         // 1.1 校验功能是否存在
         validateProductThingModelMapperExists(updateReqVO.getId());
         // 1.2 校验功能标识符是否唯一
-        validateIdentifierUniqueForUpdate(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
+        validateIdentifierUnique(updateReqVO.getId(), updateReqVO.getProductId(), updateReqVO.getIdentifier());
         // 1.3 校验产品状态,发布状态下,不允许操作功能
         validateProductStatus(updateReqVO.getProductId());
 
@@ -159,8 +159,23 @@ public class IotThingModelServiceImpl implements IotThingModelService {
         }
     }
 
-    // TODO @puhui999:这个方法,和 validateIdentifierUnique 可以融合下
-    private void validateIdentifierUniqueForUpdate(Long id, Long productId, String identifier) {
+    private void validateIdentifierUnique(Long id, Long productId, String identifier) {
+        // 1.0 情况一:创建时校验
+        if (id == null) {
+            // 1.1 系统保留字段,不能用于标识符定义
+            if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) {
+                throw exception(THING_MODEL_IDENTIFIER_INVALID);
+            }
+
+            // 1.2 校验唯一
+            IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
+            if (thingModel != null) {
+                throw exception(THING_MODEL_IDENTIFIER_EXISTS);
+            }
+            return;
+        }
+
+        // 2.0 情况二:更新时校验
         IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
         if (thingModel != null && ObjectUtil.notEqual(thingModel.getId(), id)) {
             throw exception(THING_MODEL_IDENTIFIER_EXISTS);
@@ -181,23 +196,10 @@ public class IotThingModelServiceImpl implements IotThingModelService {
         }
     }
 
-    private void validateIdentifierUnique(Long productId, String identifier) {
-        // 系统保留字段,不能用于标识符定义
-        if (StrUtil.equalsAny(identifier, "set", "get", "post", "property", "event", "time", "value")) {
-            throw exception(THING_MODEL_IDENTIFIER_INVALID);
-        }
-
-        // 校验唯一
-        IotThingModelDO thingModel = thingModelMapper.selectByProductIdAndIdentifier(productId, identifier);
-        if (thingModel != null) {
-            throw exception(THING_MODEL_IDENTIFIER_EXISTS);
-        }
-    }
-
     /**
      * 创建默认的事件和服务
      *
-     * @param productId 产品编号
+     * @param productId  产品编号
      * @param productKey 产品标识
      */
     public void createDefaultEventsAndServices(Long productId, String productKey) {
@@ -282,6 +284,7 @@ public class IotThingModelServiceImpl implements IotThingModelService {
     }
 
     // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口
+
     /**
      * 生成属性上报事件
      */
@@ -298,6 +301,7 @@ public class IotThingModelServiceImpl implements IotThingModelService {
     }
 
     // TODO @haohao:是不是不用生成这个?目前属性上报,是个批量接口
+
     /**
      * 生成属性设置服务
      */
@@ -352,7 +356,8 @@ public class IotThingModelServiceImpl implements IotThingModelService {
     }
 
     @CacheEvict(value = RedisKeyConstants.THING_MODEL_LIST, key = "#productKey")
-    public void deleteThingModelListCache0(String productKey) {}
+    public void deleteThingModelListCache0(String productKey) {
+    }
 
     private IotThingModelServiceImpl getSelf() {
         return SpringUtil.getBean(getClass());