Commit f9d782c701def246dede38b5e0b0a240ff16f4c3

Authored by YunaiV
1 parent 3ca4cf26

feat:【IoT 物联网】优化固件相关请求和响应对象,添加文件 URL 格式校验,更新固件 ID 类型为 Long

Showing 12 changed files with 131 additions and 225 deletions
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareCreateReqVO.java
@@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema; @@ -4,6 +4,7 @@ import io.swagger.v3.oas.annotations.media.Schema;
4 import jakarta.validation.constraints.NotEmpty; 4 import jakarta.validation.constraints.NotEmpty;
5 import jakarta.validation.constraints.NotNull; 5 import jakarta.validation.constraints.NotNull;
6 import lombok.Data; 6 import lombok.Data;
  7 +import org.hibernate.validator.constraints.URL;
7 8
8 @Schema(description = "管理后台 - IoT OTA 固件创建 Request VO") 9 @Schema(description = "管理后台 - IoT OTA 固件创建 Request VO")
9 @Data 10 @Data
@@ -22,17 +23,11 @@ public class IotOtaFirmwareCreateReqVO { @@ -22,17 +23,11 @@ public class IotOtaFirmwareCreateReqVO {
22 23
23 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 24 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
24 @NotNull(message = "产品编号不能为空") 25 @NotNull(message = "产品编号不能为空")
25 - private String productId; 26 + private Long productId;
26 27
27 - @Schema(description = "签名方式", example = "MD5")  
28 - // TODO @li:是不是必传哈  
29 - private String signMethod;  
30 -  
31 - @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/yudao-firmware.zip") 28 + @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/1.zip")
32 @NotEmpty(message = "固件文件 URL 不能为空") 29 @NotEmpty(message = "固件文件 URL 不能为空")
  30 + @URL(message = "固件文件 URL 格式错误")
33 private String fileUrl; 31 private String fileUrl;
34 32
35 - @Schema(description = "自定义信息,建议使用 JSON 格式", example = "{\"key1\":\"value1\",\"key2\":\"value2\"}")  
36 - private String information;  
37 -  
38 } 33 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwarePageReqVO.java
@@ -3,21 +3,24 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; @@ -3,21 +3,24 @@ package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
3 import cn.iocoder.yudao.framework.common.pojo.PageParam; 3 import cn.iocoder.yudao.framework.common.pojo.PageParam;
4 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
5 import lombok.Data; 5 import lombok.Data;
  6 +import org.springframework.format.annotation.DateTimeFormat;
  7 +
  8 +import java.time.LocalDateTime;
  9 +
  10 +import static cn.iocoder.yudao.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND;
6 11
7 -@Data  
8 @Schema(description = "管理后台 - IoT OTA 固件分页 Request VO") 12 @Schema(description = "管理后台 - IoT OTA 固件分页 Request VO")
  13 +@Data
