From 39f96be111b1a1824bafae74161a9bd6747011a5 Mon Sep 17 00:00:00 2001 From: icanci Date: Sun, 20 Nov 2022 14:02:48 +0800 Subject: [PATCH 1/2] =?UTF-8?q?=E7=AD=96=E7=95=A5=E6=B5=8B=E8=AF=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../biz/service/impl/StrategyServiceImpl.java | 33 ++++++++++--------- .../sdk/actuator/RuleEngineResponse.java | 15 ++++++++- .../rec/engine/sdk/rule/EngineExecutor.java | 2 +- 3 files changed, 32 insertions(+), 18 deletions(-) diff --git a/rec-admin/rec-admin-biz/src/main/java/cn/icanci/rec/admin/biz/service/impl/StrategyServiceImpl.java b/rec-admin/rec-admin-biz/src/main/java/cn/icanci/rec/admin/biz/service/impl/StrategyServiceImpl.java index 5c9a52f..f9f3fea 100644 --- a/rec-admin/rec-admin-biz/src/main/java/cn/icanci/rec/admin/biz/service/impl/StrategyServiceImpl.java +++ b/rec-admin/rec-admin-biz/src/main/java/cn/icanci/rec/admin/biz/service/impl/StrategyServiceImpl.java @@ -1,21 +1,5 @@ package cn.icanci.rec.admin.biz.service.impl; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.stream.Collectors; - -import javax.annotation.Resource; -import javax.script.CompiledScript; - -import org.apache.commons.collections4.CollectionUtils; -import org.apache.commons.lang3.StringUtils; -import org.springframework.stereotype.Service; - -import com.google.common.collect.Lists; -import com.google.common.collect.Maps; -import com.google.common.collect.Sets; - import cn.icanci.rec.admin.biz.event.log.LogEvent; import cn.icanci.rec.admin.biz.mapper.config.StrategyMapper; import cn.icanci.rec.admin.biz.mapper.config.StrategyVoDtoMapper; @@ -40,6 +24,22 @@ import cn.icanci.rec.engine.sdk.rule.repository.DomainSceneKey; import cn.icanci.rec.engine.sdk.rule.repository.EngineRepositoryHolder; import cn.icanci.rec.spi.event.EventDispatcher; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import javax.annotation.Resource; +import javax.script.CompiledScript; + +import org.apache.commons.collections4.CollectionUtils; +import org.apache.commons.lang3.StringUtils; +import org.springframework.stereotype.Service; + +import com.google.common.collect.Lists; +import com.google.common.collect.Maps; +import com.google.common.collect.Sets; + /** * @author icanci * @since 1.0 Created in 2022/11/12 10:38 @@ -139,6 +139,7 @@ public class StrategyServiceImpl implements StrategyService { // 9.构建执行返回结果 result.setSuccess(execute.isSuccess()); result.setRetValue(execute.getResult()); + result.setExecutorParam(FastJsonUtils.toJSONString(execute.getBindings())); result.setExceptionMessage(execute.isSuccess() ? StringUtils.EMPTY : execute.getErrorMessage()); } catch (Throwable e) { result.setSuccess(false); diff --git a/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/actuator/RuleEngineResponse.java b/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/actuator/RuleEngineResponse.java index f60790a..cabe009 100644 --- a/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/actuator/RuleEngineResponse.java +++ b/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/actuator/RuleEngineResponse.java @@ -2,6 +2,8 @@ package cn.icanci.rec.engine.sdk.actuator; import java.io.Serializable; +import javax.script.Bindings; + /** * 规则执行器返回结果 * @@ -16,6 +18,8 @@ public class RuleEngineResponse implements Serializable { private String errorMessage; /** 执行结果 */ private Object result; + /** 执行请求参数 */ + private Bindings bindings; public static RuleEngineResponse fail(String errorMessage) { RuleEngineResponse response = new RuleEngineResponse(); @@ -24,10 +28,11 @@ public class RuleEngineResponse implements Serializable { return response; } - public static RuleEngineResponse success(Object result) { + public static RuleEngineResponse success(Object result, Bindings bindings) { RuleEngineResponse response = new RuleEngineResponse(); response.setSuccess(true); response.setResult(result); + response.setBindings(bindings); return response; } @@ -54,4 +59,12 @@ public class RuleEngineResponse implements Serializable { public void setResult(Object result) { this.result = result; } + + public Bindings getBindings() { + return bindings; + } + + public void setBindings(Bindings bindings) { + this.bindings = bindings; + } } diff --git a/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/rule/EngineExecutor.java b/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/rule/EngineExecutor.java index d07cc42..042234d 100644 --- a/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/rule/EngineExecutor.java +++ b/rec-engine/rec-engine-sdk/src/main/java/cn/icanci/rec/engine/sdk/rule/EngineExecutor.java @@ -90,7 +90,7 @@ public final class EngineExecutor { // no op } // 5.返回执行结果 - return RuleEngineResponse.success(executorResult); + return RuleEngineResponse.success(executorResult, bindings); } catch (Throwable e) { return RuleEngineResponse.fail(e.getMessage()); } -- Gitee From 66c8e0b76fe2fa2df5ada4eb68783f0b29c9432b Mon Sep 17 00:00:00 2001 From: icanci Date: Sun, 20 Nov 2022 15:25:13 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E7=AD=96=E7=95=A5=E5=8A=9F=E8=83=BD?= =?UTF-8?q?=E8=87=AA=E6=B5=8B?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 3 +- .../main/resources/vueboot/src/api/common.js | 10 + .../src/main/resources/vueboot/src/main.js | 12 + .../ruleConfig/components/ruleTreeNode.vue | 2 +- .../views/ruleConfig/dialog/strategyForm.vue | 207 ++++++++++++------ .../vueboot/src/views/ruleConfig/strategy.vue | 8 +- 6 files changed, 178 insertions(+), 64 deletions(-) create mode 100644 rec-admin/rec-admin-views/src/main/resources/vueboot/src/api/common.js diff --git a/README.md b/README.md index f4dc968..4c86a1d 100644 --- a/README.md +++ b/README.md @@ -268,4 +268,5 @@ REC(Rule Engine Component)规则引擎组件:提供统一的规则处理 - mvn clean deploy - mvn versions:set -DnewVersion=0.0.0.2-SNAPSHOT - mvn versions:revert -- mvn versions:commit \ No newline at end of file +- mvn versions:commit +- mongodb数据库导出:mongodump -d rec -o /Users/icanci/Desktop \ No newline at end of file diff --git a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/api/common.js b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/api/common.js new file mode 100644 index 0000000..5007d2e --- /dev/null +++ b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/api/common.js @@ -0,0 +1,10 @@ +export function joiner(arr, join) { + let res = "" + if (!res && !join) { + return res; + } + for (let i = 0; i < arr.length; i++) { + res = res + arr[i] + join; + } + return res.substr(0, res.length - join.length) +} diff --git a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/main.js b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/main.js index bb4d330..5348ae4 100644 --- a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/main.js +++ b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/main.js @@ -25,6 +25,18 @@ Vue.prototype.recDateFormat = function (date) { return moment(date).format('YYYY-MM-DD HH:mm:ss'); } +if (!String.prototype.format) { + String.prototype.format = function () { + var args = arguments; + return this.replace(/{(\d+)}/g, function (match, number) { + return typeof args[number] != 'undefined' + ? args[number] + : match + ; + }); + }; +} + new Vue({ el: '#app', router, diff --git a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/components/ruleTreeNode.vue b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/components/ruleTreeNode.vue index 75941f6..05d9c6a 100644 --- a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/components/ruleTreeNode.vue +++ b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/components/ruleTreeNode.vue @@ -318,7 +318,7 @@ - + @@ -46,6 +48,9 @@ + + + @@ -103,7 +108,7 @@ 规则模式切换自动清除中断相关配置数据 (如果此项禁用则需要选择场景) - + @@ -143,6 +148,7 @@ import { import {remoteValidateSceneCode, remoteValidateStrategyName, saveStrategy, strategyDebug} from "../../../api/strategyApi"; import ruleTreeList from "../components/ruleTreeList"; import {dataSourceDebugForUuid} from "../../../api/dataSourceApi"; +import {joiner} from "../../../api/common"; export default { name: "strategyForm", @@ -281,7 +287,14 @@ export default { vm.ruleTypeOptions = await loadRuleTypeSelector(); vm.ruleModeOptions = await loadRuleModeSelector(); if (data) { - vm.saveData = vm.$cloneObj(data) + let saveData = vm.$cloneObj(data); + vm.preReload(saveData); + vm.saveData = saveData + if (data.domainCode) { + vm.dataSourceOptions = await loadDataSourceSelector(data.domainCode); + vm.sceneOptions = await loadDomainSceneSelector(data.domainCode); + await vm.loadSelectors(data.domainCode); + } } vm.dialogVisible = true @@ -290,14 +303,90 @@ export default { vm.$refs.ruleTreeList.load({data: vm.saveData, selectors: vm.selectors}); }) }, + preReload(saveData) { + let conditions = saveData.ruleListInfo.conditions; + for (let i = 0; i < conditions.length; i++) { + let group = conditions[i].group; + for (let j = 0; j < group.length; j++) { + if (group[j].operator === 'INCLUDED') { + group[j].rightValue = group[j].rightValue.split("::") + } + } + } + }, + async domainChange(domain) { + let vm = this + + vm.$nextTick(() => { + if (vm.saveData.sceneCode !== '') { + vm.$refs.ruleTreeList.toDisabled = false + } + }) + + vm.dataSourceOptions = await loadDataSourceSelector(domain); + vm.sceneOptions = await loadDomainSceneSelector(domain); + + vm.saveData.sceneCode = '' + vm.saveData.dataSourceUuid = '' + + let conditions = vm.saveData.ruleListInfo.conditions; + let deleteConditionLength = conditions.length - 1; + for (let i = 0; i < deleteConditionLength; i++) { + conditions.splice(0, 1) + } + // 此时只会剩下一组 + let group = conditions[0].group; + let deleteGroupLength = group.length - 1; + for (let i = 0; i < deleteGroupLength; i++) { + group.splice(0, 1) + } + // 值复原 + group[0].name = '' + group[0].leftValue = '' + group[0].operator = '' + group[0].rightValue = '' + group[0].interrupt = '' + group[0].resultType = '' + group[0].returnVal = '' + group[0].children = [] + + await vm.loadSelectors(domain); + }, + async loadSelectors(domain) { + let vm = this + // selectors + vm.selectors.leftOptions = await loadBaseDataSelector(domain) + vm.selectors.interruptOptions = await loadInterruptSelector() + vm.selectors.resultTypeOptions = await loadResultTypeSelector() + vm.selectors.metadataOptions = await loadDomainMetadataSelector(domain) + }, + sceneChange(value) { + this.$refs.ruleTreeList.toDisabled = false + }, save() { let vm = this this.$refs['ruleForm'].validate(async (valid) => { if (valid) { - await vm.doSave(this.saveData) + if (!vm.ruleValidator()) { + return; + } + await vm.doSave(vm.preSave()) } }) }, + preSave() { + let saveData = this.$cloneObj(this.saveData); + let conditions = saveData.ruleListInfo.conditions; + for (let i = 0; i < conditions.length; i++) { + let group = conditions[i].group; + for (let j = 0; j < group.length; j++) { + if (group[j].rightValue instanceof Array) { + group[j].rightValue = joiner(group[j].rightValue, "::") + } + } + } + return saveData; + }, async doSave(saveData) { let vm = this let ret = await saveStrategy(saveData); @@ -394,70 +483,66 @@ export default { } }, async debug() { - let ret = await strategyDebug(this.saveData, this.ruleDebugParam); + // 数据验证 + let vm = this + if (!vm.ruleValidator()) { + return; + } + let ret = await strategyDebug(vm.preSave(), vm.ruleDebugParam); if (ret.ok) { - this.ruleDebugResult = ret.data.result - this.testPass = this.ruleDebugResult.success + vm.ruleDebugResult = ret.data.result + vm.testPass = vm.ruleDebugResult.success } else { - this.$message({type: 'error', message: '测试失败:' + ret.message}); + vm.$message({type: 'error', message: '测试失败:' + ret.message}); } - } - }, - watch: { - 'saveData.domainCode': { - async handler(newVal, oldVal) { - let vm = this - if (newVal) { - console.log(vm.saveData) - - if (vm.saveData.sceneCode !== '') { - vm.$refs.ruleTreeList.toDisabled = false + }, + ruleValidator() { + let vm = this + let format = '规则簇第{0}组,第{1}条规则的[{2}]不能为空' + let ruleListInfo = vm.saveData.ruleListInfo; + let conditions = ruleListInfo.conditions; + for (let i = 0; i < conditions.length; i++) { + let group = conditions[i].group; + for (let j = 0; j < group.length; j++) { + if (group[j].name.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "名字")}); + return false; } - - vm.dataSourceOptions = await loadDataSourceSelector(newVal); - vm.sceneOptions = await loadDomainSceneSelector(newVal); - vm.saveData.sceneCode = '' - vm.saveData.dataSourceUuid = '' - - let conditions = vm.saveData.ruleListInfo.conditions; - let deleteConditionLength = conditions.length - 1; - for (let i = 0; i < deleteConditionLength; i++) { - conditions.splice(0, 1) + if (group[j].leftValue.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "左值")}); + return false; } - // 此时只会剩下一组 - let group = conditions[0].group; - let deleteGroupLength = group.length - 1; - for (let i = 0; i < deleteGroupLength; i++) { - group.splice(0, 1) + if (group[j].operator.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "操作符")}); + return false; + } + if (group[j].rightValue instanceof String && group[j].rightValue.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "右值")}); + return false; + } + if (group[j].rightValue instanceof Array && group[j].rightValue.length === 0) { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "右值")}); + return false; + } + if (vm.saveData.ruleMode === 'COMPLEX') { + if (group[j].interrupt.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "是否中断")}); + return false; + } + if (group[j].resultType.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "中断返回类型")}); + return false; + } + if (group[j].returnVal.trim() === '') { + vm.$message({type: 'error', message: format.format(i + 1, j + 1, "中断返回值")}); + return false; + } } - // 值复原 - group[0].name = '' - group[0].leftValue = '' - group[0].operator = '' - group[0].rightValue = '' - group[0].interrupt = '' - group[0].resultType = '' - group[0].returnVal = '' - group[0].children = [] - - // selectors - vm.selectors.leftOptions = await loadBaseDataSelector(newVal) - vm.selectors.interruptOptions = await loadInterruptSelector() - vm.selectors.resultTypeOptions = await loadResultTypeSelector() - vm.selectors.metadataOptions = await loadDomainMetadataSelector(newVal) - } - }, - immediate: true - }, - 'saveData.sceneCode': { - async handler(newVal, oldVal) { - let vm = this - if (newVal) { - vm.$refs.ruleTreeList.toDisabled = false } - }, - immediate: true - }, - } + } + return true; + } + }, + watch: {} } diff --git a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/strategy.vue b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/strategy.vue index 8a2e6e7..00aa9f2 100644 --- a/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/strategy.vue +++ b/rec-admin/rec-admin-views/src/main/resources/vueboot/src/views/ruleConfig/strategy.vue @@ -75,6 +75,11 @@ prop="sceneCode" label="场景Code"> + + { - this.$refs.domainForm.doSave(clone); + this.$refs.strategyForm.doSave(clone); }).catch(() => { this.$message({ type: 'info', -- Gitee