自定义的规则引擎,JEXL的实现

虽然drools规则引擎强大,但是部署和开发难度还是很大的,学习曲线也非常陡峭。

 

所以,想自己定义一个简单的规则引擎。设计思路就是用json文件定义一下规则,能够支持动态逻辑,而不需要修改程序。

 

所以就有了下面这些程序。

 

首先,需求如下:

一张简单的评分卡:

输入对象评分平均分区间最终得分
9060评分>9010
806060<评分<=908
5060评分<602
    

 

 

============================================================================

程序使用fastjson和jexl程序包,pom.xml需要以下内容:

 

        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-jexl</artifactId>
            <version>2.0</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.44</version>
        </dependency>

==========================================================================

规则对象

package net.transino.mls.user;
/**
 * 规则
 * @author zhouxj
 *
 */
public class RuleComd {
    private String comdName;  //规则名
    private String optValeName; //前置变量,只可以是变量名,也可以是JEXL表达式,默认输入对象InBox,输出对象OutBox
    private String optConde;     //比较条件 ,支持>,<,==,>=,<=,equels,&&并且,||或者
    private String optObjectName;//后置变量,可以是变量名,也可以是JEXL表达式
    
    private String optDeal;  //规则操作,JEXL动态表达式:89+12/4;\"世界\"+str2;
    private String reultValueName; //规则结果域,结果域值会被覆盖。
    public String getComdName() {
        return comdName;
    }

    public void setComdName(String comdName) {
        this.comdName = comdName;
    }

    public String getOptValeName() {
        return optValeName;
    }

    public void setOptValeName(String optValeName) {
        this.optValeName = optValeName;
    }

    public String getOptConde() {
        return optConde;
    }

    public void setOptConde(String optConde) {
        this.optConde = optConde;
    }

    public String getOptObjectName() {
        return optObjectName;
    }

    public void setOptObjectName(String optObjectName) {
        this.optObjectName = optObjectName;
    }

    public String getOptDeal() {
        return optDeal;
    }

    public void setOptDeal(String optDeal) {
        this.optDeal = optDeal;
    }

    public String getReultValueName() {
        return reultValueName;
    }

    public void setReultValueName(String reultValueName) {
        this.reultValueName = reultValueName;
    }
}


================================================================

运行规则主程序:

package net.transino.mls.user;


import java.util.ArrayList;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;

import com.alibaba.fastjson.JSONObject;

 

