利用ScriptEngineManager实现简单的规则运算

xiyang 2020-01-04

在JAVA开发过程中,有时会遇到一些小运算。比如传入一个List集合,我们需要根据集合中的某一属性做过滤。

相信这种场景大家都有遇到过,通常的解决办法是直接在java代码中写好一些比较规则,实现上也是比较简单的。

但是如果这个规则是动态的呢,假如A类型的数据,我们根据A字段过滤,B类型的数据,我们根据字段B过滤。这时突然又来了个C类型的数据,难道又要写个C的过滤方法,再重新发布上线吗?

当然是不用的,JAVA的开发大牛早就帮我们想好了解决的办法。因为JAVA本身编译型的限制,我们可以使用JavaScript等脚本语言来实现规则的动态外置。ScriptEngineManager这个类就是java中用来运行JavaScript脚本的引擎。

举个很简单的例子:

public static void main(String[] args) {

        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine js = manager.getEngineByName("JavaScript");
        //构建原始数据
        JSONObject jsonObject1 = JSONObject.parseObject("{‘status‘:‘success‘, ‘remark‘:‘下单成功‘}");
        JSONObject jsonObject2 = JSONObject.parseObject("{‘status‘:‘fail‘, ‘remark‘:‘下单失败,余额不足‘}");
        JSONObject jsonObject3 = JSONObject.parseObject("{‘status‘:‘success‘, ‘remark‘:‘下单成功‘}");
        List<JSONObject> list = new ArrayList<>();
        list.add(jsonObject1);
        list.add(jsonObject2);
        list.add(jsonObject3);
        //构建规则参数
        Map<String, String> filter2 = new TreeMap<>();
        filter2.put("val1", "status");
        filter2.put("val2", "remark");
        
        String rule = "‘status‘ === ‘fail‘ && ‘remark‘.indexOf(‘失败‘) > -1";
        List<JSONObject> result = new ArrayList<>();
        for (JSONObject map : list) {
            //构建参数实际值
            List<String> listValue = new ArrayList<>();
            filter2.forEach((key, val) -> {
                String s = map.get(val).toString();
                listValue.add(s);
            });
            String[] array = new String[listValue.size()];
            array = listValue.toArray(array);

            //需要执行的实际规则
            String evalRule = StringUtils.replaceEach(rule, new String[]{"status","remark"}, array);
            boolean a = false;
            try {
                //规则执行
                a = (boolean) js.eval(evalRule);
                if (a){
                    result.add(map);
                }
            } catch (ScriptException e) {
                e.printStackTrace();
            }
        }
        System.out.println(result);
    }

结果:[{"remark":"下单失败,余额不足","status":"fail"}]

上述案例中,我们传入一个size为3的list集合,根据状态和备注字段来过滤下单失败的订单,轻而易举的就得到了预期的结果值。是不是感觉在java中写js也是一种很神奇的体验呢。

想一想,如果我们将需要比较的规则字段和比较规则两个属性写入数据库中呢。这时候你传入其他类型的数据,只需要在数据库中增加相应规则的配置,而后直接根据数据库中配置的规则和字段做比较,是不是就实现了数据的动态过滤了。再也不用为解析不同的数据而烦恼,再也不用编写重复而冗余的过滤代码了。

相关推荐