fix(iot): 恢复 B2 Controller/VO 的 @PreAuthorize/@Schema/@Valid 注解

Wave 2 三个 subagent 并行时,B19 subagent 看不到主会话后补的
rule/pom.xml web/security 依赖,把 B2 已写的注解全注释掉作为编译兜底。
rule/pom.xml 现已含 web/security/biz-tenant starter,恢复注解。

- IotRuleChainController: 7 @PreAuthorize + @Tag + 7 @Operation + @Parameter + @Valid + @Validated
- IotRuleChainSaveReqVO: @Schema + @NotEmpty/@NotNull/@Valid(含 NodeVO/LinkVO 子 VO)
- IotRuleChainRespVO: @Schema
- IotRuleChainGraphVO: @Schema(含子类)
- IotRuleChainPageReqVO: @Schema

落地 B2 AC9(REST API 所有端点带权限校验)。
测试:mvn test -pl viewsh-module-iot/viewsh-module-iot-rule → 17/17 全绿

Co-Authored-By: Claude Sonnet (annotation-restore subagent) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.7 (1M context, orchestrator) <noreply@anthropic.com>
This commit is contained in:
lzh
2026-04-23 23:39:26 +08:00
parent 962e69290b
commit 48e605b3c9
5 changed files with 114 additions and 75 deletions

View File