public class TestRuleRun {

    
    
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        testSelect();    
        
    }


    /**
     * 查询操作
     */

    public static void testSelect() {
         String param = new
         Util().ReadFile("D:/workTestMaven/SelfRule/src/net/transino/mls/user/Exaple2Utf8.json");

        String encode="utf-8";
        
        System.out.println(param);
        //JSONObject jsonObj=null;
        JSONObject inputObject = JSONObject.parseObject(param);
        JSONObject outObject = new JSONObject();
                
        outObject.put("outputB", "");
        outObject.put("outputA", "");
        String jsonString = new
                 Util().ReadFile("D:/workTestMaven/SelfRule/src/net/transino/mls/user/rules.json");
//        JSONObject ruleObject = JSONObject.parseObject(rules);
//        JSONObject ruleObject = new JSONObject();
//        ArrayList rulses=new ArrayList();
//        RuleComd newC=new RuleComd();
//        newC.setComdName("a1");
//        newC.setOptValeName("InBox.rptUserdept");
//        newC.setOptConde(">");
//        newC.setOptDeal("89+12/4");
//        newC.setOptObjectName("InBox.qryReason");
//        newC.setReultValueName("OutBox.outputB");
//        RuleComd newC2=new RuleComd();
//        newC2.setComdName("a2");
//        newC2.setOptValeName("InBox.rptUserdept");
//        newC2.setOptConde("<=");
//        newC2.setOptObjectName("InBox.qryReason");
//        newC2.setOptDeal("89-12/4");
//        newC2.setReultValueName("OutBox.outputA");
//        rulses.add(newC);
//        rulses.add(newC2);
//        String jsonString = JSONObject.toJSONString(rulses);
       // JSONObject jsonObject = JSONObject.parseObject(jsonString);
        ArrayList ruleList = JSONObject.parseObject(jsonString, ArrayList.class);
        
        System.out.println(jsonString);
        fireAllrule(inputObject,outObject,ruleList);
        
        System.out.println("规则运行结果:"+outObject.toJSONString());
    }

    /**
     * 运行所有规则
     * @param inputObject
     * @param outObject
     * @param ruleObject
     */
    private static void fireAllrule(JSONObject inputObject, JSONObject outObject, ArrayList<JSONObject> ruleObject) {
        // TODO Auto-generated method stub
        for(JSONObject temp:ruleObject){
            RuleComd comd=JSONObject.parseObject(temp.toJSONString(),RuleComd.class);
            
            runComd(inputObject,outObject,comd);
        }
        
    }

    /**
     * 运行一条规则,并且根据条件设置outObject属性。
     * @param inputObject
     * @param outObject
     * @param temp
     */
    private static void runComd(JSONObject inputObject, JSONObject outObject, RuleComd temp) {
        // TODO Auto-generated method stub
        String optConde=temp.getOptConde();
        if(optConde.equals("equels")){
            equelsRunComd(inputObject,outObject);    //对象相等操作
        }else{
            calRunComd(inputObject,outObject,temp); //比较运算操作
        }
    }


    private static void calRunComd(JSONObject inputObject, JSONObject outObject, RuleComd temp) {
        JexlContext jc = new MapContext();

        jc.set("InBox", inputObject);
        jc.set("OutBox", outObject);

        String optValeName=temp.getOptValeName(); //前置变量
        String inputValue=inputObject.getString(optValeName);
        String optConde=temp.getOptConde();    //比较条件
        String optObjectName=temp.getOptObjectName(); //后置变量
        
//        String optBackValue="";
//        try{
//            optBackValue=inputObject.getString(optObjectName);
//        }catch(Exception e){
//            optBackValue=optObjectName; //后置变量不是一个变量名
//        }
        String expression =optValeName; //JEXL动态表达式
        Expression e = new JexlEngine().createExpression(expression);
        Object result=e.evaluate(jc);
        System.out.println("result:" + result.toString());
        String fntValue=result.toString();
        
        
        
        String expression2 =optObjectName; //JEXL动态表达式
        Expression e2 = new JexlEngine().createExpression(expression2);
        Object result2=e2.evaluate(jc);
        System.out.println("result2:" + result2.toString());
        String  backValue=result2.toString();        
        
        
        String expression3 =fntValue+optConde+backValue; //JEXL动态表达式
        Expression e3 = new JexlEngine().createExpression(expression3);
        Object result3=e3.evaluate(jc);
        System.out.println("result3:" + result3.toString());
        String  endResult=result3.toString();        
        if(endResult.equals("true")){
            String optDeal=temp.getOptDeal(); //规则操作
            String expression4 =optDeal; //JEXL动态表达式
            Expression e4 = new JexlEngine().createExpression(expression4);
            Object result4=e4.evaluate(jc);
            System.out.println("result4:" + result4.toString());
            String  dealRult=result4.toString();
            
            String reultValueName=temp.getReultValueName(); //规则结果域
            String expression5 =reultValueName+"="+optDeal; //JEXL动态表达式
            Expression e5 = new JexlEngine().createExpression(expression5);
            Object result5=e5.evaluate(jc);
            System.out.println("result5:" + result5.toString());
            //String  reultValue=result5.toString();    
            
        }
    }


    private static void equelsRunComd(JSONObject inputObject, JSONObject outObject) {
        
        
    }
}


=======================================================================

一个读取json文件的工具类:

package net.transino.mls.user;

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;

public class Util {

