评估配置功能
评估计算功能
基础功能:
- 实现自定义表单展示,包含项目的展示和得分规则计算
- 实现所有项目结果的评估结果组合计算和展示
数据库定义
实现原理
类似问卷调查配置表单,数据库有一个脚本保存匹配规则,类似 itemValue.include('option1633763947226'),每一项项目的得分是通过规则引擎匹配规则脚本, 匹配成功则返回该得分,计算评估结果也是和项目选项同一个原理
核心代码
规则引擎
@Slf4j public class RuleEngineManager { private scriptEngine engine; private Bindings bindings = new SimpleBindings(); private String extendscript = ""; private String rulescript; public static RuleEngineManager instance() { RuleEngineManager instance = new RuleEngineManager(); scriptEngineManager manager = new scriptEngineManager(); instance.engine = manager.getEngineByName("Javascript"); instance.extendscript(); return instance; } public RuleEngineManager addParam(String key, Object value) { bindings.put(key, value); return this; } public RuleEngineManager addParam(Mapmap) { bindings.putAll(map); return this; } public RuleEngineManager setRulescript(String rulescript) { this.rulescript = rulescript; return this; } @SuppressWarnings("unchecked") public T eval() { try { String evalscript = extendscript + ";" + rulescript; log.debug("RuleEngineManager eval script={}, bindings={}", rulescript, JsonUtil.objectToString(bindings)); return (T) engine.eval(evalscript, bindings); } catch (scriptException e) { log.error("", e); return null; } } public BigDecimal eval2() { return new BigDecimal(eval().toString()); } public boolean match() { try { String evalscript = extendscript + ";" + rulescript; log.debug("RuleEngineManager eval script={}, bindings={}", rulescript, JsonUtil.objectToString(bindings)); return (Boolean) engine.eval(evalscript, bindings); } catch (scriptException e) { log.error("", e); return false; } } private RuleEngineManager extendscript() { this.extendscript = scriptConstant.INCLUDE + ";" + scriptConstant.EXCLUDE; log.debug("RuleEngineManager extend script = {}", this.extendscript); return this; } public static void main(String[] args) throws scriptException { String s = "0.0391*a+0.7917*b+1.3388*c "; Object result1 = RuleEngineManager.instance() .addParam("a", new BigDecimal(1)) .addParam("b", new BigDecimal(2)) .addParam("c", new BigDecimal(3)) .setRulescript(s) .eval(); System.out.println(new BigDecimal(result1.toString())); Object result2 = RuleEngineManager.instance() .addParam("a", 1) .setRulescript("function contain(a){ return a.indexOf('a')} contain('aaa')") .eval(); System.out.println(result2); Object result3 = RuleEngineManager.instance() .addParam("a", "0") .addParam("b", "a") .setRulescript("a === '0'") .eval(); System.out.println(result3); } }
js扩展
public class scriptConstant { public static String INCLUDE = "String.prototype.include = function(s) {" + " return this.indexOf(s) >= 0" + "}"; public static String EXCLUDE = "String.prototype.exclude = function(s) {" + " return this.indexOf(s) < 0" + "}"; }
计算引擎
@Slf4j @Service public class AssessRuleEngine { public AssessModelResult eval(AssessModelVO modelVO, Mapparam) { // 构建项目编码->项目得分 map Map resultItemMap = new HashMap<>(); // 循环计算每个项目的得分 modelVO.getItemList().forEach(item -> { String itemCode = item.getItemCode(); Object itemValue = param.get(itemCode); AssertUtil.notNull(itemValue, MessageEnum.ASSESS_PARAM_ERROR); ScoreTypeEnum scoreType = ScoreTypeEnum.getByCode(item.getScoreType()); AssertUtil.notNull(scoreType, MessageEnum.ASSESS_CONFIG_ERROR); // 项目得分 BigDecimal itemScore = BigDecimal.ZERO; // 直接得分 if (scoreType == ScoreTypeEnum.RETURN_SCORE) { // 多选积分求和, 单选单个得分 for (AssessModelOption option : item.getOptionList()) { if (itemValue.toString().contains(option.getOptionCode())) { itemScore = itemScore.add(option.getScore()); } } log.info("计算项目得分 itemName={}, 直接得分={}", item.getItemName(), itemScore); } // 匹配规则 或 表达式 else { RuleEngineManager engineInstance = RuleEngineManager.instance() .addParam(DefaultVariableEnum.ITEM_VALUE.getCode(), itemValue); for (AssessModelRule rule : item.getRuleList()) { String script = rule.getScoreExp(); boolean match = engineInstance.setRulescript(script).match(); if (match) { itemScore = rule.getScore(); break; } } log.info("计算项目得分 itemName={}, 匹配规则={}", item.getItemName(), itemScore); } AssertUtil.notNull(itemScore, MessageEnum.ASSESS_CONFIG_ERROR); resultItemMap.put(itemCode, itemScore); }); ResultTypeEnum resultType = ResultTypeEnum.getByCode(modelVO.getResultType()); AssertUtil.notNull(resultType, MessageEnum.ASSESS_CONFIG_ERROR); // 得分求和 if (Objects.equals(resultType, ResultTypeEnum.SUM)) { BigDecimal totalScore = resultItemMap.keySet().stream() .map(key -> (BigDecimal) resultItemMap.get(key)) .reduce(BigDecimal::add).get(); resultItemMap.put(DefaultVariableEnum.TOTAL_SCORE.getCode(), totalScore); log.info("计算项目总得分 totalScore={}", totalScore); } // 得分表达式 else if (Objects.equals(resultType, ResultTypeEnum.EXP_TEXT)) { AssertUtil.notNull(modelVO.getResultExp(), MessageEnum.ASSESS_CONFIG_ERROR); BigDecimal totalScore = RuleEngineManager.instance() .addParam(resultItemMap) .setRulescript(modelVO.getResultExp()) .eval2(); resultItemMap.put(DefaultVariableEnum.TOTAL_SCORE.getCode(), totalScore); log.info("计算项目得分表达式 totalScore={}, resultExp = {}", totalScore, modelVO.getResultExp()); } // 匹配非默认结果 AssessModelResult matchResult = null; for (AssessModelResult modelResult : modelVO.getResultList()) { if (modelResult.getDefaultResult() == null || !modelResult.getDefaultResult()) { String script = modelResult.getResultExp(); boolean match = RuleEngineManager.instance().addParam(resultItemMap) .setRulescript(script) .match(); if (match) { matchResult = modelResult; break; } } else { matchResult = modelResult; } } AssertUtil.notNull(matchResult, MessageEnum.ASSESS_CONFIG_ERROR); // 计算匹配结果自定义值 if (StringUtils.isNotEmpty(matchResult.getCustomExp())) { String script = matchResult.getCustomExp(); BigDecimal value = RuleEngineManager.instance().addParam(resultItemMap) .setRulescript(script) .eval2(); matchResult.setCustomValue(value); } log.info("返回默认结果 modelResult={}", JsonUtil.objectToString(matchResult)); return matchResult; } }
项目地址
sescore: 基于java jdk自带scriptEngineManager 实现规则引擎 疾病评估
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)