9 public class IotOtaFirmwarePageReqVO extends PageParam { 14 public class IotOtaFirmwarePageReqVO extends PageParam {
10 15
11 - /**  
12 - * 固件名称  
13 - */  
14 @Schema(description = "固件名称", example = "智能开关固件") 16 @Schema(description = "固件名称", example = "智能开关固件")
15 private String name; 17 private String name;
16 18
17 - /**  
18 - * 产品标识  
19 - */  
20 @Schema(description = "产品标识", example = "1024") 19 @Schema(description = "产品标识", example = "1024")
21 private String productId; 20 private String productId;
22 21
  22 + @Schema(description = "创建时间", example = "[2022-07-01 00:00:00, 2022-07-01 23:59:59]")
  23 + @DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
  24 + private LocalDateTime[] createTime;
  25 +
23 } 26 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareRespVO.java
1 package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; 1 package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
2 2
3 -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;  
4 -import com.fhs.core.trans.anno.Trans;  
5 -import com.fhs.core.trans.constant.TransType;  
6 import com.fhs.core.trans.vo.VO; 3 import com.fhs.core.trans.vo.VO;
7 import io.swagger.v3.oas.annotations.media.Schema; 4 import io.swagger.v3.oas.annotations.media.Schema;
8 import lombok.Data; 5 import lombok.Data;
9 6
10 -@Data 7 +import java.time.LocalDateTime;
  8 +
11 @Schema(description = "管理后台 - IoT OTA 固件 Response VO") 9 @Schema(description = "管理后台 - IoT OTA 固件 Response VO")
  10 +@Data
12 public class IotOtaFirmwareRespVO implements VO { 11 public class IotOtaFirmwareRespVO implements VO {
13 12
14 - /**  
15 - * 固件编号  
16 - */  
17 @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 13 @Schema(description = "固件编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
18 private Long id; 14 private Long id;
19 - /**  
20 - * 固件名称  
21 - */  
22 - @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA固件") 15 +
  16 + @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA 固件")
23 private String name; 17 private String name;
24 - /**  
25 - * 固件描述  
26 - */ 18 +
27 @Schema(description = "固件描述") 19 @Schema(description = "固件描述")
28 private String description; 20 private String description;
29 - /**  
30 - * 版本号  
31 - */ 21 +
32 @Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0.0") 22 @Schema(description = "版本号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1.0.0")
33 private String version; 23 private String version;
34 24
35 - /**  
36 - * 产品编号  
37 - * <p>  
38 - * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}  
39 - */  
40 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 25 @Schema(description = "产品编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
41 - @Trans(type = TransType.SIMPLE, target = IotProductDO.class, fields = {"name"}, refs = {"productName"})  
42 - private String productId;  
43 - /**  
44 - * 产品标识  
45 - * <p>  
46 - * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()}  
47 - */  
48 - @Schema(description = "产品标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "iot-product-key")  
49 - private String productKey;  
50 - /**  
51 - * 产品名称  
52 - */  
53 - @Schema(description = "产品名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "OTA产品")  
54 - private String productName;  
55 - /**  
56 - * 签名方式  
57 - * <p>  
58 - * 例如说:MD5、SHA256  
59 - */  
60 - @Schema(description = "签名方式", example = "MD5")  
61 - private String signMethod;  
62 - /**  
63 - * 固件文件签名  
64 - */  
65 - @Schema(description = "固件文件签名", example = "1024")  
66 - private String fileSign;  
67 - /**  
68 - * 固件文件大小  
69 - */ 26 + private Long productId;
  27 +
  28 + @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn/firmware.bin")
  29 + private String fileUrl;
  30 +
70 @Schema(description = "固件文件大小", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024") 31 @Schema(description = "固件文件大小", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
71 private Long fileSize; 32 private Long fileSize;
72 - /**  
73 - * 固件文件 URL  
74 - */  
75 - @Schema(description = "固件文件 URL", requiredMode = Schema.RequiredMode.REQUIRED, example = "https://www.iocoder.cn")  
76 - private String fileUrl;  
77 - /**  
78 - * 自定义信息,建议使用 JSON 格式  
79 - */  
80 - @Schema(description = "自定义信息,建议使用 JSON 格式")  
81 - private String information; 33 +
  34 + @Schema(description = "固件文件签名算法", example = "MD5")
  35 + private String fileDigestAlgorithm;
  36 +
  37 + @Schema(description = "固件文件签名结果", example = "d41d8cd98f00b204e9800998ecf8427e")
  38 + private String fileDigestValue;
  39 +
  40 + @Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
  41 + private LocalDateTime createTime;
  42 +
  43 + @Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
  44 + private LocalDateTime updateTime;
82 45
83 } 46 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/controller/admin/ota/vo/firmware/IotOtaFirmwareUpdateReqVO.java
1 package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware; 1 package cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware;
2 2
3 import io.swagger.v3.oas.annotations.media.Schema; 3 import io.swagger.v3.oas.annotations.media.Schema;
4 -import jakarta.validation.constraints.NotEmpty;  
5 import jakarta.validation.constraints.NotNull; 4 import jakarta.validation.constraints.NotNull;
6 import lombok.Data; 5 import lombok.Data;
7 6
@@ -13,9 +12,7 @@ public class IotOtaFirmwareUpdateReqVO { @@ -13,9 +12,7 @@ public class IotOtaFirmwareUpdateReqVO {
13 @NotNull(message = "固件编号不能为空") 12 @NotNull(message = "固件编号不能为空")
14 private Long id; 13 private Long id;
15 14
16 - // TODO @li:name 是不是可以飞必传哈  
17 - @Schema(description = "固件名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "智能开关固件")  
18 - @NotEmpty(message = "固件名称不能为空") 15 + @Schema(description = "固件名称", example = "智能开关固件")
19 private String name; 16 private String name;
20 17
21 @Schema(description = "固件描述", example = "某品牌型号固件,测试用") 18 @Schema(description = "固件描述", example = "某品牌型号固件,测试用")
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/dataobject/ota/IotOtaFirmwareDO.java
1 package cn.iocoder.yudao.module.iot.dal.dataobject.ota; 1 package cn.iocoder.yudao.module.iot.dal.dataobject.ota;
2 2
  3 +import cn.hutool.crypto.digest.DigestAlgorithm;
3 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO; 4 import cn.iocoder.yudao.framework.mybatis.core.dataobject.BaseDO;
4 import com.baomidou.mybatisplus.annotation.KeySequence; 5 import com.baomidou.mybatisplus.annotation.KeySequence;
5 import com.baomidou.mybatisplus.annotation.TableId; 6 import com.baomidou.mybatisplus.annotation.TableId;
@@ -34,7 +35,7 @@ public class IotOtaFirmwareDO extends BaseDO { @@ -34,7 +35,7 @@ public class IotOtaFirmwareDO extends BaseDO {
34 */ 35 */
35 private String name; 36 private String name;
36 /** 37 /**
37 - * 固件版本 38 + * 固件描述
38 */ 39 */
39 private String description; 40 private String description;
40 /** 41 /**
@@ -47,37 +48,25 @@ public class IotOtaFirmwareDO extends BaseDO { @@ -47,37 +48,25 @@ public class IotOtaFirmwareDO extends BaseDO {
47 * 48 *
48 * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()} 49 * 关联 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getId()}
49 */ 50 */
50 - // TODO @li:帮我改成 Long 哈,写错了  
51 - private String productId;  
52 - /**  
53 - * 产品标识  
54 - *  
55 - * 冗余 {@link cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO#getProductKey()}  
56 - */  
57 - private String productKey; 51 + private Long productId;
58 52
59 /** 53 /**
60 - * 签名方式  
61 - *  
62 - * 例如说:MD5、SHA256  
63 - */  
64 - private String signMethod;  
65 - /**  
66 - * 固件文件签名 54 + * 固件文件 URL
67 */ 55 */
68 - private String fileSign; 56 + private String fileUrl;
69 /** 57 /**
70 * 固件文件大小 58 * 固件文件大小
71 */ 59 */
72 private Long fileSize; 60 private Long fileSize;
73 /** 61 /**
74 - * 固件文件 URL 62 + * 固件文件签名算法
  63 + *
  64 + * 枚举 {@link DigestAlgorithm},目前只使用 MD5
75 */ 65 */
76 - private String fileUrl;  
77 - 66 + private String fileDigestAlgorithm;
78 /** 67 /**
79 - * 自定义信息,建议使用 JSON 格式 68 + * 固件文件签名结果
80 */ 69 */
81 - private String information; 70 + private String fileDigestValue;
82 71
83 } 72 }
84 \ No newline at end of file 73 \ No newline at end of file
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/dal/mysql/ota/IotOtaFirmwareMapper.java
@@ -9,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper; @@ -9,7 +9,6 @@ import org.apache.ibatis.annotations.Mapper;
9 9
10 import java.util.List; 10 import java.util.List;
11 11
12 -// TODO @li:参考 IotOtaUpgradeRecordMapper 的写法  
13 @Mapper 12 @Mapper
14 public interface IotOtaFirmwareMapper extends BaseMapperX<IotOtaFirmwareDO> { 13 public interface IotOtaFirmwareMapper extends BaseMapperX<IotOtaFirmwareDO> {
15 14
@@ -20,21 +19,16 @@ public interface IotOtaFirmwareMapper extends BaseMapperX&lt;IotOtaFirmwareDO&gt; { @@ -20,21 +19,16 @@ public interface IotOtaFirmwareMapper extends BaseMapperX&lt;IotOtaFirmwareDO&gt; {
20 * @param version 固件版本号,用于筛选固件信息。 19 * @param version 固件版本号,用于筛选固件信息。
21 * @return 返回符合条件的固件信息列表。 20 * @return 返回符合条件的固件信息列表。
22 */ 21 */
23 - default List<IotOtaFirmwareDO> selectByProductIdAndVersion(String productId, String version) { 22 + default List<IotOtaFirmwareDO> selectByProductIdAndVersion(Long productId, String version) {
24 return selectList(IotOtaFirmwareDO::getProductId, productId, 23 return selectList(IotOtaFirmwareDO::getProductId, productId,
25 IotOtaFirmwareDO::getVersion, version); 24 IotOtaFirmwareDO::getVersion, version);
26 } 25 }
27 26
28 - /**  
29 - * 分页查询固件信息,支持根据名称和产品ID进行筛选,并按创建时间降序排列。  
30 - *  
31 - * @param pageReqVO 分页查询请求对象,包含分页参数和筛选条件。  
32 - * @return 返回分页查询结果,包含符合条件的固件信息列表。  
33 - */  
34 default PageResult<IotOtaFirmwareDO> selectPage(IotOtaFirmwarePageReqVO pageReqVO) { 27 default PageResult<IotOtaFirmwareDO> selectPage(IotOtaFirmwarePageReqVO pageReqVO) {
35 return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaFirmwareDO>() 28 return selectPage(pageReqVO, new LambdaQueryWrapperX<IotOtaFirmwareDO>()
36 .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName()) 29 .likeIfPresent(IotOtaFirmwareDO::getName, pageReqVO.getName())
37 .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId()) 30 .eqIfPresent(IotOtaFirmwareDO::getProductId, pageReqVO.getProductId())
  31 + .betweenIfPresent(IotOtaFirmwareDO::getCreateTime, pageReqVO.getCreateTime())
38 .orderByDesc(IotOtaFirmwareDO::getCreateTime)); 32 .orderByDesc(IotOtaFirmwareDO::getCreateTime));
39 } 33 }
40 34
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareService.java
@@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa @@ -7,7 +7,6 @@ import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwa
7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; 7 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
8 import jakarta.validation.Valid; 8 import jakarta.validation.Valid;
9 9
10 -// TODO @li:注释写的有点冗余,可以看看别的模块哈。= = AI 生成的注释,有的时候太啰嗦了,需要处理下的哈  
11 /** 10 /**
12 * OTA 固件管理 Service 11 * OTA 固件管理 Service
13 * 12 *
@@ -18,41 +17,39 @@ public interface IotOtaFirmwareService { @@ -18,41 +17,39 @@ public interface IotOtaFirmwareService {
18 /** 17 /**
19 * 创建 OTA 固件 18 * 创建 OTA 固件
20 * 19 *
21 - * @param saveReqVO OTA固件保存请求对象,包含固件的相关信息  
22 - * @return 返回新创建的固件的ID 20 + * @param saveReqVO 固件信息
  21 + * @return 固件编号
23 */ 22 */
24 Long createOtaFirmware(@Valid IotOtaFirmwareCreateReqVO saveReqVO); 23 Long createOtaFirmware(@Valid IotOtaFirmwareCreateReqVO saveReqVO);
25 24
26 /** 25 /**
27 * 更新 OTA 固件信息 26 * 更新 OTA 固件信息
28 * 27 *
29 - * @param updateReqVO OTA固件保存请求对象,包含需要更新的固件信息 28 + * @param updateReqVO 固件信息
30 */ 29 */
31 void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO); 30 void updateOtaFirmware(@Valid IotOtaFirmwareUpdateReqVO updateReqVO);
32 31
33 /** 32 /**
34 * 根据 ID 获取 OTA 固件信息 33 * 根据 ID 获取 OTA 固件信息
35 * 34 *
36 - * @param id OTA固件的唯一标识符  
37 - * @return 返回OTA固件的详细信息对象 35 + * @param id OTA 固件编号
  36 + * @return 固件信息
38 */ 37 */
39 IotOtaFirmwareDO getOtaFirmware(Long id); 38 IotOtaFirmwareDO getOtaFirmware(Long id);
40 39
41 /** 40 /**
42 * 分页查询 OTA 固件信息 41 * 分页查询 OTA 固件信息
43 * 42 *
44 - * @param pageReqVO 包含分页查询条件的请求对象  
45 - * @return 返回分页查询结果,包含固件信息列表和分页信息 43 + * @param pageReqVO 分页查询条件
  44 + * @return 分页结果
46 */ 45 */
47 PageResult<IotOtaFirmwareDO> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO); 46 PageResult<IotOtaFirmwareDO> getOtaFirmwarePage(@Valid IotOtaFirmwarePageReqVO pageReqVO);
48 47
49 /** 48 /**
50 * 验证物联网 OTA 固件是否存在 49 * 验证物联网 OTA 固件是否存在
51 * 50 *
52 - * @param id 固件的唯一标识符  
53 - * 该方法用于检查系统中是否存在与给定ID关联的物联网OTA固件信息  
54 - * 主要目的是在进行固件更新操作前,确保目标固件已经存在并可以被访问  
55 - * 如果固件不存在,该方法可能抛出异常或返回错误信息,具体行为未定义 51 + * @param id 物联网 OTA 固件编号
  52 + * @return OTA 固件
56 */ 53 */
57 IotOtaFirmwareDO validateFirmwareExists(Long id); 54 IotOtaFirmwareDO validateFirmwareExists(Long id);
58 55
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaFirmwareServiceImpl.java
1 package cn.iocoder.yudao.module.iot.service.ota; 1 package cn.iocoder.yudao.module.iot.service.ota;
2 2
3 -import cn.hutool.core.collection.CollUtil;  
4 -import cn.hutool.core.convert.Convert; 3 +import cn.hutool.crypto.digest.DigestAlgorithm;
  4 +import cn.hutool.crypto.digest.DigestUtil;
  5 +import cn.hutool.http.HttpUtil;
5 import cn.iocoder.yudao.framework.common.pojo.PageResult; 6 import cn.iocoder.yudao.framework.common.pojo.PageResult;
6 import cn.iocoder.yudao.framework.common.util.object.BeanUtils; 7 import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
7 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO; 8 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareCreateReqVO;
8 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO; 9 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwarePageReqVO;
9 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO; 10 import cn.iocoder.yudao.module.iot.controller.admin.ota.vo.firmware.IotOtaFirmwareUpdateReqVO;
10 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO; 11 import cn.iocoder.yudao.module.iot.dal.dataobject.ota.IotOtaFirmwareDO;
11 -import cn.iocoder.yudao.module.iot.dal.dataobject.product.IotProductDO;  
12 import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper; 12 import cn.iocoder.yudao.module.iot.dal.mysql.ota.IotOtaFirmwareMapper;
13 import cn.iocoder.yudao.module.iot.service.product.IotProductService; 13 import cn.iocoder.yudao.module.iot.service.product.IotProductService;
14 import jakarta.annotation.Resource; 14 import jakarta.annotation.Resource;
@@ -17,8 +17,7 @@ import org.springframework.context.annotation.Lazy; @@ -17,8 +17,7 @@ import org.springframework.context.annotation.Lazy;
17 import org.springframework.stereotype.Service; 17 import org.springframework.stereotype.Service;
18 import org.springframework.validation.annotation.Validated; 18 import org.springframework.validation.annotation.Validated;
19 19
20 -import java.util.List;  
21 -import java.util.Objects; 20 +import java.io.ByteArrayInputStream;
22 21
23 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 22 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
24 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS; 23 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.OTA_FIRMWARE_NOT_EXISTS;
@@ -37,16 +36,20 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @@ -37,16 +36,20 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
37 36
38 @Override 37 @Override
39 public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) { 38 public Long createOtaFirmware(IotOtaFirmwareCreateReqVO saveReqVO) {
40 - // 1. 校验固件产品 + 版本号不能重复 39 + // 1.1 校验固件产品 + 版本号不能重复
41 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion()); 40 validateProductAndVersionDuplicate(saveReqVO.getProductId(), saveReqVO.getVersion());
  41 + // 1.2 校验产品存在
  42 + productService.validateProductExists(saveReqVO.getProductId());
42 43
43 - // 2.1.转化数据格式,准备存储到数据库中 44 + // 2. 构建对象 + 存储
44 IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class); 45 IotOtaFirmwareDO firmware = BeanUtils.toBean(saveReqVO, IotOtaFirmwareDO.class);
45 - // 2.2.查询ProductKey  
46 - // TODO @li:productService.getProduct(Convert.toLong(firmware.getProductId())) 放到 1. 后面,先做参考校验。逻辑两段:1)先参数校验;2)构建对象 + 存储  
47 - IotProductDO product = productService.getProduct(Convert.toLong(firmware.getProductId()));  
48 - firmware.setProductKey(Objects.requireNonNull(product).getProductKey());  
49 - // TODO @芋艿: 附件、附件签名等属性的计算 46 + // 2.1 计算文件签名等属性
  47 + try {
  48 + calculateFileDigest(firmware);
  49 + } catch (Exception e) {
  50 + log.error("[createOtaFirmware][url({}) 计算文件签名失败]", firmware.getFileUrl(), e);
  51 + throw new RuntimeException("计算文件签名失败: " + e.getMessage());
  52 + }
50 otaFirmwareMapper.insert(firmware); 53 otaFirmwareMapper.insert(firmware);
51 return firmware.getId(); 54 return firmware.getId();
52 } 55 }
@@ -80,25 +83,34 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService { @@ -80,25 +83,34 @@ public class IotOtaFirmwareServiceImpl implements IotOtaFirmwareService {
80 return firmware; 83 return firmware;
81 } 84 }
82 85
83 - // TODO @li:注释有点冗余  
84 /** 86 /**
85 * 验证产品和版本号是否重复 87 * 验证产品和版本号是否重复
86 - * <p>  
87 - * 该方法用于确保在系统中不存在具有相同产品ID和版本号的固件条目  
88 - * 它通过调用otaFirmwareMapper的selectByProductIdAndVersion方法来查询数据库中是否存在匹配的产品ID和版本号的固件信息  
89 - * 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在,从而避免数据重复  
90 - *  
91 - * @param productId 产品ID,用于数据库查询  
92 - * @param version 版本号,用于数据库查询  
93 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,则抛出异常,提示固件信息已存在  
94 */ 88 */
95 - private void validateProductAndVersionDuplicate(String productId, String version) {  
96 - // 查询数据库中是否存在具有相同产品ID和版本号的固件信息  
97 - List<IotOtaFirmwareDO> list = otaFirmwareMapper.selectByProductIdAndVersion(productId, version);  
98 - // 如果查询结果非空且不为null,则抛出异常,提示固件信息已存在  
99 - if (CollUtil.isNotEmpty(list)) { 89 + private void validateProductAndVersionDuplicate(Long productId, String version) {
  90 + // 只查询1条记录检查是否存在
  91 + IotOtaFirmwareDO firmware = otaFirmwareMapper.selectOne(IotOtaFirmwareDO::getProductId, productId,
  92 + IotOtaFirmwareDO::getVersion, version);
  93 + if (firmware != null) {
100 throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE); 94 throw exception(OTA_FIRMWARE_PRODUCT_VERSION_DUPLICATE);
101 } 95 }
102 } 96 }
103 97
  98 + /**
  99 + * 计算文件签名
  100 + *
  101 + * @param firmware 固件对象
  102 + * @throws Exception 下载或计算签名失败时抛出异常
  103 + */
  104 + private void calculateFileDigest(IotOtaFirmwareDO firmware) throws Exception {
  105 + String fileUrl = firmware.getFileUrl();
  106 + // 下载文件并计算签名
  107 + byte[] fileBytes = HttpUtil.downloadBytes(fileUrl);
  108 + // 设置文件大小
  109 + firmware.setFileSize((long) fileBytes.length);
  110 + // 计算 MD5 签名
  111 + firmware.setFileDigestAlgorithm(DigestAlgorithm.MD5.getValue());
  112 + String md5Hex = DigestUtil.digester(firmware.getFileDigestAlgorithm()).digestHex(new ByteArrayInputStream(fileBytes));
  113 + firmware.setFileDigestValue(md5Hex);
  114 + }
  115 +
104 } 116 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeRecordServiceImpl.java
@@ -34,24 +34,19 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @@ -34,24 +34,19 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic
34 34
35 @Resource 35 @Resource
36 private IotOtaUpgradeRecordMapper upgradeRecordMapper; 36 private IotOtaUpgradeRecordMapper upgradeRecordMapper;
37 - // TODO @li:1)@Resource 写在 @Lazy 之前,先用关键注解;2)有必要的情况下,在写 @Lazy 注解。  
38 - @Lazy  
39 @Resource 37 @Resource
40 private IotDeviceService deviceService; 38 private IotDeviceService deviceService;
41 - @Lazy  
42 @Resource 39 @Resource
43 private IotOtaFirmwareService firmwareService; 40 private IotOtaFirmwareService firmwareService;
44 - @Lazy  
45 @Resource 41 @Resource
46 private IotOtaUpgradeTaskService upgradeTaskService; 42 private IotOtaUpgradeTaskService upgradeTaskService;
47 43
48 @Override 44 @Override
49 public void createOtaUpgradeRecordBatch(List<Long> deviceIds, Long firmwareId, Long upgradeTaskId) { 45 public void createOtaUpgradeRecordBatch(List<Long> deviceIds, Long firmwareId, Long upgradeTaskId) {
50 // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始 46 // 1. 校验升级记录信息是否存在,并且已经取消的任务可以重新开始
51 - // TODO @li:批量查询。。  
52 deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId))); 47 deviceIds.forEach(deviceId -> validateUpgradeRecordDuplicate(firmwareId, upgradeTaskId, String.valueOf(deviceId)));
53 48
54 - // 2.初始化OTA升级记录列表信息 49 + // 2. 初始化OTA升级记录列表信息
55 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId); 50 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskService.getUpgradeTask(upgradeTaskId);
56 IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId); 51 IotOtaFirmwareDO firmware = firmwareService.getOtaFirmware(firmwareId);
57 List<IotDeviceDO> deviceList = deviceService.getDeviceListByIdList(deviceIds); 52 List<IotDeviceDO> deviceList = deviceService.getDeviceListByIdList(deviceIds);
@@ -67,10 +62,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @@ -67,10 +62,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic
67 upgradeRecord.setProgress(0); 62 upgradeRecord.setProgress(0);
68 return upgradeRecord; 63 return upgradeRecord;
69 }).toList(); 64 }).toList();
70 - // 3.保存数据 65 + // 3. 保存数据
71 upgradeRecordMapper.insertBatch(upgradeRecordList); 66 upgradeRecordMapper.insertBatch(upgradeRecordList);
72 // TODO @芋艿:在这里需要处理推送升级任务的逻辑 67 // TODO @芋艿:在这里需要处理推送升级任务的逻辑
73 -  
74 } 68 }
75 69
76 // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。 70 // TODO @li:1)方法注释,简单写;2)父类写了注释,子类就不用写了。。。
@@ -116,9 +110,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @@ -116,9 +110,9 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic
116 110
117 @Override 111 @Override
118 public void retryUpgradeRecord(Long id) { 112 public void retryUpgradeRecord(Long id) {
119 - // 1.1.校验升级记录信息是否存在 113 + // 1.1 校验升级记录信息是否存在
120 IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id); 114 IotOtaUpgradeRecordDO upgradeRecord = validateUpgradeRecordExists(id);
121 - // 1.2.校验升级记录是否可以重新升级 115 + // 1.2 校验升级记录是否可以重新升级
122 validateUpgradeRecordCanRetry(upgradeRecord); 116 validateUpgradeRecordCanRetry(upgradeRecord);
123 117
124 // 2. 将一些数据重置,这样定时任务轮询就可以重启任务 118 // 2. 将一些数据重置,这样定时任务轮询就可以重启任务
@@ -191,16 +185,12 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @@ -191,16 +185,12 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic
191 * @param deviceId 设备ID,用于标识特定的设备 185 * @param deviceId 设备ID,用于标识特定的设备
192 */ 186 */
193 private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) { 187 private void validateUpgradeRecordDuplicate(Long firmwareId, Long taskId, String deviceId) {
194 - // 根据条件查询升级记录  
195 IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId); 188 IotOtaUpgradeRecordDO upgradeRecord = upgradeRecordMapper.selectByConditions(firmwareId, taskId, deviceId);
196 - // 如果查询到升级记录且状态不是已取消,则抛出异常  
197 - // TODO @li:if return,减少括号层级;  
198 - // TODO @li:ObjUtil.notEquals,尽量不用 !取否逻辑;  
199 - if (upgradeRecord != null) {  
200 - if (!IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus().equals(upgradeRecord.getStatus())) {  
201 - // TODO @li:提示的时候,需要把 deviceName 给提示出来,不然用户不知道哪个重复啦。  
202 - throw exception(OTA_UPGRADE_RECORD_DUPLICATE);  
203 - } 189 + if (upgradeRecord == null) {
  190 + return;
  191 + }
  192 + if (!Objects.equals(upgradeRecord.getStatus(), IotOtaUpgradeRecordStatusEnum.CANCELED.getStatus())) {
  193 + throw exception(OTA_UPGRADE_RECORD_DUPLICATE);
204 } 194 }
205 } 195 }
206 196
@@ -216,12 +206,10 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic @@ -216,12 +206,10 @@ public class IotOtaUpgradeRecordServiceImpl implements IotOtaUpgradeRecordServic
216 */ 206 */
217 // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法; 207 // TODO @li:这种一次性的方法(不复用的),其实一步一定要抽成小方法;
218 private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) { 208 private void validateUpgradeRecordCanRetry(IotOtaUpgradeRecordDO upgradeRecord) {
219 - // 检查升级记录的状态是否为 PENDING、PUSHED 或 UPGRADING  
220 if (ObjectUtils.equalsAny(upgradeRecord.getStatus(), 209 if (ObjectUtils.equalsAny(upgradeRecord.getStatus(),
221 IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(), 210 IotOtaUpgradeRecordStatusEnum.PENDING.getStatus(),
222 IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(), 211 IotOtaUpgradeRecordStatusEnum.PUSHED.getStatus(),
223 IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) { 212 IotOtaUpgradeRecordStatusEnum.UPGRADING.getStatus())) {
224 - // 如果升级记录处于上述状态之一,则抛出异常,表示不允许重试  
225 throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY); 213 throw exception(OTA_UPGRADE_RECORD_CANNOT_RETRY);
226 } 214 }
227 } 215 }
yudao-module-iot/yudao-module-iot-biz/src/main/java/cn/iocoder/yudao/module/iot/service/ota/IotOtaUpgradeTaskServiceImpl.java
@@ -27,10 +27,14 @@ import java.util.stream.Collectors; @@ -27,10 +27,14 @@ import java.util.stream.Collectors;
27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception; 27 import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
28 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*; 28 import static cn.iocoder.yudao.module.iot.enums.ErrorCodeConstants.*;
29 29
30 -// TODO @li:完善注释、注解顺序  
31 -@Slf4j 30 +/**
  31 + * IoT OTA升级任务 Service 实现类
  32 + *
  33 + * @author Shelly Chan
  34 + */