    public String ReadFile(String Path) {
        BufferedReader reader = null;
        String laststr = "";
        try {
            FileInputStream fileInputStream = new FileInputStream(Path);
            InputStreamReader inputStreamReader = new InputStreamReader(fileInputStream, "UTF-8");
            reader = new BufferedReader(inputStreamReader);
            String tempString = null;
            while ((tempString = reader.readLine()) != null) {
                laststr += tempString;
            }
            reader.close();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (reader != null) {
                try {
                    reader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return laststr;
    }

}


=========================================================================

输入对象json的定义文件Exaple2Utf8.json:

{
    "reqId": "345678912722277",
    "appType": "01",
    "rptUser": "superadmin",
    "rptUserdept": "777",
    "custCertno": "44068319860414231X",
    "qryReason": "02",
    "qryType": "0",
    "qryFormat": "30",
    "certValiddt": "长期有效",
    "certAddr": "辽宁省朝阳市",
    "score": "48.23",
    "avg": "60",
    "remark5": ""
}

==========================================================================

规则定义文件rules.json:

 

[
{
"comdName":"a1",
"optValeName":"InBox.score",
"optConde":">",
"optObjectName":"90",
"optDeal":"10",

"reultValueName":"OutBox.outputA"
},
{
"comdName":"a2",
"optValeName":"InBox.avg<InBox.score",
"optConde":"&&",
"optObjectName":"InBox.score<=90.0",
"optDeal":"8",

"reultValueName":"OutBox.outputA"
},
{
"comdName":"a3",
"optValeName":"InBox.score",
"optConde":"<",
"optObjectName":"InBox.avg",
"optDeal":"2",

"reultValueName":"OutBox.outputA"
}
]

========================================================

修改输入json对象的"score": "48.23",就能看到不同的分值运行的不同结果。

例如:

48.23的输出为:规则运行结果:{"outputA":2,"outputB":""}

78.23的输出为:规则运行结果:{"outputA":8,"outputB":""}

98.23的输出为:规则运行结果:{"outputA":10,"outputB":""}

======================================================

修改rules.json的"optDeal":"8",字段,就能调整评分而不需要修改任何程序。

 

 

===================================================================

后记:由于使用了JEXL语法,所以还是有一些小BUG要注意,例如:字符串结果要用单引号围起来,整数对象与浮点数对象比较会报错("optObjectName":"InBox.score<=90.0"写成90),但是不影响大局。

===================================================================

另附:JEXL小工具,用来检查JEXL语法错误,便于排错。

package net.transino.Jexl;

import org.apache.commons.jexl2.Expression;
import org.apache.commons.jexl2.JexlContext;
import org.apache.commons.jexl2.JexlEngine;
import org.apache.commons.jexl2.MapContext;

/***
 * JEXL动态表达式
 *
 * @author zhouxj
 *
 */

public class EslT {

    public static void main(String[] args) {
        simpL(); // 简单表达式
        RL(); // 规则表达
        loop();// 循环

    }

    public static void simpL() {
        JexlContext jc = new MapContext();
        int str = 10;

        jc.set("str", str);
        jc.set("ans", "");
        String expression = "ans = 56+str-20";
        Expression e = new JexlEngine().createExpression(expression);
        e.evaluate(jc);
        System.out.println("Simpl:" + jc.get("ans"));

        String str2 = "你好!";
        jc.set("str2", str2);
        
        String expression2 = "\"世界\"+str2";
        Expression e2 = new JexlEngine().createExpression(expression2);
        Object result=e2.evaluate(jc);
        System.out.println("Simpl2:" + result.toString());
        
        
        String expression3 = "98.23<=777 || 777<56";
        Expression e3 = new JexlEngine().createExpression(expression3);
        Object result3=e3.evaluate(jc);
        System.out.println("Simpl3:" + result3.toString());    
        
    }

    public static void RL() {
        JexlContext jc = new MapContext();
        String str = "一二三四五六七八九十";
        jc.set("Util", new ExUtil());
        jc.set("str", str);
        jc.set("ans", "");
        String expression = "ans = Util.regMatch(\"[\u4e00-\u9fa5]{10,}\",str)";
        Expression e = new JexlEngine().createExpression(expression);
        e.evaluate(jc);
        System.out.println(jc.get("ans"));
    }

    public static void loop() {
        JexlContext jc = new MapContext();
        jc.set("a", 1);
        jc.set("b", "0");
        jc.set("ans", new StringBuffer());
        Expression e = new JexlEngine().createExpression("while (a < 10) {a = a + 1;ans.append(b);}");
        e.evaluate(jc);
        System.out.println(jc.get("ans"));
    }

 

}

 

 

package net.transino.Jexl;

import java.util.regex.Pattern;

public class ExUtil {
    public static boolean regMatch(String regEx, String str) {
        Pattern pattern = Pattern.compile(regEx);
        return pattern.matcher(str).matches();
    }
}

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值