一、背景

在咱们编写drl规定的时候,有些时候须要本人申明一些类,用于辅助之后的规定运行,如果须要用到的类还须要在java中事后申明进去,这样就不灵便了,那么是否能够在drl文件中申明一个类呢?能够应用drools的 Type declaration来实现。

二、前置常识

1、Type declaration语法结构

2、java代码中获取drl申明的类型

1、非枚举类型

KieBase kieBase = kieContainer.getKieBase("type-kabse");                                                // 规定文件的包名  申明的类型名FactType productOrderFactType = kieBase.getFactType("rules", "ProductOrder");Object instance = productOrderFactType.newInstance();productOrderFactType.set(instance, "orderId", 20220517121212001L);

2、获取枚举类型的值

须要通过反射来获取到。

KieBase kieBase = kieContainer.getKieBase("type-kabse");// 此处的FactType的实在类型是EnumClassDefinition,能够获取到枚举中构造方法的参数的值FactType orderStatusFactType = kieBase.getFactType("rules", "OrderStatus");// 获取drools中枚举的值Class<?> factClass = orderStatusFactType.getFactClass();Method method = factClass.getMethod("valueOf", String.class);Object pay = method.invoke(null, "PAY");

留神:
如果上方的代码看不懂,则接着往下看。

三、需要

1、在drl文件中申明一个枚举类型。
2、在drl文件中申明一个类。
3、在drl文件中申明一个类并实现继承操作。
4、编写rule并应用咱们自定义的type。
5、java中给在drl文件中申明的type赋值,包含类和枚举类型。

四、实现

1、在drl文件中申明一个枚举类型

// 申明一个枚举类型declare enum OrderStatus    CREATED(0, "新创建"),    PAY(1, "已领取"),    RECEIVED(2, "已接管");    status: Integer;    desc: String;end

语法结构: declare enum 枚举名字 end

2、在drl文件中申明一个类

// 申明一个类declare BaseOrder    orderId: Long  // 订单id    createdTime: Date // 工夫    item: ProductItem // java中定义的类    orderStatus: OrderStatus // 上方定义的枚举类型end

这个类中的每个属性都有一个类型,这个类型能够是曾经存在的fact,也能够是任何无效的Java类型。

3、在drl文件中申明一个类并实现继承操作

// 实现继承操作declare ProductOrder extends BaseOrder    userId: Long // 下单用户的idend

应用extends来实现继承操作。

4、编写rule并应用咱们自定义的type

// 定义一个规定,规定内存中存在ProductOrder并且 orderStatus是已领取userId==1001rule "rule_type"    no-loop true    when        $order: ProductOrder(userId == 1001 && orderStatus == OrderStatus.PAY)    then        String createdTime = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss")                                .format($order.getCreatedTime());        System.out.println("用户["+ $order.getUserId() +"]在["+ createdTime +"]购买的["+ $order.getItem().getItemName() +"]已实现付款");        modify($order){            setOrderStatus(OrderStatus.RECEIVED)        }end

解释:
1、如果规定内存中存在ProductOrder对象,并且userId的值是1001orderStatus的值是PAY则该规定被激活了。
2、当该规定激活时,批改订单的状态为RECEIVED,在java代码中获取批改后的值。

5、java中给在drl文件中申明的type赋值

@Slf4jpublic class DroolsTypeDeclareApplication {    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {        KieServices kieServices = KieServices.get();        KieContainer kieContainer = kieServices.getKieClasspathContainer();        KieSession kieSession = kieContainer.newKieSession("type-ksession");        kieSession.addEventListener(new DebugRuleRuntimeEventListener());        kieSession.addEventListener(new DebugAgendaEventListener());        kieSession.addEventListener(new DebugProcessEventListener());        KieBase kieBase = kieContainer.getKieBase("type-kabse");        FactType productOrderFactType = kieBase.getFactType("rules", "ProductOrder");        FactType orderStatusFactType = kieBase.getFactType("rules", "OrderStatus");        // 获取drools中枚举的值        Class<?> factClass = orderStatusFactType.getFactClass();        Method method = factClass.getMethod("valueOf", String.class);        Object pay = method.invoke(null, "PAY");        Object instance = productOrderFactType.newInstance();        ProductItem item = new ProductItem();        item.setItemName("iphone 13");        productOrderFactType.set(instance, "orderId", 20220517121212001L);        productOrderFactType.set(instance, "createdTime", new Date());        productOrderFactType.set(instance, "item", item);        productOrderFactType.set(instance, "orderStatus", pay);        productOrderFactType.set(instance, "userId", 1001L);        kieSession.insert(instance);        kieSession.fireAllRules();        Object orderStatus = productOrderFactType.get(instance, "orderStatus");        log.info("获取rule中批改之后的枚举字段的值:[{}]", orderStatus);        kieSession.dispose();    }}

留神:
1、在java中获取到drl文件中申明的类型,须要应用 kieBase.getFactType来获取。
2、如果须要获取到drl文件中申明的枚举类型的值,能够通过反射来获取。

6、运行上方的代码

用户[1001]在[2022-05-17 11:42:27]购买的[iphone 13]已实现付款11:42:27.724 [main] INFO com.huan.drools.querys.DroolsTypeDeclareApplication - 获取rule中批改之后的枚举字段的值:[RECEIVED]

能够看到规定执行了,并且java中也获取到了工作内存中批改后的值。

五、残缺代码

https://gitee.com/huan1993/spring-cloud-parent/tree/master/drools/drools-drl-type-declarations

六、参考链接

1、https://docs.drools.org/7.69.0.Final/drools-docs/html_single/index.html#drl-declarations-con_drl-rules