32 @Service 35 @Service
33 @Validated 36 @Validated
  37 +@Slf4j
34 public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { 38 public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService {
35 39
36 @Resource 40 @Resource
@@ -105,102 +109,65 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService { @@ -105,102 +109,65 @@ public class IotOtaUpgradeTaskServiceImpl implements IotOtaUpgradeTaskService {
105 upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder().id(id).status(status).build()); 109 upgradeTaskMapper.updateById(IotOtaUpgradeTaskDO.builder().id(id).status(status).build());
106 } 110 }
107 111
108 - // TODO @li:注释有点冗余  
109 /** 112 /**
110 * 校验固件升级任务是否重复 113 * 校验固件升级任务是否重复
111 - * <p>  
112 - * 该方法用于检查给定固件ID和任务名称组合是否已存在于数据库中,如果存在则抛出异常,  
113 - * 表示任务名称对于该固件而言是重复的此检查确保用户不能创建具有相同名称的任务,  
114 - * 从而避免数据重复和混淆  
115 - *  
116 - * @param firmwareId 固件的唯一标识符,用于区分不同的固件  
117 - * @param taskName 升级任务的名称,用于与固件ID一起检查重复性  
118 - * @throws cn.iocoder.yudao.framework.common.exception.ServerException 则抛出预定义的异常  
119 */ 114 */
120 private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) { 115 private void validateFirmwareTaskDuplicate(Long firmwareId, String taskName) {
121 - // 查询数据库中是否有相同固件ID和任务名称的升级任务存在  
122 List<IotOtaUpgradeTaskDO> upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName); 116 List<IotOtaUpgradeTaskDO> upgradeTaskList = upgradeTaskMapper.selectByFirmwareIdAndName(firmwareId, taskName);
123 - // 如果查询结果不为空,说明存在重复的任务名称,抛出异常  
124 if (CollUtil.isNotEmpty(upgradeTaskList)) { 117 if (CollUtil.isNotEmpty(upgradeTaskList)) {
125 throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE); 118 throw exception(OTA_UPGRADE_TASK_NAME_DUPLICATE);
126 } 119 }
127 } 120 }
128 121
129 - // TODO @li:注释有点冗余  
130 /** 122 /**
131 * 验证升级任务的范围和设备列表的有效性。 123 * 验证升级任务的范围和设备列表的有效性。
132 - * <p>  
133 - * 根据升级任务的范围(scope),验证设备列表(deviceIds)或产品ID(productId)是否有效。  
134 - * 如果范围是“选择设备”(SELECT),则必须提供设备列表;如果范围是“所有设备”(ALL),则必须根据产品ID获取设备列表,并确保列表不为空。  
135 * 124 *
136 * @param scope 升级任务的范围,参考 IotOtaUpgradeTaskScopeEnum 枚举值 125 * @param scope 升级任务的范围,参考 IotOtaUpgradeTaskScopeEnum 枚举值
137 - * @param deviceIds 设备ID列表,当范围为“选择设备”时,该列表不能为空  
138 - * @param productId 产品ID,当范围为“所有设备”时,用于获取设备列表 126 + * @param deviceIds 设备ID列表,当范围为"选择设备"时,该列表不能为空
  127 + * @param productId 产品ID,当范围为"所有设备"时,用于获取设备列表
139 * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常 128 * @throws cn.iocoder.yudao.framework.common.exception.ServiceException,抛出相应的异常
140 */ 129 */
141 - private void validateScopeAndDevice(Integer scope, List<Long> deviceIds, String productId) {  
142 - // TODO @li:if return  
143 - // 验证范围为“选择设备”时,设备列表不能为空 130 + private void validateScopeAndDevice(Integer scope, List<Long> deviceIds, Long productId) {
144 if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) { 131 if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.SELECT.getScope())) {
145 if (CollUtil.isEmpty(deviceIds)) { 132 if (CollUtil.isEmpty(deviceIds)) {
146 throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY); 133 throw exception(OTA_UPGRADE_TASK_DEVICE_IDS_EMPTY);
147 } 134 }
148 - } else if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) {  
149 - // 验证范围为“所有设备”时,根据产品ID获取的设备列表不能为空  
150 - List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId)); 135 + return;
  136 + }
  137 +
  138 + if (Objects.equals(scope, IotOtaUpgradeTaskScopeEnum.ALL.getScope())) {
  139 + List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(productId);
151 if (CollUtil.isEmpty(deviceList)) { 140 if (CollUtil.isEmpty(deviceList)) {
152 throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY); 141 throw exception(OTA_UPGRADE_TASK_DEVICE_LIST_EMPTY);
153 } 142 }
154 } 143 }
155 } 144 }
156 145
157 - // TODO @li:注释有点冗余  
158 /** 146 /**
159 * 验证升级任务是否存在 147 * 验证升级任务是否存在
160 - * <p>  
161 - * 通过查询数据库来验证给定ID的升级任务是否存在此方法主要用于确保后续操作所针对的升级任务是有效的  
162 - *  
163 - * @param id 升级任务的唯一标识符如果为null或数据库中不存在对应的记录,则认为任务不存在  
164 - * @throws cn.iocoder.yudao.framework.common.exception.ServiceException 如果升级任务不存在,则抛出异常提示任务不存在  
165 */ 148 */
166 private IotOtaUpgradeTaskDO validateUpgradeTaskExists(Long id) { 149 private IotOtaUpgradeTaskDO validateUpgradeTaskExists(Long id) {
167 - // 查询数据库中是否有相同固件ID和任务名称的升级任务存在  
168 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskMapper.selectById(id); 150 IotOtaUpgradeTaskDO upgradeTask = upgradeTaskMapper.selectById(id);
169 - // 如果查询结果不为空,说明存在重复的任务名称,抛出异常  
170 if (Objects.isNull(upgradeTask)) { 151 if (Objects.isNull(upgradeTask)) {
171 throw exception(OTA_UPGRADE_TASK_NOT_EXISTS); 152 throw exception(OTA_UPGRADE_TASK_NOT_EXISTS);
172 } 153 }
173 return upgradeTask; 154 return upgradeTask;
174 } 155 }
175 156
176 - // TODO @li:注释有点冗余  
177 /** 157 /**
178 * 初始化升级任务 158 * 初始化升级任务
179 - * <p>  
180 - * 根据请求参数创建升级任务对象,并根据选择的范围初始化设备数量  
181 - * 如果选择特定设备进行升级,则设备数量为所选设备的总数  
182 - * 如果选择全部设备进行升级,则设备数量为该固件对应产品下的所有设备总数  
183 - *  
184 - * @param createReqVO 升级任务保存请求对象,包含创建升级任务所需的信息  
185 - * @return 返回初始化后的升级任务对象  
186 */ 159 */
187 - // TODO @li:一次性的方法,不用特别抽小方法  
188 - private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, String productId) {  
189 - // 将请求参数转换为升级任务对象 160 + private IotOtaUpgradeTaskDO initOtaUpgradeTask(IotOtaUpgradeTaskSaveReqVO createReqVO, Long productId) {
190 IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class); 161 IotOtaUpgradeTaskDO upgradeTask = BeanUtils.toBean(createReqVO, IotOtaUpgradeTaskDO.class);
191 - // 初始化的时候,设置设备数量和状态  
192 upgradeTask.setDeviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds()))) 162 upgradeTask.setDeviceCount(Convert.toLong(CollUtil.size(createReqVO.getDeviceIds())))
193 .setStatus(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus()); 163 .setStatus(IotOtaUpgradeTaskStatusEnum.IN_PROGRESS.getStatus());
194 - // 如果选择全选,则需要查询设备数量 164 +
195 if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) { 165 if (Objects.equals(createReqVO.getScope(), IotOtaUpgradeTaskScopeEnum.ALL.getScope())) {
196 - // 根据产品ID查询设备数量  
197 - List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(Convert.toLong(productId));  
198 - // 设置升级任务的设备数量 166 + List<IotDeviceDO> deviceList = deviceService.getDeviceListByProductId(productId);
199 upgradeTask.setDeviceCount((long) deviceList.size()); 167 upgradeTask.setDeviceCount((long) deviceList.size());
200 upgradeTask.setDeviceIds( 168 upgradeTask.setDeviceIds(
201 deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList())); 169 deviceList.stream().map(IotDeviceDO::getId).collect(Collectors.toList()));
202 } 170 }
203 - // 返回初始化后的升级任务对象  
204 return upgradeTask; 171 return upgradeTask;
205 } 172 }
206 173
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/protocol/emqx/router/IotEmqxDownstreamHandler.java
@@ -70,7 +70,6 @@ public class IotEmqxDownstreamHandler { @@ -70,7 +70,6 @@ public class IotEmqxDownstreamHandler {
70 private String buildTopicByMethod(IotDeviceMessage message, String productKey, String deviceName) { 70 private String buildTopicByMethod(IotDeviceMessage message, String productKey, String deviceName) {
71 // 1. 判断是否为回复消息 71 // 1. 判断是否为回复消息
72 boolean isReply = IotDeviceMessageUtils.isReplyMessage(message); 72 boolean isReply = IotDeviceMessageUtils.isReplyMessage(message);
73 -  
74 // 2. 根据消息方法类型构建对应的主题 73 // 2. 根据消息方法类型构建对应的主题
75 return IotMqttTopicUtils.buildTopicByMethod(message.getMethod(), productKey, deviceName, isReply); 74 return IotMqttTopicUtils.buildTopicByMethod(message.getMethod(), productKey, deviceName, isReply);
76 } 75 }
yudao-module-iot/yudao-module-iot-gateway/src/main/java/cn/iocoder/yudao/module/iot/gateway/util/IotMqttTopicUtils.java
@@ -18,6 +18,11 @@ public final class IotMqttTopicUtils { @@ -18,6 +18,11 @@ public final class IotMqttTopicUtils {
18 */ 18 */
19 private static final String SYS_TOPIC_PREFIX = "/sys/"; 19 private static final String SYS_TOPIC_PREFIX = "/sys/";
20 20
  21 + /**
  22 + * 回复主题后缀
  23 + */
  24 + private static final String REPLY_TOPIC_SUFFIX = "_reply";
  25 +
21 // ========== MQTT HTTP 接口路径常量 ========== 26 // ========== MQTT HTTP 接口路径常量 ==========
22 27
23 /** 28 /**
@@ -48,15 +53,12 @@ public final class IotMqttTopicUtils { @@ -48,15 +53,12 @@ public final class IotMqttTopicUtils {
48 if (StrUtil.isBlank(method)) { 53 if (StrUtil.isBlank(method)) {
49 return null; 54 return null;
50 } 55 }
51 -  
52 // 1. 将点分隔符转换为斜杠 56 // 1. 将点分隔符转换为斜杠
53 String topicSuffix = method.replace('.', '/'); 57 String topicSuffix = method.replace('.', '/');
54 -  
55 // 2. 对于回复消息,添加 _reply 后缀 58 // 2. 对于回复消息,添加 _reply 后缀
56 if (isReply) { 59 if (isReply) {
57 - topicSuffix += "_reply"; 60 + topicSuffix += REPLY_TOPIC_SUFFIX;
58 } 61 }
59 -  
60 // 3. 构建完整主题 62 // 3. 构建完整主题
61 return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + "/" + topicSuffix; 63 return SYS_TOPIC_PREFIX + productKey + "/" + deviceName + "/" + topicSuffix;
62 } 64 }