From 7ca1eef232edf7534c6f8665d936b6b21caf6e4d Mon Sep 17 00:00:00 2001 From: AprilWind <2100166581@qq.com> Date: Fri, 21 Jun 2024 14:46:51 +0800 Subject: [PATCH] =?UTF-8?q?add=20=E6=96=B0=E5=A2=9E=E8=A7=84=E5=88=99?= =?UTF-8?q?=E5=BC=95=E6=93=8E?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- pom.xml | 84 ++++++++ ruoyi-admin/pom.xml | 6 + .../src/main/resources/application.yml | 53 +++++ ruoyi-common/pom.xml | 1 + ruoyi-common/ruoyi-common-bom/pom.xml | 7 + ruoyi-common/ruoyi-common-liteflow/pom.xml | 91 ++++++++ .../liteflow/config/LiteFlowConfig.java | 25 +++ .../liteflow/constant/LiteFlowConstants.java | 20 ++ .../liteflow/entity/LiteflowFlowBus.java | 35 ++++ .../common/liteflow/enums/LiteflowType.java | 36 ++++ .../handler/LiteFlowExceptionHandler.java | 30 +++ ...ot.autoconfigure.AutoConfiguration.imports | 1 + ruoyi-modules/pom.xml | 1 + ruoyi-modules/ruoyi-liteflow/pom.xml | 69 ++++++ .../controller/LiteflowChainController.java | 109 ++++++++++ .../controller/LiteflowScriptController.java | 109 ++++++++++ .../liteflow/domain/LiteflowChain.java | 74 +++++++ .../liteflow/domain/LiteflowScript.java | 79 +++++++ .../liteflow/domain/bo/LiteflowChainBo.java | 69 ++++++ .../liteflow/domain/bo/LiteflowScriptBo.java | 77 +++++++ .../liteflow/domain/vo/LiteflowChainVo.java | 78 +++++++ .../liteflow/domain/vo/LiteflowScriptVo.java | 83 ++++++++ .../liteflow/listener/LiteflowListener.java | 79 +++++++ .../liteflow/mapper/LiteflowChainMapper.java | 15 ++ .../liteflow/mapper/LiteflowScriptMapper.java | 15 ++ .../service/ILiteflowChainService.java | 76 +++++++ .../service/ILiteflowScriptService.java | 76 +++++++ .../impl/LiteflowChainServiceImpl.java | 191 +++++++++++++++++ .../impl/LiteflowScriptServiceImpl.java | 198 ++++++++++++++++++ .../mapper/liteflow/LiteflowChainMapper.xml | 6 + .../mapper/liteflow/LiteflowScriptMapper.xml | 6 + script/sql/liteflow.sql | 38 ++++ 32 files changed, 1837 insertions(+) create mode 100644 ruoyi-common/ruoyi-common-liteflow/pom.xml create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java create mode 100644 ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports create mode 100644 ruoyi-modules/ruoyi-liteflow/pom.xml create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml create mode 100644 ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml create mode 100644 script/sql/liteflow.sql diff --git a/pom.xml b/pom.xml index 900b61b53..2a218f6f6 100644 --- a/pom.xml +++ b/pom.xml @@ -59,6 +59,9 @@ 3.11.0 3.1.2 1.3.0 + + + 2.12.1 @@ -339,6 +342,80 @@ ${fastjson.version} + + com.yomahub + liteflow-spring-boot-starter + ${liteflow.version} + + + + com.yomahub + liteflow-core + ${liteflow.version} + + + + com.yomahub + liteflow-rule-sql + ${liteflow.version} + + + + + com.yomahub + liteflow-script-groovy + ${liteflow.version} + + + + + com.yomahub + liteflow-script-graaljs + ${liteflow.version} + + + + + com.yomahub + liteflow-script-java + ${liteflow.version} + + + + + com.yomahub + liteflow-script-qlexpress + ${liteflow.version} + + + + + com.yomahub + liteflow-script-python + ${liteflow.version} + + + + + com.yomahub + liteflow-script-lua + ${liteflow.version} + + + + + com.yomahub + liteflow-script-aviator + ${liteflow.version} + + + + + com.yomahub + liteflow-script-kotlin + ${liteflow.version} + + org.dromara ruoyi-system @@ -370,6 +447,13 @@ ${revision} + + + org.dromara + ruoyi-liteflow + ${revision} + + diff --git a/ruoyi-admin/pom.xml b/ruoyi-admin/pom.xml index 610e9d706..0edfff176 100644 --- a/ruoyi-admin/pom.xml +++ b/ruoyi-admin/pom.xml @@ -86,6 +86,12 @@ ruoyi-workflow + + + org.dromara + ruoyi-liteflow + + de.codecentric spring-boot-admin-starter-client diff --git a/ruoyi-admin/src/main/resources/application.yml b/ruoyi-admin/src/main/resources/application.yml index 27de286f0..6b7a6518d 100644 --- a/ruoyi-admin/src/main/resources/application.yml +++ b/ruoyi-admin/src/main/resources/application.yml @@ -285,3 +285,56 @@ flowable: enabled: false app: enabled: false + +--- # 规则引擎 +liteflow: + # 组件降级 + fallback-cmp-enable: true + # 执行过程中的日志 + print-execution-log: true + # 5000条规则以上的时候,开启可将加载性能能提高4倍 + fast-load: false + # 默认线程池的worker数目 + parallel-max-workers: 16 + # 默认线程池的队列长度 + parallel-queue-limit: 512 + # 指定自定义的线程池全类名的方式指定异步循环线程池 + # parallel-loop-executor-class: + # 启动时不解析规则,但是第一次执行相关规则时,只解析对应的规则 + parse-mode: PARSE_ONE_ON_FIRST_EXEC + rule-source-ext-data-map: + applicationName: @profiles.active@ + # 编排规则表 + chainTableName: liteflow_chain + # 应用名称存储字段名 + chainApplicationNameField: application_name + # 规则名称存储的字段名 + chainNameField: chain_name + # EL表达式的字段(只存EL) + elDataField: el_str + # 决策路由EL字段 + routeField: route + # namespace字段 + namespaceField: name_space + # 是否生效 1为生效,0为不生效 + chainEnableField: chain_status + # 脚本存储表的表名 + scriptTableName: liteflow_script + # 应用名称存储字段名 + scriptApplicationNameField: application_name + # 脚本组件的Id的字段名 + scriptIdField: script_id + # 脚本组件名称的字段名 + scriptNameField: script_name + # 脚本数据的字段名 + scriptDataField: script_data + # 脚本类型的字段名 + scriptTypeField: script_type + # 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin) + scriptLanguageField: script_language + # 是否生效 1为生效,0为不生效 + scriptEnableField: script_status + #以下是轮询机制的配置 + pollingEnabled: true + pollingStartSeconds: 600 + pollingIntervalSeconds: 600 diff --git a/ruoyi-common/pom.xml b/ruoyi-common/pom.xml index 45493d3e9..b243e2e1e 100644 --- a/ruoyi-common/pom.xml +++ b/ruoyi-common/pom.xml @@ -20,6 +20,7 @@ ruoyi-common-log ruoyi-common-mail ruoyi-common-mybatis + ruoyi-common-liteflow ruoyi-common-oss ruoyi-common-ratelimiter ruoyi-common-redis diff --git a/ruoyi-common/ruoyi-common-bom/pom.xml b/ruoyi-common/ruoyi-common-bom/pom.xml index d546275c9..052b9ee27 100644 --- a/ruoyi-common/ruoyi-common-bom/pom.xml +++ b/ruoyi-common/ruoyi-common-bom/pom.xml @@ -47,6 +47,13 @@ ${revision} + + + org.dromara + ruoyi-common-liteflow + ${revision} + + org.dromara diff --git a/ruoyi-common/ruoyi-common-liteflow/pom.xml b/ruoyi-common/ruoyi-common-liteflow/pom.xml new file mode 100644 index 000000000..be04c605a --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/pom.xml @@ -0,0 +1,91 @@ + + + + org.dromara + ruoyi-common + ${revision} + + 4.0.0 + + ruoyi-common-liteflow + + + ruoyi-common-liteflow 规则引擎 + + + + + + + org.dromara + ruoyi-common-core + + + + com.yomahub + liteflow-spring-boot-starter + + + + com.yomahub + liteflow-core + + + + com.yomahub + liteflow-rule-sql + + + + + com.yomahub + liteflow-script-lua + + + + + com.yomahub + liteflow-script-java + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java new file mode 100644 index 000000000..30950c711 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/config/LiteFlowConfig.java @@ -0,0 +1,25 @@ +package org.dromara.common.liteflow.config; + +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.liteflow.handler.LiteFlowExceptionHandler; +import org.springframework.boot.autoconfigure.AutoConfiguration; +import org.springframework.context.annotation.Bean; + +/** + * LiteFlow 配置 + * + * @author AprilWind + */ +@Slf4j +@AutoConfiguration +public class LiteFlowConfig { + + /** + * 异常处理器 + */ + @Bean + public LiteFlowExceptionHandler liteFlowExceptionHandler() { + return new LiteFlowExceptionHandler(); + } + +} diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java new file mode 100644 index 000000000..f53fc0622 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/constant/LiteFlowConstants.java @@ -0,0 +1,20 @@ +package org.dromara.common.liteflow.constant; + +/** + * Liteflow 常量 + * + * @author AprilWind + */ +public interface LiteFlowConstants { + + /** + * 激活 + */ + Integer LITEFLOW_NORMAL = 1; + + /** + * 未激活 + */ + Integer LITEFLOW_DISABLE = 0; + +} diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java new file mode 100644 index 000000000..0521f4a36 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/entity/LiteflowFlowBus.java @@ -0,0 +1,35 @@ +package org.dromara.common.liteflow.entity; + +import lombok.Data; +import org.dromara.common.liteflow.enums.LiteflowType; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 规则引擎事件 + * + * @author AprilWind + */ +@Data +public class LiteflowFlowBus implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * 规则引擎事件类型 + */ + private LiteflowType liteflowType; + + /** + * 事件关联的ID + */ + private String id; + + /** + * 事件的内容 + */ + private String content; + +} diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java new file mode 100644 index 000000000..e807ffc93 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/enums/LiteflowType.java @@ -0,0 +1,36 @@ +package org.dromara.common.liteflow.enums; + +import lombok.AllArgsConstructor; +import lombok.Getter; + +/** + * 规则引擎事件枚举 + * + * @author AprilWind + */ +@Getter +@AllArgsConstructor +public enum LiteflowType { + + /** + * 重新加载规则 + */ + RELOAD_CHAIN("reload_chain"), + + /** + * 移除规则 + */ + REMOVE_CHAIN("remove_chain"), + + /** + * 重新加载脚本 + */ + RELOAD_SCRIPT("reload_script"), + + /** + * 卸载脚本节点 + */ + UNLOAD_SCRIPT("unload_script"); + + private final String flowBus; +} diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java new file mode 100644 index 000000000..ac1121497 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/java/org/dromara/common/liteflow/handler/LiteFlowExceptionHandler.java @@ -0,0 +1,30 @@ +package org.dromara.common.liteflow.handler; + +import cn.hutool.http.HttpStatus; +import com.yomahub.liteflow.exception.LiteFlowException; +import jakarta.servlet.http.HttpServletRequest; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.core.domain.R; +import org.springframework.web.bind.annotation.ExceptionHandler; +import org.springframework.web.bind.annotation.RestControllerAdvice; + +/** + * LiteFlow 异常处理器 + * + * @author AprilWind + */ +@Slf4j +@RestControllerAdvice +public class LiteFlowExceptionHandler { + + /** + * 规则引擎内部逻辑发生错误抛出的异常 + */ + @ExceptionHandler(LiteFlowException.class) + public R handleLockFailureException(LiteFlowException e, HttpServletRequest request) { + String requestURI = request.getRequestURI(); + log.error("处理请求'{}'时发生LiteFlow异常: ", requestURI, e); + return R.fail(HttpStatus.HTTP_INTERNAL_ERROR, "系统内部错误,请稍后再试..."); + } + +} diff --git a/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports new file mode 100644 index 000000000..f02911399 --- /dev/null +++ b/ruoyi-common/ruoyi-common-liteflow/src/main/resources/META-INF/spring/org.springframework.boot.autoconfigure.AutoConfiguration.imports @@ -0,0 +1 @@ +org.dromara.common.liteflow.config.LiteFlowConfig diff --git a/ruoyi-modules/pom.xml b/ruoyi-modules/pom.xml index daff497a0..5df7b602e 100644 --- a/ruoyi-modules/pom.xml +++ b/ruoyi-modules/pom.xml @@ -15,6 +15,7 @@ ruoyi-job ruoyi-system ruoyi-workflow + ruoyi-liteflow ruoyi-modules diff --git a/ruoyi-modules/ruoyi-liteflow/pom.xml b/ruoyi-modules/ruoyi-liteflow/pom.xml new file mode 100644 index 000000000..d4d911899 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/pom.xml @@ -0,0 +1,69 @@ + + + + org.dromara + ruoyi-modules + ${revision} + + 4.0.0 + + ruoyi-liteflow + + + liteflow 规则引擎 + + + + + + org.dromara + ruoyi-common-doc + + + + org.dromara + ruoyi-common-mybatis + + + + org.dromara + ruoyi-common-translation + + + + org.dromara + ruoyi-common-log + + + + + org.dromara + ruoyi-common-excel + + + + org.dromara + ruoyi-common-tenant + + + + org.dromara + ruoyi-common-web + + + + org.dromara + ruoyi-common-idempotent + + + + + org.dromara + ruoyi-common-liteflow + + + + + diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java new file mode 100644 index 000000000..025191cd3 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowChainController.java @@ -0,0 +1,109 @@ +package org.dromara.liteflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.liteflow.domain.bo.LiteflowChainBo; +import org.dromara.liteflow.domain.vo.LiteflowChainVo; +import org.dromara.liteflow.service.ILiteflowChainService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 编排规则 + * + * @author AprilWind + * @date 2024-06-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/liteflow/chain") +public class LiteflowChainController extends BaseController { + + private final ILiteflowChainService liteflowChainService; + + /** + * 查询编排规则列表 + */ + @SaCheckPermission("liteflow:chain:list") + @GetMapping("/list") + public TableDataInfo list(LiteflowChainBo bo, PageQuery pageQuery) { + return liteflowChainService.queryPageList(bo, pageQuery); + } + + /** + * 导出编排规则列表 + */ + @SaCheckPermission("liteflow:chain:export") + @Log(title = "编排规则", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(LiteflowChainBo bo, HttpServletResponse response) { + List list = liteflowChainService.queryList(bo); + ExcelUtil.exportExcel(list, "编排规则", LiteflowChainVo.class, response); + } + + /** + * 获取编排规则详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("liteflow:chain:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(liteflowChainService.queryById(id)); + } + + /** + * 新增编排规则 + */ + @SaCheckPermission("liteflow:chain:add") + @Log(title = "编排规则", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody LiteflowChainBo bo) { + if (!liteflowChainService.checkChainNameUnique(bo)) { + return R.fail("新增编排规则'" + bo.getChainName() + "'失败,规则名称已存在"); + } + return toAjax(liteflowChainService.insertByBo(bo)); + } + + /** + * 修改编排规则 + */ + @SaCheckPermission("liteflow:chain:edit") + @Log(title = "编排规则", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody LiteflowChainBo bo) { + return toAjax(liteflowChainService.updateByBo(bo)); + } + + /** + * 删除编排规则 + * + * @param ids 主键串 + */ + @SaCheckPermission("liteflow:chain:remove") + @Log(title = "编排规则", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(liteflowChainService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java new file mode 100644 index 000000000..f6349fb62 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/controller/LiteflowScriptController.java @@ -0,0 +1,109 @@ +package org.dromara.liteflow.controller; + +import cn.dev33.satoken.annotation.SaCheckPermission; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.validation.constraints.NotEmpty; +import jakarta.validation.constraints.NotNull; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.domain.R; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.excel.utils.ExcelUtil; +import org.dromara.common.idempotent.annotation.RepeatSubmit; +import org.dromara.common.log.annotation.Log; +import org.dromara.common.log.enums.BusinessType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.common.web.core.BaseController; +import org.dromara.liteflow.domain.bo.LiteflowScriptBo; +import org.dromara.liteflow.domain.vo.LiteflowScriptVo; +import org.dromara.liteflow.service.ILiteflowScriptService; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.*; + +import java.util.List; + +/** + * 脚本 + * + * @author AprilWind + * @date 2024-06-21 + */ +@Validated +@RequiredArgsConstructor +@RestController +@RequestMapping("/liteflow/script") +public class LiteflowScriptController extends BaseController { + + private final ILiteflowScriptService liteflowScriptService; + + /** + * 查询脚本列表 + */ + @SaCheckPermission("liteflow:script:list") + @GetMapping("/list") + public TableDataInfo list(LiteflowScriptBo bo, PageQuery pageQuery) { + return liteflowScriptService.queryPageList(bo, pageQuery); + } + + /** + * 导出脚本列表 + */ + @SaCheckPermission("liteflow:script:export") + @Log(title = "脚本", businessType = BusinessType.EXPORT) + @PostMapping("/export") + public void export(LiteflowScriptBo bo, HttpServletResponse response) { + List list = liteflowScriptService.queryList(bo); + ExcelUtil.exportExcel(list, "脚本", LiteflowScriptVo.class, response); + } + + /** + * 获取脚本详细信息 + * + * @param id 主键 + */ + @SaCheckPermission("liteflow:script:query") + @GetMapping("/{id}") + public R getInfo(@NotNull(message = "主键不能为空") + @PathVariable Long id) { + return R.ok(liteflowScriptService.queryById(id)); + } + + /** + * 新增脚本 + */ + @SaCheckPermission("liteflow:script:add") + @Log(title = "脚本", businessType = BusinessType.INSERT) + @RepeatSubmit() + @PostMapping() + public R add(@Validated(AddGroup.class) @RequestBody LiteflowScriptBo bo) { + if (!liteflowScriptService.checkScriptIdUnique(bo)) { + return R.fail("新增脚本'" + bo.getScriptId() + "'失败,脚本ID已存在"); + } + return toAjax(liteflowScriptService.insertByBo(bo)); + } + + /** + * 修改脚本 + */ + @SaCheckPermission("liteflow:script:edit") + @Log(title = "脚本", businessType = BusinessType.UPDATE) + @RepeatSubmit() + @PutMapping() + public R edit(@Validated(EditGroup.class) @RequestBody LiteflowScriptBo bo) { + return toAjax(liteflowScriptService.updateByBo(bo)); + } + + /** + * 删除脚本 + * + * @param ids 主键串 + */ + @SaCheckPermission("liteflow:script:remove") + @Log(title = "脚本", businessType = BusinessType.DELETE) + @DeleteMapping("/{ids}") + public R remove(@NotEmpty(message = "主键不能为空") + @PathVariable Long[] ids) { + return toAjax(liteflowScriptService.deleteWithValidByIds(List.of(ids), true)); + } +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java new file mode 100644 index 000000000..e5e985908 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowChain.java @@ -0,0 +1,74 @@ +package org.dromara.liteflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 编排规则对象 liteflow_chain + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("liteflow_chain") +public class LiteflowChain extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 配置环境 + */ + private String applicationName; + + /** + * 编排规则ID + */ + private String chainName; + + /** + * 状态(0未激活 1激活) + */ + private Integer chainStatus; + + /** + * EL表达式 + */ + private String elStr; + + /** + * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数) + */ + private String nameSpace; + + /** + * 决策路由EL + */ + private String route; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java new file mode 100644 index 000000000..3c93f5cb4 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/LiteflowScript.java @@ -0,0 +1,79 @@ +package org.dromara.liteflow.domain; + +import com.baomidou.mybatisplus.annotation.TableId; +import com.baomidou.mybatisplus.annotation.TableLogic; +import com.baomidou.mybatisplus.annotation.TableName; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.mybatis.core.domain.BaseEntity; + +import java.io.Serial; + +/** + * 脚本对象 liteflow_script + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@TableName("liteflow_script") +public class LiteflowScript extends BaseEntity { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @TableId(value = "id") + private Long id; + + /** + * 配置环境 + */ + private String applicationName; + + /** + * 脚本ID + */ + private String scriptId; + + /** + * 脚本名称 + */ + private String scriptName; + + /** + * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin) + */ + private String scriptLanguage; + + /** + * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数) + */ + private String scriptType; + + /** + * 状态(0未激活 1激活) + */ + private Integer scriptStatus; + + /** + * 脚本内容 + */ + private String scriptData; + + /** + * 删除标志(0代表存在 2代表删除) + */ + @TableLogic + private String delFlag; + + /** + * 备注 + */ + private String remark; + + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java new file mode 100644 index 000000000..5a052771b --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowChainBo.java @@ -0,0 +1,69 @@ +package org.dromara.liteflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.liteflow.domain.LiteflowChain; + +/** + * 编排规则业务对象 liteflow_chain + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = LiteflowChain.class, reverseConvertGenerate = false) +public class LiteflowChainBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 配置环境 + */ + @NotBlank(message = "配置环境不能为空", groups = {AddGroup.class}) + private String applicationName; + + /** + * 编排规则ID + */ + @NotBlank(message = "编排规则ID不能为空", groups = {AddGroup.class}) + private String chainName; + + /** + * 状态(0未激活 1激活) + */ + private Integer chainStatus; + + /** + * EL表达式 + */ + @NotBlank(message = "EL表达式不能为空", groups = {AddGroup.class, EditGroup.class}) + private String elStr; + + /** + * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数) + */ + private String nameSpace; + + /** + * 决策路由EL + */ + private String route; + + /** + * 备注 + */ + @NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class}) + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java new file mode 100644 index 000000000..fe576f8d0 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/bo/LiteflowScriptBo.java @@ -0,0 +1,77 @@ +package org.dromara.liteflow.domain.bo; + +import io.github.linpeilie.annotations.AutoMapper; +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.NotNull; +import lombok.Data; +import lombok.EqualsAndHashCode; +import org.dromara.common.core.validate.AddGroup; +import org.dromara.common.core.validate.EditGroup; +import org.dromara.common.mybatis.core.domain.BaseEntity; +import org.dromara.liteflow.domain.LiteflowScript; + +/** + * 脚本业务对象 liteflow_script + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@EqualsAndHashCode(callSuper = true) +@AutoMapper(target = LiteflowScript.class, reverseConvertGenerate = false) +public class LiteflowScriptBo extends BaseEntity { + + /** + * id + */ + @NotNull(message = "id不能为空", groups = {EditGroup.class}) + private Long id; + + /** + * 配置环境 + */ + @NotBlank(message = "配置环境不能为空", groups = {AddGroup.class}) + private String applicationName; + + /** + * 脚本ID + */ + @NotBlank(message = "脚本ID不能为空", groups = {AddGroup.class}) + private String scriptId; + + /** + * 脚本名称 + */ + @NotBlank(message = "脚本名称不能为空", groups = {AddGroup.class}) + private String scriptName; + + /** + * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin) + */ + @NotBlank(message = "脚本语言类型不能为空", groups = {AddGroup.class}) + private String scriptLanguage; + + /** + * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数) + */ + @NotBlank(message = "脚本类型不能为空", groups = {AddGroup.class}) + private String scriptType; + + /** + * 状态(0未激活 1激活) + */ + private Integer scriptStatus; + + /** + * 脚本内容 + */ + @NotBlank(message = "脚本内容不能为空", groups = {AddGroup.class, EditGroup.class}) + private String scriptData; + + /** + * 备注 + */ + @NotBlank(message = "备注不能为空", groups = {AddGroup.class, EditGroup.class}) + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java new file mode 100644 index 000000000..1de01ca5e --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowChainVo.java @@ -0,0 +1,78 @@ +package org.dromara.liteflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.liteflow.domain.LiteflowChain; + +import java.io.Serial; +import java.io.Serializable; + + +/** + * 编排规则视图对象 liteflow_chain + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = LiteflowChain.class) +public class LiteflowChainVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 配置环境 + */ + @ExcelProperty(value = "配置环境") + private String applicationName; + + /** + * 编排规则ID + */ + @ExcelProperty(value = "编排规则ID") + private String chainName; + + /** + * 状态(0未激活 1激活) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未激活,1=激活") + private Integer chainStatus; + + /** + * EL表达式 + */ + @ExcelProperty(value = "EL表达式") + private String elStr; + + /** + * namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数) + */ + @ExcelProperty(value = "namespace", converter = ExcelDictConvert.class) + private String nameSpace; + + /** + * 决策路由EL + */ + @ExcelProperty(value = "决策路由EL") + private String route; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java new file mode 100644 index 000000000..97cf41254 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/domain/vo/LiteflowScriptVo.java @@ -0,0 +1,83 @@ +package org.dromara.liteflow.domain.vo; + +import com.alibaba.excel.annotation.ExcelIgnoreUnannotated; +import com.alibaba.excel.annotation.ExcelProperty; +import io.github.linpeilie.annotations.AutoMapper; +import lombok.Data; +import org.dromara.common.excel.annotation.ExcelDictFormat; +import org.dromara.common.excel.convert.ExcelDictConvert; +import org.dromara.liteflow.domain.LiteflowScript; + +import java.io.Serial; +import java.io.Serializable; + +/** + * 脚本视图对象 liteflow_script + * + * @author AprilWind + * @date 2024-06-21 + */ +@Data +@ExcelIgnoreUnannotated +@AutoMapper(target = LiteflowScript.class) +public class LiteflowScriptVo implements Serializable { + + @Serial + private static final long serialVersionUID = 1L; + + /** + * id + */ + @ExcelProperty(value = "id") + private Long id; + + /** + * 配置环境 + */ + @ExcelProperty(value = "配置环境") + private String applicationName; + + /** + * 脚本ID + */ + @ExcelProperty(value = "脚本ID") + private String scriptId; + + /** + * 脚本名称 + */ + @ExcelProperty(value = "脚本名称") + private String scriptName; + + /** + * 脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin) + */ + @ExcelProperty(value = "脚本语言类型", converter = ExcelDictConvert.class) + private String scriptLanguage; + + /** + * 脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数) + */ + @ExcelProperty(value = "脚本类型") + private String scriptType; + + /** + * 状态(0未激活 1激活) + */ + @ExcelProperty(value = "状态", converter = ExcelDictConvert.class) + @ExcelDictFormat(readConverterExp = "0=未激活,1=激活") + private Integer scriptStatus; + + /** + * 脚本内容 + */ + @ExcelProperty(value = "脚本内容") + private String scriptData; + + /** + * 备注 + */ + @ExcelProperty(value = "备注") + private String remark; + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java new file mode 100644 index 000000000..df67c6706 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/listener/LiteflowListener.java @@ -0,0 +1,79 @@ +package org.dromara.liteflow.listener; + +import com.yomahub.liteflow.flow.FlowBus; +import lombok.RequiredArgsConstructor; +import lombok.extern.slf4j.Slf4j; +import org.dromara.common.liteflow.entity.LiteflowFlowBus; +import org.dromara.common.liteflow.enums.LiteflowType; +import org.springframework.context.event.EventListener; +import org.springframework.scheduling.annotation.Async; +import org.springframework.stereotype.Component; + +import java.util.List; + +/** + * 规则引擎 侦听器 + * + * @author AprilWind + * @date 2024-06-21 + */ +@RequiredArgsConstructor +@Component +@Slf4j +public class LiteflowListener { + + /** + * 处理规则引擎事件 + * + * @param liteflowFlowBus 包含规则引擎事件信息的对象 + */ + @Async + @EventListener + public void handleLiteflowEvent(LiteflowFlowBus liteflowFlowBus) { + // 获取事件的类型 + LiteflowType flowBusType = liteflowFlowBus.getLiteflowType(); + // 获取事件关联的ID + String id = liteflowFlowBus.getId(); + // 获取事件的内容 + String content = liteflowFlowBus.getContent(); + + // 根据事件类型执行相应的操作 + switch (flowBusType) { + case RELOAD_CHAIN: + // 重新加载链式规则 + FlowBus.reloadChain(id, content); + log.info("重新加载链式规则:{}", id); + break; + case REMOVE_CHAIN: + // 移除链式规则 + FlowBus.removeChain(id); + log.info("移除链式规则:{}", id); + break; + case RELOAD_SCRIPT: + // 重新加载脚本 + FlowBus.reloadScript(id, content); + log.info("重新加载脚本:{}", id); + break; + case UNLOAD_SCRIPT: + // 卸载脚本节点 + FlowBus.unloadScriptNode(id); + log.info("卸载脚本节点:{}", id); + break; + default: + log.error("未知的LiteflowType: {}", flowBusType); + } + } + + /** + * 异步处理规则引擎事件列表 + * 注意:虽然方法标记了 @Async 注解,但内部的方法调用不会异步执行,需要手动使用 TaskExecutor 实现异步 + * + * @param liteflowFlowBus 包含规则引擎事件信息的对象列表 + */ + @Async + @EventListener + public void handleLiteflowEvent(List liteflowFlowBus) { + liteflowFlowBus.forEach(this::handleLiteflowEvent); + } + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java new file mode 100644 index 000000000..59c8583e0 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowChainMapper.java @@ -0,0 +1,15 @@ +package org.dromara.liteflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.liteflow.domain.LiteflowChain; +import org.dromara.liteflow.domain.vo.LiteflowChainVo; + +/** + * 编排规则Mapper接口 + * + * @author AprilWind + * @date 2024-06-21 + */ +public interface LiteflowChainMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java new file mode 100644 index 000000000..a4323f277 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/mapper/LiteflowScriptMapper.java @@ -0,0 +1,15 @@ +package org.dromara.liteflow.mapper; + +import org.dromara.common.mybatis.core.mapper.BaseMapperPlus; +import org.dromara.liteflow.domain.LiteflowScript; +import org.dromara.liteflow.domain.vo.LiteflowScriptVo; + +/** + * 脚本Mapper接口 + * + * @author AprilWind + * @date 2024-06-21 + */ +public interface LiteflowScriptMapper extends BaseMapperPlus { + +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java new file mode 100644 index 000000000..d78ead4ec --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowChainService.java @@ -0,0 +1,76 @@ +package org.dromara.liteflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.liteflow.domain.bo.LiteflowChainBo; +import org.dromara.liteflow.domain.vo.LiteflowChainVo; + +import java.util.Collection; +import java.util.List; + +/** + * 编排规则Service接口 + * + * @author AprilWind + * @date 2024-06-21 + */ +public interface ILiteflowChainService { + + /** + * 查询编排规则 + * + * @param id 主键 + * @return 编排规则 + */ + LiteflowChainVo queryById(Long id); + + /** + * 分页查询编排规则列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 编排规则分页列表 + */ + TableDataInfo queryPageList(LiteflowChainBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的编排规则列表 + * + * @param bo 查询条件 + * @return 编排规则列表 + */ + List queryList(LiteflowChainBo bo); + + /** + * 校验编排规则ID是否唯一 + * + * @param chain 规则信息 + * @return 结果,true表示唯一,false表示不唯一 + */ + boolean checkChainNameUnique(LiteflowChainBo chain); + + /** + * 新增编排规则 + * + * @param bo 编排规则 + * @return 是否新增成功 + */ + Boolean insertByBo(LiteflowChainBo bo); + + /** + * 修改编排规则 + * + * @param bo 编排规则 + * @return 是否修改成功 + */ + Boolean updateByBo(LiteflowChainBo bo); + + /** + * 校验并批量删除编排规则信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java new file mode 100644 index 000000000..6fe4b434e --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/ILiteflowScriptService.java @@ -0,0 +1,76 @@ +package org.dromara.liteflow.service; + +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.liteflow.domain.bo.LiteflowScriptBo; +import org.dromara.liteflow.domain.vo.LiteflowScriptVo; + +import java.util.Collection; +import java.util.List; + +/** + * 脚本Service接口 + * + * @author AprilWind + * @date 2024-06-21 + */ +public interface ILiteflowScriptService { + + /** + * 查询脚本 + * + * @param id 主键 + * @return 脚本 + */ + LiteflowScriptVo queryById(Long id); + + /** + * 分页查询脚本列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 脚本分页列表 + */ + TableDataInfo queryPageList(LiteflowScriptBo bo, PageQuery pageQuery); + + /** + * 查询符合条件的脚本列表 + * + * @param bo 查询条件 + * @return 脚本列表 + */ + List queryList(LiteflowScriptBo bo); + + /** + * 校验脚本ID是否唯一 + * + * @param script 脚本信息 + * @return 结果,true表示唯一,false表示不唯一 + */ + boolean checkScriptIdUnique(LiteflowScriptBo script); + + /** + * 新增脚本 + * + * @param bo 脚本 + * @return 是否新增成功 + */ + Boolean insertByBo(LiteflowScriptBo bo); + + /** + * 修改脚本 + * + * @param bo 脚本 + * @return 是否修改成功 + */ + Boolean updateByBo(LiteflowScriptBo bo); + + /** + * 校验并批量删除脚本信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + Boolean deleteWithValidByIds(Collection ids, Boolean isValid); +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java new file mode 100644 index 000000000..54c6cecb3 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowChainServiceImpl.java @@ -0,0 +1,191 @@ +package org.dromara.liteflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yomahub.liteflow.builder.el.LiteFlowChainELBuilder; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.liteflow.entity.LiteflowFlowBus; +import org.dromara.common.liteflow.enums.LiteflowType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.liteflow.domain.LiteflowChain; +import org.dromara.liteflow.domain.bo.LiteflowChainBo; +import org.dromara.liteflow.domain.vo.LiteflowChainVo; +import org.dromara.liteflow.mapper.LiteflowChainMapper; +import org.dromara.liteflow.service.ILiteflowChainService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_DISABLE; +import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_NORMAL; + +/** + * 编排规则Service业务层处理 + * + * @author AprilWind + * @date 2024-06-21 + */ +@RequiredArgsConstructor +@Service +public class LiteflowChainServiceImpl implements ILiteflowChainService { + + private final LiteflowChainMapper baseMapper; + + /** + * 查询编排规则 + * + * @param id 主键 + * @return 编排规则 + */ + @Override + public LiteflowChainVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询编排规则列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 编排规则分页列表 + */ + @Override + public TableDataInfo queryPageList(LiteflowChainBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的编排规则列表 + * + * @param bo 查询条件 + * @return 编排规则列表 + */ + @Override + public List queryList(LiteflowChainBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(LiteflowChainBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getApplicationName()), LiteflowChain::getApplicationName, bo.getApplicationName()); + lqw.eq(StringUtils.isNotBlank(bo.getChainName()), LiteflowChain::getChainName, bo.getChainName()); + lqw.eq(bo.getChainStatus() != null, LiteflowChain::getChainStatus, bo.getChainStatus()); + lqw.eq(StringUtils.isNotBlank(bo.getNameSpace()), LiteflowChain::getNameSpace, bo.getNameSpace()); + lqw.like(StringUtils.isNotBlank(bo.getRemark()), LiteflowChain::getRemark, bo.getRemark()); + return lqw; + } + + /** + * 校验编排规则ID是否唯一 + * + * @param chain 规则信息 + * @return 结果,true表示唯一,false表示不唯一 + */ + @Override + public boolean checkChainNameUnique(LiteflowChainBo chain) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(LiteflowChain::getApplicationName, chain.getApplicationName()) + .eq(LiteflowChain::getChainName, chain.getChainName()) + .ne(ObjectUtil.isNotNull(chain.getId()), LiteflowChain::getId, chain.getId())); + return !exist; + } + + /** + * 新增编排规则 + * + * @param bo 编排规则 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(LiteflowChainBo bo) { + LiteflowChain add = MapstructUtils.convert(bo, LiteflowChain.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改编排规则 + * + * @param bo 编排规则 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(LiteflowChainBo bo) { + LiteflowChain update = MapstructUtils.convert(bo, LiteflowChain.class); + validEntityBeforeSave(update); + LiteflowChainVo vo = baseMapper.selectVoById(bo.getId()); + if (LITEFLOW_NORMAL.equals(vo.getChainStatus())) { + LiteflowFlowBus bus = new LiteflowFlowBus(); + bus.setId(vo.getChainName()); + if (LITEFLOW_DISABLE.equals(update.getChainStatus())) { + bus.setLiteflowType(LiteflowType.REMOVE_CHAIN); + } else { + bus.setLiteflowType(LiteflowType.RELOAD_CHAIN); + bus.setContent(update.getElStr()); + } + SpringUtils.context().publishEvent(bus); + } + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(LiteflowChain entity) { + // 校验EL表达式 + if (!LiteFlowChainELBuilder.validate(entity.getElStr())) { + throw new ServiceException("EL表达式校验失败!"); + } + // 如果路由不为空,校验路由 + if (StringUtils.isNotBlank(entity.getRoute()) && !LiteFlowChainELBuilder.validate(entity.getRoute())) { + throw new ServiceException("决策路由EL校验失败!"); + } + } + + /** + * 校验并批量删除编排规则信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + List liteflowChainVos = baseMapper.selectVoList( + new LambdaQueryWrapper().in(LiteflowChain::getId, ids)); + if (isValid) { + if (CollUtil.isEmpty(liteflowChainVos)) { + return true; + } + } + List liteflowFlowBus = liteflowChainVos.stream() + .map(x -> { + LiteflowFlowBus flowBus = new LiteflowFlowBus(); + flowBus.setLiteflowType(LiteflowType.REMOVE_CHAIN); + flowBus.setId(x.getChainName()); + return flowBus; + }).collect(Collectors.toList()); + // 发布规则引擎事件 + SpringUtils.context().publishEvent(liteflowFlowBus); + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java new file mode 100644 index 000000000..ba6e113f6 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/java/org/dromara/liteflow/service/impl/LiteflowScriptServiceImpl.java @@ -0,0 +1,198 @@ +package org.dromara.liteflow.service.impl; + +import cn.hutool.core.collection.CollUtil; +import cn.hutool.core.util.ObjectUtil; +import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper; +import com.baomidou.mybatisplus.core.toolkit.Wrappers; +import com.baomidou.mybatisplus.extension.plugins.pagination.Page; +import com.yomahub.liteflow.enums.ScriptTypeEnum; +import com.yomahub.liteflow.script.validator.ScriptValidator; +import lombok.RequiredArgsConstructor; +import org.dromara.common.core.exception.ServiceException; +import org.dromara.common.core.utils.MapstructUtils; +import org.dromara.common.core.utils.SpringUtils; +import org.dromara.common.core.utils.StringUtils; +import org.dromara.common.liteflow.entity.LiteflowFlowBus; +import org.dromara.common.liteflow.enums.LiteflowType; +import org.dromara.common.mybatis.core.page.PageQuery; +import org.dromara.common.mybatis.core.page.TableDataInfo; +import org.dromara.liteflow.domain.LiteflowScript; +import org.dromara.liteflow.domain.bo.LiteflowScriptBo; +import org.dromara.liteflow.domain.vo.LiteflowScriptVo; +import org.dromara.liteflow.mapper.LiteflowScriptMapper; +import org.dromara.liteflow.service.ILiteflowScriptService; +import org.springframework.stereotype.Service; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_DISABLE; +import static org.dromara.common.liteflow.constant.LiteFlowConstants.LITEFLOW_NORMAL; + +/** + * 脚本Service业务层处理 + * + * @author AprilWind + * @date 2024-06-21 + */ +@RequiredArgsConstructor +@Service +public class LiteflowScriptServiceImpl implements ILiteflowScriptService { + + private final LiteflowScriptMapper baseMapper; + + /** + * 查询脚本 + * + * @param id 主键 + * @return 脚本 + */ + @Override + public LiteflowScriptVo queryById(Long id) { + return baseMapper.selectVoById(id); + } + + /** + * 分页查询脚本列表 + * + * @param bo 查询条件 + * @param pageQuery 分页参数 + * @return 脚本分页列表 + */ + @Override + public TableDataInfo queryPageList(LiteflowScriptBo bo, PageQuery pageQuery) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + Page result = baseMapper.selectVoPage(pageQuery.build(), lqw); + return TableDataInfo.build(result); + } + + /** + * 查询符合条件的脚本列表 + * + * @param bo 查询条件 + * @return 脚本列表 + */ + @Override + public List queryList(LiteflowScriptBo bo) { + LambdaQueryWrapper lqw = buildQueryWrapper(bo); + return baseMapper.selectVoList(lqw); + } + + private LambdaQueryWrapper buildQueryWrapper(LiteflowScriptBo bo) { + Map params = bo.getParams(); + LambdaQueryWrapper lqw = Wrappers.lambdaQuery(); + lqw.eq(StringUtils.isNotBlank(bo.getApplicationName()), LiteflowScript::getApplicationName, bo.getApplicationName()); + lqw.eq(StringUtils.isNotBlank(bo.getScriptId()), LiteflowScript::getScriptId, bo.getScriptId()); + lqw.eq(StringUtils.isNotBlank(bo.getScriptName()), LiteflowScript::getScriptName, bo.getScriptName()); + lqw.eq(StringUtils.isNotBlank(bo.getScriptLanguage()), LiteflowScript::getScriptLanguage, bo.getScriptLanguage()); + lqw.eq(StringUtils.isNotBlank(bo.getScriptType()), LiteflowScript::getScriptType, bo.getScriptType()); + lqw.eq(bo.getScriptStatus() != null, LiteflowScript::getScriptStatus, bo.getScriptStatus()); + lqw.like(StringUtils.isNotBlank(bo.getRemark()), LiteflowScript::getRemark, bo.getRemark()); + return lqw; + } + + /** + * 校验脚本ID是否唯一 + * + * @param script 脚本信息 + * @return 结果,true表示唯一,false表示不唯一 + */ + @Override + public boolean checkScriptIdUnique(LiteflowScriptBo script) { + boolean exist = baseMapper.exists(new LambdaQueryWrapper() + .eq(LiteflowScript::getApplicationName, script.getApplicationName()) + .eq(LiteflowScript::getScriptId, script.getScriptId()) + .ne(ObjectUtil.isNotNull(script.getId()), LiteflowScript::getId, script.getId())); + return !exist; + } + + /** + * 新增脚本 + * + * @param bo 脚本 + * @return 是否新增成功 + */ + @Override + public Boolean insertByBo(LiteflowScriptBo bo) { + LiteflowScript add = MapstructUtils.convert(bo, LiteflowScript.class); + validEntityBeforeSave(add); + boolean flag = baseMapper.insert(add) > 0; + if (flag) { + bo.setId(add.getId()); + } + return flag; + } + + /** + * 修改脚本 + * + * @param bo 脚本 + * @return 是否修改成功 + */ + @Override + public Boolean updateByBo(LiteflowScriptBo bo) { + LiteflowScript update = MapstructUtils.convert(bo, LiteflowScript.class); + validEntityBeforeSave(update); + LiteflowScriptVo vo = baseMapper.selectVoById(update.getId()); + + if (LITEFLOW_NORMAL.equals(vo.getScriptStatus())) { + LiteflowFlowBus bus = new LiteflowFlowBus(); + bus.setId(vo.getScriptId()); + if (LITEFLOW_DISABLE.equals(update.getScriptStatus())) { + bus.setLiteflowType(LiteflowType.UNLOAD_SCRIPT); + } else { + bus.setLiteflowType(LiteflowType.RELOAD_SCRIPT); + bus.setContent(update.getScriptData()); + } + SpringUtils.context().publishEvent(bus); + } + return baseMapper.updateById(update) > 0; + } + + /** + * 保存前的数据校验 + */ + private void validEntityBeforeSave(LiteflowScript entity) { + // 检查脚本语言是否合法 + if (!ScriptTypeEnum.checkScriptType(entity.getScriptLanguage())) { + throw new ServiceException("脚本语言不合法!"); + } + + ScriptTypeEnum enumByDisplayName = ScriptTypeEnum.getEnumByDisplayName(entity.getScriptLanguage()); + // 验证脚本数据是否符合规范 + if (!ScriptValidator.validate(entity.getScriptData(), enumByDisplayName)) { + // 具体错误请查看日志,暂不支持返回错误详细异常信息 + throw new ServiceException("脚本内容不规范!"); + } + } + + /** + * 校验并批量删除脚本信息 + * + * @param ids 待删除的主键集合 + * @param isValid 是否进行有效性校验 + * @return 是否删除成功 + */ + @Override + public Boolean deleteWithValidByIds(Collection ids, Boolean isValid) { + List liteflowScriptVos = baseMapper.selectVoList( + new LambdaQueryWrapper().in(LiteflowScript::getId, ids)); + if (isValid) { + if (CollUtil.isEmpty(liteflowScriptVos)) { + return true; + } + } + List liteflowFlowBus = liteflowScriptVos.stream() + .map(x -> { + LiteflowFlowBus flowBus = new LiteflowFlowBus(); + flowBus.setLiteflowType(LiteflowType.UNLOAD_SCRIPT); + flowBus.setId(x.getScriptId()); + return flowBus; + }).collect(Collectors.toList()); + // 发布规则引擎事件 + SpringUtils.context().publishEvent(liteflowFlowBus); + return baseMapper.deleteByIds(ids) > 0; + } +} diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml new file mode 100644 index 000000000..f1fb6e316 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowChainMapper.xml @@ -0,0 +1,6 @@ + + + + diff --git a/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml new file mode 100644 index 000000000..181918848 --- /dev/null +++ b/ruoyi-modules/ruoyi-liteflow/src/main/resources/mapper/liteflow/LiteflowScriptMapper.xml @@ -0,0 +1,6 @@ + + + + diff --git a/script/sql/liteflow.sql b/script/sql/liteflow.sql new file mode 100644 index 000000000..b1a3d6cd9 --- /dev/null +++ b/script/sql/liteflow.sql @@ -0,0 +1,38 @@ +CREATE TABLE liteflow_chain +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `application_name` varchar(32) NOT NULL COMMENT '配置环境', + `chain_name` varchar(32) NOT NULL COMMENT '编排规则ID', + `chain_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(0未激活 1激活)', + `el_str` text NOT NULL COMMENT 'EL表达式', + `name_space` varchar(32) DEFAULT NULL COMMENT 'namespace(决策路由很多,想要判断某一组决策路由时在chain层面加入namespace参数)', + `route` text COMMENT '决策路由EL', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) +) engine = innodb comment = '编排规则表'; + +CREATE TABLE liteflow_script +( + `id` bigint(20) NOT NULL AUTO_INCREMENT COMMENT 'id', + `application_name` varchar(32) NOT NULL COMMENT '配置环境', + `script_id` varchar(32) NOT NULL COMMENT '脚本ID', + `script_name` varchar(64) NOT NULL COMMENT '脚本名称', + `script_language` varchar(32) NOT NULL COMMENT '脚本语言类型(groovy | qlexpress | js | python | lua | aviator | java | kotlin)', + `script_type` varchar(16) NOT NULL COMMENT '脚本类型(script普通脚本节点,脚本里无需返回 switch_script选择脚本节点,脚本里需要返回选择的节点Id boolean_script条件脚本节点,脚本里需要返回true/false for_script数量循环节点,脚本里需要返回数值类型,表示循环次数)', + `script_status` tinyint(1) NOT NULL DEFAULT '0' COMMENT '状态(0未激活 1激活)', + `script_data` text NOT NULL COMMENT '脚本内容', + `del_flag` char(1) DEFAULT '0' COMMENT '删除标志(0代表存在 2代表删除)', + `create_dept` bigint(20) DEFAULT NULL COMMENT '创建部门', + `create_by` bigint(20) DEFAULT NULL COMMENT '创建者', + `create_time` datetime DEFAULT NULL COMMENT '创建时间', + `update_by` bigint(20) DEFAULT NULL COMMENT '更新者', + `update_time` datetime DEFAULT NULL COMMENT '更新时间', + `remark` varchar(500) DEFAULT NULL COMMENT '备注', + PRIMARY KEY (`id`) +) engine = innodb comment = '脚本表';