前三篇文章已从groovy脚本的基本使用到java解析,json对象结合作了一基础铺垫。这篇文章是本系列的最后一篇文章。
在第二篇文章中,说到用groovy编写的规则脚本,然后采用文件+字符串的形式加载到java中,解析并运行。
在我的应用场景中,每一条规则就是一个业务指标项。每一个指标项能够单独维护,而不是把所有指标项统一放到一个文件中。
那么,我需要对规则按每一个指标项进行碎片化切分。
这些指标项一般而言,是存放在数据表中的,然后提供统一的配置界面进行调整维护。
上代案例代码:
1package com.amarsoft.rax.rulengine; 2 3 4import java.util.ArrayList; 5import java.util.Iterator; 6import java.util.List; 7 8import javax.script.Bindings; 9import javax.script.ScriptEngine; 10import javax.script.ScriptEngineManager; 11import javax.script.ScriptException; 12 13import com.amarsoft.rax.lang.DataObject; 14 15 16public class DynamicGroovyScript { 17 18 /** 19 * 规则集以及每个指标项的计算脚本 20 * @return 21 */ 22 private DataObject getRuleset(){ 23 DataObject ruleSet = new DataObject(); 24 25 ruleSet.xput("规则集.基础信息.是否90后", "student.birth >= '1990/01/01'?'是':'否'"); 26 ruleSet.xput("规则集.基础信息.性别", "student.gender == 'M' ? '男' : '女'"); 27 ruleSet.xput("规则集.基础信息.注册天数", "to_date(today) - to_date(student.createTime)"); 28 ruleSet.xput("规则集.基础信息.地区", areaScript()); 29 ruleSet.xput("规则集.评级.学费档次", "tuitionFee>=60000?'A':(tuitionFee>=40000&&tuitionFee<60000?'B':(tuitionFee>=20000&&tuitionFee<40000)?'C':'D')"); 30 ruleSet.xput("规则集.评级.收入档次", incomeScript()); 31 ruleSet.xput("规则集.学习情况.总学时", totalHoursScript()); 32 ruleSet.xput("规则集.学习情况.迟到次数", delayTimes()); 33 ruleSet.xput("规则集.学习情况.出勤次数", "student.extra.attendanceLog.size()"); 34 ruleSet.xput("规则集.学习情况.单门课程最长学时", maxCourseHours()); 35 36 return ruleSet; 37 } 38 /** 39 * 业务原始数据 40 * @return 41 */ 42 private DataObject getBusinessData(){ 43 DataObject businessData = new DataObject(); 44 45 businessData.xput("collegeName", "EMBA业余大学"); 46 businessData.xput("tuitionFee", 80000); 47 businessData.xput("startDate", "2016/02/01"); 48 businessData.xput("finishDate", "2016/09/01"); 49 businessData.xput("today", "2017/01/21"); 50 //下一层级的学生对象 51 businessData.xput("student.id", "E9527"); 52 businessData.xput("student.name", "于小小"); 53 businessData.xput("student.gender", "F"); 54 businessData.xput("student.kind", "EMBA"); 55 businessData.xput("student.className", "重庆理工大学MBA三年级四班"); 56 businessData.xput("student.grade", 4); 57 businessData.xput("student.birth", "1989/03/02"); 58 businessData.xput("student.address", "重庆市巴南区红光大道"); 59 businessData.xput("student.salary", 50000); 60 businessData.xput("student.createTime", "2016/01/21 11:31:00"); 61 businessData.xput("student.courses", getCourses()); 62 businessData.xput("student.mainInstructor", null); 63 businessData.xput("student.extra.attendanceLog", getAttendanceLog()); 64 65 return businessData; 66 } 67 68 public static void main(String[] args) throws ScriptException{ 69 ScriptEngineManager engineManager = new ScriptEngineManager(); 70 ScriptEngine engine = engineManager.getEngineByName("groovy"); 71 Bindings variables = engine.createBindings(); 72 73 DynamicGroovyScript ins = new DynamicGroovyScript(); 74 DataObject businessData = ins.getBusinessData(); 75 variables.putAll(businessData); 76 77 DataObject ruleSet = ins.getRuleset(); 78// System.out.println(ruleSet.getJSONString()); 79 80// System.out.println(engine.eval("student.birth >= '1990/01/01'?'是':'否'",variables)); 81 Iterator<String> iterator = ruleSet.xpathKeyIterator(); 82 while(iterator.hasNext()){ 83 String key = iterator.next(); 84 Object value = ruleSet.getObject(key); 85 if(!(value instanceof String))continue; 86 String script = (String)value; 87 if(script == null||script.replaceAll("\\s+", "").length()==0)continue; 88 engine.eval(ins.getGlobleScript("")); //先执行下,把全局函数放进去 89// System.out.println(key+"="+value+" --->值:["+engine.eval(script,variables)+"]"); 90 System.out.println(key+"="+engine.eval(script,variables)); 91 } 92 } 93 94 private List<String> getAttendanceLog(){ 95 List<String> list = new ArrayList<String>(); 96 97 list.add("2016/02/01 09:00:02"); 98 list.add("2016/02/03 08:50:03"); 99 list.add("2016/02/15 09:12:34"); 100 list.add("2016/04/01 07:30:11"); 101 102 return list; 103 } 104 105 private DataObject[] getCourses(){ 106 DataObject[] courses = new DataObject[]{ 107 new DataObject(), 108 new DataObject(), 109 new DataObject(), 110 new DataObject(), 111 new DataObject(), 112 new DataObject(), 113 }; 114 courses[0].xput("id", "GJC"); 115 courses[0].xput("name", "公共基础"); 116 courses[0].xput("classHour", 32); 117 118 courses[1].xput("id", "ZXW"); 119 courses[1].xput("name", "组织行为学"); 120 courses[1].xput("classHour", 40); 121 122 courses[2].xput("id", "TJX"); 123 courses[2].xput("name", "统计学"); 124 courses[2].xput("classHour", 20); 125 126 courses[3].xput("id", "CJR"); 127 courses[3].xput("name", "财务与金融"); 128 courses[3].xput("classHour", 60); 129 130 courses[4].xput("id", "JJF"); 131 courses[4].xput("name", "经济法"); 132 courses[4].xput("classHour", 48); 133 134 courses[5].xput("id", "JSJ"); 135 courses[5].xput("name", "计算机技能"); 136 courses[5].xput("classHour", 16); 137 return courses; 138 } 139 140 private String areaScript(){ 141 StringBuilder execScript = new StringBuilder(); 142 execScript.append("({").append("\n"); 143 execScript.append(" def province = student.address.subSequence(0,3)").append("\n"); 144 execScript.append(" def areaMapping = ['西南':['重庆市','四川省','贵州省','云南省'],'江浙沪':['上海市','江苏省','浙江省'],'京津冀':['北京市','天津市','河北省']]").append("\n"); 145 execScript.append(" def entry = areaMapping.find {key,value -> ").append("\n"); 146 execScript.append(" value.contains(province)").append("\n"); 147 execScript.append(" }").append("\n"); 148 execScript.append(" entry.key").append("\n"); 149 execScript.append("})()").append("\n"); 150 151 return execScript.toString(); 152 } 153 private String incomeScript(){ 154 StringBuilder execScript = new StringBuilder(); 155 execScript.append("({").append("\n"); 156 execScript.append(" if(student.salary>=20000) '高收入'").append("\n"); 157 execScript.append(" else if(student.salary>=10000) '中等收入'").append("\n"); 158 execScript.append(" else if(student.salary>=5000) '一般收入'").append("\n"); 159 execScript.append(" else '低收入'").append("\n"); 160 execScript.append("})()").append("\n"); 161 162 return execScript.toString(); 163 } 164 private String totalHoursScript(){ 165 StringBuilder execScript = new StringBuilder(); 166 execScript.append("({").append("\n"); 167 execScript.append(" int totalHourse = 0;").append("\n"); 168 execScript.append(" student.courses.each { totalHourse += it.classHour}").append("\n"); 169 execScript.append(" totalHourse").append("\n"); 170 execScript.append("})()").append("\n"); 171 172 return execScript.toString(); 173 } 174 private String delayTimes(){ 175 StringBuilder execScript = new StringBuilder(); 176 execScript.append("({").append("\n"); 177 execScript.append(" int _count = 0").append("\n"); 178 execScript.append(" student.extra.attendanceLog.each {").append("\n"); 179 execScript.append(" Date _date = to_date(it)").append("\n"); 180 execScript.append(" _count += (_date.hours>=9&&_date.seconds>=1)?1:0").append("\n"); 181 execScript.append(" }").append("\n"); 182 execScript.append(" _count").append("\n"); 183 execScript.append("})()").append("\n"); 184 185 return execScript.toString(); 186 } 187 private String maxCourseHours(){ 188 StringBuilder execScript = new StringBuilder(); 189 execScript.append("({").append("\n"); 190 execScript.append(" int maxHour = 0;").append("\n"); 191 execScript.append(" student.courses.each { maxHour = Math.max(maxHour,it.classHour)}").append("\n"); 192 execScript.append(" student.courses.find({it.classHour == maxHour}) //默认最后一句为返回值").append("\n"); 193 execScript.append("})()").append("\n"); 194 195 return execScript.toString(); 196 } 197 198 199 public String getGlobleScript(String script){ 200 StringBuilder execScript = new StringBuilder(); 201 //增加一个日期处理方法 202 execScript.append("import java.text.SimpleDateFormat").append("\n"); 203 execScript.append("import java.text.ParseException").append("\n"); 204 205 execScript.append("def to_date(_date){").append("\n"); 206 execScript.append(" try{").append("\n"); 207 execScript.append(" return (new SimpleDateFormat(\"yyyy/MM/dd hh:mm:ss\")).parse(_date);").append("\n"); 208 execScript.append(" }catch(ParseException e){").append("\n"); 209 execScript.append(" return (new SimpleDateFormat(\"yyyy/MM/dd\")).parse(_date);").append("\n"); 210 execScript.append(" }").append("\n"); 211 execScript.append("}").append("\n"); 212 213 execScript.append(script); 214 215 return execScript.toString(); 216 } 217 218}
运行效果如下图:
