1.规范增量 SQL 文件命名
2.新增数据总线模块(未完成) 3.新增规则模块(未完成) 4.新增组织编码与外部系统组织编码映射关系表 5.补全 e 办单点登录回调逻辑
This commit is contained in:
@@ -1,24 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modules>
|
||||
<module>zt-module-rule-api</module>
|
||||
<module>zt-module-rule-server</module>
|
||||
</modules>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
|
||||
<artifactId>zt-module-rule</artifactId>
|
||||
<packaging>pom</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
Rule 模块。
|
||||
</description>
|
||||
|
||||
</project>
|
||||
@@ -1,46 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt-module-rule</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<artifactId>zt-module-rule-api</artifactId>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
暴露给其它模块调用
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-common</artifactId>
|
||||
</dependency>
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springdoc</groupId> <!-- 接口文档:使用最新版本的 Swagger 模型 -->
|
||||
<artifactId>springdoc-openapi-starter-webmvc-api</artifactId>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
<!-- 参数校验 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-validation</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>org.springframework.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-openfeign</artifactId>
|
||||
<optional>true</optional>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
</project>
|
||||
@@ -0,0 +1,42 @@
|
||||
package com.zt.plat.module.rule.api;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.rule.api.dto.RuleChainExecuteMetaRespDTO;
|
||||
import com.zt.plat.module.rule.api.dto.RuleChainLoadReqDTO;
|
||||
import com.zt.plat.module.rule.api.dto.RuleChainVersionRespDTO;
|
||||
import com.zt.plat.module.rule.enums.ApiConstants;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import jakarta.validation.Valid;
|
||||
import org.springframework.cloud.openfeign.FeignClient;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* RPC interface to expose rule engine capabilities to other micro services.
|
||||
*/
|
||||
@FeignClient(name = ApiConstants.NAME)
|
||||
@Tag(name = "RPC 服务 - 规则引擎")
|
||||
public interface RuleEngineApi {
|
||||
|
||||
String PREFIX = ApiConstants.PREFIX + "/engine";
|
||||
|
||||
@PostMapping(PREFIX + "/load")
|
||||
@Operation(summary = "按业务+版本加载链路执行元数据")
|
||||
CommonResult<RuleChainExecuteMetaRespDTO> loadChain(@Valid @RequestBody RuleChainLoadReqDTO reqDTO);
|
||||
|
||||
@GetMapping(PREFIX + "/latest")
|
||||
@Operation(summary = "获取业务最新链路")
|
||||
CommonResult<RuleChainExecuteMetaRespDTO> getLatestChain(@Parameter(description = "业务标识", required = true)
|
||||
@RequestParam("business") String business);
|
||||
|
||||
@GetMapping(PREFIX + "/versions")
|
||||
@Operation(summary = "查询业务链路版本列表")
|
||||
CommonResult<List<RuleChainVersionRespDTO>> listChainVersions(@Parameter(description = "业务标识", required = true)
|
||||
@RequestParam("business") String business);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zt.plat.module.rule.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Response DTO exposing the LiteFlow execution metadata for a business chain.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainExecuteMetaRespDTO {
|
||||
|
||||
@Schema(description = "业务标识", example = "order.create")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链路版本", example = "v3")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "LiteFlow 链路唯一标识", example = "order.create:v3")
|
||||
private String chainId;
|
||||
|
||||
@Schema(description = "LiteFlow DSL 内容", example = "{\"chain\":...}")
|
||||
private String liteflowDsl;
|
||||
|
||||
@Schema(description = "发布状态", example = "1")
|
||||
private Integer status;
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zt.plat.module.rule.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Request DTO used when remote services need to fetch a LiteFlow chain.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainLoadReqDTO {
|
||||
|
||||
@Schema(description = "业务标识", example = "order.create")
|
||||
@NotBlank(message = "业务标识不能为空")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链路版本,空则返回最新版本", example = "v3")
|
||||
private String version;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zt.plat.module.rule.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Simplified view of a chain for dropdowns or quick lookups.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainSimpleRespDTO {
|
||||
|
||||
@Schema(description = "链编号", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "链编码", example = "order_main_flow")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "链名称", example = "订单主流程")
|
||||
private String name;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.rule.api.dto;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* DTO describing available chain versions for a business code.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainVersionRespDTO {
|
||||
|
||||
@Schema(description = "业务标识", example = "order.create")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链路版本", example = "v3")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "绑定的链编码", example = "order_main_flow")
|
||||
private String chainCode;
|
||||
|
||||
@Schema(description = "发布状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "发布人", example = "1001")
|
||||
private Long releaseUserId;
|
||||
|
||||
@Schema(description = "发布时间")
|
||||
private LocalDateTime releaseTime;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import com.zt.plat.framework.common.enums.RpcConstants;
|
||||
|
||||
/**
|
||||
* RPC constants for the Rule module.
|
||||
*/
|
||||
public interface ApiConstants {
|
||||
|
||||
/**
|
||||
* Spring service name for the rule module. Must align with spring.application.name.
|
||||
*/
|
||||
String NAME = "rule-server";
|
||||
|
||||
/**
|
||||
* Prefix used by rule RPC endpoints.
|
||||
*/
|
||||
String PREFIX = RpcConstants.RPC_API_PREFIX + "/rule";
|
||||
|
||||
/**
|
||||
* RPC contract version.
|
||||
*/
|
||||
String VERSION = "1.0.0";
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import com.zt.plat.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* rule 错误码枚举类
|
||||
*
|
||||
* rule 系统,使用 1-xxx-xxx-xxx 段
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 示例模块 1-001-000-000 ==========
|
||||
ErrorCode EXAMPLE_NOT_EXISTS = new ErrorCode(1_001_000_001, "示例不存在");
|
||||
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Strategies supported when a child business inherits parent chains.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum OverrideStrategyEnum {
|
||||
|
||||
/**
|
||||
* Fully inherit parent chain without change.
|
||||
*/
|
||||
INHERIT(0, "继承"),
|
||||
/**
|
||||
* Override nodes with the same code in parent chain.
|
||||
*/
|
||||
OVERRIDE(1, "覆盖"),
|
||||
/**
|
||||
* Disable matched nodes from parent chain.
|
||||
*/
|
||||
DISABLE(2, "禁用"),
|
||||
/**
|
||||
* Append additional nodes after inherited chain.
|
||||
*/
|
||||
APPEND(3, "追加");
|
||||
|
||||
private final Integer strategy;
|
||||
private final String label;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Node types available when orchestrating a LiteFlow chain.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RuleNodeTypeEnum {
|
||||
|
||||
/**
|
||||
* Sequential node executed in order.
|
||||
*/
|
||||
THEN(1, "顺序"),
|
||||
/**
|
||||
* Conditional branch (IF/ELSE) node.
|
||||
*/
|
||||
IF(2, "条件"),
|
||||
/**
|
||||
* Switch-case control node.
|
||||
*/
|
||||
SWITCH(3, "分支"),
|
||||
/**
|
||||
* Loop node such as FOR/WHILE.
|
||||
*/
|
||||
LOOP(4, "循环"),
|
||||
/**
|
||||
* Parallel orchestrator node.
|
||||
*/
|
||||
PARALLEL(5, "并行"),
|
||||
/**
|
||||
* Nested sub-chain invocation.
|
||||
*/
|
||||
CHAIN(6, "子链"),
|
||||
/**
|
||||
* Atomic rule node.
|
||||
*/
|
||||
ATOM(7, "原子规则");
|
||||
|
||||
private final Integer type;
|
||||
private final String label;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Release status for a business rule publication.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RulePublishStatusEnum {
|
||||
|
||||
/**
|
||||
* Waiting for publish processing.
|
||||
*/
|
||||
PENDING(0, "待发布"),
|
||||
/**
|
||||
* Successfully pushed to registry and activated.
|
||||
*/
|
||||
SUCCESS(1, "成功"),
|
||||
/**
|
||||
* Failed to publish to runtime.
|
||||
*/
|
||||
FAILED(2, "失败"),
|
||||
/**
|
||||
* Release rolled back.
|
||||
*/
|
||||
ROLLBACK(3, "回滚");
|
||||
|
||||
private final Integer status;
|
||||
private final String label;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Common lifecycle statuses for rule entities.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RuleStatusEnum {
|
||||
|
||||
/**
|
||||
* Draft state, not yet published.
|
||||
*/
|
||||
DRAFT(0, "草稿"),
|
||||
/**
|
||||
* Active state, can be orchestrated or executed.
|
||||
*/
|
||||
ENABLED(1, "启用"),
|
||||
/**
|
||||
* Disabled state, excluded from execution.
|
||||
*/
|
||||
DISABLED(2, "禁用"),
|
||||
/**
|
||||
* Deprecated or archived state.
|
||||
*/
|
||||
ARCHIVED(3, "归档");
|
||||
|
||||
private final Integer status;
|
||||
private final String label;
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
package com.zt.plat.module.rule.enums;
|
||||
|
||||
import lombok.AllArgsConstructor;
|
||||
import lombok.Getter;
|
||||
|
||||
/**
|
||||
* Types of atomic rules supported by the rule engine.
|
||||
*/
|
||||
@Getter
|
||||
@AllArgsConstructor
|
||||
public enum RuleTypeEnum {
|
||||
|
||||
/**
|
||||
* Script-based rule (Groovy/JS/QLExpress).
|
||||
*/
|
||||
SCRIPT(1, "脚本"),
|
||||
/**
|
||||
* Spring bean rule implementation.
|
||||
*/
|
||||
SPRING_BEAN(2, "Spring Bean"),
|
||||
/**
|
||||
* Custom LiteFlow component rule.
|
||||
*/
|
||||
COMPONENT(3, "组件"),
|
||||
/**
|
||||
* External chain reference for composite reuse.
|
||||
*/
|
||||
CHAIN_REFERENCE(4, "引用链");
|
||||
|
||||
private final Integer type;
|
||||
private final String label;
|
||||
}
|
||||
@@ -1,158 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project xmlns="http://maven.apache.org/POM/4.0.0"
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
|
||||
<parent>
|
||||
<artifactId>zt-module-rule</artifactId>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<version>${revision}</version>
|
||||
</parent>
|
||||
<modelVersion>4.0.0</modelVersion>
|
||||
<packaging>jar</packaging>
|
||||
|
||||
<artifactId>zt-module-rule-server</artifactId>
|
||||
|
||||
<name>${project.artifactId}</name>
|
||||
<description>
|
||||
Rule 模块。
|
||||
</description>
|
||||
|
||||
<dependencies>
|
||||
<!-- Spring Cloud 基础 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-env</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 依赖服务 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-system-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-infra-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-module-rule-api</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- 业务组件 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-data-permission</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-tenant</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Web 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-security</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- DB 相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mybatis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-redis</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- RPC 远程调用相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-rpc</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Registry 注册中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Config 配置中心相关 -->
|
||||
<dependency>
|
||||
<groupId>com.alibaba.cloud</groupId>
|
||||
<artifactId>spring-cloud-starter-alibaba-nacos-config</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Job 定时任务相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-job</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 消息队列相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-mq</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- Test 测试相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-test</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 工具类相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-excel</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!-- 监控相关 -->
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-monitor</artifactId>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.zt.plat</groupId>
|
||||
<artifactId>zt-spring-boot-starter-biz-business</artifactId>
|
||||
<version>${revision}</version>
|
||||
</dependency>
|
||||
|
||||
<!-- LiteFlow 规则引擎相关 -->
|
||||
<dependency>
|
||||
<groupId>com.yomahub</groupId>
|
||||
<artifactId>liteflow-spring-boot-starter</artifactId>
|
||||
<version>2.15.0</version>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
<!-- 设置构建的 jar 包名 -->
|
||||
<finalName>${project.artifactId}</finalName>
|
||||
<plugins>
|
||||
<!-- 打包 -->
|
||||
<plugin>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-maven-plugin</artifactId>
|
||||
<version>${spring.boot.version}</version>
|
||||
<executions>
|
||||
<execution>
|
||||
<goals>
|
||||
<goal>repackage</goal> <!-- 将引入的 jar 打入其中 -->
|
||||
</goals>
|
||||
</execution>
|
||||
</executions>
|
||||
</plugin>
|
||||
</plugins>
|
||||
</build>
|
||||
|
||||
</project>
|
||||
@@ -3,16 +3,10 @@ package com.zt.plat.module.rule;
|
||||
import org.springframework.boot.SpringApplication;
|
||||
import org.springframework.boot.autoconfigure.SpringBootApplication;
|
||||
|
||||
/**
|
||||
* Rule 模块的启动类
|
||||
*
|
||||
* @author ZT
|
||||
*/
|
||||
@SpringBootApplication
|
||||
public class RuleServerApplication {
|
||||
|
||||
public static void main(String[] args) {
|
||||
SpringApplication.run(RuleServerApplication.class, args);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessChainViewRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessRelationSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessTreeNodeRespVO;
|
||||
import com.zt.plat.module.rule.service.business.RuleBusinessService;
|
||||
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 jakarta.validation.constraints.NotBlank;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 业务链路")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/business")
|
||||
@Validated
|
||||
public class RuleBusinessController {
|
||||
|
||||
@Resource
|
||||
private RuleBusinessService ruleBusinessService;
|
||||
|
||||
@PostMapping("/binding/save")
|
||||
@Operation(summary = "保存业务链绑定")
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:update')")
|
||||
public CommonResult<Boolean> saveBinding(@Valid @RequestBody RuleBusinessBindSaveReqVO reqVO) {
|
||||
ruleBusinessService.saveBinding(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/binding/page")
|
||||
@Operation(summary = "分页查询业务链绑定")
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:query')")
|
||||
public CommonResult<PageResult<RuleBusinessBindRespVO>> getBindingPage(@Valid RuleBusinessBindPageReqVO reqVO) {
|
||||
return success(ruleBusinessService.getBindingPage(reqVO));
|
||||
}
|
||||
|
||||
@GetMapping("/binding/get")
|
||||
@Operation(summary = "获取业务链绑定详情")
|
||||
@Parameter(name = "business", description = "业务标识", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:query')")
|
||||
public CommonResult<RuleBusinessBindRespVO> getBinding(@RequestParam("business") String business) {
|
||||
return success(ruleBusinessService.getBinding(business));
|
||||
}
|
||||
|
||||
@DeleteMapping("/binding/remove")
|
||||
@Operation(summary = "删除业务链绑定")
|
||||
@Parameter(name = "business", description = "业务标识", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:delete')")
|
||||
public CommonResult<Boolean> removeBinding(@RequestParam("business") String business) {
|
||||
ruleBusinessService.removeBinding(business);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@PostMapping("/relation/save")
|
||||
@Operation(summary = "设置业务继承关系")
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:update')")
|
||||
public CommonResult<Boolean> saveRelation(@Valid @RequestBody RuleBusinessRelationSaveReqVO reqVO) {
|
||||
ruleBusinessService.saveRelation(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/relation/remove")
|
||||
@Operation(summary = "移除业务继承关系")
|
||||
@Parameter(name = "childBusiness", description = "子业务标识", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:delete')")
|
||||
public CommonResult<Boolean> removeRelation(@RequestParam("childBusiness") String childBusiness) {
|
||||
ruleBusinessService.removeRelation(childBusiness);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/tree")
|
||||
@Operation(summary = "查询业务继承树")
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:query')")
|
||||
public CommonResult<List<RuleBusinessTreeNodeRespVO>> getBusinessTree() {
|
||||
return success(ruleBusinessService.getBusinessTree());
|
||||
}
|
||||
|
||||
@GetMapping("/preview")
|
||||
@Operation(summary = "预览业务链执行结构")
|
||||
@PreAuthorize("@ss.hasPermission('rule:business:preview')")
|
||||
public CommonResult<RuleBusinessChainViewRespVO> previewBusinessChain(@RequestParam("business") @NotBlank String business,
|
||||
@RequestParam(value = "version", required = false) String version) {
|
||||
return success(ruleBusinessService.previewBusinessChain(business, version));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleBusinessBindPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "继承策略")
|
||||
private Integer overrideStrategy;
|
||||
|
||||
@Schema(description = "是否锁定")
|
||||
private Boolean locked;
|
||||
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class RuleBusinessBindRespVO {
|
||||
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链ID")
|
||||
private Long ruleChainId;
|
||||
|
||||
@Schema(description = "链编码")
|
||||
private String ruleChainCode;
|
||||
|
||||
@Schema(description = "链名称")
|
||||
private String ruleChainName;
|
||||
|
||||
private Integer overrideStrategy;
|
||||
|
||||
private Boolean locked;
|
||||
|
||||
private String effectiveVersion;
|
||||
|
||||
private String remark;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleBusinessBindSaveReqVO {
|
||||
|
||||
@Schema(description = "业务标识", example = "order.create")
|
||||
@NotBlank(message = "业务标识不能为空")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链ID", example = "1001")
|
||||
@NotNull(message = "链ID不能为空")
|
||||
private Long ruleChainId;
|
||||
|
||||
@Schema(description = "继承策略", example = "1")
|
||||
private Integer overrideStrategy;
|
||||
|
||||
@Schema(description = "是否锁定")
|
||||
private Boolean locked;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainStructureVO;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleBusinessChainViewRespVO {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "链ID")
|
||||
private String chainId;
|
||||
|
||||
@Schema(description = "LiteFlow DSL")
|
||||
private String liteflowDsl;
|
||||
|
||||
private RuleChainStructureVO structure;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleBusinessRelationSaveReqVO {
|
||||
|
||||
@Schema(description = "父业务标识")
|
||||
@NotBlank(message = "父业务不能为空")
|
||||
private String parentBusiness;
|
||||
|
||||
@Schema(description = "子业务标识")
|
||||
@NotBlank(message = "子业务不能为空")
|
||||
private String childBusiness;
|
||||
|
||||
@Schema(description = "顺序")
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.module.rule.controller.admin.business.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RuleBusinessTreeNodeRespVO {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链编码")
|
||||
private String chainCode;
|
||||
|
||||
@Schema(description = "链名称")
|
||||
private String chainName;
|
||||
|
||||
@Schema(description = "子节点")
|
||||
private List<RuleBusinessTreeNodeRespVO> children = new ArrayList<>();
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainStructureVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainUpdateReqVO;
|
||||
import com.zt.plat.module.rule.convert.chain.RuleChainConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
import com.zt.plat.module.rule.service.chain.RuleChainService;
|
||||
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.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 规则链")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/chain")
|
||||
@Validated
|
||||
public class RuleChainController {
|
||||
|
||||
@Resource
|
||||
private RuleChainService ruleChainService;
|
||||
@Resource
|
||||
private RuleChainConvert ruleChainConvert;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建规则链")
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:create')")
|
||||
public CommonResult<Long> createChain(@Valid @RequestBody RuleChainCreateReqVO reqVO) {
|
||||
return success(ruleChainService.createChain(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新规则链")
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:update')")
|
||||
public CommonResult<Boolean> updateChain(@Valid @RequestBody RuleChainUpdateReqVO reqVO) {
|
||||
ruleChainService.updateChain(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除规则链")
|
||||
@Parameter(name = "id", description = "规则链编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:delete')")
|
||||
public CommonResult<Boolean> deleteChain(@RequestParam("id") Long id) {
|
||||
ruleChainService.deleteChain(id);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取规则链详情")
|
||||
@Parameter(name = "id", description = "规则链编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:query')")
|
||||
public CommonResult<RuleChainRespVO> getChain(@RequestParam("id") Long id) {
|
||||
RuleChainDO chain = ruleChainService.getChain(id);
|
||||
return success(chain != null ? ruleChainConvert.convert(chain) : null);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询规则链")
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:query')")
|
||||
public CommonResult<PageResult<RuleChainRespVO>> getChainPage(@Valid RuleChainPageReqVO reqVO) {
|
||||
PageResult<RuleChainDO> pageResult = ruleChainService.getChainPage(reqVO);
|
||||
return success(ruleChainConvert.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/structure")
|
||||
@Operation(summary = "获取规则链结构")
|
||||
@Parameter(name = "id", description = "规则链编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:chain:query')")
|
||||
public CommonResult<RuleChainStructureVO> getChainStructure(@RequestParam("id") Long id) {
|
||||
return success(ruleChainService.getChainStructure(id));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.Valid;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Base VO for rule chain operations.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainBaseVO {
|
||||
|
||||
@Schema(description = "链编码", example = "order_main_flow")
|
||||
@NotBlank(message = "链编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "链名称", example = "订单主流程")
|
||||
@NotBlank(message = "链名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "链描述")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "链状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "链结构")
|
||||
@Valid
|
||||
private RuleChainStructureVO structure;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,13 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainCreateReqVO extends RuleChainBaseVO {
|
||||
|
||||
@Schema(description = "链版本号", example = "1.0.0")
|
||||
private String version;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleChainLinkVO {
|
||||
|
||||
@Schema(description = "连线ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "起点节点ID")
|
||||
private String source;
|
||||
|
||||
@Schema(description = "终点节点ID")
|
||||
private String target;
|
||||
|
||||
@Schema(description = "条件表达式")
|
||||
private String conditionExpr;
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class RuleChainNodeVO {
|
||||
|
||||
@Schema(description = "画布节点ID")
|
||||
private String id;
|
||||
|
||||
@Schema(description = "节点编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "节点名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "节点类型")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "引用的规则ID")
|
||||
private Long ruleId;
|
||||
|
||||
@Schema(description = "引用的规则编码")
|
||||
private String ruleCode;
|
||||
|
||||
@Schema(description = "排序索引")
|
||||
private Integer orderIndex;
|
||||
|
||||
@Schema(description = "并行组标识")
|
||||
private String parallelGroup;
|
||||
|
||||
@Schema(description = "条件表达式")
|
||||
private String conditionExpr;
|
||||
|
||||
@Schema(description = "是否禁用")
|
||||
private Boolean disabled;
|
||||
|
||||
@Schema(description = "节点配置")
|
||||
private Map<String, Object> config;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "链编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "链名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "链状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间范围")
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainRespVO extends RuleChainBaseVO {
|
||||
|
||||
@Schema(description = "链ID")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "LiteFlow DSL")
|
||||
private String liteflowDsl;
|
||||
|
||||
private LocalDateTime createTime;
|
||||
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
@Data
|
||||
public class RuleChainStructureVO {
|
||||
|
||||
@Schema(description = "节点列表")
|
||||
private List<RuleChainNodeVO> nodes = new ArrayList<>();
|
||||
|
||||
@Schema(description = "连线列表")
|
||||
private List<RuleChainLinkVO> links = new ArrayList<>();
|
||||
|
||||
@Schema(description = "自定义 LiteFlow 表达式")
|
||||
private String entryExpression;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.zt.plat.module.rule.controller.admin.chain.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainUpdateReqVO extends RuleChainBaseVO {
|
||||
|
||||
@Schema(description = "链ID", example = "1001")
|
||||
@NotNull(message = "链ID不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "链版本号", example = "1.0.1")
|
||||
private String version;
|
||||
}
|
||||
@@ -0,0 +1,96 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionUpdateReqVO;
|
||||
import com.zt.plat.module.rule.convert.definition.RuleDefinitionConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.definition.RuleDefinitionDO;
|
||||
import com.zt.plat.module.rule.service.definition.RuleDefinitionService;
|
||||
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 jakarta.validation.constraints.NotEmpty;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.DeleteMapping;
|
||||
import org.springframework.web.bind.annotation.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.PutMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 规则定义")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/definition")
|
||||
@Validated
|
||||
public class RuleDefinitionController {
|
||||
|
||||
@Resource
|
||||
private RuleDefinitionService ruleDefinitionService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建规则定义")
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:create')")
|
||||
public CommonResult<Long> createRule(@Valid @RequestBody RuleDefinitionCreateReqVO reqVO) {
|
||||
return success(ruleDefinitionService.createRule(reqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新规则定义")
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:update')")
|
||||
public CommonResult<Boolean> updateRule(@Valid @RequestBody RuleDefinitionUpdateReqVO reqVO) {
|
||||
ruleDefinitionService.updateRule(reqVO);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除规则定义")
|
||||
@Parameter(name = "id", description = "规则定义编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:delete')")
|
||||
public CommonResult<Boolean> deleteRule(@RequestParam("id") Long id) {
|
||||
ruleDefinitionService.deleteRule(id);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获取规则定义详情")
|
||||
@Parameter(name = "id", description = "规则定义编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:query')")
|
||||
public CommonResult<RuleDefinitionRespVO> getRule(@RequestParam("id") Long id) {
|
||||
RuleDefinitionDO ruleDefinition = ruleDefinitionService.getRule(id);
|
||||
return success(ruleDefinition != null ? RuleDefinitionConvert.INSTANCE.convert(ruleDefinition) : null);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询规则定义")
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:query')")
|
||||
public CommonResult<PageResult<RuleDefinitionRespVO>> getRulePage(@Valid RuleDefinitionPageReqVO reqVO) {
|
||||
PageResult<RuleDefinitionDO> pageResult = ruleDefinitionService.getRulePage(reqVO);
|
||||
return success(RuleDefinitionConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/list")
|
||||
@Operation(summary = "批量查询规则定义")
|
||||
@PreAuthorize("@ss.hasPermission('rule:definition:query')")
|
||||
public CommonResult<List<RuleDefinitionRespVO>> getRuleList(@RequestParam("ids") @NotEmpty Collection<Long> ids) {
|
||||
List<RuleDefinitionDO> rules = ruleDefinitionService.getRules(ids);
|
||||
if (Objects.isNull(rules) || rules.isEmpty()) {
|
||||
return success(Collections.emptyList());
|
||||
}
|
||||
return success(RuleDefinitionConvert.INSTANCE.convertList(rules));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Base VO for creating/updating rule definitions.
|
||||
*/
|
||||
@Data
|
||||
public class RuleDefinitionBaseVO {
|
||||
|
||||
@Schema(description = "规则编码", example = "order_amount_check")
|
||||
@NotBlank(message = "规则编码不能为空")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "规则名称", example = "订单金额校验")
|
||||
@NotBlank(message = "规则名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "规则类型", example = "1")
|
||||
@NotNull(message = "规则类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "LiteFlow 脚本内容")
|
||||
private String dsl;
|
||||
|
||||
@Schema(description = "脚本语言", example = "groovy")
|
||||
private String scriptLanguage;
|
||||
|
||||
@Schema(description = "Spring Bean 引用", example = "ruleAmountCheckComponent")
|
||||
private String beanRef;
|
||||
|
||||
@Schema(description = "规则配置 JSON")
|
||||
private String configJson;
|
||||
|
||||
@Schema(description = "状态", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "备注")
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Request VO for creating a rule definition.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleDefinitionCreateReqVO extends RuleDefinitionBaseVO {
|
||||
|
||||
@Schema(description = "初始版本号", example = "1.0.0")
|
||||
private String version;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition.vo;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Paging request for rule definitions.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleDefinitionPageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "规则编码")
|
||||
private String code;
|
||||
|
||||
@Schema(description = "规则名称")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "规则类型")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "规则状态")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "创建时间范围")
|
||||
private LocalDateTime[] createTime;
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Response VO describing a rule definition.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleDefinitionRespVO extends RuleDefinitionBaseVO {
|
||||
|
||||
@Schema(description = "主键", example = "1001")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "版本号", example = "1.0.1")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间")
|
||||
private LocalDateTime updateTime;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.rule.controller.admin.definition.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotNull;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Request VO for updating a rule definition.
|
||||
*/
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleDefinitionUpdateReqVO extends RuleDefinitionBaseVO {
|
||||
|
||||
@Schema(description = "主键", example = "1001")
|
||||
@NotNull(message = "主键不能为空")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "版本号", example = "1.0.1")
|
||||
private String version;
|
||||
}
|
||||
@@ -0,0 +1,74 @@
|
||||
package com.zt.plat.module.rule.controller.admin.publish;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleasePageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseRollbackReqVO;
|
||||
import com.zt.plat.module.rule.convert.publish.RuleReleaseConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.release.RuleReleaseRecordDO;
|
||||
import com.zt.plat.module.rule.service.publish.RulePublishService;
|
||||
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.GetMapping;
|
||||
import org.springframework.web.bind.annotation.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RequestParam;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 规则发布")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/publish")
|
||||
@Validated
|
||||
public class RulePublishController {
|
||||
|
||||
@Resource
|
||||
private RulePublishService rulePublishService;
|
||||
|
||||
@PostMapping("/publish")
|
||||
@Operation(summary = "发布业务规则链")
|
||||
@PreAuthorize("@ss.hasPermission('rule:publish:publish')")
|
||||
public CommonResult<RuleReleaseRespVO> publish(@Valid @RequestBody RuleReleaseCreateReqVO reqVO) {
|
||||
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||
String username = SecurityFrameworkUtils.getLoginUserNickname();
|
||||
RuleReleaseRecordDO record = rulePublishService.publish(reqVO, userId, username);
|
||||
return success(RuleReleaseConvert.INSTANCE.convert(record));
|
||||
}
|
||||
|
||||
@PostMapping("/rollback")
|
||||
@Operation(summary = "回滚业务规则链版本")
|
||||
@PreAuthorize("@ss.hasPermission('rule:publish:rollback')")
|
||||
public CommonResult<Boolean> rollback(@Valid @RequestBody RuleReleaseRollbackReqVO reqVO) {
|
||||
Long userId = SecurityFrameworkUtils.getLoginUserId();
|
||||
String username = SecurityFrameworkUtils.getLoginUserNickname();
|
||||
rulePublishService.rollback(reqVO, userId, username);
|
||||
return success(Boolean.TRUE);
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "分页查询发布记录")
|
||||
@PreAuthorize("@ss.hasPermission('rule:publish:query')")
|
||||
public CommonResult<PageResult<RuleReleaseRespVO>> getReleasePage(@Valid RuleReleasePageReqVO reqVO) {
|
||||
PageResult<RuleReleaseRecordDO> pageResult = rulePublishService.getReleasePage(reqVO);
|
||||
return success(RuleReleaseConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/latest")
|
||||
@Operation(summary = "获取最新发布记录")
|
||||
@Parameter(name = "business", description = "业务标识", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:publish:query')")
|
||||
public CommonResult<RuleReleaseRespVO> getLatest(@RequestParam("business") String business) {
|
||||
RuleReleaseRecordDO record = rulePublishService.getLatest(business);
|
||||
return success(record != null ? RuleReleaseConvert.INSTANCE.convert(record) : null);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
package com.zt.plat.module.rule.controller.admin.publish.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleReleaseCreateReqVO {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
@NotBlank(message = "业务标识不能为空")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "目标版本号", example = "v3")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "是否仅生成不发布", example = "false")
|
||||
private Boolean dryRun;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.controller.admin.publish.vo;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleReleasePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "版本号")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "状态")
|
||||
private Integer status;
|
||||
|
||||
private LocalDateTime[] releaseTime;
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package com.zt.plat.module.rule.controller.admin.publish.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Data
|
||||
public class RuleReleaseRespVO {
|
||||
|
||||
private Long id;
|
||||
|
||||
private String business;
|
||||
|
||||
private String chainId;
|
||||
|
||||
private String chainCode;
|
||||
|
||||
private String version;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private Long releaseUserId;
|
||||
|
||||
private String releaseUserName;
|
||||
|
||||
private LocalDateTime releaseTime;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
package com.zt.plat.module.rule.controller.admin.publish.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
@Data
|
||||
public class RuleReleaseRollbackReqVO {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
@NotBlank(message = "业务标识不能为空")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "目标回滚版本")
|
||||
@NotBlank(message = "回滚版本不能为空")
|
||||
private String version;
|
||||
}
|
||||
@@ -1,136 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.common.util.object.BeanUtils;
|
||||
import com.zt.plat.framework.excel.core.util.ExcelUtils;
|
||||
import com.zt.plat.framework.operatelog.core.annotations.OperateLog;
|
||||
import com.zt.plat.module.rule.controller.admin.rule.vo.*;
|
||||
import com.zt.plat.module.rule.convert.rule.RuleConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.rule.RuleDO;
|
||||
import com.zt.plat.module.rule.service.rule.RuleService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
import io.swagger.v3.oas.annotations.Parameter;
|
||||
import io.swagger.v3.oas.annotations.tags.Tag;
|
||||
import org.springframework.security.access.prepost.PreAuthorize;
|
||||
import org.springframework.validation.annotation.Validated;
|
||||
import org.springframework.web.bind.annotation.*;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
import javax.validation.Valid;
|
||||
import java.io.IOException;
|
||||
import java.util.List;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
import static com.zt.plat.framework.operatelog.core.enums.OperateTypeEnum.*;
|
||||
|
||||
@Tag(name = "管理后台 - 规则引擎")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/rule")
|
||||
@Validated
|
||||
public class RuleController {
|
||||
|
||||
@Resource
|
||||
private RuleService ruleService;
|
||||
|
||||
@PostMapping("/create")
|
||||
@Operation(summary = "创建规则")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:create')")
|
||||
@OperateLog(type = CREATE)
|
||||
public CommonResult<Long> createRule(@Valid @RequestBody RuleCreateReqVO createReqVO) {
|
||||
return success(ruleService.createRule(createReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/update")
|
||||
@Operation(summary = "更新规则")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:update')")
|
||||
@OperateLog(type = UPDATE)
|
||||
public CommonResult<Boolean> updateRule(@Valid @RequestBody RuleUpdateReqVO updateReqVO) {
|
||||
ruleService.updateRule(updateReqVO);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@DeleteMapping("/delete")
|
||||
@Operation(summary = "删除规则")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:delete')")
|
||||
@OperateLog(type = DELETE)
|
||||
public CommonResult<Boolean> deleteRule(@RequestParam("id") Long id) {
|
||||
ruleService.deleteRule(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@GetMapping("/get")
|
||||
@Operation(summary = "获得规则")
|
||||
@Parameter(name = "id", description = "编号", required = true, example = "1024")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:query')")
|
||||
public CommonResult<RuleRespVO> getRule(@RequestParam("id") Long id) {
|
||||
RuleDO rule = ruleService.getRule(id);
|
||||
return success(RuleConvert.INSTANCE.convert(rule));
|
||||
}
|
||||
|
||||
@GetMapping("/page")
|
||||
@Operation(summary = "获得规则分页")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:query')")
|
||||
public CommonResult<PageResult<RuleRespVO>> getRulePage(@Valid RulePageReqVO pageReqVO) {
|
||||
PageResult<RuleDO> pageResult = ruleService.getRulePage(pageReqVO);
|
||||
return success(RuleConvert.INSTANCE.convertPage(pageResult));
|
||||
}
|
||||
|
||||
@GetMapping("/export-excel")
|
||||
@Operation(summary = "导出规则 Excel")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:export')")
|
||||
@OperateLog(type = EXPORT)
|
||||
public void exportRuleExcel(@Valid RulePageReqVO pageReqVO,
|
||||
HttpServletResponse response) throws IOException {
|
||||
pageReqVO.setPageSize(PageParam.PAGE_SIZE_NONE);
|
||||
List<RuleDO> list = ruleService.getRulePage(pageReqVO).getList();
|
||||
// 导出 Excel
|
||||
ExcelUtils.write(response, "规则.xls", "数据", RuleRespVO.class,
|
||||
BeanUtils.toBean(list, RuleRespVO.class));
|
||||
}
|
||||
|
||||
@PostMapping("/execute")
|
||||
@Operation(summary = "执行规则")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:execute')")
|
||||
@OperateLog(type = OTHER)
|
||||
public CommonResult<RuleExecuteRespVO> executeRule(@Valid @RequestBody RuleExecuteReqVO executeReqVO) {
|
||||
return success(ruleService.executeRule(executeReqVO));
|
||||
}
|
||||
|
||||
@PutMapping("/enable")
|
||||
@Operation(summary = "启用规则")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:update')")
|
||||
@OperateLog(type = UPDATE)
|
||||
public CommonResult<Boolean> enableRule(@RequestParam("id") Long id) {
|
||||
ruleService.enableRule(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PutMapping("/disable")
|
||||
@Operation(summary = "禁用规则")
|
||||
@Parameter(name = "id", description = "编号", required = true)
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:update')")
|
||||
@OperateLog(type = UPDATE)
|
||||
public CommonResult<Boolean> disableRule(@RequestParam("id") Long id) {
|
||||
ruleService.disableRule(id);
|
||||
return success(true);
|
||||
}
|
||||
|
||||
@PostMapping("/validate")
|
||||
@Operation(summary = "验证规则配置")
|
||||
@PreAuthorize("@ss.hasPermission('rule:rule:validate')")
|
||||
public CommonResult<Boolean> validateRuleConfig(@RequestBody String config) {
|
||||
return success(ruleService.validateRuleConfig(config));
|
||||
}
|
||||
|
||||
@GetMapping("/hello")
|
||||
@Operation(summary = "Hello Rule")
|
||||
public CommonResult<String> hello() {
|
||||
return success("Hello, Rule!");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import javax.validation.constraints.NotBlank;
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
/**
|
||||
* 规则 Base VO,提供给添加、修改、详细的子 VO 使用
|
||||
* 如果子 VO 存在差异的字段,请不要添加到这里,影响 Swagger 文档生成
|
||||
*/
|
||||
@Data
|
||||
public class RuleBaseVO {
|
||||
|
||||
@Schema(description = "规则名称", requiredMode = Schema.RequiredMode.REQUIRED, example = "用户积分计算规则")
|
||||
@NotBlank(message = "规则名称不能为空")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "规则描述", example = "根据用户行为计算积分奖励")
|
||||
private String description;
|
||||
|
||||
@Schema(description = "规则类型:1-原子规则 2-链式规则", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "规则类型不能为空")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "规则状态:0-禁用 1-启用", requiredMode = Schema.RequiredMode.REQUIRED, example = "1")
|
||||
@NotNull(message = "规则状态不能为空")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "规则配置(JSON格式)", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
@NotBlank(message = "规则配置不能为空")
|
||||
private String config;
|
||||
|
||||
@Schema(description = "LiteFlow规则链ID", example = "userPointsChain")
|
||||
private String chainId;
|
||||
|
||||
@Schema(description = "规则版本", example = "1.0.0")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "排序", example = "1")
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
@@ -1,14 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
@Schema(description = "管理后台 - 规则创建 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RuleCreateReqVO extends RuleBaseVO {
|
||||
|
||||
}
|
||||
@@ -1,116 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 规则执行请求 VO
|
||||
*/
|
||||
@Data
|
||||
public class RuleExecuteReqVO {
|
||||
|
||||
/**
|
||||
* 规则ID
|
||||
*/
|
||||
private Long ruleId;
|
||||
|
||||
/**
|
||||
* 规则链ID(与ruleId二选一)
|
||||
*/
|
||||
private String chainId;
|
||||
|
||||
/**
|
||||
* 执行上下文数据
|
||||
*/
|
||||
private Map<String, Object> contextData;
|
||||
|
||||
/**
|
||||
* 扩展参数
|
||||
*/
|
||||
private Map<String, Object> extParams;
|
||||
|
||||
/**
|
||||
* 规则执行配置(JSON格式的规则定义)
|
||||
*/
|
||||
@Data
|
||||
public static class RuleConfig {
|
||||
|
||||
/**
|
||||
* 规则链配置
|
||||
*/
|
||||
private ChainConfig chain;
|
||||
|
||||
/**
|
||||
* 节点配置列表
|
||||
*/
|
||||
private List<NodeConfig> nodes;
|
||||
}
|
||||
|
||||
/**
|
||||
* 规则链配置
|
||||
*/
|
||||
@Data
|
||||
public static class ChainConfig {
|
||||
|
||||
/**
|
||||
* 链ID
|
||||
*/
|
||||
private String chainId;
|
||||
|
||||
/**
|
||||
* 链名称
|
||||
*/
|
||||
private String chainName;
|
||||
|
||||
/**
|
||||
* 执行表达式(THEN、WHEN、FOR等)
|
||||
*/
|
||||
private String expression;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Boolean enable;
|
||||
}
|
||||
|
||||
/**
|
||||
* 节点配置
|
||||
*/
|
||||
@Data
|
||||
public static class NodeConfig {
|
||||
|
||||
/**
|
||||
* 节点ID
|
||||
*/
|
||||
private String nodeId;
|
||||
|
||||
/**
|
||||
* 节点名称
|
||||
*/
|
||||
private String nodeName;
|
||||
|
||||
/**
|
||||
* 节点类型:common-普通节点,condition-条件节点,switch-选择节点,for-循环节点
|
||||
*/
|
||||
private String nodeType;
|
||||
|
||||
/**
|
||||
* 节点类全限定名
|
||||
*/
|
||||
private String clazz;
|
||||
|
||||
/**
|
||||
* 节点配置参数
|
||||
*/
|
||||
private Map<String, Object> properties;
|
||||
|
||||
/**
|
||||
* 是否启用
|
||||
*/
|
||||
private Boolean enable;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,59 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 规则执行结果 VO
|
||||
*/
|
||||
@Data
|
||||
public class RuleExecuteRespVO {
|
||||
|
||||
/**
|
||||
* 执行是否成功
|
||||
*/
|
||||
private Boolean success;
|
||||
|
||||
/**
|
||||
* 错误消息
|
||||
*/
|
||||
private String errorMessage;
|
||||
|
||||
/**
|
||||
* 执行结果数据
|
||||
*/
|
||||
private Map<String, Object> resultData;
|
||||
|
||||
/**
|
||||
* 执行耗时(毫秒)
|
||||
*/
|
||||
private Long executionTime;
|
||||
|
||||
/**
|
||||
* 执行开始时间
|
||||
*/
|
||||
private LocalDateTime startTime;
|
||||
|
||||
/**
|
||||
* 执行结束时间
|
||||
*/
|
||||
private LocalDateTime endTime;
|
||||
|
||||
/**
|
||||
* 执行的规则链ID
|
||||
*/
|
||||
private String chainId;
|
||||
|
||||
/**
|
||||
* 执行的节点列表
|
||||
*/
|
||||
private String executedNodes;
|
||||
|
||||
/**
|
||||
* 执行上下文快照
|
||||
*/
|
||||
private Map<String, Object> contextSnapshot;
|
||||
|
||||
}
|
||||
@@ -1,32 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageParam;
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 规则分页 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RulePageReqVO extends PageParam {
|
||||
|
||||
@Schema(description = "规则名称", example = "用户积分规则")
|
||||
private String name;
|
||||
|
||||
@Schema(description = "规则类型:1-原子规则 2-链式规则", example = "1")
|
||||
private Integer type;
|
||||
|
||||
@Schema(description = "规则状态:0-禁用 1-启用", example = "1")
|
||||
private Integer status;
|
||||
|
||||
@Schema(description = "规则链ID", example = "userPointsChain")
|
||||
private String chainId;
|
||||
|
||||
@Schema(description = "创建时间")
|
||||
private LocalDateTime[] createTime;
|
||||
|
||||
}
|
||||
@@ -1,25 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Schema(description = "管理后台 - 规则 Response VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RuleRespVO extends RuleBaseVO {
|
||||
|
||||
@Schema(description = "规则ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
private Long id;
|
||||
|
||||
@Schema(description = "创建时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime createTime;
|
||||
|
||||
@Schema(description = "更新时间", requiredMode = Schema.RequiredMode.REQUIRED)
|
||||
private LocalDateTime updateTime;
|
||||
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package com.zt.plat.module.rule.controller.admin.rule.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
import lombok.ToString;
|
||||
|
||||
import javax.validation.constraints.NotNull;
|
||||
|
||||
@Schema(description = "管理后台 - 规则更新 Request VO")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
public class RuleUpdateReqVO extends RuleBaseVO {
|
||||
|
||||
@Schema(description = "规则ID", requiredMode = Schema.RequiredMode.REQUIRED, example = "1024")
|
||||
@NotNull(message = "规则ID不能为空")
|
||||
private Long id;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.zt.plat.module.rule.controller.admin.simulation;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.CommonResult;
|
||||
import com.zt.plat.module.rule.controller.admin.simulation.vo.RuleSimulationExecuteReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.simulation.vo.RuleSimulationExecuteRespVO;
|
||||
import com.zt.plat.module.rule.service.simulation.RuleSimulationService;
|
||||
import io.swagger.v3.oas.annotations.Operation;
|
||||
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.PostMapping;
|
||||
import org.springframework.web.bind.annotation.RequestBody;
|
||||
import org.springframework.web.bind.annotation.RequestMapping;
|
||||
import org.springframework.web.bind.annotation.RestController;
|
||||
|
||||
import static com.zt.plat.framework.common.pojo.CommonResult.success;
|
||||
|
||||
@Tag(name = "管理后台 - 规则模拟")
|
||||
@RestController
|
||||
@RequestMapping("/admin/rule/simulation")
|
||||
@Validated
|
||||
public class RuleSimulationController {
|
||||
|
||||
@Resource
|
||||
private RuleSimulationService ruleSimulationService;
|
||||
|
||||
@PostMapping("/execute")
|
||||
@Operation(summary = "模拟执行业务规则链")
|
||||
@PreAuthorize("@ss.hasPermission('rule:simulation:execute')")
|
||||
public CommonResult<RuleSimulationExecuteRespVO> execute(@Valid @RequestBody RuleSimulationExecuteReqVO reqVO) {
|
||||
return success(ruleSimulationService.execute(reqVO));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.controller.admin.simulation.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import jakarta.validation.constraints.NotBlank;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class RuleSimulationExecuteReqVO {
|
||||
|
||||
@Schema(description = "业务标识")
|
||||
@NotBlank(message = "业务标识不能为空")
|
||||
private String business;
|
||||
|
||||
@Schema(description = "链版本,可为空表示最新")
|
||||
private String version;
|
||||
|
||||
@Schema(description = "链ID,可覆盖业务+版本")
|
||||
private String chainId;
|
||||
|
||||
@Schema(description = "请求数据")
|
||||
private Map<String, Object> requestData;
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.rule.controller.admin.simulation.vo;
|
||||
|
||||
import io.swagger.v3.oas.annotations.media.Schema;
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@Data
|
||||
public class RuleSimulationExecuteRespVO {
|
||||
|
||||
@Schema(description = "是否执行成功")
|
||||
private boolean success;
|
||||
|
||||
@Schema(description = "LiteFlow 响应消息")
|
||||
private String message;
|
||||
|
||||
@Schema(description = "返回数据快照")
|
||||
private Map<String, Object> slotData;
|
||||
|
||||
@Schema(description = "LiteFlow Trace")
|
||||
private String trace;
|
||||
|
||||
@Schema(description = "使用的链ID")
|
||||
private String chainId;
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.convert.business;
|
||||
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindSaveReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessBindingDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleBusinessConvert {
|
||||
|
||||
RuleBusinessConvert INSTANCE = Mappers.getMapper(RuleBusinessConvert.class);
|
||||
|
||||
@Mapping(target = "configJson", ignore = true)
|
||||
@Mapping(target = "effectiveVersion", ignore = true)
|
||||
RuleBusinessBindingDO convert(RuleBusinessBindSaveReqVO bean);
|
||||
|
||||
RuleBusinessBindRespVO convert(RuleBusinessBindingDO bean);
|
||||
|
||||
List<RuleBusinessBindRespVO> convertList(List<RuleBusinessBindingDO> list);
|
||||
}
|
||||
@@ -0,0 +1,81 @@
|
||||
package com.zt.plat.module.rule.convert.chain;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainStructureVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainUpdateReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainStructureDTO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.Mapping;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Mapper(componentModel = "spring")
|
||||
public abstract class RuleChainConvert {
|
||||
|
||||
@Autowired
|
||||
protected ObjectMapper objectMapper;
|
||||
|
||||
@Mapping(target = "structureJson", ignore = true)
|
||||
@Mapping(target = "liteflowDsl", ignore = true)
|
||||
public abstract RuleChainDO convert(RuleChainCreateReqVO bean);
|
||||
|
||||
@Mapping(target = "structureJson", ignore = true)
|
||||
@Mapping(target = "liteflowDsl", ignore = true)
|
||||
public abstract RuleChainDO convert(RuleChainUpdateReqVO bean);
|
||||
|
||||
public RuleChainRespVO convert(RuleChainDO bean) {
|
||||
RuleChainRespVO vo = new RuleChainRespVO();
|
||||
vo.setId(bean.getId());
|
||||
vo.setCode(bean.getCode());
|
||||
vo.setName(bean.getName());
|
||||
vo.setDescription(bean.getDescription());
|
||||
vo.setStatus(bean.getStatus());
|
||||
vo.setVersion(bean.getVersion());
|
||||
vo.setLiteflowDsl(bean.getLiteflowDsl());
|
||||
vo.setRemark(bean.getRemark());
|
||||
vo.setCreateTime(bean.getCreateTime());
|
||||
vo.setUpdateTime(bean.getUpdateTime());
|
||||
if (bean.getStructureJson() != null) {
|
||||
vo.setStructure(readStructure(bean.getStructureJson()));
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
public List<RuleChainRespVO> convertList(List<RuleChainDO> list) {
|
||||
return list.stream().map(this::convert).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public PageResult<RuleChainRespVO> convertPage(PageResult<RuleChainDO> page) {
|
||||
return new PageResult<>(convertList(page.getList()), page.getTotal());
|
||||
}
|
||||
|
||||
public RuleChainStructureVO readStructure(String structureJson) {
|
||||
try {
|
||||
return objectMapper.readValue(structureJson, RuleChainStructureVO.class);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public String writeStructure(RuleChainStructureVO structure) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(structure);
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public RuleChainStructureDTO toDto(RuleChainStructureVO vo) {
|
||||
return objectMapper.convertValue(vo, RuleChainStructureDTO.class);
|
||||
}
|
||||
|
||||
public RuleChainStructureVO toVo(RuleChainStructureDTO dto) {
|
||||
return objectMapper.convertValue(dto, RuleChainStructureVO.class);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package com.zt.plat.module.rule.convert.definition;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionUpdateReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.definition.RuleDefinitionDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleDefinitionConvert {
|
||||
|
||||
RuleDefinitionConvert INSTANCE = Mappers.getMapper(RuleDefinitionConvert.class);
|
||||
|
||||
RuleDefinitionDO convert(RuleDefinitionCreateReqVO bean);
|
||||
|
||||
RuleDefinitionDO convert(RuleDefinitionUpdateReqVO bean);
|
||||
|
||||
RuleDefinitionRespVO convert(RuleDefinitionDO bean);
|
||||
|
||||
List<RuleDefinitionRespVO> convertList(List<RuleDefinitionDO> list);
|
||||
|
||||
PageResult<RuleDefinitionRespVO> convertPage(PageResult<RuleDefinitionDO> page);
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.rule.convert.publish;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseRespVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.release.RuleReleaseRecordDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleReleaseConvert {
|
||||
|
||||
RuleReleaseConvert INSTANCE = Mappers.getMapper(RuleReleaseConvert.class);
|
||||
|
||||
RuleReleaseRespVO convert(RuleReleaseRecordDO bean);
|
||||
|
||||
List<RuleReleaseRespVO> convertList(List<RuleReleaseRecordDO> list);
|
||||
|
||||
PageResult<RuleReleaseRespVO> convertPage(PageResult<RuleReleaseRecordDO> page);
|
||||
}
|
||||
@@ -1,31 +0,0 @@
|
||||
package com.zt.plat.module.rule.convert.rule;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.rule.vo.*;
|
||||
import com.zt.plat.module.rule.dal.dataobject.rule.RuleDO;
|
||||
import org.mapstruct.Mapper;
|
||||
import org.mapstruct.factory.Mappers;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* 规则 Convert
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface RuleConvert {
|
||||
|
||||
RuleConvert INSTANCE = Mappers.getMapper(RuleConvert.class);
|
||||
|
||||
RuleDO convert(RuleCreateReqVO bean);
|
||||
|
||||
RuleDO convert(RuleUpdateReqVO bean);
|
||||
|
||||
RuleRespVO convert(RuleDO bean);
|
||||
|
||||
List<RuleRespVO> convertList(List<RuleDO> list);
|
||||
|
||||
PageResult<RuleRespVO> convertPage(PageResult<RuleDO> page);
|
||||
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.business;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Mapping between business code and selected rule chain.
|
||||
*/
|
||||
@TableName(value = "rule_business", autoResultMap = true)
|
||||
@KeySequence("rule_business_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleBusinessBindingDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Business identifier, e.g. order.create.
|
||||
*/
|
||||
private String business;
|
||||
|
||||
@TableField("rule_chain_id")
|
||||
private Long ruleChainId;
|
||||
|
||||
@TableField("override_strategy")
|
||||
private Integer overrideStrategy;
|
||||
|
||||
private Boolean locked;
|
||||
|
||||
@TableField("effective_version")
|
||||
private String effectiveVersion;
|
||||
|
||||
/**
|
||||
* Additional metadata retained as JSON.
|
||||
*/
|
||||
@TableField("config_json")
|
||||
private String configJson;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.business;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Parent-child hierarchy of business codes to support inheritance.
|
||||
*/
|
||||
@TableName(value = "rule_business_relation", autoResultMap = true)
|
||||
@KeySequence("rule_business_relation_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleBusinessRelationDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@TableField("parent_business")
|
||||
private String parentBusiness;
|
||||
|
||||
@TableField("child_business")
|
||||
private String childBusiness;
|
||||
|
||||
private Integer sort;
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.chain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Stored chain definition with designer structure and compiled DSL.
|
||||
*/
|
||||
@TableName(value = "rule_chain", autoResultMap = true)
|
||||
@KeySequence("rule_chain_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* JSON serialized structure returned by the visual orchestrator.
|
||||
*/
|
||||
private String structureJson;
|
||||
|
||||
/**
|
||||
* LiteFlow DSL compiled from the structure.
|
||||
*/
|
||||
private String liteflowDsl;
|
||||
|
||||
private Integer status;
|
||||
|
||||
private String version;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.chain;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Relationship between a chain and its component rules or nested chains.
|
||||
*/
|
||||
@TableName(value = "rule_chain_dependency", autoResultMap = true)
|
||||
@KeySequence("rule_chain_dependency_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleChainDependencyDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
@TableField("parent_chain_id")
|
||||
private Long parentChainId;
|
||||
|
||||
@TableField("child_rule_id")
|
||||
private Long childRuleId;
|
||||
|
||||
/**
|
||||
* Dependency type, such as ATOM/CHAIN/CONDITION/... referencing {@link com.zt.plat.module.rule.enums.RuleNodeTypeEnum}.
|
||||
*/
|
||||
private Integer linkType;
|
||||
|
||||
@TableField("order_index")
|
||||
private Integer orderIndex;
|
||||
|
||||
@TableField("parallel_group")
|
||||
private String parallelGroup;
|
||||
|
||||
@TableField("condition_expr")
|
||||
private String conditionExpr;
|
||||
|
||||
/**
|
||||
* Additional configuration or node metadata serialized to JSON.
|
||||
*/
|
||||
@TableField("config_json")
|
||||
private String configJson;
|
||||
}
|
||||
@@ -0,0 +1,72 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.definition;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
/**
|
||||
* Data object representing an atomic rule definition.
|
||||
*/
|
||||
@TableName(value = "rule_definition", autoResultMap = true)
|
||||
@KeySequence("rule_definition_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleDefinitionDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* Unique code of the rule for reference in chains.
|
||||
*/
|
||||
private String code;
|
||||
|
||||
/**
|
||||
* Display name of the rule.
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Rule type, see {@link com.zt.plat.module.rule.enums.RuleTypeEnum}.
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* DSL content for LiteFlow script nodes if applicable.
|
||||
*/
|
||||
private String dsl;
|
||||
|
||||
/**
|
||||
* Script language identifier when the rule is script based.
|
||||
*/
|
||||
private String scriptLanguage;
|
||||
|
||||
/**
|
||||
* Spring bean reference when the rule delegates to a bean.
|
||||
*/
|
||||
private String beanRef;
|
||||
|
||||
/**
|
||||
* Serialized configuration for the rule (JSON).
|
||||
*/
|
||||
private String configJson;
|
||||
|
||||
/**
|
||||
* Rule status, see {@link com.zt.plat.module.rule.enums.RuleStatusEnum}.
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* Rule version, semantic or numeric.
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* Additional remarks.
|
||||
*/
|
||||
private String remark;
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.release;
|
||||
|
||||
import com.baomidou.mybatisplus.annotation.IdType;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableField;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import com.zt.plat.framework.tenant.core.db.TenantBaseDO;
|
||||
import lombok.Data;
|
||||
import lombok.EqualsAndHashCode;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
/**
|
||||
* Publication audit record for business rule chains.
|
||||
*/
|
||||
@TableName(value = "rule_release_record", autoResultMap = true)
|
||||
@KeySequence("rule_release_record_seq")
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
public class RuleReleaseRecordDO extends TenantBaseDO {
|
||||
|
||||
@TableId(type = IdType.ASSIGN_ID)
|
||||
private Long id;
|
||||
|
||||
private String business;
|
||||
|
||||
/**
|
||||
* Generated chain id, usually business:version.
|
||||
*/
|
||||
@TableField("chain_id")
|
||||
private String chainId;
|
||||
|
||||
@TableField("chain_code")
|
||||
private String chainCode;
|
||||
|
||||
private String version;
|
||||
|
||||
private Integer status;
|
||||
|
||||
@TableField("release_user_id")
|
||||
private Long releaseUserId;
|
||||
|
||||
@TableField("release_user_name")
|
||||
private String releaseUserName;
|
||||
|
||||
@TableField("release_time")
|
||||
private LocalDateTime releaseTime;
|
||||
|
||||
private String remark;
|
||||
}
|
||||
@@ -1,70 +0,0 @@
|
||||
package com.zt.plat.module.rule.dal.dataobject.rule;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.dataobject.BaseDO;
|
||||
import com.baomidou.mybatisplus.annotation.KeySequence;
|
||||
import com.baomidou.mybatisplus.annotation.TableId;
|
||||
import com.baomidou.mybatisplus.annotation.TableName;
|
||||
import lombok.*;
|
||||
|
||||
/**
|
||||
* 规则 DO
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@TableName("rule_rule")
|
||||
@KeySequence("rule_rule_seq") // 用于 Oracle、PostgreSQL、Kingbase、DB2、H2 数据库的主键自增。如果是 MySQL 等数据库,可不写。
|
||||
@Data
|
||||
@EqualsAndHashCode(callSuper = true)
|
||||
@ToString(callSuper = true)
|
||||
@Builder
|
||||
@NoArgsConstructor
|
||||
@AllArgsConstructor
|
||||
public class RuleDO extends BaseDO {
|
||||
|
||||
/**
|
||||
* 规则ID
|
||||
*/
|
||||
@TableId
|
||||
private Long id;
|
||||
|
||||
/**
|
||||
* 规则名称
|
||||
*/
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* 规则描述
|
||||
*/
|
||||
private String description;
|
||||
|
||||
/**
|
||||
* 规则类型:1-原子规则 2-链式规则
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
/**
|
||||
* 规则状态:0-禁用 1-启用
|
||||
*/
|
||||
private Integer status;
|
||||
|
||||
/**
|
||||
* 规则配置(JSON格式)
|
||||
*/
|
||||
private String config;
|
||||
|
||||
/**
|
||||
* LiteFlow规则链ID
|
||||
*/
|
||||
private String chainId;
|
||||
|
||||
/**
|
||||
* 规则版本
|
||||
*/
|
||||
private String version;
|
||||
|
||||
/**
|
||||
* 排序
|
||||
*/
|
||||
private Integer sort;
|
||||
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.business;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindPageReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessBindingDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleBusinessBindingMapper extends BaseMapperX<RuleBusinessBindingDO> {
|
||||
|
||||
default RuleBusinessBindingDO selectByBusiness(String business) {
|
||||
return selectOne(RuleBusinessBindingDO::getBusiness, business);
|
||||
}
|
||||
|
||||
default List<RuleBusinessBindingDO> selectChildren(String parentBusinessPrefix) {
|
||||
return selectList(new LambdaQueryWrapperX<RuleBusinessBindingDO>()
|
||||
.likeRight(RuleBusinessBindingDO::getBusiness, parentBusinessPrefix));
|
||||
}
|
||||
|
||||
default PageResult<RuleBusinessBindingDO> selectPage(RuleBusinessBindPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<RuleBusinessBindingDO>()
|
||||
.likeIfPresent(RuleBusinessBindingDO::getBusiness, reqVO.getBusiness())
|
||||
.eqIfPresent(RuleBusinessBindingDO::getOverrideStrategy, reqVO.getOverrideStrategy())
|
||||
.eqIfPresent(RuleBusinessBindingDO::getLocked, reqVO.getLocked())
|
||||
.betweenIfPresent(RuleBusinessBindingDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(RuleBusinessBindingDO::getId));
|
||||
}
|
||||
|
||||
default List<RuleBusinessBindingDO> selectAll() {
|
||||
return selectList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.business;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessRelationDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleBusinessRelationMapper extends BaseMapperX<RuleBusinessRelationDO> {
|
||||
|
||||
default List<RuleBusinessRelationDO> selectChildren(String parentBusiness) {
|
||||
return selectList(new LambdaQueryWrapperX<RuleBusinessRelationDO>()
|
||||
.eqIfPresent(RuleBusinessRelationDO::getParentBusiness, parentBusiness)
|
||||
.orderByAsc(RuleBusinessRelationDO::getSort));
|
||||
}
|
||||
|
||||
default RuleBusinessRelationDO selectByChild(String childBusiness) {
|
||||
return selectOne(RuleBusinessRelationDO::getChildBusiness, childBusiness);
|
||||
}
|
||||
|
||||
default List<RuleBusinessRelationDO> selectAll() {
|
||||
return selectList();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.chain;
|
||||
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDependencyDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleChainDependencyMapper extends BaseMapperX<RuleChainDependencyDO> {
|
||||
|
||||
default List<RuleChainDependencyDO> selectByParentChainId(Long parentChainId) {
|
||||
return selectList(RuleChainDependencyDO::getParentChainId, parentChainId);
|
||||
}
|
||||
|
||||
default void deleteByParentChainId(Long parentChainId) {
|
||||
delete(RuleChainDependencyDO::getParentChainId, parentChainId);
|
||||
}
|
||||
|
||||
default List<RuleChainDependencyDO> selectByParentChainIds(Collection<Long> parentChainIds) {
|
||||
return selectList(RuleChainDependencyDO::getParentChainId, parentChainIds);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,31 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.chain;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainPageReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleChainMapper extends BaseMapperX<RuleChainDO> {
|
||||
|
||||
default RuleChainDO selectByCode(String code) {
|
||||
return selectOne(RuleChainDO::getCode, code);
|
||||
}
|
||||
|
||||
default PageResult<RuleChainDO> selectPage(RuleChainPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<RuleChainDO>()
|
||||
.likeIfPresent(RuleChainDO::getName, reqVO.getName())
|
||||
.eqIfPresent(RuleChainDO::getCode, reqVO.getCode())
|
||||
.eqIfPresent(RuleChainDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(RuleChainDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(RuleChainDO::getId));
|
||||
}
|
||||
|
||||
default List<RuleChainDO> selectByCodes(List<String> codes) {
|
||||
return selectList(RuleChainDO::getCode, codes);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.definition;
|
||||
|
||||
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionPageReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.definition.RuleDefinitionDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleDefinitionMapper extends BaseMapperX<RuleDefinitionDO> {
|
||||
|
||||
default RuleDefinitionDO selectByCode(String code) {
|
||||
return selectOne(RuleDefinitionDO::getCode, code);
|
||||
}
|
||||
|
||||
default PageResult<RuleDefinitionDO> selectPage(RuleDefinitionPageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<RuleDefinitionDO>()
|
||||
.likeIfPresent(RuleDefinitionDO::getName, reqVO.getName())
|
||||
.eqIfPresent(RuleDefinitionDO::getCode, reqVO.getCode())
|
||||
.eqIfPresent(RuleDefinitionDO::getType, reqVO.getType())
|
||||
.eqIfPresent(RuleDefinitionDO::getStatus, reqVO.getStatus())
|
||||
.betweenIfPresent(RuleDefinitionDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(RuleDefinitionDO::getId));
|
||||
}
|
||||
|
||||
default List<RuleDefinitionDO> selectListByIds(Collection<Long> ids) {
|
||||
return selectList(RuleDefinitionDO::getId, ids);
|
||||
}
|
||||
|
||||
default void updateStatusBatch(Collection<Long> ids, Integer status) {
|
||||
update(null, new LambdaUpdateWrapper<RuleDefinitionDO>()
|
||||
.in(RuleDefinitionDO::getId, ids)
|
||||
.set(RuleDefinitionDO::getStatus, status));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.release;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleasePageReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.release.RuleReleaseRecordDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mapper
|
||||
public interface RuleReleaseRecordMapper extends BaseMapperX<RuleReleaseRecordDO> {
|
||||
|
||||
default PageResult<RuleReleaseRecordDO> selectPage(RuleReleasePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<RuleReleaseRecordDO>()
|
||||
.eqIfPresent(RuleReleaseRecordDO::getBusiness, reqVO.getBusiness())
|
||||
.eqIfPresent(RuleReleaseRecordDO::getStatus, reqVO.getStatus())
|
||||
.likeIfPresent(RuleReleaseRecordDO::getVersion, reqVO.getVersion())
|
||||
.betweenIfPresent(RuleReleaseRecordDO::getReleaseTime, reqVO.getReleaseTime())
|
||||
.orderByDesc(RuleReleaseRecordDO::getReleaseTime));
|
||||
}
|
||||
|
||||
default RuleReleaseRecordDO selectLatest(String business) {
|
||||
List<RuleReleaseRecordDO> records = selectList(new LambdaQueryWrapperX<RuleReleaseRecordDO>()
|
||||
.eq(RuleReleaseRecordDO::getBusiness, business)
|
||||
.orderByDesc(RuleReleaseRecordDO::getReleaseTime)
|
||||
.last("limit 1"));
|
||||
return records.isEmpty() ? null : records.get(0);
|
||||
}
|
||||
|
||||
default RuleReleaseRecordDO selectByBusinessAndVersion(String business, String version) {
|
||||
return selectOne(new LambdaQueryWrapperX<RuleReleaseRecordDO>()
|
||||
.eq(RuleReleaseRecordDO::getBusiness, business)
|
||||
.eq(RuleReleaseRecordDO::getVersion, version));
|
||||
}
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package com.zt.plat.module.rule.dal.mysql.rule;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.framework.mybatis.core.mapper.BaseMapperX;
|
||||
import com.zt.plat.framework.mybatis.core.query.LambdaQueryWrapperX;
|
||||
import com.zt.plat.module.rule.controller.admin.rule.vo.RulePageReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.rule.RuleDO;
|
||||
import org.apache.ibatis.annotations.Mapper;
|
||||
|
||||
/**
|
||||
* 规则 Mapper
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Mapper
|
||||
public interface RuleMapper extends BaseMapperX<RuleDO> {
|
||||
|
||||
default PageResult<RuleDO> selectPage(RulePageReqVO reqVO) {
|
||||
return selectPage(reqVO, new LambdaQueryWrapperX<RuleDO>()
|
||||
.likeIfPresent(RuleDO::getName, reqVO.getName())
|
||||
.eqIfPresent(RuleDO::getType, reqVO.getType())
|
||||
.eqIfPresent(RuleDO::getStatus, reqVO.getStatus())
|
||||
.eqIfPresent(RuleDO::getChainId, reqVO.getChainId())
|
||||
.betweenIfPresent(RuleDO::getCreateTime, reqVO.getCreateTime())
|
||||
.orderByDesc(RuleDO::getId));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,19 +3,26 @@ package com.zt.plat.module.rule.enums;
|
||||
import com.zt.plat.framework.common.exception.ErrorCode;
|
||||
|
||||
/**
|
||||
* Rule 错误码枚举类
|
||||
*
|
||||
* rule 系统,使用 1-009-000-000 段
|
||||
* Error code definitions for the rule module (range 1-045-000-000 ~ 1-045-099-999).
|
||||
*/
|
||||
public interface ErrorCodeConstants {
|
||||
|
||||
// ========== 规则相关错误码 1-009-001-000 ==========
|
||||
ErrorCode RULE_NOT_EXISTS = new ErrorCode(1_009_001_000, "规则不存在");
|
||||
ErrorCode RULE_CONFIG_INVALID = new ErrorCode(1_009_001_001, "规则配置无效");
|
||||
ErrorCode RULE_LOAD_FAILED = new ErrorCode(1_009_001_002, "规则加载失败");
|
||||
ErrorCode RULE_NOT_ENABLED = new ErrorCode(1_009_001_003, "规则未启用");
|
||||
ErrorCode RULE_CHAIN_ID_EMPTY = new ErrorCode(1_009_001_004, "规则链ID不能为空");
|
||||
ErrorCode RULE_EXECUTE_FAILED = new ErrorCode(1_009_001_005, "规则执行失败");
|
||||
ErrorCode RULE_VALIDATION_FAILED = new ErrorCode(1_009_001_006, "规则验证失败");
|
||||
ErrorCode RULE_DEFINITION_NOT_EXISTS = new ErrorCode(1_045_000_001, "规则定义不存在");
|
||||
ErrorCode RULE_DEFINITION_CODE_DUPLICATE = new ErrorCode(1_045_000_002, "规则编码已存在");
|
||||
ErrorCode RULE_DEFINITION_STATUS_INVALID = new ErrorCode(1_045_000_003, "规则状态不允许当前操作");
|
||||
|
||||
}
|
||||
ErrorCode RULE_CHAIN_NOT_EXISTS = new ErrorCode(1_045_000_101, "规则链不存在");
|
||||
ErrorCode RULE_CHAIN_CODE_DUPLICATE = new ErrorCode(1_045_000_102, "规则链编码已存在");
|
||||
ErrorCode RULE_CHAIN_STRUCTURE_INVALID = new ErrorCode(1_045_000_103, "规则链结构不合法");
|
||||
ErrorCode RULE_CHAIN_DEPEND_RULE_MISSING = new ErrorCode(1_045_000_104, "规则链引用的规则不存在");
|
||||
|
||||
ErrorCode RULE_BUSINESS_NOT_EXISTS = new ErrorCode(1_045_000_201, "业务绑定不存在");
|
||||
ErrorCode RULE_BUSINESS_RELATION_CYCLE = new ErrorCode(1_045_000_202, "业务父子关系存在循环依赖");
|
||||
ErrorCode RULE_BUSINESS_LOCKED = new ErrorCode(1_045_000_203, "业务链路已锁定不允许修改");
|
||||
|
||||
ErrorCode RULE_RELEASE_NOT_EXISTS = new ErrorCode(1_045_000_301, "规则发布记录不存在");
|
||||
ErrorCode RULE_RELEASE_IN_PROGRESS = new ErrorCode(1_045_000_302, "存在进行中的发布任务");
|
||||
ErrorCode RULE_PUBLISH_PUSH_FAILED = new ErrorCode(1_045_000_303, "发布LiteFlow DSL失败");
|
||||
|
||||
ErrorCode RULE_SIMULATION_FAILED = new ErrorCode(1_045_000_401, "规则链模拟执行失败");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
package com.zt.plat.module.rule.framework.config;
|
||||
|
||||
import org.springframework.boot.context.properties.EnableConfigurationProperties;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* Shared configuration entry point for the rule module.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
@EnableConfigurationProperties(RulePublishProperties.class)
|
||||
public class RuleModuleConfiguration {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zt.plat.module.rule.framework.config;
|
||||
|
||||
import lombok.Data;
|
||||
import org.springframework.boot.context.properties.ConfigurationProperties;
|
||||
|
||||
/**
|
||||
* Rule module properties customised for publishing DSL to configuration center.
|
||||
*/
|
||||
@Data
|
||||
@ConfigurationProperties(prefix = "rule.publish")
|
||||
public class RulePublishProperties {
|
||||
|
||||
/**
|
||||
* Nacos group used when pushing LiteFlow DSL.
|
||||
*/
|
||||
private String nacosGroup = "RULES";
|
||||
|
||||
/**
|
||||
* DataId prefix, final DataId is prefix + "/" + business + "/" + version.
|
||||
*/
|
||||
private String dataIdPrefix = "rule";
|
||||
}
|
||||
@@ -1,42 +1,28 @@
|
||||
package com.zt.plat.module.rule.framework.security.config;
|
||||
package com.zt.plat.module.rule.framework.config;
|
||||
|
||||
import com.zt.plat.framework.security.config.AuthorizeRequestsCustomizer;
|
||||
import com.zt.plat.module.infra.enums.ApiConstants;
|
||||
import com.zt.plat.module.rule.enums.ApiConstants;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
|
||||
import org.springframework.security.config.annotation.web.configurers.AuthorizeHttpRequestsConfigurer;
|
||||
|
||||
|
||||
/**
|
||||
* Rule 模块的 Security 配置
|
||||
*
|
||||
* @author ZT
|
||||
* Security configuration for rule module web endpoints.
|
||||
*/
|
||||
@Configuration(proxyBeanMethods = false)
|
||||
public class SecurityConfiguration {
|
||||
|
||||
@Bean
|
||||
public AuthorizeRequestsCustomizer authorizeRequestsCustomizer() {
|
||||
public AuthorizeRequestsCustomizer ruleModuleAuthorizeCustomizer() {
|
||||
return new AuthorizeRequestsCustomizer() {
|
||||
|
||||
@Override
|
||||
public void customize(AuthorizeHttpRequestsConfigurer<HttpSecurity>.AuthorizationManagerRequestMatcherRegistry registry) {
|
||||
// Swagger 接口文档
|
||||
registry.requestMatchers("/v3/api-docs/**").permitAll()
|
||||
.requestMatchers("/webjars/**").permitAll()
|
||||
.requestMatchers("/swagger-ui").permitAll()
|
||||
.requestMatchers("/swagger-ui/**").permitAll();
|
||||
// Druid 监控
|
||||
registry.requestMatchers("/v3/api-docs/**", "/webjars/**", "/swagger-ui", "/swagger-ui/**").permitAll();
|
||||
registry.requestMatchers("/druid/**").permitAll();
|
||||
// Spring Boot Actuator 的安全配置
|
||||
registry.requestMatchers("/actuator").permitAll()
|
||||
.requestMatchers("/actuator/**").permitAll();
|
||||
// RPC 服务的安全配置
|
||||
registry.requestMatchers("/actuator", "/actuator/**").permitAll();
|
||||
registry.requestMatchers(ApiConstants.PREFIX + "/**").permitAll();
|
||||
}
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,110 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow;
|
||||
|
||||
import com.fasterxml.jackson.core.JsonProcessingException;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.fasterxml.jackson.databind.node.ArrayNode;
|
||||
import com.fasterxml.jackson.databind.node.ObjectNode;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainNodeDTO;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainStructureDTO;
|
||||
import jakarta.validation.ValidationException;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Comparator;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Utility responsible for validating chain structure and producing LiteFlow DSL.
|
||||
*/
|
||||
@Component
|
||||
public class RuleChainAssembler {
|
||||
|
||||
private final ObjectMapper objectMapper;
|
||||
|
||||
public RuleChainAssembler(ObjectMapper objectMapper) {
|
||||
this.objectMapper = objectMapper;
|
||||
}
|
||||
|
||||
public void validate(RuleChainStructureDTO structure) {
|
||||
if (structure == null || CollectionUtils.isEmpty(structure.getNodes())) {
|
||||
throw new ValidationException("链路结构不能为空");
|
||||
}
|
||||
}
|
||||
|
||||
public String buildLiteflowDsl(RuleChainStructureDTO structure, String chainName) {
|
||||
validate(structure);
|
||||
|
||||
String expression = structure.getEntryExpression();
|
||||
if (!StringUtils.hasText(expression)) {
|
||||
expression = buildSequentialExpression(structure.getNodes());
|
||||
}
|
||||
if (!StringUtils.hasText(expression)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_STRUCTURE_INVALID);
|
||||
}
|
||||
|
||||
ObjectNode root = objectMapper.createObjectNode();
|
||||
ObjectNode flow = objectMapper.createObjectNode();
|
||||
ArrayNode chainList = flow.putArray("chainList");
|
||||
ObjectNode chain = objectMapper.createObjectNode();
|
||||
chain.put("name", chainName);
|
||||
chain.put("value", expression);
|
||||
chainList.add(chain);
|
||||
|
||||
ArrayNode nodeList = flow.putArray("nodeList");
|
||||
for (RuleChainNodeDTO node : structure.getNodes()) {
|
||||
ObjectNode nodeJson = objectMapper.createObjectNode();
|
||||
nodeJson.put("id", StringUtils.hasText(node.getCode()) ? node.getCode() : node.getId());
|
||||
nodeJson.put("name", node.getName());
|
||||
nodeJson.put("type", resolveNodeType(node));
|
||||
if (node.getConfig() != null) {
|
||||
nodeJson.set("config", objectMapper.valueToTree(node.getConfig()));
|
||||
}
|
||||
if (StringUtils.hasText(node.getRuleCode())) {
|
||||
nodeJson.put("ref", node.getRuleCode());
|
||||
}
|
||||
nodeList.add(nodeJson);
|
||||
}
|
||||
root.set("flow", flow);
|
||||
|
||||
try {
|
||||
return objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(root);
|
||||
} catch (JsonProcessingException e) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_STRUCTURE_INVALID, e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String buildSequentialExpression(List<RuleChainNodeDTO> nodes) {
|
||||
List<String> orderedCodes = nodes.stream()
|
||||
.sorted(Comparator.comparing(node -> node.getOrderIndex() == null ? Integer.MAX_VALUE : node.getOrderIndex()))
|
||||
.map(node -> StringUtils.hasText(node.getRuleCode()) ? node.getRuleCode() : node.getCode())
|
||||
.filter(StringUtils::hasText)
|
||||
.toList();
|
||||
if (orderedCodes.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
if (orderedCodes.size() == 1) {
|
||||
return orderedCodes.get(0);
|
||||
}
|
||||
return String.format(Locale.ROOT, "THEN(%s)", String.join(",", orderedCodes));
|
||||
}
|
||||
|
||||
private String resolveNodeType(RuleChainNodeDTO node) {
|
||||
if (node.getType() == null) {
|
||||
return "COMMON";
|
||||
}
|
||||
return switch (node.getType()) {
|
||||
case 1 -> "THEN";
|
||||
case 2 -> "IF";
|
||||
case 3 -> "SWITCH";
|
||||
case 4 -> "FOR";
|
||||
case 5 -> "WHEN";
|
||||
case 6 -> "CHAIN";
|
||||
case 7 -> "NODE";
|
||||
default -> "COMMON";
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow;
|
||||
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.enums.FlowParserTypeEnum;
|
||||
import com.yomahub.liteflow.flow.FlowBus;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Thin wrapper over LiteFlow {@link FlowExecutor} to register chains dynamically
|
||||
* and execute sandbox simulations.
|
||||
*/
|
||||
@Component
|
||||
public class RuleLiteflowManager {
|
||||
|
||||
private final FlowExecutor flowExecutor;
|
||||
|
||||
public RuleLiteflowManager(FlowExecutor flowExecutor) {
|
||||
this.flowExecutor = flowExecutor;
|
||||
}
|
||||
|
||||
public void registerOrUpdate(String resourceId, String liteflowDsl) {
|
||||
if (!StringUtils.hasText(liteflowDsl)) {
|
||||
return;
|
||||
}
|
||||
try {
|
||||
if (StringUtils.hasText(resourceId) && FlowBus.containChain(resourceId)) {
|
||||
FlowBus.removeChain(resourceId);
|
||||
}
|
||||
FlowBus.refreshFlowMetaData(FlowParserTypeEnum.TYPE_EL_JSON, liteflowDsl);
|
||||
flowExecutor.reloadRule();
|
||||
} catch (Exception ex) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_PUBLISH_PUSH_FAILED, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public LiteflowResponse execute(String chainId, Map<String, Object> requestData) {
|
||||
return flowExecutor.execute2Resp(chainId, requestData);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component;
|
||||
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.flow.element.Node;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* Base LiteFlow component that exposes helper methods to read JSON configuration
|
||||
* and interact with the shared request/context data maps.
|
||||
*/
|
||||
public abstract class AbstractJsonConfigNodeComponent extends NodeComponent {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(getClass());
|
||||
|
||||
protected Map<String, Object> getComponentConfig() {
|
||||
Node node = getRefNode();
|
||||
if (node == null) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
String cmpData = node.getCmpData();
|
||||
if (!StringUtils.hasText(cmpData)) {
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(cmpData, new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
logger.warn("Failed to parse component config for node {}: {}", node.getId(), ex.getMessage());
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
protected Map<String, Object> getMutableRequestMap() {
|
||||
Object data = getRequestData();
|
||||
if (data instanceof Map) {
|
||||
return (Map<String, Object>) data;
|
||||
}
|
||||
Map<String, Object> mutable = new HashMap<>();
|
||||
if (data != null) {
|
||||
mutable.put("requestData", data);
|
||||
}
|
||||
return mutable;
|
||||
}
|
||||
|
||||
protected void storeResult(String key, Object value) {
|
||||
if (!StringUtils.hasText(key)) {
|
||||
return;
|
||||
}
|
||||
Map<String, Object> requestMap = getMutableRequestMap();
|
||||
requestMap.put(key, value);
|
||||
try {
|
||||
getSlot().setOutput(key, value);
|
||||
} catch (Exception ex) {
|
||||
logger.debug("Unable to record output value for key {}: {}", key, ex.getMessage());
|
||||
}
|
||||
try {
|
||||
getSlot().setChainReqData(key, value);
|
||||
} catch (Exception ex) {
|
||||
logger.debug("Unable to record chain data for key {}: {}", key, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
protected String readString(Map<String, Object> config, Map<String, Object> requestMap, String key) {
|
||||
Object value = config.getOrDefault(key, requestMap.get(key));
|
||||
return value != null ? String.valueOf(value) : null;
|
||||
}
|
||||
|
||||
protected BigDecimal readDecimal(Map<String, Object> config, Map<String, Object> requestMap, String key) {
|
||||
Object value = config.getOrDefault(key, requestMap.get(key));
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof BigDecimal) {
|
||||
return (BigDecimal) value;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return new BigDecimal(value.toString());
|
||||
}
|
||||
String str = value.toString();
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(str.trim());
|
||||
} catch (NumberFormatException ex) {
|
||||
logger.warn("Invalid decimal value '{}' for key '{}' in node '{}'", str, key,
|
||||
Optional.ofNullable(getRefNode()).map(Node::getId).orElse("unknown"));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Integer readInteger(Map<String, Object> config, Map<String, Object> requestMap, String key) {
|
||||
Object value = config.getOrDefault(key, requestMap.get(key));
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Number) {
|
||||
return ((Number) value).intValue();
|
||||
}
|
||||
String str = value.toString();
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(str.trim());
|
||||
} catch (NumberFormatException ex) {
|
||||
logger.warn("Invalid integer value '{}' for key '{}' in node '{}'", str, key,
|
||||
Optional.ofNullable(getRefNode()).map(Node::getId).orElse("unknown"));
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
protected Boolean readBoolean(Map<String, Object> config, Map<String, Object> requestMap, String key) {
|
||||
Object value = config.getOrDefault(key, requestMap.get(key));
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
if (value instanceof Boolean) {
|
||||
return (Boolean) value;
|
||||
}
|
||||
String str = value.toString();
|
||||
if (!StringUtils.hasText(str)) {
|
||||
return null;
|
||||
}
|
||||
return Boolean.parseBoolean(str.toLowerCase(Locale.ROOT));
|
||||
}
|
||||
|
||||
protected String resolveResultKey(Map<String, Object> config, String defaultKey) {
|
||||
Object resultKey = config.get("resultKey");
|
||||
String key = resultKey != null ? resultKey.toString() : defaultKey;
|
||||
return StringUtils.hasText(key) ? key : defaultKey;
|
||||
}
|
||||
|
||||
protected Logger getLogger() {
|
||||
return logger;
|
||||
}
|
||||
}
|
||||
@@ -1,75 +1,130 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component.action;
|
||||
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.base.BaseRuleComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.fasterxml.jackson.core.type.TypeReference;
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.AbstractJsonConfigNodeComponent;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Collections;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 数据设置组件
|
||||
* 用于设置上下文数据
|
||||
*
|
||||
* @author 芋道源码
|
||||
* Writes a value into the shared request/context map so that subsequent nodes can consume it.
|
||||
*/
|
||||
@LiteflowComponent("dataSetNode")
|
||||
@Slf4j
|
||||
public class DataSetComponent extends BaseRuleComponent {
|
||||
public class DataSetComponent extends AbstractJsonConfigNodeComponent {
|
||||
|
||||
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
// 获取参数
|
||||
String dataKey = getNodeProperty("dataKey", String.class);
|
||||
Object dataValue = getNodeProperty("dataValue", Object.class);
|
||||
String valueType = getNodeProperty("valueType", String.class);
|
||||
public void process() {
|
||||
Map<String, Object> config = getComponentConfig();
|
||||
Map<String, Object> request = getMutableRequestMap();
|
||||
|
||||
if (dataKey == null) {
|
||||
throw new IllegalArgumentException("数据设置组件参数不完整: dataKey 不能为空");
|
||||
String dataKey = readString(config, request, "dataKey");
|
||||
if (!StringUtils.hasText(dataKey)) {
|
||||
getLogger().warn("DataSetComponent skipped because dataKey is missing");
|
||||
return;
|
||||
}
|
||||
|
||||
Object finalValue = dataValue;
|
||||
|
||||
// 根据valueType进行类型转换
|
||||
if (valueType != null && dataValue != null) {
|
||||
String strValue = String.valueOf(dataValue);
|
||||
switch (valueType.toLowerCase()) {
|
||||
case "string":
|
||||
finalValue = strValue;
|
||||
break;
|
||||
case "integer":
|
||||
case "int":
|
||||
finalValue = Integer.valueOf(strValue);
|
||||
break;
|
||||
case "long":
|
||||
finalValue = Long.valueOf(strValue);
|
||||
break;
|
||||
case "double":
|
||||
finalValue = Double.valueOf(strValue);
|
||||
break;
|
||||
case "boolean":
|
||||
finalValue = Boolean.valueOf(strValue);
|
||||
break;
|
||||
case "object":
|
||||
// 保持原有类型
|
||||
break;
|
||||
default:
|
||||
log.warn("不支持的数据类型: {}, 将保持原有类型", valueType);
|
||||
}
|
||||
}
|
||||
|
||||
// 设置数据到上下文
|
||||
setContextData(dataKey, finalValue);
|
||||
|
||||
// 同时设置到结果数据中
|
||||
Map<String, Object> resultData = getContextData("resultData", Map.class);
|
||||
if (resultData == null) {
|
||||
resultData = new HashMap<>();
|
||||
setContextData("resultData", resultData);
|
||||
}
|
||||
resultData.put(dataKey, finalValue);
|
||||
|
||||
log.info("设置数据: key={}, value={}, valueType={}", dataKey, finalValue, valueType);
|
||||
Object value = resolveValue(config, request);
|
||||
storeResult(dataKey, value);
|
||||
}
|
||||
|
||||
}
|
||||
private Object resolveValue(Map<String, Object> config, Map<String, Object> request) {
|
||||
String valueKey = readString(config, request, "valueKey");
|
||||
Object value;
|
||||
if (StringUtils.hasText(valueKey) && request.containsKey(valueKey)) {
|
||||
value = request.get(valueKey);
|
||||
} else if (config.containsKey("dataValue")) {
|
||||
value = config.get("dataValue");
|
||||
} else {
|
||||
value = null;
|
||||
}
|
||||
|
||||
String valueType = readString(config, request, "valueType");
|
||||
if (!StringUtils.hasText(valueType) || value == null) {
|
||||
return value;
|
||||
}
|
||||
return switch (valueType.trim().toLowerCase(Locale.ROOT)) {
|
||||
case "string" -> String.valueOf(value);
|
||||
case "int", "integer" -> convertToInteger(value);
|
||||
case "long" -> convertToLong(value);
|
||||
case "decimal", "bigdecimal" -> convertToDecimal(value);
|
||||
case "double" -> convertToDouble(value);
|
||||
case "boolean" -> convertToBoolean(value);
|
||||
case "json" -> parseJson(value);
|
||||
case "map" -> value instanceof Map ? value : Collections.emptyMap();
|
||||
default -> value;
|
||||
};
|
||||
}
|
||||
|
||||
private Integer convertToInteger(Object value) {
|
||||
if (value instanceof Number number) {
|
||||
return number.intValue();
|
||||
}
|
||||
try {
|
||||
return Integer.parseInt(String.valueOf(value));
|
||||
} catch (NumberFormatException ex) {
|
||||
getLogger().warn("Failed to convert value '{}' to integer", value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Long convertToLong(Object value) {
|
||||
if (value instanceof Number number) {
|
||||
return number.longValue();
|
||||
}
|
||||
try {
|
||||
return Long.parseLong(String.valueOf(value));
|
||||
} catch (NumberFormatException ex) {
|
||||
getLogger().warn("Failed to convert value '{}' to long", value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private BigDecimal convertToDecimal(Object value) {
|
||||
if (value instanceof BigDecimal decimal) {
|
||||
return decimal;
|
||||
}
|
||||
if (value instanceof Number number) {
|
||||
return new BigDecimal(number.toString());
|
||||
}
|
||||
try {
|
||||
return new BigDecimal(String.valueOf(value));
|
||||
} catch (NumberFormatException ex) {
|
||||
getLogger().warn("Failed to convert value '{}' to BigDecimal", value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Double convertToDouble(Object value) {
|
||||
if (value instanceof Number number) {
|
||||
return number.doubleValue();
|
||||
}
|
||||
try {
|
||||
return Double.parseDouble(String.valueOf(value));
|
||||
} catch (NumberFormatException ex) {
|
||||
getLogger().warn("Failed to convert value '{}' to double", value);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
private Boolean convertToBoolean(Object value) {
|
||||
if (value instanceof Boolean bool) {
|
||||
return bool;
|
||||
}
|
||||
return Boolean.parseBoolean(String.valueOf(value));
|
||||
}
|
||||
|
||||
private Object parseJson(Object value) {
|
||||
try {
|
||||
return OBJECT_MAPPER.readValue(String.valueOf(value), new TypeReference<Map<String, Object>>() {
|
||||
});
|
||||
} catch (Exception ex) {
|
||||
getLogger().warn("Failed to parse JSON value '{}': {}", value, ex.getMessage());
|
||||
return Collections.emptyMap();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,96 +1,83 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component.action;
|
||||
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.base.BaseRuleComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.AbstractJsonConfigNodeComponent;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.math.RoundingMode;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
/**
|
||||
* 数值计算组件
|
||||
* 支持加减乘除等数学运算
|
||||
*
|
||||
* @author 芋道源码
|
||||
* Executes basic math operations and stores the result for subsequent nodes.
|
||||
*/
|
||||
@LiteflowComponent("mathCalculateNode")
|
||||
@Slf4j
|
||||
public class MathCalculateComponent extends BaseRuleComponent {
|
||||
public class MathCalculateComponent extends AbstractJsonConfigNodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
// 获取参数
|
||||
String leftValue = getNodeProperty("leftValue", String.class);
|
||||
String rightValue = getNodeProperty("rightValue", String.class);
|
||||
String operator = getNodeProperty("operator", String.class);
|
||||
String resultKey = getNodeProperty("resultKey", String.class);
|
||||
Integer scale = getNodeProperty("scale", Integer.class);
|
||||
public void process() {
|
||||
Map<String, Object> config = getComponentConfig();
|
||||
Map<String, Object> request = getMutableRequestMap();
|
||||
|
||||
if (leftValue == null || rightValue == null || operator == null) {
|
||||
throw new IllegalArgumentException("数值计算组件参数不完整: leftValue, rightValue, operator 都不能为空");
|
||||
BigDecimal left = Optional.ofNullable(readDecimal(config, request, "leftValue")).orElse(BigDecimal.ZERO);
|
||||
BigDecimal right = Optional.ofNullable(readDecimal(config, request, "rightValue")).orElse(BigDecimal.ZERO);
|
||||
String operator = readString(config, request, "operator");
|
||||
if (!StringUtils.hasText(operator)) {
|
||||
getLogger().warn("MathCalculateComponent skipped due to missing operator");
|
||||
return;
|
||||
}
|
||||
|
||||
if (resultKey == null) {
|
||||
resultKey = "calculateResult";
|
||||
}
|
||||
int scale = Optional.ofNullable(readInteger(config, request, "scale")).orElse(2);
|
||||
RoundingMode roundingMode = resolveRoundingMode(readString(config, request, "roundingMode"));
|
||||
|
||||
if (scale == null) {
|
||||
scale = 2; // 默认保留2位小数
|
||||
}
|
||||
|
||||
try {
|
||||
// 转换为数值
|
||||
BigDecimal left = new BigDecimal(leftValue);
|
||||
BigDecimal right = new BigDecimal(rightValue);
|
||||
BigDecimal result;
|
||||
|
||||
// 根据操作符进行计算
|
||||
switch (operator) {
|
||||
case "+":
|
||||
case "add":
|
||||
result = left.add(right);
|
||||
break;
|
||||
case "-":
|
||||
case "subtract":
|
||||
result = left.subtract(right);
|
||||
break;
|
||||
case "*":
|
||||
case "multiply":
|
||||
result = left.multiply(right);
|
||||
break;
|
||||
case "/":
|
||||
case "divide":
|
||||
if (right.compareTo(BigDecimal.ZERO) == 0) {
|
||||
throw new IllegalArgumentException("除数不能为0");
|
||||
}
|
||||
result = left.divide(right, scale, RoundingMode.HALF_UP);
|
||||
break;
|
||||
case "%":
|
||||
case "mod":
|
||||
result = left.remainder(right);
|
||||
break;
|
||||
case "max":
|
||||
result = left.max(right);
|
||||
break;
|
||||
case "min":
|
||||
result = left.min(right);
|
||||
break;
|
||||
case "pow":
|
||||
result = left.pow(right.intValue());
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("不支持的数学操作符: " + operator);
|
||||
BigDecimal result = switch (operator.trim()) {
|
||||
case "+" -> left.add(right);
|
||||
case "-" -> left.subtract(right);
|
||||
case "*" -> left.multiply(right);
|
||||
case "/" -> right.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : left.divide(right, scale, roundingMode);
|
||||
case "%" -> right.compareTo(BigDecimal.ZERO) == 0 ? BigDecimal.ZERO : left.remainder(right);
|
||||
default -> {
|
||||
getLogger().warn("Unsupported math operator: {}", operator);
|
||||
yield null;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置计算结果
|
||||
setContextData(resultKey, result);
|
||||
setContextData("lastCalculateResult", result);
|
||||
|
||||
log.info("数值计算: {} {} {} = {}", leftValue, operator, rightValue, result);
|
||||
if (result == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("数值格式错误: leftValue=" + leftValue + ", rightValue=" + rightValue, e);
|
||||
String resultType = readString(config, request, "resultType");
|
||||
Object storedValue = convertResult(result, resultType, scale, roundingMode);
|
||||
storeResult(resolveResultKey(config, "mathCalculateResult"), storedValue);
|
||||
}
|
||||
|
||||
private RoundingMode resolveRoundingMode(String mode) {
|
||||
if (!StringUtils.hasText(mode)) {
|
||||
return RoundingMode.HALF_UP;
|
||||
}
|
||||
try {
|
||||
return RoundingMode.valueOf(mode.trim().toUpperCase(Locale.ROOT));
|
||||
} catch (IllegalArgumentException ex) {
|
||||
getLogger().warn("Unsupported rounding mode '{}', fallback to HALF_UP", mode);
|
||||
return RoundingMode.HALF_UP;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
private Object convertResult(BigDecimal value, String resultType, int scale, RoundingMode roundingMode) {
|
||||
if (!StringUtils.hasText(resultType)) {
|
||||
return value;
|
||||
}
|
||||
String normalized = resultType.trim().toLowerCase(Locale.ROOT);
|
||||
return switch (normalized) {
|
||||
case "int", "integer" -> value.setScale(0, roundingMode).intValue();
|
||||
case "long" -> value.setScale(0, roundingMode).longValue();
|
||||
case "double" -> value.doubleValue();
|
||||
case "float" -> value.floatValue();
|
||||
case "string" -> value.setScale(scale, roundingMode).toPlainString();
|
||||
default -> {
|
||||
getLogger().warn("Unknown result type '{}', keep BigDecimal", resultType);
|
||||
yield value;
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,149 +0,0 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component.base;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 基础规则组件
|
||||
* 提供通用的属性获取和上下文操作方法
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
public abstract class BaseRuleComponent extends NodeComponent {
|
||||
|
||||
/**
|
||||
* 获取节点配置属性
|
||||
*
|
||||
* @param key 属性键
|
||||
* @param clazz 属性类型
|
||||
* @return 属性值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getNodeProperty(String key, Class<T> clazz) {
|
||||
DefaultContext context = this.getContextBean(DefaultContext.class);
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// 首先尝试从节点配置中获取
|
||||
String nodeConfigKey = "nodeConfig_" + this.getNodeId();
|
||||
Object nodeConfig = context.getData(nodeConfigKey);
|
||||
|
||||
if (nodeConfig instanceof Map) {
|
||||
Map<String, Object> configMap = (Map<String, Object>) nodeConfig;
|
||||
Object value = configMap.get(key);
|
||||
if (value != null) {
|
||||
return convertValue(value, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
// 其次尝试从上下文数据中获取
|
||||
Object value = context.getData(key);
|
||||
if (value != null) {
|
||||
return convertValue(value, clazz);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 设置上下文数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param value 值
|
||||
*/
|
||||
protected void setContextData(String key, Object value) {
|
||||
DefaultContext context = this.getContextBean(DefaultContext.class);
|
||||
if (context != null) {
|
||||
context.setData(key, value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取上下文数据
|
||||
*
|
||||
* @param key 键
|
||||
* @param clazz 类型
|
||||
* @return 值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
protected <T> T getContextData(String key, Class<T> clazz) {
|
||||
DefaultContext context = this.getContextBean(DefaultContext.class);
|
||||
if (context == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
Object value = context.getData(key);
|
||||
if (value != null) {
|
||||
return convertValue(value, clazz);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* 类型转换
|
||||
*
|
||||
* @param value 原始值
|
||||
* @param clazz 目标类型
|
||||
* @return 转换后的值
|
||||
*/
|
||||
@SuppressWarnings("unchecked")
|
||||
private <T> T convertValue(Object value, Class<T> clazz) {
|
||||
if (value == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if (clazz.isInstance(value)) {
|
||||
return (T) value;
|
||||
}
|
||||
|
||||
if (clazz == String.class) {
|
||||
return (T) String.valueOf(value);
|
||||
}
|
||||
|
||||
if (clazz == Integer.class || clazz == int.class) {
|
||||
if (value instanceof Number) {
|
||||
return (T) Integer.valueOf(((Number) value).intValue());
|
||||
}
|
||||
return (T) Integer.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
if (clazz == Long.class || clazz == long.class) {
|
||||
if (value instanceof Number) {
|
||||
return (T) Long.valueOf(((Number) value).longValue());
|
||||
}
|
||||
return (T) Long.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
if (clazz == Boolean.class || clazz == boolean.class) {
|
||||
if (value instanceof Boolean) {
|
||||
return (T) value;
|
||||
}
|
||||
return (T) Boolean.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
if (clazz == Double.class || clazz == double.class) {
|
||||
if (value instanceof Number) {
|
||||
return (T) Double.valueOf(((Number) value).doubleValue());
|
||||
}
|
||||
return (T) Double.valueOf(String.valueOf(value));
|
||||
}
|
||||
|
||||
// 尝试JSON转换
|
||||
if (value instanceof String && !clazz.isPrimitive()) {
|
||||
String strValue = (String) value;
|
||||
if (JSONUtil.isTypeJSON(strValue)) {
|
||||
return JSONUtil.toBean(strValue, clazz);
|
||||
}
|
||||
}
|
||||
|
||||
throw new IllegalArgumentException("无法将类型 " + value.getClass().getSimpleName() +
|
||||
" 转换为 " + clazz.getSimpleName());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,80 +1,48 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component.common;
|
||||
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.base.BaseRuleComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import com.yomahub.liteflow.core.NodeComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.AbstractJsonConfigNodeComponent;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 条件判断组件 - 数值比较
|
||||
* 支持大于、小于、等于、大于等于、小于等于比较
|
||||
*
|
||||
* @author 芋道源码
|
||||
* Performs a numeric comparison based on configured operands and operator.
|
||||
*/
|
||||
@LiteflowComponent("numberCompareNode")
|
||||
@Slf4j
|
||||
public class NumberCompareComponent extends BaseRuleComponent {
|
||||
public class NumberCompareComponent extends AbstractJsonConfigNodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
// 获取参数
|
||||
String leftValue = getNodeProperty("leftValue", String.class);
|
||||
String operator = getNodeProperty("operator", String.class);
|
||||
String rightValue = getNodeProperty("rightValue", String.class);
|
||||
public void process() {
|
||||
Map<String, Object> config = getComponentConfig();
|
||||
Map<String, Object> request = getMutableRequestMap();
|
||||
|
||||
if (leftValue == null || operator == null || rightValue == null) {
|
||||
throw new IllegalArgumentException("数值比较组件参数不完整: leftValue, operator, rightValue 都不能为空");
|
||||
BigDecimal left = readDecimal(config, request, "leftValue");
|
||||
BigDecimal right = readDecimal(config, request, "rightValue");
|
||||
String operator = readString(config, request, "operator");
|
||||
|
||||
if (left == null || right == null || !StringUtils.hasText(operator)) {
|
||||
getLogger().warn("NumberCompareComponent skipped due to missing operands/operator");
|
||||
storeResult(resolveResultKey(config, "numberCompareResult"), Boolean.FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// 转换为数值
|
||||
BigDecimal left = new BigDecimal(leftValue);
|
||||
BigDecimal right = new BigDecimal(rightValue);
|
||||
|
||||
boolean result = false;
|
||||
|
||||
// 根据操作符进行比较
|
||||
switch (operator) {
|
||||
case ">":
|
||||
case "gt":
|
||||
result = left.compareTo(right) > 0;
|
||||
break;
|
||||
case "<":
|
||||
case "lt":
|
||||
result = left.compareTo(right) < 0;
|
||||
break;
|
||||
case "=":
|
||||
case "==":
|
||||
case "eq":
|
||||
result = left.compareTo(right) == 0;
|
||||
break;
|
||||
case ">=":
|
||||
case "gte":
|
||||
result = left.compareTo(right) >= 0;
|
||||
break;
|
||||
case "<=":
|
||||
case "lte":
|
||||
result = left.compareTo(right) <= 0;
|
||||
break;
|
||||
case "!=":
|
||||
case "ne":
|
||||
result = left.compareTo(right) != 0;
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("不支持的比较操作符: " + operator);
|
||||
boolean result = switch (operator.trim()) {
|
||||
case ">" -> left.compareTo(right) > 0;
|
||||
case ">=" -> left.compareTo(right) >= 0;
|
||||
case "<" -> left.compareTo(right) < 0;
|
||||
case "<=" -> left.compareTo(right) <= 0;
|
||||
case "==", "=" -> left.compareTo(right) == 0;
|
||||
case "!=" -> left.compareTo(right) != 0;
|
||||
default -> {
|
||||
getLogger().warn("Unsupported compare operator: {}", operator);
|
||||
yield false;
|
||||
}
|
||||
};
|
||||
|
||||
// 设置比较结果
|
||||
this.setIsEnd(!result);
|
||||
getSlot().setData("compareResult", result);
|
||||
|
||||
log.info("数值比较: {} {} {} = {}", leftValue, operator, rightValue, result);
|
||||
|
||||
} catch (NumberFormatException e) {
|
||||
throw new IllegalArgumentException("数值格式错误: leftValue=" + leftValue + ", rightValue=" + rightValue, e);
|
||||
storeResult(resolveResultKey(config, "numberCompareResult"), result);
|
||||
Boolean stopOnFailure = readBoolean(config, request, "stopOnFailure");
|
||||
if (!result && Boolean.TRUE.equals(stopOnFailure)) {
|
||||
setIsEnd(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,98 +1,66 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.component.common;
|
||||
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.base.BaseRuleComponent;
|
||||
import com.yomahub.liteflow.annotation.LiteflowComponent;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import com.zt.plat.module.rule.framework.liteflow.component.AbstractJsonConfigNodeComponent;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* 字符串判断组件
|
||||
* 支持字符串相等、包含、长度等判断
|
||||
*
|
||||
* @author 芋道源码
|
||||
* Evaluates string based conditions such as equality or containment checks.
|
||||
*/
|
||||
@LiteflowComponent("stringConditionNode")
|
||||
@Slf4j
|
||||
public class StringConditionComponent extends BaseRuleComponent {
|
||||
public class StringConditionComponent extends AbstractJsonConfigNodeComponent {
|
||||
|
||||
@Override
|
||||
public void process() throws Exception {
|
||||
// 获取参数
|
||||
String sourceValue = getNodeProperty("sourceValue", String.class);
|
||||
String targetValue = getNodeProperty("targetValue", String.class);
|
||||
String operator = getNodeProperty("operator", String.class);
|
||||
public void process() {
|
||||
Map<String, Object> config = getComponentConfig();
|
||||
Map<String, Object> request = getMutableRequestMap();
|
||||
|
||||
if (sourceValue == null || operator == null) {
|
||||
throw new IllegalArgumentException("字符串判断组件参数不完整: sourceValue, operator 不能为空");
|
||||
String left = readString(config, request, "leftValue");
|
||||
String right = readString(config, request, "rightValue");
|
||||
String operator = readString(config, request, "operator");
|
||||
boolean ignoreCase = Boolean.TRUE.equals(readBoolean(config, request, "ignoreCase"));
|
||||
|
||||
if (!StringUtils.hasText(operator)) {
|
||||
getLogger().warn("StringConditionComponent skipped due to missing operator");
|
||||
storeResult(resolveResultKey(config, "stringConditionResult"), Boolean.FALSE);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean result = false;
|
||||
|
||||
// 根据操作符进行判断
|
||||
switch (operator) {
|
||||
case "equals":
|
||||
case "eq":
|
||||
result = StrUtil.equals(sourceValue, targetValue);
|
||||
break;
|
||||
case "equalsIgnoreCase":
|
||||
case "eqIgnoreCase":
|
||||
result = StrUtil.equalsIgnoreCase(sourceValue, targetValue);
|
||||
break;
|
||||
case "contains":
|
||||
result = StrUtil.contains(sourceValue, targetValue);
|
||||
break;
|
||||
case "startsWith":
|
||||
result = StrUtil.startWith(sourceValue, targetValue);
|
||||
break;
|
||||
case "endsWith":
|
||||
result = StrUtil.endWith(sourceValue, targetValue);
|
||||
break;
|
||||
case "isEmpty":
|
||||
result = StrUtil.isEmpty(sourceValue);
|
||||
break;
|
||||
case "isNotEmpty":
|
||||
result = StrUtil.isNotEmpty(sourceValue);
|
||||
break;
|
||||
case "isBlank":
|
||||
result = StrUtil.isBlank(sourceValue);
|
||||
break;
|
||||
case "isNotBlank":
|
||||
result = StrUtil.isNotBlank(sourceValue);
|
||||
break;
|
||||
case "lengthEquals":
|
||||
Integer expectedLength = getNodeProperty("expectedLength", Integer.class);
|
||||
if (expectedLength != null) {
|
||||
result = sourceValue.length() == expectedLength;
|
||||
}
|
||||
break;
|
||||
case "lengthGreaterThan":
|
||||
Integer minLength = getNodeProperty("minLength", Integer.class);
|
||||
if (minLength != null) {
|
||||
result = sourceValue.length() > minLength;
|
||||
}
|
||||
break;
|
||||
case "lengthLessThan":
|
||||
Integer maxLength = getNodeProperty("maxLength", Integer.class);
|
||||
if (maxLength != null) {
|
||||
result = sourceValue.length() < maxLength;
|
||||
}
|
||||
break;
|
||||
case "matches":
|
||||
String pattern = getNodeProperty("pattern", String.class);
|
||||
if (pattern != null) {
|
||||
result = sourceValue.matches(pattern);
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw new IllegalArgumentException("不支持的字符串操作符: " + operator);
|
||||
String normalizedOp = operator.trim().toLowerCase(Locale.ROOT);
|
||||
String leftValue = left != null ? left : "";
|
||||
String rightValue = right != null ? right : "";
|
||||
if (ignoreCase) {
|
||||
leftValue = leftValue.toLowerCase(Locale.ROOT);
|
||||
rightValue = rightValue.toLowerCase(Locale.ROOT);
|
||||
}
|
||||
|
||||
// 设置判断结果
|
||||
this.setIsEnd(!result);
|
||||
setContextData("stringConditionResult", result);
|
||||
|
||||
log.info("字符串判断: sourceValue={}, operator={}, targetValue={}, result={}",
|
||||
sourceValue, operator, targetValue, result);
|
||||
boolean result = switch (normalizedOp) {
|
||||
case "equals", "==", "=" -> leftValue.equals(rightValue);
|
||||
case "notequals", "!=", "<>" -> !leftValue.equals(rightValue);
|
||||
case "contains" -> leftValue.contains(rightValue);
|
||||
case "startswith" -> leftValue.startsWith(rightValue);
|
||||
case "endswith" -> leftValue.endsWith(rightValue);
|
||||
case "blank" -> !StringUtils.hasText(left);
|
||||
case "notblank" -> StringUtils.hasText(left);
|
||||
case "matches" -> {
|
||||
try {
|
||||
yield (left != null ? left : "").matches(right != null ? right : "");
|
||||
} catch (Exception ex) {
|
||||
getLogger().warn("Invalid regex '{}' in StringConditionComponent: {}", right, ex.getMessage());
|
||||
yield false;
|
||||
}
|
||||
}
|
||||
default -> {
|
||||
getLogger().warn("Unsupported string operator: {}", operator);
|
||||
yield false;
|
||||
}
|
||||
};
|
||||
|
||||
storeResult(resolveResultKey(config, "stringConditionResult"), result);
|
||||
Boolean stopOnFailure = readBoolean(config, request, "stopOnFailure");
|
||||
if (!result && Boolean.TRUE.equals(stopOnFailure)) {
|
||||
setIsEnd(true);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.config;
|
||||
|
||||
import com.yomahub.liteflow.spring.ComponentScanner;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
/**
|
||||
* LiteFlow 配置类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Configuration
|
||||
public class LiteFlowConfiguration {
|
||||
|
||||
/**
|
||||
* 组件扫描器
|
||||
* 自动扫描LiteFlow组件
|
||||
*/
|
||||
@Bean
|
||||
public ComponentScanner componentScanner() {
|
||||
return new ComponentScanner("com.zt.plat.module.rule.framework.liteflow.component");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,212 +0,0 @@
|
||||
package com.zt.plat.module.rule.framework.liteflow.service;
|
||||
|
||||
import cn.hutool.core.map.MapUtil;
|
||||
import cn.hutool.core.util.StrUtil;
|
||||
import cn.hutool.json.JSONObject;
|
||||
import cn.hutool.json.JSONUtil;
|
||||
import com.zt.plat.module.rule.controller.admin.rule.vo.RuleExecuteReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.rule.RuleDO;
|
||||
import com.yomahub.liteflow.core.FlowExecutor;
|
||||
import com.yomahub.liteflow.flow.LiteflowResponse;
|
||||
import com.yomahub.liteflow.flow.element.chain.LiteFlowChain;
|
||||
import com.yomahub.liteflow.flow.element.chain.LiteFlowChainBuilder;
|
||||
import com.yomahub.liteflow.slot.DefaultContext;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
import org.springframework.stereotype.Service;
|
||||
|
||||
import javax.annotation.Resource;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* LiteFlow 服务实现类
|
||||
*
|
||||
* @author 芋道源码
|
||||
*/
|
||||
@Service
|
||||
@Slf4j
|
||||
public class LiteFlowService {
|
||||
|
||||
@Resource
|
||||
private FlowExecutor flowExecutor;
|
||||
|
||||
/**
|
||||
* 执行规则
|
||||
*
|
||||
* @param chainId 规则链ID
|
||||
* @param contextData 上下文数据
|
||||
* @param extParams 扩展参数
|
||||
* @return 执行结果
|
||||
*/
|
||||
public Map<String, Object> executeRule(String chainId, Map<String, Object> contextData, Map<String, Object> extParams) {
|
||||
try {
|
||||
// 创建上下文
|
||||
DefaultContext context = new DefaultContext();
|
||||
|
||||
// 设置上下文数据
|
||||
if (MapUtil.isNotEmpty(contextData)) {
|
||||
contextData.forEach(context::setData);
|
||||
}
|
||||
|
||||
// 设置扩展参数
|
||||
if (MapUtil.isNotEmpty(extParams)) {
|
||||
extParams.forEach(context::setData);
|
||||
}
|
||||
|
||||
// 执行规则链
|
||||
LiteflowResponse response = flowExecutor.execute2Resp(chainId, null, context);
|
||||
|
||||
// 构建返回结果
|
||||
Map<String, Object> resultData = new HashMap<>();
|
||||
resultData.put("success", response.isSuccess());
|
||||
resultData.put("message", response.getMessage());
|
||||
resultData.put("executeStepStr", response.getExecuteStepStr());
|
||||
|
||||
// 获取执行结果数据
|
||||
if (response.getSlot() != null && response.getSlot().getContextBean() instanceof DefaultContext) {
|
||||
DefaultContext resultContext = (DefaultContext) response.getSlot().getContextBean();
|
||||
if (resultContext != null) {
|
||||
resultData.put("contextData", resultContext.getData());
|
||||
}
|
||||
}
|
||||
|
||||
return resultData;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("执行规则链失败: chainId={}", chainId, e);
|
||||
throw new RuntimeException("规则执行失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 加载规则到LiteFlow
|
||||
*
|
||||
* @param rule 规则DO
|
||||
*/
|
||||
public void loadRule(RuleDO rule) {
|
||||
try {
|
||||
if (StrUtil.isBlank(rule.getConfig())) {
|
||||
throw new IllegalArgumentException("规则配置不能为空");
|
||||
}
|
||||
|
||||
// 解析JSON配置
|
||||
JSONObject configJson = JSONUtil.parseObj(rule.getConfig());
|
||||
RuleExecuteReqVO.RuleConfig ruleConfig = JSONUtil.toBean(configJson, RuleExecuteReqVO.RuleConfig.class);
|
||||
|
||||
if (ruleConfig.getChain() == null) {
|
||||
throw new IllegalArgumentException("规则链配置不能为空");
|
||||
}
|
||||
|
||||
// 构建LiteFlow规则链
|
||||
String chainId = StrUtil.isNotBlank(rule.getChainId()) ? rule.getChainId() : ruleConfig.getChain().getChainId();
|
||||
String expression = ruleConfig.getChain().getExpression();
|
||||
|
||||
if (StrUtil.isBlank(expression)) {
|
||||
throw new IllegalArgumentException("规则链表达式不能为空");
|
||||
}
|
||||
|
||||
// 创建并加载规则链
|
||||
LiteFlowChain chain = LiteFlowChainBuilder.createChain()
|
||||
.setChainId(chainId)
|
||||
.setChainName(ruleConfig.getChain().getChainName())
|
||||
.setEL(expression)
|
||||
.build();
|
||||
|
||||
// 注册规则链
|
||||
flowExecutor.getChainContainer().setChain(chainId, chain);
|
||||
|
||||
log.info("成功加载规则链: chainId={}, expression={}", chainId, expression);
|
||||
|
||||
} catch (Exception e) {
|
||||
log.error("加载规则到LiteFlow失败: ruleId={}", rule.getId(), e);
|
||||
throw new RuntimeException("加载规则失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 重新加载规则
|
||||
*
|
||||
* @param rule 规则DO
|
||||
*/
|
||||
public void reloadRule(RuleDO rule) {
|
||||
// 先移除再加载
|
||||
if (StrUtil.isNotBlank(rule.getChainId())) {
|
||||
removeRule(rule.getChainId());
|
||||
}
|
||||
loadRule(rule);
|
||||
}
|
||||
|
||||
/**
|
||||
* 移除规则
|
||||
*
|
||||
* @param chainId 规则链ID
|
||||
*/
|
||||
public void removeRule(String chainId) {
|
||||
try {
|
||||
if (StrUtil.isNotBlank(chainId)) {
|
||||
flowExecutor.getChainContainer().removeChain(chainId);
|
||||
log.info("成功移除规则链: chainId={}", chainId);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
log.error("移除规则链失败: chainId={}", chainId, e);
|
||||
throw new RuntimeException("移除规则失败: " + e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 验证规则配置
|
||||
*
|
||||
* @param config 规则配置JSON
|
||||
* @return 验证结果
|
||||
*/
|
||||
public Boolean validateRuleConfig(String config) {
|
||||
try {
|
||||
if (StrUtil.isBlank(config)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 解析JSON
|
||||
JSONObject configJson = JSONUtil.parseObj(config);
|
||||
RuleExecuteReqVO.RuleConfig ruleConfig = JSONUtil.toBean(configJson, RuleExecuteReqVO.RuleConfig.class);
|
||||
|
||||
// 验证必要字段
|
||||
if (ruleConfig.getChain() == null) {
|
||||
log.warn("规则链配置为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(ruleConfig.getChain().getChainId())) {
|
||||
log.warn("规则链ID为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (StrUtil.isBlank(ruleConfig.getChain().getExpression())) {
|
||||
log.warn("规则链表达式为空");
|
||||
return false;
|
||||
}
|
||||
|
||||
// 验证节点配置
|
||||
List<RuleExecuteReqVO.NodeConfig> nodes = ruleConfig.getNodes();
|
||||
if (nodes != null) {
|
||||
for (RuleExecuteReqVO.NodeConfig node : nodes) {
|
||||
if (StrUtil.isBlank(node.getNodeId())) {
|
||||
log.warn("节点ID为空");
|
||||
return false;
|
||||
}
|
||||
if (StrUtil.isBlank(node.getClazz())) {
|
||||
log.warn("节点类名为空: nodeId={}", node.getNodeId());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
|
||||
} catch (Exception e) {
|
||||
log.warn("验证规则配置时发生异常", e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
package com.zt.plat.module.rule.framework.nacos;
|
||||
|
||||
import com.alibaba.cloud.nacos.NacosConfigManager;
|
||||
import com.alibaba.nacos.api.config.ConfigService;
|
||||
import com.alibaba.nacos.api.exception.NacosException;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.rule.framework.config.RulePublishProperties;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.nio.charset.StandardCharsets;
|
||||
|
||||
/**
|
||||
* Publishes LiteFlow DSL to Nacos for runtime consumption.
|
||||
*/
|
||||
@Component
|
||||
public class RuleNacosPublisher {
|
||||
|
||||
private final NacosConfigManager nacosConfigManager;
|
||||
private final RulePublishProperties properties;
|
||||
|
||||
public RuleNacosPublisher(NacosConfigManager nacosConfigManager,
|
||||
RulePublishProperties properties) {
|
||||
this.nacosConfigManager = nacosConfigManager;
|
||||
this.properties = properties;
|
||||
}
|
||||
|
||||
public void publish(String business, String version, String liteflowDsl) {
|
||||
if (!StringUtils.hasText(liteflowDsl)) {
|
||||
return;
|
||||
}
|
||||
String dataId = buildDataId(business, version);
|
||||
try {
|
||||
ConfigService configService = nacosConfigManager.getConfigService();
|
||||
boolean success = configService.publishConfig(dataId, properties.getNacosGroup(), liteflowDsl, StandardCharsets.UTF_8.name());
|
||||
if (!success) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_PUBLISH_PUSH_FAILED, "Nacos publish returned false");
|
||||
}
|
||||
} catch (NacosException ex) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_PUBLISH_PUSH_FAILED, ex.getErrMsg());
|
||||
}
|
||||
}
|
||||
|
||||
public void remove(String business, String version) {
|
||||
String dataId = buildDataId(business, version);
|
||||
try {
|
||||
nacosConfigManager.getConfigService().removeConfig(dataId, properties.getNacosGroup());
|
||||
} catch (NacosException ex) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_PUBLISH_PUSH_FAILED, ex.getErrMsg());
|
||||
}
|
||||
}
|
||||
|
||||
public String buildDataId(String business, String version) {
|
||||
return properties.getDataIdPrefix() + "/" + business + "/" + version;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
package com.zt.plat.module.rule.service.business;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessChainViewRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessRelationSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessTreeNodeRespVO;
|
||||
import com.zt.plat.module.rule.service.dto.BusinessChainAssembleResultDTO;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface RuleBusinessService {
|
||||
|
||||
void saveBinding(RuleBusinessBindSaveReqVO reqVO);
|
||||
|
||||
PageResult<RuleBusinessBindRespVO> getBindingPage(RuleBusinessBindPageReqVO reqVO);
|
||||
|
||||
RuleBusinessBindRespVO getBinding(String business);
|
||||
|
||||
void removeBinding(String business);
|
||||
|
||||
void saveRelation(RuleBusinessRelationSaveReqVO reqVO);
|
||||
|
||||
void removeRelation(String childBusiness);
|
||||
|
||||
List<RuleBusinessTreeNodeRespVO> getBusinessTree();
|
||||
|
||||
RuleBusinessChainViewRespVO previewBusinessChain(String business, String version);
|
||||
|
||||
BusinessChainAssembleResultDTO assembleBusinessChain(String business, String version);
|
||||
}
|
||||
@@ -0,0 +1,331 @@
|
||||
package com.zt.plat.module.rule.service.business;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessBindSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessChainViewRespVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessRelationSaveReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.business.vo.RuleBusinessTreeNodeRespVO;
|
||||
import com.zt.plat.module.rule.convert.business.RuleBusinessConvert;
|
||||
import com.zt.plat.module.rule.convert.chain.RuleChainConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessBindingDO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessRelationDO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
import com.zt.plat.module.rule.dal.mysql.business.RuleBusinessBindingMapper;
|
||||
import com.zt.plat.module.rule.dal.mysql.business.RuleBusinessRelationMapper;
|
||||
import com.zt.plat.module.rule.dal.mysql.chain.RuleChainMapper;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.rule.enums.OverrideStrategyEnum;
|
||||
import com.zt.plat.module.rule.framework.liteflow.RuleChainAssembler;
|
||||
import com.zt.plat.module.rule.service.dto.BusinessChainAssembleResultDTO;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainNodeDTO;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainStructureDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Deque;
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class RuleBusinessServiceImpl implements RuleBusinessService {
|
||||
|
||||
@Resource
|
||||
private RuleBusinessBindingMapper bindingMapper;
|
||||
@Resource
|
||||
private RuleBusinessRelationMapper relationMapper;
|
||||
@Resource
|
||||
private RuleChainMapper ruleChainMapper;
|
||||
@Resource
|
||||
private RuleChainConvert ruleChainConvert;
|
||||
@Resource
|
||||
private RuleChainAssembler ruleChainAssembler;
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveBinding(RuleBusinessBindSaveReqVO reqVO) {
|
||||
RuleBusinessBindingDO existed = bindingMapper.selectByBusiness(reqVO.getBusiness());
|
||||
RuleBusinessBindingDO entity = RuleBusinessConvert.INSTANCE.convert(reqVO);
|
||||
if (Boolean.TRUE.equals(existed != null ? existed.getLocked() : Boolean.FALSE)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_LOCKED);
|
||||
}
|
||||
if (existed == null) {
|
||||
bindingMapper.insert(entity);
|
||||
} else {
|
||||
entity.setId(existed.getId());
|
||||
entity.setEffectiveVersion(existed.getEffectiveVersion());
|
||||
bindingMapper.updateById(entity);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RuleBusinessBindRespVO> getBindingPage(RuleBusinessBindPageReqVO reqVO) {
|
||||
PageResult<RuleBusinessBindingDO> pageResult = bindingMapper.selectPage(reqVO);
|
||||
List<RuleBusinessBindingDO> list = pageResult.getList();
|
||||
if (CollectionUtils.isEmpty(list)) {
|
||||
return new PageResult<>(List.of(), pageResult.getTotal());
|
||||
}
|
||||
Map<Long, RuleChainDO> chainMap = ruleChainMapper.selectBatchIds(
|
||||
list.stream().map(RuleBusinessBindingDO::getRuleChainId).collect(Collectors.toSet()))
|
||||
.stream().collect(Collectors.toMap(RuleChainDO::getId, c -> c));
|
||||
List<RuleBusinessBindRespVO> records = list.stream().map(item -> {
|
||||
RuleBusinessBindRespVO vo = RuleBusinessConvert.INSTANCE.convert(item);
|
||||
RuleChainDO chain = chainMap.get(item.getRuleChainId());
|
||||
if (chain != null) {
|
||||
vo.setRuleChainCode(chain.getCode());
|
||||
vo.setRuleChainName(chain.getName());
|
||||
}
|
||||
return vo;
|
||||
}).collect(Collectors.toList());
|
||||
return new PageResult<>(records, pageResult.getTotal());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleBusinessBindRespVO getBinding(String business) {
|
||||
RuleBusinessBindingDO entity = bindingMapper.selectByBusiness(business);
|
||||
if (entity == null) {
|
||||
return null;
|
||||
}
|
||||
RuleBusinessBindRespVO vo = RuleBusinessConvert.INSTANCE.convert(entity);
|
||||
RuleChainDO chain = ruleChainMapper.selectById(entity.getRuleChainId());
|
||||
if (chain != null) {
|
||||
vo.setRuleChainCode(chain.getCode());
|
||||
vo.setRuleChainName(chain.getName());
|
||||
}
|
||||
return vo;
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeBinding(String business) {
|
||||
RuleBusinessBindingDO entity = bindingMapper.selectByBusiness(business);
|
||||
if (entity != null) {
|
||||
if (Boolean.TRUE.equals(entity.getLocked())) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_LOCKED);
|
||||
}
|
||||
bindingMapper.deleteById(entity.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void saveRelation(RuleBusinessRelationSaveReqVO reqVO) {
|
||||
validateNoCycle(reqVO.getParentBusiness(), reqVO.getChildBusiness());
|
||||
RuleBusinessRelationDO existed = relationMapper.selectByChild(reqVO.getChildBusiness());
|
||||
if (existed == null) {
|
||||
RuleBusinessRelationDO entity = new RuleBusinessRelationDO();
|
||||
entity.setParentBusiness(reqVO.getParentBusiness());
|
||||
entity.setChildBusiness(reqVO.getChildBusiness());
|
||||
entity.setSort(reqVO.getSort());
|
||||
relationMapper.insert(entity);
|
||||
} else {
|
||||
existed.setParentBusiness(reqVO.getParentBusiness());
|
||||
existed.setSort(reqVO.getSort());
|
||||
relationMapper.updateById(existed);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void removeRelation(String childBusiness) {
|
||||
RuleBusinessRelationDO existed = relationMapper.selectByChild(childBusiness);
|
||||
if (existed != null) {
|
||||
relationMapper.deleteById(existed.getId());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuleBusinessTreeNodeRespVO> getBusinessTree() {
|
||||
Map<String, RuleBusinessTreeNodeRespVO> nodeMap = new HashMap<>();
|
||||
List<RuleBusinessBindingDO> bindings = bindingMapper.selectAll();
|
||||
for (RuleBusinessBindingDO binding : bindings) {
|
||||
RuleBusinessTreeNodeRespVO node = nodeMap.computeIfAbsent(binding.getBusiness(), key -> new RuleBusinessTreeNodeRespVO());
|
||||
node.setBusiness(binding.getBusiness());
|
||||
RuleChainDO chain = ruleChainMapper.selectById(binding.getRuleChainId());
|
||||
if (chain != null) {
|
||||
node.setChainCode(chain.getCode());
|
||||
node.setChainName(chain.getName());
|
||||
}
|
||||
}
|
||||
List<RuleBusinessRelationDO> relations = relationMapper.selectAll();
|
||||
Set<String> childSet = new HashSet<>();
|
||||
for (RuleBusinessRelationDO relation : relations) {
|
||||
RuleBusinessTreeNodeRespVO parent = nodeMap.computeIfAbsent(relation.getParentBusiness(), key -> {
|
||||
RuleBusinessTreeNodeRespVO vo = new RuleBusinessTreeNodeRespVO();
|
||||
vo.setBusiness(key);
|
||||
return vo;
|
||||
});
|
||||
RuleBusinessTreeNodeRespVO child = nodeMap.computeIfAbsent(relation.getChildBusiness(), key -> {
|
||||
RuleBusinessTreeNodeRespVO vo = new RuleBusinessTreeNodeRespVO();
|
||||
vo.setBusiness(key);
|
||||
return vo;
|
||||
});
|
||||
parent.getChildren().add(child);
|
||||
childSet.add(relation.getChildBusiness());
|
||||
}
|
||||
return nodeMap.values().stream()
|
||||
.filter(node -> !childSet.contains(node.getBusiness()))
|
||||
.collect(Collectors.toList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleBusinessChainViewRespVO previewBusinessChain(String business, String version) {
|
||||
BusinessChainAssembleResultDTO assembled = assembleBusinessChain(business, version);
|
||||
RuleBusinessChainViewRespVO respVO = new RuleBusinessChainViewRespVO();
|
||||
respVO.setBusiness(assembled.getBusiness());
|
||||
respVO.setVersion(assembled.getVersion());
|
||||
respVO.setChainId(assembled.getChainId());
|
||||
respVO.setLiteflowDsl(assembled.getLiteflowDsl());
|
||||
respVO.setStructure(ruleChainConvert.toVo(assembled.getStructure()));
|
||||
return respVO;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BusinessChainAssembleResultDTO assembleBusinessChain(String business, String version) {
|
||||
Deque<String> lineage = new ArrayDeque<>();
|
||||
String current = business;
|
||||
while (StringUtils.hasText(current)) {
|
||||
if (!lineage.add(current)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_RELATION_CYCLE);
|
||||
}
|
||||
RuleBusinessRelationDO relation = relationMapper.selectByChild(current);
|
||||
current = relation != null ? relation.getParentBusiness() : null;
|
||||
}
|
||||
List<String> businesses = new ArrayList<>(lineage);
|
||||
Collections.reverse(businesses);
|
||||
|
||||
RuleChainStructureDTO aggregatedStructure = null;
|
||||
Long lastChainId = null;
|
||||
String chainCode = null;
|
||||
for (String biz : businesses) {
|
||||
RuleBusinessBindingDO binding = bindingMapper.selectByBusiness(biz);
|
||||
if (binding == null) {
|
||||
continue;
|
||||
}
|
||||
RuleChainDO chain = ruleChainMapper.selectById(binding.getRuleChainId());
|
||||
if (chain == null) {
|
||||
continue;
|
||||
}
|
||||
RuleChainStructureDTO structure = readStructure(chain.getStructureJson());
|
||||
aggregatedStructure = mergeStructure(aggregatedStructure, structure, binding.getOverrideStrategy());
|
||||
lastChainId = chain.getId();
|
||||
chainCode = chain.getCode();
|
||||
}
|
||||
if (aggregatedStructure == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_NOT_EXISTS);
|
||||
}
|
||||
BusinessChainAssembleResultDTO result = new BusinessChainAssembleResultDTO();
|
||||
result.setBusiness(business);
|
||||
result.setVersion(version != null ? version : "latest");
|
||||
result.setChainDbId(lastChainId);
|
||||
String finalChainCode = StringUtils.hasText(chainCode) ? chainCode : business;
|
||||
result.setChainCode(finalChainCode);
|
||||
result.setStructure(aggregatedStructure);
|
||||
result.setChainId(finalChainCode + ":" + result.getVersion());
|
||||
result.setLiteflowDsl(ruleChainAssembler.buildLiteflowDsl(aggregatedStructure, result.getChainId()));
|
||||
return result;
|
||||
}
|
||||
|
||||
private RuleChainStructureDTO mergeStructure(RuleChainStructureDTO base,
|
||||
RuleChainStructureDTO addition,
|
||||
Integer strategyCode) {
|
||||
if (base == null) {
|
||||
return cloneStructure(addition);
|
||||
}
|
||||
RuleChainStructureDTO result = cloneStructure(base);
|
||||
OverrideStrategyEnum strategy = resolveStrategy(strategyCode);
|
||||
if (strategy == OverrideStrategyEnum.INHERIT) {
|
||||
return result;
|
||||
}
|
||||
if (strategy == OverrideStrategyEnum.DISABLE) {
|
||||
Set<String> disableCodes = addition.getNodes().stream()
|
||||
.map(RuleChainNodeDTO::getRuleCode)
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.toSet());
|
||||
result.setNodes(result.getNodes().stream()
|
||||
.filter(node -> !disableCodes.contains(node.getRuleCode()))
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
return result;
|
||||
}
|
||||
List<RuleChainNodeDTO> additionNodes = addition.getNodes().stream()
|
||||
.map(this::cloneNode)
|
||||
.collect(Collectors.toList());
|
||||
if (strategy == OverrideStrategyEnum.OVERRIDE) {
|
||||
Set<String> additionCodes = additionNodes.stream()
|
||||
.map(RuleChainNodeDTO::getRuleCode)
|
||||
.filter(StringUtils::hasText)
|
||||
.collect(Collectors.toSet());
|
||||
result.setNodes(result.getNodes().stream()
|
||||
.filter(node -> !additionCodes.contains(node.getRuleCode()))
|
||||
.collect(Collectors.toCollection(ArrayList::new)));
|
||||
}
|
||||
result.getNodes().addAll(additionNodes);
|
||||
if (!CollectionUtils.isEmpty(addition.getLinks())) {
|
||||
if (CollectionUtils.isEmpty(result.getLinks())) {
|
||||
result.setLinks(new ArrayList<>());
|
||||
}
|
||||
result.getLinks().addAll(addition.getLinks());
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
private OverrideStrategyEnum resolveStrategy(Integer code) {
|
||||
for (OverrideStrategyEnum value : OverrideStrategyEnum.values()) {
|
||||
if (Objects.equals(value.getStrategy(), code)) {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
return OverrideStrategyEnum.INHERIT;
|
||||
}
|
||||
|
||||
private RuleChainStructureDTO cloneStructure(RuleChainStructureDTO source) {
|
||||
return objectMapper.convertValue(source, RuleChainStructureDTO.class);
|
||||
}
|
||||
|
||||
private RuleChainNodeDTO cloneNode(RuleChainNodeDTO node) {
|
||||
return objectMapper.convertValue(node, RuleChainNodeDTO.class);
|
||||
}
|
||||
|
||||
private RuleChainStructureDTO readStructure(String json) {
|
||||
try {
|
||||
return objectMapper.readValue(json, RuleChainStructureDTO.class);
|
||||
} catch (Exception ex) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_STRUCTURE_INVALID, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private void validateNoCycle(String parent, String child) {
|
||||
if (Objects.equals(parent, child)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_RELATION_CYCLE);
|
||||
}
|
||||
Set<String> visited = new HashSet<>();
|
||||
Deque<String> stack = new ArrayDeque<>();
|
||||
stack.push(parent);
|
||||
while (!stack.isEmpty()) {
|
||||
String current = stack.pop();
|
||||
if (!visited.add(current)) {
|
||||
continue;
|
||||
}
|
||||
if (Objects.equals(current, child)) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_BUSINESS_RELATION_CYCLE);
|
||||
}
|
||||
relationMapper.selectChildren(current).forEach(rel -> stack.push(rel.getChildBusiness()));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package com.zt.plat.module.rule.service.chain;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainStructureVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainUpdateReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
|
||||
public interface RuleChainService {
|
||||
|
||||
Long createChain(RuleChainCreateReqVO reqVO);
|
||||
|
||||
void updateChain(RuleChainUpdateReqVO reqVO);
|
||||
|
||||
void deleteChain(Long id);
|
||||
|
||||
RuleChainDO getChain(Long id);
|
||||
|
||||
PageResult<RuleChainDO> getChainPage(RuleChainPageReqVO reqVO);
|
||||
|
||||
RuleChainStructureVO getChainStructure(Long id);
|
||||
}
|
||||
@@ -0,0 +1,188 @@
|
||||
package com.zt.plat.module.rule.service.chain;
|
||||
|
||||
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainStructureVO;
|
||||
import com.zt.plat.module.rule.controller.admin.chain.vo.RuleChainUpdateReqVO;
|
||||
import com.zt.plat.module.rule.convert.chain.RuleChainConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.chain.RuleChainDependencyDO;
|
||||
import com.zt.plat.module.rule.dal.mysql.chain.RuleChainDependencyMapper;
|
||||
import com.zt.plat.module.rule.dal.mysql.chain.RuleChainMapper;
|
||||
import com.zt.plat.module.rule.dal.mysql.definition.RuleDefinitionMapper;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.rule.framework.liteflow.RuleChainAssembler;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainNodeDTO;
|
||||
import com.zt.plat.module.rule.service.dto.RuleChainStructureDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import jakarta.validation.ValidationException;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
@Service
|
||||
public class RuleChainServiceImpl implements RuleChainService {
|
||||
|
||||
@Resource
|
||||
private RuleChainMapper ruleChainMapper;
|
||||
@Resource
|
||||
private RuleChainDependencyMapper ruleChainDependencyMapper;
|
||||
@Resource
|
||||
private RuleDefinitionMapper ruleDefinitionMapper;
|
||||
@Resource
|
||||
private RuleChainAssembler ruleChainAssembler;
|
||||
@Resource
|
||||
private RuleChainConvert ruleChainConvert;
|
||||
@Resource
|
||||
private ObjectMapper objectMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createChain(RuleChainCreateReqVO reqVO) {
|
||||
validateChainCodeUnique(null, reqVO.getCode());
|
||||
RuleChainStructureDTO structure = ruleChainConvert.toDto(reqVO.getStructure());
|
||||
validateStructure(structure);
|
||||
|
||||
RuleChainDO chain = ruleChainConvert.convert(reqVO);
|
||||
chain.setStructureJson(writeStructure(reqVO.getStructure()));
|
||||
chain.setLiteflowDsl(ruleChainAssembler.buildLiteflowDsl(structure, reqVO.getCode()));
|
||||
if (!StringUtils.hasText(chain.getVersion())) {
|
||||
chain.setVersion("1.0.0");
|
||||
}
|
||||
ruleChainMapper.insert(chain);
|
||||
|
||||
persistDependencies(chain.getId(), structure);
|
||||
return chain.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateChain(RuleChainUpdateReqVO reqVO) {
|
||||
RuleChainDO existed = validateChainExists(reqVO.getId());
|
||||
validateChainCodeUnique(reqVO.getId(), reqVO.getCode());
|
||||
RuleChainStructureDTO structure = ruleChainConvert.toDto(reqVO.getStructure());
|
||||
validateStructure(structure);
|
||||
|
||||
RuleChainDO updateObj = ruleChainConvert.convert(reqVO);
|
||||
updateObj.setStructureJson(writeStructure(reqVO.getStructure()));
|
||||
updateObj.setLiteflowDsl(ruleChainAssembler.buildLiteflowDsl(structure, reqVO.getCode()));
|
||||
if (!StringUtils.hasText(updateObj.getVersion())) {
|
||||
updateObj.setVersion(existed.getVersion());
|
||||
}
|
||||
ruleChainMapper.updateById(updateObj);
|
||||
|
||||
ruleChainDependencyMapper.deleteByParentChainId(reqVO.getId());
|
||||
persistDependencies(reqVO.getId(), structure);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteChain(Long id) {
|
||||
validateChainExists(id);
|
||||
ruleChainMapper.deleteById(id);
|
||||
ruleChainDependencyMapper.deleteByParentChainId(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleChainDO getChain(Long id) {
|
||||
return ruleChainMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RuleChainDO> getChainPage(RuleChainPageReqVO reqVO) {
|
||||
return ruleChainMapper.selectPage(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleChainStructureVO getChainStructure(Long id) {
|
||||
RuleChainDO chain = validateChainExists(id);
|
||||
try {
|
||||
return objectMapper.readValue(chain.getStructureJson(), RuleChainStructureVO.class);
|
||||
} catch (Exception ex) {
|
||||
throw new ValidationException("链路结构数据异常: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private RuleChainDO validateChainExists(Long id) {
|
||||
RuleChainDO chain = ruleChainMapper.selectById(id);
|
||||
if (chain == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_NOT_EXISTS);
|
||||
}
|
||||
return chain;
|
||||
}
|
||||
|
||||
private void validateChainCodeUnique(Long id, String code) {
|
||||
RuleChainDO existed = ruleChainMapper.selectByCode(code);
|
||||
if (existed != null && (id == null || !Objects.equals(existed.getId(), id))) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_CODE_DUPLICATE);
|
||||
}
|
||||
}
|
||||
|
||||
private void validateStructure(RuleChainStructureDTO structure) {
|
||||
ruleChainAssembler.validate(structure);
|
||||
if (!CollectionUtils.isEmpty(structure.getNodes())) {
|
||||
List<Long> missingRuleIds = structure.getNodes().stream()
|
||||
.map(RuleChainNodeDTO::getRuleId)
|
||||
.filter(Objects::nonNull)
|
||||
.distinct()
|
||||
.filter(ruleId -> ruleDefinitionMapper.selectById(ruleId) == null)
|
||||
.collect(Collectors.toList());
|
||||
if (!missingRuleIds.isEmpty()) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_CHAIN_DEPEND_RULE_MISSING,
|
||||
"缺少规则: " + missingRuleIds);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void persistDependencies(Long chainId, RuleChainStructureDTO structure) {
|
||||
if (CollectionUtils.isEmpty(structure.getNodes())) {
|
||||
return;
|
||||
}
|
||||
List<RuleChainDependencyDO> dependencies = new ArrayList<>();
|
||||
for (RuleChainNodeDTO node : structure.getNodes()) {
|
||||
if (node.getRuleId() == null) {
|
||||
continue;
|
||||
}
|
||||
RuleChainDependencyDO dependency = new RuleChainDependencyDO();
|
||||
dependency.setParentChainId(chainId);
|
||||
dependency.setChildRuleId(node.getRuleId());
|
||||
dependency.setLinkType(node.getType());
|
||||
dependency.setOrderIndex(node.getOrderIndex());
|
||||
dependency.setParallelGroup(node.getParallelGroup());
|
||||
dependency.setConditionExpr(node.getConditionExpr());
|
||||
dependency.setConfigJson(writeConfig(node));
|
||||
dependencies.add(dependency);
|
||||
}
|
||||
if (!dependencies.isEmpty()) {
|
||||
dependencies.forEach(ruleChainDependencyMapper::insert);
|
||||
}
|
||||
}
|
||||
|
||||
private String writeStructure(RuleChainStructureVO structure) {
|
||||
try {
|
||||
return objectMapper.writeValueAsString(structure);
|
||||
} catch (Exception ex) {
|
||||
throw new ValidationException("链路结构序列化失败: " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
private String writeConfig(RuleChainNodeDTO node) {
|
||||
if (node.getConfig() == null) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
return objectMapper.writeValueAsString(node.getConfig());
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package com.zt.plat.module.rule.service.definition;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionUpdateReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.definition.RuleDefinitionDO;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
public interface RuleDefinitionService {
|
||||
|
||||
Long createRule(RuleDefinitionCreateReqVO reqVO);
|
||||
|
||||
void updateRule(RuleDefinitionUpdateReqVO reqVO);
|
||||
|
||||
void deleteRule(Long id);
|
||||
|
||||
RuleDefinitionDO getRule(Long id);
|
||||
|
||||
PageResult<RuleDefinitionDO> getRulePage(RuleDefinitionPageReqVO reqVO);
|
||||
|
||||
List<RuleDefinitionDO> getRules(Collection<Long> ids);
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
package com.zt.plat.module.rule.service.definition;
|
||||
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionPageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.definition.vo.RuleDefinitionUpdateReqVO;
|
||||
import com.zt.plat.module.rule.convert.definition.RuleDefinitionConvert;
|
||||
import com.zt.plat.module.rule.dal.dataobject.definition.RuleDefinitionDO;
|
||||
import com.zt.plat.module.rule.dal.mysql.definition.RuleDefinitionMapper;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
@Service
|
||||
public class RuleDefinitionServiceImpl implements RuleDefinitionService {
|
||||
|
||||
@Resource
|
||||
private RuleDefinitionMapper ruleDefinitionMapper;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public Long createRule(RuleDefinitionCreateReqVO reqVO) {
|
||||
validateRuleCodeUnique(null, reqVO.getCode());
|
||||
RuleDefinitionDO rule = RuleDefinitionConvert.INSTANCE.convert(reqVO);
|
||||
if (!StringUtils.hasText(rule.getVersion())) {
|
||||
rule.setVersion("1.0.0");
|
||||
}
|
||||
ruleDefinitionMapper.insert(rule);
|
||||
return rule.getId();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void updateRule(RuleDefinitionUpdateReqVO reqVO) {
|
||||
RuleDefinitionDO existed = validateRuleExists(reqVO.getId());
|
||||
validateRuleCodeUnique(reqVO.getId(), reqVO.getCode());
|
||||
RuleDefinitionDO updateObj = RuleDefinitionConvert.INSTANCE.convert(reqVO);
|
||||
if (!StringUtils.hasText(updateObj.getVersion())) {
|
||||
updateObj.setVersion(existed.getVersion());
|
||||
}
|
||||
ruleDefinitionMapper.updateById(updateObj);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void deleteRule(Long id) {
|
||||
validateRuleExists(id);
|
||||
ruleDefinitionMapper.deleteById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleDefinitionDO getRule(Long id) {
|
||||
return ruleDefinitionMapper.selectById(id);
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RuleDefinitionDO> getRulePage(RuleDefinitionPageReqVO reqVO) {
|
||||
return ruleDefinitionMapper.selectPage(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<RuleDefinitionDO> getRules(Collection<Long> ids) {
|
||||
return ruleDefinitionMapper.selectListByIds(ids);
|
||||
}
|
||||
|
||||
private RuleDefinitionDO validateRuleExists(Long id) {
|
||||
RuleDefinitionDO rule = ruleDefinitionMapper.selectById(id);
|
||||
if (rule == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_DEFINITION_NOT_EXISTS);
|
||||
}
|
||||
return rule;
|
||||
}
|
||||
|
||||
private void validateRuleCodeUnique(Long id, String code) {
|
||||
RuleDefinitionDO existed = ruleDefinitionMapper.selectByCode(code);
|
||||
if (existed != null && (id == null || !existed.getId().equals(id))) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_DEFINITION_CODE_DUPLICATE);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package com.zt.plat.module.rule.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Aggregation result after applying business inheritance rules.
|
||||
*/
|
||||
@Data
|
||||
public class BusinessChainAssembleResultDTO {
|
||||
|
||||
private String business;
|
||||
|
||||
private String version;
|
||||
|
||||
private String chainId;
|
||||
|
||||
private Long chainDbId;
|
||||
|
||||
private String chainCode;
|
||||
|
||||
private RuleChainStructureDTO structure;
|
||||
|
||||
private String liteflowDsl;
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
package com.zt.plat.module.rule.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
/**
|
||||
* Edge representation connecting nodes on the designer canvas.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainLinkDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String source;
|
||||
|
||||
private String target;
|
||||
|
||||
/**
|
||||
* Optional condition for the edge.
|
||||
*/
|
||||
private String conditionExpr;
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package com.zt.plat.module.rule.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* Node representation used by the rule chain designer.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainNodeDTO {
|
||||
|
||||
private String id;
|
||||
|
||||
private String code;
|
||||
|
||||
private String name;
|
||||
|
||||
/**
|
||||
* Node type referencing {@link com.zt.plat.module.rule.enums.RuleNodeTypeEnum}.
|
||||
*/
|
||||
private Integer type;
|
||||
|
||||
private Long ruleId;
|
||||
|
||||
private String ruleCode;
|
||||
|
||||
private Integer orderIndex;
|
||||
|
||||
private String parallelGroup;
|
||||
|
||||
private String conditionExpr;
|
||||
|
||||
private Boolean disabled;
|
||||
|
||||
private Map<String, Object> config;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package com.zt.plat.module.rule.service.dto;
|
||||
|
||||
import lombok.Data;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Structured representation of a chain composed by nodes and edges.
|
||||
*/
|
||||
@Data
|
||||
public class RuleChainStructureDTO {
|
||||
|
||||
private List<RuleChainNodeDTO> nodes = new ArrayList<>();
|
||||
|
||||
private List<RuleChainLinkDTO> links = new ArrayList<>();
|
||||
|
||||
/**
|
||||
* Custom LiteFlow expression assembled on the client, optional.
|
||||
*/
|
||||
private String entryExpression;
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package com.zt.plat.module.rule.service.publish;
|
||||
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleasePageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseRollbackReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.release.RuleReleaseRecordDO;
|
||||
|
||||
public interface RulePublishService {
|
||||
|
||||
RuleReleaseRecordDO publish(RuleReleaseCreateReqVO reqVO, Long userId, String username);
|
||||
|
||||
void rollback(RuleReleaseRollbackReqVO reqVO, Long userId, String username);
|
||||
|
||||
PageResult<RuleReleaseRecordDO> getReleasePage(RuleReleasePageReqVO reqVO);
|
||||
|
||||
RuleReleaseRecordDO getLatest(String business);
|
||||
}
|
||||
@@ -0,0 +1,141 @@
|
||||
package com.zt.plat.module.rule.service.publish;
|
||||
|
||||
import com.zt.plat.framework.common.exception.util.ServiceExceptionUtil;
|
||||
import com.zt.plat.framework.common.pojo.PageResult;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseCreateReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleasePageReqVO;
|
||||
import com.zt.plat.module.rule.controller.admin.publish.vo.RuleReleaseRollbackReqVO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.business.RuleBusinessBindingDO;
|
||||
import com.zt.plat.module.rule.dal.dataobject.release.RuleReleaseRecordDO;
|
||||
import com.zt.plat.module.rule.dal.mysql.business.RuleBusinessBindingMapper;
|
||||
import com.zt.plat.module.rule.dal.mysql.release.RuleReleaseRecordMapper;
|
||||
import com.zt.plat.module.rule.enums.ErrorCodeConstants;
|
||||
import com.zt.plat.module.rule.enums.RulePublishStatusEnum;
|
||||
import com.zt.plat.module.rule.framework.liteflow.RuleLiteflowManager;
|
||||
import com.zt.plat.module.rule.framework.nacos.RuleNacosPublisher;
|
||||
import com.zt.plat.module.rule.service.business.RuleBusinessService;
|
||||
import com.zt.plat.module.rule.service.dto.BusinessChainAssembleResultDTO;
|
||||
import jakarta.annotation.Resource;
|
||||
import org.springframework.stereotype.Service;
|
||||
import org.springframework.transaction.annotation.Transactional;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import java.time.LocalDateTime;
|
||||
|
||||
@Service
|
||||
public class RulePublishServiceImpl implements RulePublishService {
|
||||
|
||||
@Resource
|
||||
private RuleBusinessService ruleBusinessService;
|
||||
@Resource
|
||||
private RuleReleaseRecordMapper ruleReleaseRecordMapper;
|
||||
@Resource
|
||||
private RuleBusinessBindingMapper ruleBusinessBindingMapper;
|
||||
@Resource
|
||||
private RuleNacosPublisher ruleNacosPublisher;
|
||||
@Resource
|
||||
private RuleLiteflowManager ruleLiteflowManager;
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public RuleReleaseRecordDO publish(RuleReleaseCreateReqVO reqVO, Long userId, String username) {
|
||||
String business = reqVO.getBusiness();
|
||||
String targetVersion = StringUtils.hasText(reqVO.getVersion()) ? reqVO.getVersion() : nextVersion(business);
|
||||
BusinessChainAssembleResultDTO assembleResult = ruleBusinessService.assembleBusinessChain(business, targetVersion);
|
||||
assembleResult.setVersion(targetVersion);
|
||||
assembleResult.setChainId(assembleResult.getChainCode() + ":" + targetVersion);
|
||||
|
||||
RuleReleaseRecordDO record = buildReleaseRecord(assembleResult, RulePublishStatusEnum.PENDING, userId, username);
|
||||
if (Boolean.TRUE.equals(reqVO.getDryRun())) {
|
||||
return record;
|
||||
}
|
||||
|
||||
try {
|
||||
ruleNacosPublisher.publish(business, targetVersion, assembleResult.getLiteflowDsl());
|
||||
ruleLiteflowManager.registerOrUpdate(assembleResult.getChainId(), assembleResult.getLiteflowDsl());
|
||||
|
||||
record.setStatus(RulePublishStatusEnum.SUCCESS.getStatus());
|
||||
record.setReleaseTime(LocalDateTime.now());
|
||||
ruleReleaseRecordMapper.insert(record);
|
||||
|
||||
RuleBusinessBindingDO binding = ruleBusinessBindingMapper.selectByBusiness(business);
|
||||
if (binding != null) {
|
||||
binding.setEffectiveVersion(targetVersion);
|
||||
ruleBusinessBindingMapper.updateById(binding);
|
||||
}
|
||||
return record;
|
||||
} catch (Exception ex) {
|
||||
record.setStatus(RulePublishStatusEnum.FAILED.getStatus());
|
||||
record.setRemark(ex.getMessage());
|
||||
ruleReleaseRecordMapper.insert(record);
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_PUBLISH_PUSH_FAILED, ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@Transactional(rollbackFor = Exception.class)
|
||||
public void rollback(RuleReleaseRollbackReqVO reqVO, Long userId, String username) {
|
||||
RuleReleaseRecordDO existed = ruleReleaseRecordMapper.selectByBusinessAndVersion(reqVO.getBusiness(), reqVO.getVersion());
|
||||
if (existed == null) {
|
||||
throw ServiceExceptionUtil.exception(ErrorCodeConstants.RULE_RELEASE_NOT_EXISTS);
|
||||
}
|
||||
BusinessChainAssembleResultDTO assembleResult = ruleBusinessService.assembleBusinessChain(reqVO.getBusiness(), reqVO.getVersion());
|
||||
assembleResult.setChainId(assembleResult.getChainCode() + ":" + assembleResult.getVersion());
|
||||
|
||||
ruleNacosPublisher.publish(reqVO.getBusiness(), reqVO.getVersion(), assembleResult.getLiteflowDsl());
|
||||
ruleLiteflowManager.registerOrUpdate(assembleResult.getChainId(), assembleResult.getLiteflowDsl());
|
||||
|
||||
RuleReleaseRecordDO record = buildReleaseRecord(assembleResult, RulePublishStatusEnum.ROLLBACK, userId, username);
|
||||
record.setReleaseTime(LocalDateTime.now());
|
||||
ruleReleaseRecordMapper.insert(record);
|
||||
|
||||
RuleBusinessBindingDO binding = ruleBusinessBindingMapper.selectByBusiness(reqVO.getBusiness());
|
||||
if (binding != null) {
|
||||
binding.setEffectiveVersion(reqVO.getVersion());
|
||||
ruleBusinessBindingMapper.updateById(binding);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public PageResult<RuleReleaseRecordDO> getReleasePage(RuleReleasePageReqVO reqVO) {
|
||||
return ruleReleaseRecordMapper.selectPage(reqVO);
|
||||
}
|
||||
|
||||
@Override
|
||||
public RuleReleaseRecordDO getLatest(String business) {
|
||||
return ruleReleaseRecordMapper.selectLatest(business);
|
||||
}
|
||||
|
||||
private String nextVersion(String business) {
|
||||
RuleReleaseRecordDO latest = ruleReleaseRecordMapper.selectLatest(business);
|
||||
if (latest == null) {
|
||||
return "v1";
|
||||
}
|
||||
String version = latest.getVersion();
|
||||
if (!StringUtils.hasText(version)) {
|
||||
return "v1";
|
||||
}
|
||||
try {
|
||||
String numeric = version.startsWith("v") ? version.substring(1) : version;
|
||||
int num = Integer.parseInt(numeric);
|
||||
return "v" + (num + 1);
|
||||
} catch (NumberFormatException ex) {
|
||||
return version + "_next";
|
||||
}
|
||||
}
|
||||
|
||||
private RuleReleaseRecordDO buildReleaseRecord(BusinessChainAssembleResultDTO assembleResult,
|
||||
RulePublishStatusEnum statusEnum,
|
||||
Long userId,
|
||||
String username) {
|
||||
RuleReleaseRecordDO record = new RuleReleaseRecordDO();
|
||||
record.setBusiness(assembleResult.getBusiness());
|
||||
record.setChainId(assembleResult.getChainId());
|
||||
record.setChainCode(assembleResult.getChainCode());
|
||||
record.setVersion(assembleResult.getVersion());
|
||||
record.setStatus(statusEnum.getStatus());
|
||||
record.setReleaseUserId(userId);
|
||||
record.setReleaseUserName(username);
|
||||
return record;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user