基于规则引擎实现的疾病评估得分卡

评估配置功能

 

评估计算功能

基础功能:

  • 实现自定义表单展示,包含项目的展示和得分规则计算
  • 实现所有项目结果的评估结果组合计算和展示

数据库定义

 

 

 

实现原理

类似问卷调查配置表单,数据库有一个脚本保存匹配规则,类似   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(Map<String, Object> map) {
        bindings.putAll(map);
        return this;
    }

    public RuleEngineManager setRuleScript(String ruleScript) {
        this.ruleScript = ruleScript;
        return this;
    }

    @SuppressWarnings("unchecked")
    public <T> 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, Map<String, Object> param) {

        // 构建项目编码->项目得分 map
        Map<String, Object> 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 实现规则引擎 疾病评估

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值