希望大家提出保贵意见~
优点:
1、规则规范业务流程,且现有规则已经实现不仅使用在流程平台上且可以其他模块,如:作业计划。仅需配置。
2、支持xml中配置表达式,工程人员将输入/输出参数使用表达式配置进行赋值(不需书写任何代码),故而影响流程的流向。
3、支持xml中配置规则分组,并将规则赋予优先级,规则会按照规则分组优先级执行规则,直到满足规则条件退出。
4、支持除表达式复杂的业务逻辑,工程人员可以开发java代码实现业务方法,在xml中简单配置即可以实现复杂业务逻辑。
5、支持listener,在调用规则之前、之后都会触发before(),after()方法。工程人员可按业务编写多个lisener,使lisener有效只需要简单xml配置。
6、支持输入输出参数的验证,根据二次开发人员的xml配置,按输入输出参数配置类型进行验证,若输入/输出参数不符合业务要求则抛出异常。
发展:
1、xml的web页面配置,提供eclipse plugin配置,将需要手动xml配置的地方使用web,eclipse plugin的方式实现工具配置,
其中可实现,若需要判断值,如执行类型,工程人员在配置xml时每次要查数据库对应找出值配上,而现在只要求二次二发人员提供取数据库表的方法,
规则配置工具会将表中的内存如:1,草稿;2,转派;这些内容以下拉列表方式供工程人员选对,以节省工程人员的麻烦。
2、支持drools。
3、与使用规则的组件更有机的结果,如流程平台、作业计划。
依赖关系:
1、文件配置
2、castor
3、ongl
使用:
规则关心的是输入/输出参数,也即将输入参数以java.util.Map传入,通过key="参数名称",value="参数类型"
根据传入的参数组合条件,将输出参数以java.util.Map类型返回,也通过key="参数名称",value="参数类型"
以com.boco.eoms.commons.rule.test.service.RuleServiceFacadeTest.java 为例测试自定义java规则及规则分组调用
为说明例子,我编写了com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample.java及同包下的Rule1InputParameter2Sample.java
做为输入参数
com.boco.eoms.commons.rule.Rule1OutputParameter1Sample.java及同包下Rule1OutputParameter2Sample.java做为输出参数
com.boco.eoms.commons.rule.Rule1Sample.java及com.boco.eoms.commons.rule.Rule2Sample.java为例说明自定义java规则及规则分组
com.boco.eoms.commons.rule.sample.Rule1ListenerSample.java为自定义listener
com.boco.eoms.commons.rule.sample.RuleSample.xml配置规则,先介绍轮廓,之后会详细介绍
rule的说明是个比较不好说明的东西,所以有些枯燥,:-)
配置文件如下说明:
style=" ( $parameter != $l{springbean.getNames} || false ) && $text ? $r{springbean.getName} : 3 " />
id="Rule1Sample">
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
expression=""
name="rule1OutputParameter1Sample"
type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
drl=""
expStyleId="rule1Express" />
expression=""
name="rule1OutputParameter2Sample"
type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
drl=""
expStyleId="rule1Express" />
name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
id="Rule2Sample">
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
expression=" ( ${rule1InputParameter1Sample.name} != 'value3' || false) && true ? $b{springbean.getName} : 3 "
name="rule1OutputParameter1Sample"
type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
drl="classpath:com.boco.eoms.commons.rule.sample.rule1Parameter1Sample.drl"
expStyleId="rule1Express" />
expression=" rule1InputParameter1Sample.name != '234' && rule1InputParameter1Sample.age >10 ? rule1InputParameter1Sample.name : rule1InputParameter1Sample.age "
name="rule1OutputParameter2Sample"
type="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
drl="classpath:com.boco.eoms.commons.rule.sample.rule1Parameter2Sample.drl"
expStyleId="rule1Express" />
name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
OK,现在我们看看自定义java写了什么
public class Rule1Sample extends RuleService {
/**
* @param ruleListeners
* @param rules
* @param rule
* @param xmlPath
*/
public Rule1Sample(List ruleListeners, RuleEngine rules, Rule rule,
String xmlPath) {
super(ruleListeners, rules, rule, xmlPath);
}
/**
* 二次开发人员需实现的业务接口
*
* @param map
* 根据配置文件中input的配置,二次开发人员取出配置的参数,
* 如sample配置key="rule1InputParameter1Sample",value="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample"
* key="rule1Parameter2InputSample",value="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample"
* 这时二次发人员在execute中按这种方式取参数
* com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample
* param1=(com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample)
* map.get("rule1InputParameter1Sample");
* com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample
* param2=(com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample)
* map.get("rule1InputParameter2Sample");
*
* @return 根据配置文件output的配置,二次开发人员需返回配置的参数 如sample配置
* key="rule1OutputParameter1Sample",value="com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample"
* key="rule1OutputParameter2Sample",value="com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample"
* 配置人员需按业务要求,返回
* map.put("rule1OutputParameter1Sample",com.boco.eoms.commons.rule.sample.Rule1OutputParameter1Sample);
* map.put("rule1OutputParameter2Sample",com.boco.eoms.commons.rule.sample.Rule1OutputParameter2Sample);
* return map;
* @throws RuleException
*/
public Map execute(Map map,Rule rule) throws RuleException {
// 规则业务
// 取输入参数
Rule1InputParameter1Sample inputParam1 = (Rule1InputParameter1Sample) map
.get("rule1InputParameter1Sample");
Rule1InputParameter2Sample inputParam2 = (Rule1InputParameter2Sample) map
.get("rule1InputParameter2Sample");
Map outMap = new HashMap();
Rule1OutputParameter1Sample outParam1 = new Rule1OutputParameter1Sample();
Rule1OutputParameter2Sample outParam2 = new Rule1OutputParameter2Sample();
// 模拟规则,年龄大于10数,姓名不为匿名,则outParam1设为可通过
if (inputParam1.getAge() > 10
&& !"anonym".equals(inputParam1.getName())) {
// 为说明业务逻辑所以将setName放入判断条件
outParam1.setName(inputParam1.getName());
outParam1.setOk(true);
} else {
// 为说明业务逻辑所以将setName放入判断条件
outParam1.setName(inputParam1.getName());
outParam1.setOk(false);
}
// 性别为男则通过
if ("male".equals(inputParam2.getSex())) {
outParam2.setSex("male");
outParam2.setOk(true);
} else {
outParam2.setSex("male");
outParam2.setOk(false);
}
outMap.put("rule1OutputParameter1Sample", outParam1);
outMap.put("rule1OutputParameter2Sample", outParam2);
// 返回输出参数
return outMap;
}
}
以Rule1Sample.java为例,需继承RuleService并实现execute方法,业务逻辑写在该方法内,如Rule1Sample.java
按照配置的输入/输出参数进行操作。
同时开发人员需要 像RuleServiceFacadeTest这样调用,按注释调用,请看注释
public class RuleServiceFacadeTest extends TestCase {
private RuleServiceFacade facade;
private Map inputMap;
private Rule1InputParameter1Sample inputParam1;
private Rule1InputParameter2Sample inputParam2;
private String xmlPath = "";
private String groupId = "";
/**
* 输入参数初始化
*/
protected void setUp() throws Exception {
facade = RuleServiceFacade.create();
// 测试输入参数类弄与xml是否匹配
inputMap = new HashMap();
inputParam1 = new Rule1InputParameter1Sample();
inputParam2 = new Rule1InputParameter2Sample();
inputParam1.setAge(10);
inputParam1.setName("qjb");
inputParam2.setSex("male");
inputMap.put("rule1InputParameter1Sample", inputParam1);
inputMap.put("rule1InputParameter2Sample", inputParam2);
xmlPath = "classpath:com/boco/eoms/commons/rule/sample/RuleSample.xml";
groupId = "group1";
super.setUp();
}
protected void tearDown() throws Exception {
super.tearDown();
}
/**
* 以classpath:com/boco/eoms/commons/rule/sample/RuleSample.xml为配置文件,调用rule1Sample为ruleId,以inputMap为输入参数,
*
*/
public void testInvokeRuleService() {
try {
facade.invokeRuleService(xmlPath, "Rule1Sample", inputMap);
} catch (RuleException e) {
fail();
}
}
/**
* 以规则分组(路由)方式调用,调用groupId即group1,按照xml配置是调用了两个rule,按照优先级(数字由大到小)先后调用
* 以不同输入参数调用
*/
public void testInvokeRuleGroupForDiffInputMap() {
Map map = new HashMap();
Map outMap = null;
// 以不同输入参数调用
map.put("Rule1Sample", inputMap);
map.put("Rule2Sample", inputMap);
try {
outMap = facade.invokeRuleGroupForDiffInputMap(xmlPath, groupId,
map);
} catch (RuleException e) {
fail();
}
checkOutMap(outMap);
}
/**
* 以规则分组(路由)方式调用,调用groupId即group1,按照xml配置是调用了两个rule,按照优先级(数字由大到小)先后调用
* 以相同输入参数调用
*
*/
public void testInvokeRuleGroupForSampeInputMap() {
Map outMap = null;
try {
outMap = facade.invokeRuleGroupForSampeInputMap(xmlPath, groupId,
inputMap);
} catch (RuleException e) {
e.printStackTrace();
fail();
}
checkOutMap(outMap);
}
/**
* 验证输出参数,用于测试
*
* @param outMap
*/
private void checkOutMap(Map outMap) {
Rule1OutputParameter2Sample outPram2 = (Rule1OutputParameter2Sample) outMap
.get("rule1OutputParameter2Sample");
assertEquals(outPram2.getSex(), "male");
assertEquals(outPram2.isOk(), true);
}
}
这时再看自定义的listener
com.boco.eoms.commons.rule.sample.Rule1ListenerSample.java
public class Rule1ListenerSample implements IRuleListener {
private Logger logger = Logger.getLogger(this.getClass());
/**
* 执行规则后调用
*/
public void after(Map inputMap, Rule rule) throws RuleException {
logger.debug(rule.getId() + " after");
}
/**
* 执行规则前调用
*/
public void before(Map outputMap, Rule rule) throws RuleException {
logger.debug(rule.getId() + " before");
}
}
需要实现IRuleListener.java的after及before方法
ok,运行com.boco.eoms.commons.rule.RuleServiceFacadeTest.java测试用例。
晕了吧~,重新看下,OK,以上内容为自定义调用,下面说说表达式方式调用
以com.boco.eoms.commons.rule.test.service.ExpressionRuleServiceTest.java 为例测试表达式的规则
按com.boco.eoms.commons.rule.sample.ExpressionRuleSample.xml中配置
style=" ( $parameter != $l{springbean.getNames} || false ) && $text ? $r{springbean.getName} : 3 " />
className="com.boco.eoms.commons.rule.service.ExpressionRuleService"
id="ExpressionRule">
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
expression="#rule1InputParameter1Sample.age>5 && #rule1InputParameter1Sample.name=='qjb'?#rule1InputParameter1Sample.result:#rule1InputParameter1Sample.getStr(#rule1InputParameter1Sample.name)"
name="rule1OutputParameter1Sample"
type="java.lang.String"
drl="" expStyleId="" />
expression="#rule1InputParameter1Sample.age>5?#rule1InputParameter1Sample.setAge(5):#rule1InputParameter1Sample.setAge(6),#rule1InputParameter1Sample"
name="rule1OutputParameter2Sample"
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample"
drl="" expStyleId="" />
name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
运行com.boco.eoms.commons.rule.test.service.ExpressionRuleServiceTest.java测试用例
仔细看下测试用例,应该很好理解,
恭喜,恭喜,熟练掌握rule了吧?:-)
痛苦的再写下去,再说说rule的扩展吧~
基于rule去扩展是很简单的~
举个例子,其实表达式的支持,就是我扩展的一个类,看下
com.boco.eoms.commons.rule.service.ExpressionRuleService.java
public class ExpressionRuleService extends RuleService {
@Override
protected Map execute(Map inputMap,
Rule rule) throws RuleException {
// 创建表达式解析service
OgnlExpressionService oes = OgnlExpressionService.create(null);
Map outMap = new HashMap();
// 取输出参数
for (Iterator it = rule.getOutput().getParameters().iterator(); it
.hasNext();) {
Parameter para = (Parameter) it.next();
// 将输出参数配置的表达式结果按照配置名称写入outMap
outMap.put(para.getName(), oes.getValue(para.getExpression(),
inputMap));
}
return outMap;
}
/**
* @param ruleListeners
* @param rules
* @param rule
* @param xmlPath
*/
public ExpressionRuleService(List ruleListeners, RuleEngine rules,
Rule rule, String xmlPath) {
super(ruleListeners, rules, rule, xmlPath);
}
}
看下,没什么内容吧,只需继承RuleService,重写execute方法,在里面实现你的业务逻辑,
其实就是自定义规则,但也可以写成通用的呀。就像将来要扩展的drools一样,将来新增个
DroolsRuleService就OK了。这时在xml配置时,在className配置刚刚写的DroolsRuleService的类就OK了。
这样就实现了对drools的支持
className="com.boco.eoms.commons.rule.service.ExpressionRuleService"
id="ExpressionRule">
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter1Sample" />
type="com.boco.eoms.commons.rule.sample.Rule1InputParameter2Sample" />
再说说监听,有人说你的监听不是没用的吗,我要实现自定义业务逻辑,只需在execute方法最前端及后端加上我要在listener中要做的事,
这不一样能解决吗,OK,我们来看下,完全没错,可以解决,除非你想将listener的东西藕荷在业务逻辑,当然listener的before(),after()方法
不包含你的业务逻辑。再说下,若你不实现自定义规则呢,你怎么实现在before(),after()方法的内容呢,哈哈。再以一个例子说明,其实rule的
参数验证机制就是一个listener实现的,看一下com.boco.eoms.rule.listener.RuleCheckListener.java
public class RuleCheckListener implements IRuleListener {
public void after(Map map, Rule rule) throws RuleException {
// 取输入参数
for (Iterator outputIt = rule.getOutput().getParameters().iterator(); outputIt
.hasNext();) {
Parameter para = (Parameter) outputIt.next();
// 验证map中的所存的对象与xml配置是否相符
RuleConfigWrapper.checkMapType(map, para);
}
}
public void before(Map map, Rule rule) throws RuleException {
// 取输入参数
for (Iterator inputIt = rule.getInput().getParameters().iterator(); inputIt
.hasNext();) {
Parameter para = (Parameter) inputIt.next();
// 验证map中的所存的对象与xml配置是否相符
RuleConfigWrapper.checkMapType(map, para);
}
}
}
这就是输入/输出参数与xml配置的验证呀,呵呵~
OK,现在编写你的listenr吧
只需实现IRuleListener,并实现after(),befor()方法,
配置时在xml中配置,贴一段
name="com.boco.eoms.commons.rule.sample.Rule1ListenerSample" />
name="com.boco.eoms.commons.rule.listener.RuleCheckListener" />
很简单吧~
posted on 2007-04-28 09:49 曲静波 阅读(1199) 评论(0) 编辑 收藏 所属分类: others