@@ -7,64 +7,77 @@ import com.viewsh.module.iot.rule.controller.admin.vo.IotRuleChainPageReqVO;
import com.viewsh.module.iot.rule.controller.admin.vo.IotRuleChainRespVO;
import com.viewsh.module.iot.rule.controller.admin.vo.IotRuleChainSaveReqVO;
import com.viewsh.module.iot.rule.service.IotRuleChainService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.annotation.Resource;
import jakarta.validation.Valid;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import static com.viewsh.framework.common.pojo.CommonResult.success;
/**
* 管理后台 - IoT 规则链DAGController
*
* <p>权限iot:rule:create / iot:rule:update / iot:rule:delete / iot:rule:query
* (由部署层 @PreAuthorize 保证,运行时需引入 spring-security
*/
@Tag(name = "管理后台 - IoT 规则链")
@RestController
@RequestMapping("/iot/rule-chain")
@Validated
public class IotRuleChainController {
@Resource
private IotRuleChainService ruleChainService;
// @PreAuthorize("@ss.hasPermission('iot:rule:create')")
@PostMapping("/create")
public CommonResult<Long> createRuleChain(@RequestBody IotRuleChainSaveReqVO createReqVO) {
@Operation(summary = "创建规则链")
@PreAuthorize("@ss.hasPermission('iot:rule:create')")
public CommonResult<Long> createRuleChain(@Valid @RequestBody IotRuleChainSaveReqVO createReqVO) {
return success(ruleChainService.createRuleChain(createReqVO));
}
// @PreAuthorize("@ss.hasPermission('iot:rule:update')")
@PutMapping("/update")
public CommonResult<Boolean> updateRuleChain(@RequestBody IotRuleChainSaveReqVO updateReqVO) {
@Operation(summary = "更新规则链")
@PreAuthorize("@ss.hasPermission('iot:rule:update')")
public CommonResult<Boolean> updateRuleChain(@Valid @RequestBody IotRuleChainSaveReqVO updateReqVO) {
ruleChainService.updateRuleChain(updateReqVO);
return success(true);
}
// @PreAuthorize("@ss.hasPermission('iot:rule:delete')")
@DeleteMapping("/delete")
@Operation(summary = "删除规则链")
@Parameter(name = "id", description = "规则链编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:rule:delete')")
public CommonResult<Boolean> deleteRuleChain(@RequestParam("id") Long id) {
ruleChainService.deleteRuleChain(id);
return success(true);
}
// @PreAuthorize("@ss.hasPermission('iot:rule:query')")
@GetMapping("/get/{id}")
@Operation(summary = "获得规则链")
@Parameter(name = "id", description = "规则链编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:rule:query')")
public CommonResult<IotRuleChainRespVO> getRuleChain(@PathVariable("id") Long id) {
return success(ruleChainService.getRuleChain(id));
}
// @PreAuthorize("@ss.hasPermission('iot:rule:query')")
@GetMapping("/graph/{id}")
@Operation(summary = "获得规则链图(含节点和连线)")
@Parameter(name = "id", description = "规则链编号", required = true, example = "1024")
@PreAuthorize("@ss.hasPermission('iot:rule:query')")
public CommonResult<IotRuleChainGraphVO> getRuleChainGraph(@PathVariable("id") Long id) {
return success(ruleChainService.getRuleChainGraph(id));
}
// @PreAuthorize("@ss.hasPermission('iot:rule:query')")
@GetMapping("/page")
@Operation(summary = "获得规则链分页")
@PreAuthorize("@ss.hasPermission('iot:rule:query')")
public CommonResult<PageResult<IotRuleChainRespVO>> getRuleChainPage(IotRuleChainPageReqVO pageReqVO) {
return success(ruleChainService.getRuleChainPage(pageReqVO));
}
// @PreAuthorize("@ss.hasPermission('iot:rule:update')")
@PutMapping("/enable")
@Operation(summary = "启用规则链")
@Parameter(name = "id", description = "规则链编号", required = true)
@PreAuthorize("@ss.hasPermission('iot:rule:update')")
public CommonResult<Boolean> enableRuleChain(@RequestParam("id") Long id) {
ruleChainService.enableRuleChain(id);
return success(true);

View File

@@ -1,5 +1,6 @@
package com.viewsh.module.iot.rule.controller.admin.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
@@ -10,52 +11,54 @@ import java.util.List;
/**
* 管理后台 - IoT 规则链图 VO含 nodes + links 的完整图)
*/
@Schema(description = "管理后台 - IoT 规则链图 VO含节点和连线")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class IotRuleChainGraphVO {
/** 规则链基础信息 */
@Schema(description = "规则链基础信息")
private IotRuleChainRespVO chain;
/** 节点列表 */
@Schema(description = "节点列表")
private List<NodeVO> nodes;
/** 连线列表 */
@Schema(description = "连线列表")
private List<LinkVO> links;
/**
* 节点 VO
*/
@Schema(description = "规则节点 VO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class NodeVO {
/** 节点编号 */
@Schema(description = "节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
/** 所属规则链编号 */
@Schema(description = "所属规则链编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long ruleChainId;
/** 节点名称 */
@Schema(description = "节点名称", example = "温度触发器")
private String name;
/** 节点类别trigger/condition/action */
@Schema(description = "节点类别trigger/condition/action", requiredMode = Schema.RequiredMode.REQUIRED, example = "trigger")
private String category;
/** Provider 标识 */
@Schema(description = "Provider 标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device.attribute.trigger")
private String type;
/** 节点配置JSON */
@Schema(description = "节点配置JSON", example = "{\"attribute\":\"temperature\"}")
private String configuration;
/** 画布 X 坐标 */
@Schema(description = "画布 X 坐标", example = "100")
private Integer positionX;
/** 画布 Y 坐标 */
@Schema(description = "画布 Y 坐标", example = "200")
private Integer positionY;
}
@@ -63,31 +66,32 @@ public class IotRuleChainGraphVO {
/**
* 连线 VO
*/
@Schema(description = "规则连线 VO")
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public static class LinkVO {
/** 连线编号 */
@Schema(description = "连线编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long id;
/** 所属规则链编号 */
@Schema(description = "所属规则链编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long ruleChainId;
/** 源节点编号 */
@Schema(description = "源节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Long sourceNodeId;
/** 目标节点编号 */
@Schema(description = "目标节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
private Long targetNodeId;
/** 关系类型Success/Failure/True/False/Timeout/Skip */
@Schema(description = "关系类型Success/Failure/True/False/Timeout/Skip", requiredMode = Schema.RequiredMode.REQUIRED, example = "Success")
private String relationType;
/** 连线条件JSON */
@Schema(description = "连线条件JSON", example = "{}")
private String condition;
/** 排序 */
@Schema(description = "排序", example = "0")
private Integer sortOrder;
}

View File

@@ -1,6 +1,7 @@
package com.viewsh.module.iot.rule.controller.admin.vo;
import com.viewsh.framework.common.pojo.PageParam;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.ToString;
@@ -13,24 +14,25 @@ import static com.viewsh.framework.common.util.date.DateUtils.FORMAT_YEAR_MONTH_
/**
* 管理后台 - IoT 规则链分页 Request VO
*/
@Schema(description = "管理后台 - IoT 规则链分页 Request VO")
@Data
@EqualsAndHashCode(callSuper = true)
@ToString(callSuper = true)
public class IotRuleChainPageReqVO extends PageParam {
/** 租户编号(内部使用) */
@Schema(description = "租户编号(内部使用)", example = "1")
private Long tenantId;
/** 规则链名称 */
@Schema(description = "规则链名称", example = "温度告警")
private String name;
/** 状态0=禁用 1=启用 2=WARNING */
@Schema(description = "状态0=禁用 1=启用 2=WARNING", example = "1")
private Integer status;
/** 规则链类型SCENE/DATA/CUSTOM */
@Schema(description = "规则链类型SCENE/DATA/CUSTOM", example = "SCENE")
private String type;
/** 创建时间 */
@Schema(description = "创建时间")
@DateTimeFormat(pattern = FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND)
private LocalDateTime[] createTime;

View File

@@ -1,5 +1,6 @@
package com.viewsh.module.iot.rule.controller.admin.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Data;
import java.time.LocalDateTime;
@@ -7,46 +8,47 @@ import java.time.LocalDateTime;
/**
* 管理后台 - IoT 规则链 Response VO
*/
@Schema(description = "管理后台 - IoT 规则链 Response VO")
@Data
public class IotRuleChainRespVO {
/** 规则链编号 */
@Schema(description = "规则链编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
private Long id;
/** 规则链名称 */
@Schema(description = "规则链名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "设备温度告警链")
private String name;
/** 规则链描述 */
@Schema(description = "规则链描述", example = "监控设备温度并触发告警")
private String description;
/** 规则链类型SCENE/DATA/CUSTOM */
@Schema(description = "规则链类型SCENE/DATA/CUSTOM", requiredMode = Schema.RequiredMode.REQUIRED, example = "SCENE")
private String type;
/** 状态0=禁用 1=启用 2=WARNING */
@Schema(description = "状态0=禁用 1=启用 2=WARNING", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
private Integer status;
/** 优先级 */
@Schema(description = "优先级", example = "10")
private Integer priority;
/** 版本号(乐观锁) */
@Schema(description = "版本号(乐观锁)", example = "1")
private Long version;
/** 调试模式 */
@Schema(description = "调试模式", example = "false")
private Boolean debugMode;
/** 子系统编号 */
@Schema(description = "子系统编号", example = "1")
private Long subsystemId;
/** 产品编号 */
@Schema(description = "产品编号", example = "1")
private Long productId;
/** 设备编号 */
@Schema(description = "设备编号", example = "0")
private Long deviceId;
/** 创建时间 */
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
private LocalDateTime createTime;
/** 更新时间 */
@Schema(description = "更新时间")
private LocalDateTime updateTime;
}

View File

@@ -1,5 +1,9 @@
package com.viewsh.module.iot.rule.controller.admin.vo;
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;
import java.util.List;
@@ -7,67 +11,77 @@ import java.util.List;
/**
* 管理后台 - IoT 规则链新增/修改 Request VO
*/
@Schema(description = "管理后台 - IoT 规则链新增/修改 Request VO")
@Data
public class IotRuleChainSaveReqVO {
/** 规则链编号(修改时必填) */
@Schema(description = "规则链编号(修改时必填)", example = "1024")
private Long id;
/** 规则链名称(必填) */
@Schema(description = "规则链名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "设备温度告警链")
@NotEmpty(message = "规则链名称不能为空")
private String name;
/** 规则链描述 */
@Schema(description = "规则链描述", example = "监控设备温度并触发告警")
private String description;
/** 规则链类型SCENE/DATA/CUSTOM必填 */
@Schema(description = "规则链类型SCENE/DATA/CUSTOM", requiredMode = Schema.RequiredMode.REQUIRED, example = "SCENE")
@NotEmpty(message = "规则链类型不能为空")
private String type;
/** 优先级 */
@Schema(description = "优先级", example = "10")
private Integer priority;
/** 调试模式 */
@Schema(description = "调试模式", example = "false")
private Boolean debugMode;
/** 子系统编号NULL=全局规则) */
@Schema(description = "子系统编号NULL=全局规则)", example = "1")
private Long subsystemId;
/** 产品编号NULL=不限产品) */
@Schema(description = "产品编号NULL=不限产品)", example = "1")
private Long productId;
/** 设备编号NULL/0=范围内所有设备) */
@Schema(description = "设备编号NULL/0=范围内所有设备)", example = "0")
private Long deviceId;
/** 规则节点列表(必填) */
@Schema(description = "规则节点列表", requiredMode = Schema.RequiredMode.REQUIRED)
@NotNull(message = "规则节点列表不能为空")
@Valid
private List<NodeVO> nodes;
/** 规则连线列表 */
@Schema(description = "规则连线列表")
@Valid
private List<LinkVO> links;
/**
* 节点子 VO
*/
@Schema(description = "规则节点 VO")
@Data
public static class NodeVO {
/** 节点编号(更新时填写,新增可不填) */
@Schema(description = "节点编号(更新时填写,新增可不填)", example = "1")
private Long id;
/** 节点名称 */
@Schema(description = "节点名称", example = "温度触发器")
private String name;
/** 节点类别trigger/condition/action必填 */
@Schema(description = "节点类别trigger/condition/action", requiredMode = Schema.RequiredMode.REQUIRED, example = "trigger")
@NotEmpty(message = "节点类别不能为空")
private String category;
/** Provider 标识(必填) */
@Schema(description = "Provider 标识", requiredMode = Schema.RequiredMode.REQUIRED, example = "device.attribute.trigger")
@NotEmpty(message = "节点类型Provider 标识)不能为空")
private String type;
/** 节点配置JSON 字符串,必填) */
@Schema(description = "节点配置JSON 字符串)", requiredMode = Schema.RequiredMode.REQUIRED, example = "{\"attribute\":\"temperature\"}")
@NotEmpty(message = "节点配置不能为空")
private String configuration;
/** 画布 X 坐标 */
@Schema(description = "画布 X 坐标", example = "100")
private Integer positionX;
/** 画布 Y 坐标 */
@Schema(description = "画布 Y 坐标", example = "200")
private Integer positionY;
}
@@ -75,25 +89,29 @@ public class IotRuleChainSaveReqVO {
/**
* 连线子 VO
*/
@Schema(description = "规则连线 VO")
@Data
public static class LinkVO {
/** 连线编号(更新时填写,新增可不填) */
@Schema(description = "连线编号(更新时填写,新增可不填)", example = "1")
private Long id;
/** 源节点编号(必填) */
@Schema(description = "源节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
@NotNull(message = "源节点编号不能为空")
private Long sourceNodeId;
/** 目标节点编号(必填) */
@Schema(description = "目标节点编号", requiredMode = Schema.RequiredMode.REQUIRED, example = "2")
@NotNull(message = "目标节点编号不能为空")
private Long targetNodeId;
/** 关系类型Success/Failure/True/False/Timeout/Skip,必填) */
@Schema(description = "关系类型Success/Failure/True/False/Timeout/Skip", requiredMode = Schema.RequiredMode.REQUIRED, example = "Success")
@NotEmpty(message = "关系类型不能为空")
private String relationType;
/** 连线条件JSON可选 */
@Schema(description = "连线条件JSON可选", example = "{}")
private String condition;
/** 排序 */
@Schema(description = "排序", example = "0")
private Integer sortOrder;
}