├── .gitignore ├── Drools-ComplexProblem.md ├── Drools-Example.md ├── Drools-Language.md ├── Drools-Use.md ├── README.md ├── pom.xml └── src ├── main ├── java │ └── com │ │ └── xu │ │ └── drools │ │ ├── DroolsSpringbootApplication.java │ │ ├── bean │ │ ├── Golfer.java │ │ ├── Hope.java │ │ ├── Message.java │ │ ├── Person.java │ │ ├── Politician.java │ │ ├── Rules.java │ │ ├── Student.java │ │ ├── World.java │ │ └── XiaoMing.java │ │ ├── common │ │ ├── bean │ │ │ └── ExceptionType.java │ │ ├── exception │ │ │ ├── BusinessException.java │ │ │ └── JsonResponse.java │ │ └── web │ │ │ └── JsonHandlerExceptionResolver.java │ │ ├── config │ │ └── DataSourceConfig.java │ │ ├── dao │ │ └── RulesDao.java │ │ ├── rule │ │ ├── complexProblem │ │ │ ├── GolferProblem.java │ │ │ ├── MingDrink.java │ │ │ └── WorldProblem.java │ │ ├── honestpolitician │ │ │ └── HonestPoliticianExample.java │ │ ├── rule1 │ │ │ └── rule1.java │ │ └── rule2 │ │ │ └── rule2.java │ │ ├── service │ │ ├── RuleTableService.java │ │ └── RulesService.java │ │ └── web │ │ ├── ComplexProblem.java │ │ └── RulesController.java └── resources │ ├── META-INF │ └── kmodule.xml │ ├── application.yml │ ├── com │ └── xu │ │ └── drools │ │ └── rule │ │ ├── complexProblem │ │ ├── golfer.drl │ │ ├── ming.drl │ │ └── world.drl │ │ ├── honestpolitician │ │ └── HonestPolitician.drl │ │ ├── rule1 │ │ └── rule1.drl │ │ └── rule2 │ │ └── rule2.drl │ ├── drools_rule.sql │ ├── log4j2.xml │ └── tables │ └── rule.xlsx └── test └── java └── com └── xu └── drools └── DroolsSpringbootApplicationTests.java /.gitignore: -------------------------------------------------------------------------------- 1 | target/ 2 | !.mvn/wrapper/maven-wrapper.jar 3 | 4 | ### STS ### 5 | .apt_generated 6 | .classpath 7 | .factorypath 8 | .project 9 | .settings 10 | .springBeans 11 | 12 | ### IntelliJ IDEA ### 13 | .idea 14 | *.iws 15 | *.iml 16 | *.ipr 17 | 18 | ### NetBeans ### 19 | nbproject/private/ 20 | build/ 21 | nbbuild/ 22 | dist/ 23 | nbdist/ 24 | .nb-gradle/ -------------------------------------------------------------------------------- /Drools-ComplexProblem.md: -------------------------------------------------------------------------------- 1 | ## Drools-Example 2 | 3 | 使用Drools来解决一些复杂的逻辑问题。 4 | 5 | ### MingDrink 6 | 7 | - problem 8 | 9 | 小明喝汽水问题: 10 | 11 | 1元钱一瓶汽水,喝完后两个空瓶换一瓶汽水,问:小明有20元钱,最多可以喝到几瓶汽水? 12 | - rule 13 | 14 | ``` 15 | package com.xu.drools 16 | 17 | import com.xu.drools.bean.XiaoMing; 18 | 19 | 20 | // 小明喝汽水问题 21 | // 1元钱一瓶汽水,喝完后两个空瓶换一瓶汽水,问:小明有20元钱,最多可以喝到几瓶汽水? 22 | // 规则1:1元钱一瓶汽水 23 | // 规则2:两个空瓶换一瓶汽水 24 | 25 | //规则1:1元钱一瓶汽水。有钱就买水,空瓶+1,钱-1,喝水+1; 26 | rule "rule1" 27 | salience 3 28 | when 29 | $m:XiaoMing(money>0); 30 | then 31 | System.out.println("有钱即可喝水,钱:"+$m.getMoney()); 32 | $m.setBottle($m.getBottle()+1); 33 | $m.setMoney($m.getMoney()-1); 34 | $m.setDrink($m.getDrink()+1); 35 | update($m) 36 | end 37 | 38 | //规则2:两个空瓶换一瓶汽水。有空瓶就换钱,空瓶-2,钱+1; 39 | rule "rule2" 40 | salience 2 41 | when 42 | $m:XiaoMing(bottle>=2); 43 | then 44 | System.out.println("有瓶子就换钱,瓶子:"+$m.getBottle()); 45 | $m.setBottle($m.getBottle()-2); 46 | $m.setMoney($m.getMoney()+1); 47 | update($m) 48 | end 49 | 50 | //规则3,打印已经喝掉的数量 51 | rule "rule3" 52 | salience 1 53 | when 54 | $m:XiaoMing(); 55 | then 56 | System.out.println("总共喝掉:"+$m.getDrink()); 57 | end 58 | ``` 59 | 60 | ### WorldProblem 61 | 62 | - problem 63 | 64 | 猜对错问题: 65 | 在一次数学竞赛中,获得前三名的同学是A,B,C. 老师对他们说:“祝贺你们,请你们猜一猜名次。” 66 | * 甲:“A是第二,C是第三.” 67 | * 乙:“A是第一,B是第三.” 68 | * 丙:“B是第二,A是第三.” 69 | 70 | `感觉有更好的方法,但是写不出规则来0.0` 71 | - rule 72 | 73 | ``` 74 | package com.xu.drools 75 | 76 | import com.xu.drools.bean.Student; 77 | import com.xu.drools.bean.World 78 | 79 | rule "find jia1" 80 | salience 2 81 | when 82 | $jia1 : Student(name == "jia",word1=="A",word2=="C",desc1=="2",desc2!="3") 83 | then 84 | insert( new World($jia1.getDesc1(),0,$jia1.getDesc2()) ); 85 | end 86 | 87 | rule "find jia2" 88 | salience 2 89 | when 90 | $jia2 : Student(name == "jia",word1=="A",word2=="C",desc1!="2",desc2=="3") 91 | then 92 | insert( new World($jia2.getDesc1(),0,$jia2.getDesc2()) ); 93 | end 94 | 95 | rule "find yi1" 96 | salience 3 97 | when 98 | $yi1 : Student(name == "yi",word1=="A",word2=="B",desc1=="1",desc2!="3"); 99 | $w : World(a==$yi1.getDesc1()) 100 | then 101 | $w.setB($yi1.getDesc2()); 102 | update($w) 103 | end 104 | 105 | rule "find yi2" 106 | salience 3 107 | when 108 | $yi2 : Student(name == "yi",word1=="A",word2=="B",desc1=="1",desc2!="3") 109 | $w : World(a==$yi2.getDesc1()) 110 | then 111 | $w.setB($yi2.getDesc2()); 112 | update($w) 113 | end 114 | 115 | 116 | rule "find bing1" 117 | salience 4 118 | when 119 | $bing1 : Student(name == "bing",word1=="A",word2=="B",desc1=="3",desc2!="2") 120 | $w : World(a==$bing1.getDesc1(),b==$bing1.getDesc2()) 121 | then 122 | System.out.println("-------"+$w.toString()); 123 | end 124 | 125 | 126 | rule "find bing2" 127 | salience 4 128 | when 129 | $bing2 : Student(name == "bing",word1=="A",word2=="B",desc1!="3",desc2=="2") 130 | $w : World(a==$bing2.getDesc1(),b==$bing2.getDesc2()) 131 | then 132 | System.out.println("-------"+$w.toString()); 133 | end 134 | ``` 135 | 136 | ### GolferProblem 137 | 138 | - problem 139 | 140 | 高尔夫球员站位问题: 141 | 142 | 已知有四个高尔夫球员,他们的名字是Fred,Joe,Bob,Tom; 143 | * 今天他们分别穿着红色,蓝色,橙色,以及格子衣服,并且他们按照从左往右的顺序站成一排。 144 | * 我们将最左边的位置定为1,最右边的位置定为4,中间依次是2,3位置。 145 | * 现在我们了解的情况是: 146 | * 1.高尔夫球员Fred,目前不知道他的位置和衣服颜色 147 | * 2.Fred右边紧挨着的球员穿蓝色衣服 148 | * 3.Joe排在第2个位置 149 | * 4.Bob穿着格子短裤 150 | * 5.Tom没有排在第1位或第4位,也没有穿橙色衣服 151 | * 请问,这四名球员的位置和衣服颜色。 152 | 153 | - rule 154 | 155 | ``` 156 | package com.xu.drools 157 | 158 | import com.xu.drools.bean.Golfer; 159 | 160 | rule "find solution" 161 | when 162 | //1.高尔夫球员Fred,目前不知道他的位置和衣服颜色 163 | $fred : Golfer( name == "Fred" ) 164 | 165 | //3.Joe排在第2个位置 166 | $joe : Golfer( name == "Joe", 167 | position == 2, 168 | position != $fred.position, 169 | color != $fred.color ) 170 | 171 | //4.Bob穿着格子短裤 172 | $bob : Golfer( name == "Bob", 173 | position != $fred.position, 174 | position != $joe.position, 175 | color == "plaid", 176 | color != $fred.color, 177 | color != $joe.color ) 178 | 179 | //5.Tom没有排在第1位或第4位,也没有穿橙色衣服 180 | $tom : Golfer( name == "Tom", 181 | position != 1, 182 | position != 4, 183 | position != $fred.position, 184 | position != $joe.position, 185 | position != $bob.position, 186 | color != "orange", 187 | color != $fred.color, 188 | color != $joe.color, 189 | color != $bob.color ) 190 | 191 | //2.Fred右边紧挨着的球员穿蓝色衣服 192 | Golfer( position == ( $fred.position + 1 ), 193 | color == "blue", 194 | this in ( $joe, $bob, $tom ) ) 195 | 196 | then 197 | System.out.println( "Fred " + $fred.getPosition() + " " + $fred.getColor() ); 198 | System.out.println( "Joe " + $joe.getPosition() + " " + $joe.getColor() ); 199 | System.out.println( "Bob " + $bob.getPosition() + " " + $bob.getColor() ); 200 | System.out.println( "Tom " + $tom.getPosition() + " " + $tom.getColor() ); 201 | end 202 | ``` -------------------------------------------------------------------------------- /Drools-Example.md: -------------------------------------------------------------------------------- 1 | ## Drools-Example 2 | 3 | ### Honest Politician 4 | 5 | - 使用kmodule的方式调用drools 6 | 创建文件:/resources/META-INF/kmodule.xml 7 | ``` 8 | 9 | 11 | 12 | 13 | 14 | 15 | ``` 16 | - rule 17 | ``` 18 | package com.xu.drools //package指定命名空间:com.xu.drools 19 | 20 | import com.xu.drools.bean.Politician; //import要使用的对象:Politician 21 | import com.xu.drools.bean.Hope; //import要使用的对象:Hope 22 | 23 | rule "We have an honest Politician" //rule,定义规则:We have an honest Politician 24 | salience 10 //salience,属性部分,定义优先级:10 25 | when 26 | exists( Politician( honest == true ) ) //exists,条件部分-LHS,定义当前规则的条件:存在honest==true的Politician 27 | then 28 | insertLogical( new Hope() ); //insertLogical,结果部分-RHS,定义规则满足后执行的操作:往当前workingMemory中插入一个新的Hope对象 29 | end //规则结束 30 | 31 | rule "Hope Lives" 32 | salience 10 33 | when 34 | exists( Hope() ) 35 | then 36 | System.out.println("Hurrah!!! Democracy Lives"); 37 | end 38 | 39 | rule "Hope is Dead" 40 | when 41 | not( Hope() ) //not,不存在:不存在Hope对象 42 | then 43 | System.out.println( "We are all Doomed!!! Democracy is Dead" ); 44 | end 45 | 46 | rule "Corrupt the Honest" 47 | when 48 | politician : Politician( honest == true ) 49 | exists( Hope() ) 50 | then 51 | System.out.println( "I'm an evil corporation and I have corrupted " + politician.getName() ); 52 | modify( politician ) { //modify,修改:修改politician的Honest为false 53 | setHonest( false ) 54 | } 55 | end 56 | ``` 57 | - 数据的输入 58 | 59 | ``` 60 | public static void main(final String[] args) { 61 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 62 | System.out.println(kc.verify().getMessages().toString()); 63 | execute( kc ); 64 | } 65 | 66 | public static void execute( KieContainer kc ) { 67 | KieSession ksession = kc.newKieSession("HonestPoliticianKS"); 68 | 69 | final Politician p1 = new Politician( "President of Umpa Lumpa", true ); 70 | final Politician p2 = new Politician( "Prime Minster of Cheeseland", true ); 71 | final Politician p3 = new Politician( "Tsar of Pringapopaloo", true ); 72 | final Politician p4 = new Politician( "Omnipotence Om", true ); 73 | 74 | ksession.insert( p1 ); 75 | ksession.insert( p2 ); 76 | ksession.insert( p3 ); 77 | ksession.insert( p4 ); 78 | 79 | ksession.fireAllRules(); 80 | 81 | ksession.dispose(); 82 | } 83 | ``` 84 | - rule的执行顺序 85 | 86 | http://cdn.heroxu.com/20190829156706732481281.png 87 | 88 | ![](http://cdn.heroxu.com/20190829156706732481281.png) 89 | 90 | - 执行结果 91 | ``` 92 | Hurrah!!! Democracy Lives 93 | I'm an evil corporation and I have corrupted President of Umpa Lumpa 94 | I'm an evil corporation and I have corrupted Prime Minster of Cheeseland 95 | I'm an evil corporation and I have corrupted Tsar of Pringapopaloo 96 | I'm an evil corporation and I have corrupted Omnipotence Om 97 | We are all Doomed!!! Democracy is Dead 98 | ``` 99 | -------------------------------------------------------------------------------- /Drools-Language.md: -------------------------------------------------------------------------------- 1 | [toc] 2 | ## Drools语法-Language 3 | ### 关键词 4 | - Hard keywords(Cannot use any): 5 | 6 | `true,false,null` 7 | - Soft keywords(avoid use) 8 | 9 | `lock-on-active date-effective date-expires no-loop auto-focus activation-group agenda-group ruleflow-group entry-point duration package import dialect salience enabled attributes rule extend when then template query declare function global eval not in or and exists forall accumulate collect from action reverse result end over init` 10 | 11 | ### 注释 12 | - 单行注释 13 | 14 | ``` 15 | rule "Testing Comments" 16 | when 17 | // this is a single line comment 18 | eval( true ) // this is a comment in the same line of a pattern 19 | then 20 | // this is a comment inside a semantic code block 21 | end 22 | ``` 23 | - 多行注释 24 | 25 | ``` 26 | rule "Test Multi-line Comments" 27 | when 28 | /* this is a multi-line comment 29 | in the left hand side of a rule */ 30 | eval( true ) 31 | then 32 | /* and this is a multi-line comment 33 | in the right hand side of a rule */ 34 | end 35 | ``` 36 | 37 | ### Pakage 38 | - package 39 | 40 | `package`表示一个命名空间.package是必须定义的,必须放在规则文件第一行. 41 | - import 42 | 43 | `import`语句的工作方式类似于Java中的import语句。您需要为要在规则中使用的任何对象指定完全限定路径和类型名称。 44 | - global 45 | 46 | `global`用于定义全局变量。 47 | 48 | Rules: 49 | ``` 50 | global java.util.List myGlobalList; 51 | 52 | rule "Using a global" 53 | when 54 | eval( true ) 55 | then 56 | myGlobalList.add( "Hello World" ); 57 | end 58 | ``` 59 | Set the global value: 60 | ``` 61 | List list = new ArrayList(); 62 | KieSession kieSession = kiebase.newKieSession(); 63 | kieSession.setGlobal( "myGlobalList", list ); 64 | ``` 65 | 66 | ### Function 67 | - function 68 | 69 | `function`是一种将语义代码放置在规则源文件中的方法,而不是普通的Java类 70 | ``` 71 | function String hello(String name) { 72 | return "Hello "+name+"!"; 73 | } 74 | import function my.package.Foo.hello 75 | rule "using a static function" 76 | when 77 | eval( true ) 78 | then 79 | System.out.println( hello( "Bob" ) ); 80 | end 81 | ``` 82 | 83 | ### Query 84 | - query 85 | 86 | `query`是一种搜索工作内存中与指定条件匹配的事实的简单方法. 87 | ``` 88 | 对所有30岁以上的人的简单查询 89 | query "people over the age of 30" 90 | person : Person( age > 30 ) 91 | end 92 | 93 | 查询超过x岁的人,以及居住在y的人 94 | query "people over the age of x" (int x, String y) 95 | person : Person( age > x, location == y ) 96 | end 97 | 98 | QueryResults results = ksession.getQueryResults( "people over the age of 30" ); 99 | System.out.println( "we have " + results.size() + " people over the age of 30" ); 100 | 101 | System.out.println( "These people are are over 30:" ); 102 | 103 | for ( QueryResultsRow row : results ) { 104 | Person person = ( Person ) row.get( "person" ); 105 | System.out.println( person.getName() + "\n" ); 106 | } 107 | ``` 108 | 109 | ### Rule 110 | 111 | `rule`定义规则。`rule "ruleName"`。 112 | 113 | 一个规则可以包含三个部分:属性部分,条件部分:即`LHS`,结果部分:即`RHS`. 114 | ![](http://of0qa2hzs.bkt.clouddn.com/rule.jpg) 115 | 116 | #### 属性部分-Attributes 117 | 118 | 定义当前规则执行的一些属性等,比如是否可被重复执行、过期时间、生效时间等。 119 | `activation-group` `agenda-group` `auto-focus` `date-effective` `date-expires` `dialect` `duration` `duration-value` `enabled` `lock-on-active` `no-loop` `ruleflow-group` `salience` 120 | 121 | ![](http://of0qa2hzs.bkt.clouddn.com/1484118982%281%29.jpg) 122 | 123 | - no-loop 124 | 125 | 默认值:false 126 | 127 | 类型:Boolean 128 | 129 | 在一个规则当中如果条件满足就对`Working Memory`当中的某个Fact对象进行了修改,比如使用update 将其更新到当前的`Working Memory`当中,这时引擎会再次检查所有的规则是否满足条件,如果满足会再次执行. 130 | - ruleflow-group 131 | 132 | 默认值:N/A 133 | 134 | 类型:String 135 | 136 | `Ruleflow`是一个Drools功能,可让您控制规则的触发。由相同的规则流组标识汇编的规则仅在其组处于活动状态时触发。将规则划分为一个个的组,然后在规则流当中通过使用`ruleflow-group`属性的值,从而使用对应的规则。 137 | - lock-on-active 138 | 139 | 默认值:false 140 | 141 | 类型:Boolean 142 | 143 | 当在规则上使用`ruleflow-group` 属性或`agenda-group` 属性的时候,将`lock-on-action` 属性的值设置为true,可能避免因某些Fact 对象被修改而使已经执行过的规则再次被激活执行。可以看出该属性与`no-loop` 属性有相似之处,`no-loop` 属性是为了避免Fact 修改或调用了`insert`、`retract`、`update` 之类而导致规则再次激活执行,这里的`lock-on-action` 属性也是起这个作用,`lock-on-active` 是`no-loop` 的增强版属性,它主要作用在使用`ruleflow-group` 属性或`agenda-group` 属性的时候 144 | 145 | - salience 146 | 147 | 默认值:0 148 | 149 | 类型:integer 150 | 151 | 设置规则执行的优先级,`salience` 属性的值是一个数字,数字越大执行优先级越高,同时它的值可以是一个负数. 152 | 规则的`salience` 默认值为0,所以如果我们不手动设置规则的`salience` 属性,那么它的执行顺序是随机的. 153 | 154 | - agenda-group 155 | 156 | 默认值:MAIN 157 | 158 | 类型:String 159 | 160 | 规则的调用与执行是通过`StatelessSession` 或`StatefulSession` 来实现的,一般的顺序是创建一个`StatelessSession` 或`StatefulSession`,将各种经过编译的规则的package 添加到session当中,接下来将规则当中可能用到的Global对象和Fact对象插入到Session 当中,最后调用fireAllRules 方法来触发、执行规则。在没有调用最后一步`fireAllRules`方法之前,所有的规则及插入的`Fact`对象都存放在一个名叫`Agenda`表的对象当中,这个`Agenda`表中每一个规则及与其匹配相关业务数据叫做`Activation`,在调用`fireAllRules`方法后,这些Activation 会依次执行,这些位于Agenda 表中的Activation 的执行顺序在没有设置相关用来控制顺序的属性时(比如salience 属性),它的执行顺序是随机的,不确定的。`Agenda Group` 是用来在Agenda 的基础之上,对现在的规则进行再次分组,具体的分组方法可以采用为规则添加`agenda-group`属性来实现。`agenda-group` 属性的值也是一个字符串,通过这个字符串,可以将规则分为若干个`Agenda Group`,默认情况下,引擎在调用这些设置了`agenda-group` 属性的规则的时候需要显示的指定某个`Agenda Group` 得到`Focus`(焦点),这样位于该`Agenda Group` 当中的规则才会触发执行,否则将不执行。 161 | 162 | - auto-focus 163 | 164 | 默认值:false 165 | 166 | 类型:Boolean 167 | 168 | 用来在已设置了`agenda-group`的规则上设置该规则是否可以自动独取`Focus`,如果该属性设置为true,那么在引擎执行时,就不需要显示的为某个`Agenda Group`设置`Focus`,否则需要。对于规则的执行的控制,还可以使用`Agenda Filter` 来实现。在Drools 当中,提供了一个名为`org.drools.runtime.rule.AgendaFilter 的Agenda Filter` 接口,用户可以实现该接口,通过规则当中的某些属性来控制规则要不要执行。`org.drools.runtime.rule.AgendaFilter` 接口只有一个方法需要实现,方法体如下: ` public boolean accept(Activation activation);` 在该方法当中提供了一个`Activation` 参数,通过该参数我们可以得到当前正在执行的规则对象或其它一些属性,该方法要返回一个布尔值,该布尔值就决定了要不要执行当前这个规则,返回true 就执行规则,否则就不执行。 169 | 170 | - activation-group 171 | 172 | 默认值:N/A 173 | 174 | 类型:String 175 | 176 | 该属性的作用是将若干个规则划分成一个组,用一个字符串来给这个组命名,这样在执行的时候,具有相同`activation-group`属性的规则中只要有一个会被执行,其它的规则都将不再执行。也就是说,在一组具有相同`activation-group`属性的规则当中,只有一个规则会被执行,其它规则都将不会被执行。当然对于具有相同`activation-group`属性的规则当中究竟哪一个会先执行,则可以用类似`salience`之类属性来实现。 177 | 178 | - dialect 179 | 180 | 默认值: 根据package指定 181 | 182 | 类型:String,"java" or "mvel" 183 | 184 | `dialect`种类是用于LHS或RHS代码块中的任何代码表达式的语言。目前有两种`dialect`,`Java`和`MVEL`。虽然`dialect`可以在包级别指定,但此属性允许为规则覆盖包定义。 185 | 186 | - date-effective 187 | 188 | 默认值:N/A 189 | 190 | 类型:字符串,包含日期和时间定义。格式:`dd-MMM-yyyy`(25-Sep-2009). 191 | 192 | 仅当当前日期和时间在日期有效属性后面时,才能激活规则。 193 | - date-expires 194 | 195 | 默认值:N/A 196 | 197 | 类型:字符串,包含日期和时间定义。格式:`dd-MMM-yyyy`(25-Sep-2009). 198 | 199 | 如果当前日期和时间在`date-expires`属性之后,则无法激活规则. 200 | - enabled 201 | 202 | 默认值:false 203 | 204 | 类型:String 205 | 206 | 表示规则是可用的,如果手工为一个规则添加一个`enabled`属性,并且设置其`enabled`属性值为false,那么引擎就不会执行该规则. 207 | 208 | - duration 209 | 210 | 默认值:无 211 | 212 | 类型:long 213 | 214 | 持续时间指示规则将在指定的持续时间之后触发,如果它仍然是true. 215 | 216 | #### 条件部分-LHS 217 | 218 | 定义当前规则的条件,如`when Message()`; 判断当前workingMemory中是否存在Message对象。 219 | 220 | `Left Hand Side`(`LHS`)是规则的条件部分的公共名称。它由零个或多个条件元素组成。 221 | 如果LHS为空,它将被认为是一个条件元素,它总是为真,并且当创建一个新的WorkingMemory会话时,它将被激活一次。 222 | ``` 223 | Conditions / LHS —匹配模式(Patterns) 224 | 225 | 没有字段约束的Pattern 226 | Person() 227 | 228 | 有文本字段约束的Pattern 229 | Person( name == “bob” ) 230 | 231 | 字段绑定的Pattern 232 | Person( $name : name == “bob” ) 233 | 变量名称可以是任何合法的java变量,$是可选的,可由于区分字段和变量 234 | 235 | Fact绑定的Pattern 236 | $bob : Person( name == “bob” )字段绑定的Pattern 237 | 238 | 变量约束的Pattern 239 | Person( name == $name ) 240 | ``` 241 | 242 | Drools提供了十二种类型比较操作符: 243 | `>` `>=` `<` `<=` `==` `!=` `contains` `not contains` `memberOf` `not memberOf` `matches` `not matches` 244 | 245 | - contains 246 | 247 | 运算符`contains`用于检查作为Collection或elements的字段是否包含指定的值. 248 | ``` 249 | Cheese( name contains "tilto" ) 250 | Person( fullName contains "Jr" ) 251 | String( this contains "foo" ) 252 | ``` 253 | - not contains 254 | 255 | 和`contains`相反 256 | 257 | - memberOf 258 | 259 | 运算符`memberOf`用于检查字段是否是集合的成员或元素;该集合必须是一个变量。 260 | ``` 261 | CheeseCounter( cheese memberOf $matureCheeses ) 262 | ``` 263 | - not memberOf 264 | 265 | 和`memberOf`相反 266 | 267 | - matches 268 | 269 | 正则表达式匹配,与java不同的是,不用考虑'/'的转义问题 270 | ``` 271 | Cheese( type matches "(Buffalo)?\\S*Mozarella" ) 272 | ``` 273 | - not matches 274 | 275 | 和`matches`相反 276 | 277 | 其他条件元素: 278 | - exists 279 | 280 | 存在。检查Working Memory是否存在某物。使用模式`exists`,则规则将只激活最多一次,而不管在工作存储器中存在与存在模式中的条件匹配的数据量 281 | 282 | - not 283 | 284 | 不存在,检查工作存储器中是否存在某物。认为“`not`”意味着“`there must be none of...`”。 285 | 286 | #### 结果部分-RHS 287 | 288 | 这里可以写普通java代码,即当前规则条件满足后执行的操作,可以直接调用Fact对象的方法来操作应用。 289 | 290 | `Right Hand Side`(`RHS`)是规则的结果或动作部分的通用名称;此部分应包含要执行的操作的列表。在规则的RHS中使用命令式或条件式代码是不好的做法;作为一个规则应该是`原子`的性质 - “`when this, then do this`”,而不是“`when this, maybe do this`”。规则的RHS部分也应该保持较小,从而保持声明性和可读性。如果你发现你需要在RHS中的命令式和/或条件代码,那么也许你应该把这个规则分成多个规则。 `RHS`的主要目的是插入,删除或修改工作存储器数据。为了协助,有一些方便的方法可以用来修改工作记忆;而不必首先引用工作内存实例。 291 | 292 | - update 293 | 294 | 更新,告诉引擎对象已经改变(已经绑定到LHS上的某个东西),并且规则可能需要重新考虑。 295 | - insert(new Something()) 296 | 297 | 插入,往当前`workingMemory`中插入一个新的Fact对象,会触发规则的再次执行,除非使用`no-loop`限定; 298 | 299 | - insertLogical(new Something()) 300 | 301 | 类似于`insert`,但是当没有更多的facts支持当前触发规则的真实性时,对象将被自动删除。 302 | - modify 303 | 304 | 修改,与`update`语法不同,结果都是更新操作。该语言扩展提供了一种结构化的方法来更新事实。它将更新操作与一些setter调用相结合来更改对象的字段。 305 | - retract 306 | 307 | 删除 308 | 309 | 一些内置的method。 310 | 311 | - drools.halt() 312 | 313 | 调用`drools.halt()`立即终止规则执行。这是需要将控制权返回到当前会话使用`fireUntilHalt()`的点。 314 | - drools.getWorkingMemory() 315 | 316 | 返回WorkingMemory对象. 317 | - drools.setFocus( String s) 318 | 319 | 将焦点设置为指定的`agenda group`. 320 | - drools.getRule().getName() 321 | 322 | 从规则的RHS调用,返回规则的名称。 323 | - drools.getTuple() 324 | 325 | 返回与当前执行的规则匹配的`Tuple`,而drools.getActivation()传递相应的激活。 326 | -------------------------------------------------------------------------------- /Drools-Use.md: -------------------------------------------------------------------------------- 1 | ## Drools应用 2 | 3 | ### 动态规则 4 | 5 | #### 动态获取KieSession 6 | ``` 7 | public KieSession getKieSession(String rules) { 8 | KieServices kieServices = KieServices.Factory.get(); 9 | KieFileSystem kfs = kieServices.newKieFileSystem(); 10 | kfs.write("src/main/resources/rules/rules.drl", rules.getBytes()); 11 | KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); 12 | Results results = kieBuilder.getResults(); 13 | if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) { 14 | System.out.println(results.getMessages()); 15 | throw new BusinessException(300003,results.getMessages().toString(),4); 16 | } 17 | KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()); 18 | KieBase kieBase = kieContainer.getKieBase(); 19 | 20 | return kieBase.newKieSession(); 21 | } 22 | ``` 23 | #### 激活规则 24 | ``` 25 | KieSession kieSession = rulesService.getKieSession(rule); 26 | Gson gson = new Gson(); 27 | Person person = gson.fromJson(json, Person.class); 28 | kieSession.insert(person); 29 | kieSession.fireAllRules(); 30 | kieSession.dispose(); 31 | ``` 32 | 33 | ### 决策表 34 | 35 | #### 将文件翻译为drl文件 36 | ``` 37 | public String getRuleTable() { 38 | //把excel翻译成drl文件 39 | SpreadsheetCompiler compiler = new SpreadsheetCompiler(); 40 | String rules = compiler.compile(ResourceFactory.newClassPathResource(RULES_PATH + File.separator + "rule.xlsx", "UTF-8"), "rule-table"); 41 | System.out.println(rules); 42 | return rules; 43 | } 44 | ``` 45 | #### 将文件流翻译为drl文件 46 | ``` 47 | public String getRuleTable(InputStream inputStream) { 48 | //把excel翻译成drl文件 49 | SpreadsheetCompiler compiler = new SpreadsheetCompiler(); 50 | String rules = compiler.compile(ResourceFactory.newInputStreamResource(inputStream, "UTF-8"), "rule-table"); 51 | logger.info("get rule from xls:" + rules); 52 | return rules; 53 | } 54 | ``` -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # drools-spring-boot 2 | 3 | 规则引擎Drools与SpringBoot的使用 4 | 5 | ## SpringBoot与Drools 6 | 7 | #### SpringBoot项目 8 | 略 9 | #### Drools 10 | - 依赖 11 | ``` 12 | 6.5.0.Final 13 | 14 | 15 | org.kie 16 | kie-api 17 | ${drools.version} 18 | 19 | 20 | org.drools 21 | drools-core 22 | ${drools.version} 23 | 24 | 25 | org.drools 26 | drools-compiler 27 | ${drools.version} 28 | 29 | 30 | org.drools 31 | drools-decisiontables 32 | ${drools.version} 33 | 34 | 35 | org.drools 36 | drools-templates 37 | ${drools.version} 38 | 39 | ``` 40 | 41 | 42 | ## Drools 43 | 44 | - 规则 45 | [Drools-Language](https://github.com/MyHerux/drools-springboot/blob/master/Drools-Language.md) 46 | 47 | - Rule示例 48 | [Drools-Example](https://github.com/MyHerux/drools-springboot/blob/master/Drools-Example.md) 49 | 50 | - Drools动态规则与决策表 51 | [Drools-Use](https://github.com/MyHerux/drools-springboot/blob/master/Drools-Use.md) 52 | 53 | - Drools解决复杂逻辑问题 54 | [Drools-ComplexProblem](https://github.com/MyHerux/drools-springboot/blob/master/Drools-ComplexProblem.md) 55 | -------------------------------------------------------------------------------- /pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.xu 7 | drools-springboot 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | drools-springboot 12 | Demo project for Spring Boot 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.4.3.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | UTF-8 24 | 1.8 25 | 26 | com.xu.drools.DroolsSpringbootApplication 27 | 28 | 6.5.0.Final 29 | 1.0.18 30 | 3.4.1 31 | 1.1.1 32 | 33 | 34 | 35 | 36 | 37 | org.kie 38 | kie-api 39 | ${drools.version} 40 | 41 | 42 | org.drools 43 | drools-core 44 | ${drools.version} 45 | 46 | 47 | org.drools 48 | drools-compiler 49 | ${drools.version} 50 | 51 | 52 | org.drools 53 | drools-decisiontables 54 | ${drools.version} 55 | 56 | 57 | org.drools 58 | drools-templates 59 | ${drools.version} 60 | 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter 66 | 67 | 68 | org.springframework.boot 69 | spring-boot-starter-logging 70 | 71 | 72 | 73 | 74 | 75 | 76 | org.springframework.boot 77 | spring-boot-starter-log4j2 78 | 79 | 80 | 81 | org.springframework.boot 82 | spring-boot-starter-aop 83 | 84 | 85 | org.springframework.boot 86 | spring-boot-starter-web 87 | 88 | 89 | org.springframework.boot 90 | spring-boot-starter-tomcat 91 | 92 | 93 | org.apache.tomcat.embed 94 | tomcat-embed-jasper 95 | 96 | 97 | 98 | 99 | mysql 100 | mysql-connector-java 101 | 102 | 103 | org.apache.tomcat 104 | tomcat-jdbc 105 | 106 | 107 | com.alibaba 108 | druid 109 | ${druid.version} 110 | 111 | 112 | org.mybatis 113 | mybatis 114 | ${mybatis.version} 115 | 116 | 117 | 118 | org.mybatis.spring.boot 119 | mybatis-spring-boot-starter 120 | ${mybatis-spring-boot.version} 121 | 122 | 123 | 124 | 125 | com.hynnet 126 | json-lib 127 | 2.4 128 | 129 | 130 | com.google.code.gson 131 | gson 132 | 133 | 134 | 135 | 136 | io.springfox 137 | springfox-swagger2 138 | 2.5.0 139 | 140 | 141 | io.springfox 142 | springfox-swagger-ui 143 | 2.5.0 144 | 145 | 146 | 147 | org.springframework.boot 148 | spring-boot-starter-test 149 | test 150 | 151 | 152 | org.springframework 153 | spring-jdbc 154 | 5.0.0.BUILD-SNAPSHOT 155 | 156 | 157 | 158 | 159 | 160 | spring-snapshots 161 | http://repo.spring.io/libs-snapshot 162 | 163 | 164 | 165 | 166 | 167 | spring-snapshots 168 | http://repo.spring.io/libs-snapshot 169 | 170 | 171 | 172 | 173 | 174 | fullProfile 175 | 176 | 177 | full 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | org.springframework.boot 187 | spring-boot-maven-plugin 188 | 189 | ${start-class} 190 | 191 | 192 | 193 | 194 | repackage 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/DroolsSpringbootApplication.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools; 2 | 3 | import org.springframework.boot.SpringApplication; 4 | import org.springframework.boot.autoconfigure.SpringBootApplication; 5 | import org.springframework.context.annotation.ComponentScan; 6 | import org.springframework.scheduling.annotation.EnableScheduling; 7 | import springfox.documentation.swagger2.annotations.EnableSwagger2; 8 | 9 | @SpringBootApplication 10 | @ComponentScan(basePackages ="com.xu.drools") 11 | @EnableScheduling 12 | @EnableSwagger2 13 | public class DroolsSpringbootApplication { 14 | 15 | public static void main(String[] args) { 16 | SpringApplication.run(DroolsSpringbootApplication.class, args); 17 | } 18 | 19 | } 20 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Golfer.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | public class Golfer{ 4 | 5 | private String name; 6 | private String color; 7 | private int position; 8 | 9 | public Golfer(String name, String color, int position) { 10 | this.name = name; 11 | this.color = color; 12 | this.position = position; 13 | } 14 | 15 | public String getName() { 16 | return name; 17 | } 18 | 19 | public void setName(String name) { 20 | this.name = name; 21 | } 22 | 23 | public String getColor() { 24 | return color; 25 | } 26 | 27 | public void setColor(String color) { 28 | this.color = color; 29 | } 30 | 31 | public int getPosition() { 32 | return position; 33 | } 34 | 35 | public void setPosition(int position) { 36 | this.position = position; 37 | } 38 | } -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Hope.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | public class Hope { 4 | 5 | public Hope() { 6 | 7 | } 8 | 9 | } 10 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Message.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | import java.io.Serializable; 4 | 5 | public class Message implements Serializable{ 6 | 7 | private static final long serialVersionUID = 1L; 8 | 9 | private String status; 10 | 11 | public String getStatus() { 12 | return status; 13 | } 14 | 15 | public void setStatus(String status) { 16 | this.status = status; 17 | } 18 | 19 | } -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Person.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | 4 | import java.io.Serializable; 5 | 6 | public class Person implements Serializable { 7 | 8 | private static final long serialVersionUID = 1L; 9 | 10 | private Integer age; 11 | 12 | private String name; 13 | 14 | private String desc; 15 | 16 | 17 | 18 | public Person() { 19 | } 20 | 21 | public Person(Integer age, String name, String desc) { 22 | this.age = age; 23 | this.name = name; 24 | this.desc = desc; 25 | } 26 | 27 | public Integer getAge() { 28 | return age; 29 | } 30 | 31 | public void setAge(Integer age) { 32 | this.age = age; 33 | } 34 | 35 | public String getName() { 36 | return name; 37 | } 38 | 39 | public void setName(String name) { 40 | this.name = name; 41 | } 42 | 43 | public String getDesc() { 44 | return desc; 45 | } 46 | 47 | public void setDesc(String desc) { 48 | this.desc = desc; 49 | } 50 | 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Politician.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | public class Politician { 4 | private String name; 5 | 6 | private boolean honest; 7 | 8 | public Politician() { 9 | 10 | } 11 | 12 | public Politician(String name, 13 | boolean honest) { 14 | super(); 15 | this.name = name; 16 | this.honest = honest; 17 | } 18 | 19 | public boolean isHonest() { 20 | return honest; 21 | } 22 | 23 | public void setHonest(boolean honest) { 24 | this.honest = honest; 25 | } 26 | 27 | public String getName() { 28 | return name; 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Rules.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | 4 | import java.util.Date; 5 | 6 | public class Rules { 7 | 8 | private Integer id; 9 | private String rule; 10 | private String name; 11 | private Date create_time; 12 | private Date update_time; 13 | private Integer visible; 14 | 15 | public String getRule() { 16 | return rule; 17 | } 18 | 19 | public void setRule(String rule) { 20 | this.rule = rule; 21 | } 22 | public String getName() { 23 | return name; 24 | } 25 | 26 | public void setName(String name) { 27 | this.name = name; 28 | } 29 | 30 | public Integer getId() { 31 | return id; 32 | } 33 | 34 | public void setId(Integer id) { 35 | this.id = id; 36 | } 37 | 38 | public Integer getVisible() { 39 | return visible; 40 | } 41 | 42 | public void setVisible(Integer visible) { 43 | this.visible = visible; 44 | } 45 | 46 | public Date getUpdate_time() { 47 | return update_time; 48 | } 49 | 50 | public void setUpdate_time(Date update_time) { 51 | this.update_time = update_time; 52 | } 53 | 54 | public Date getCreate_time() { 55 | return create_time; 56 | } 57 | 58 | public void setCreate_time(Date create_time) { 59 | this.create_time = create_time; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/Student.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | /** 4 | * Created by xu on 2017/6/5. 5 | */ 6 | public class Student { 7 | private String name; 8 | private String word1; 9 | private String word2; 10 | private Integer desc1; 11 | private Integer desc2; 12 | 13 | public Student(String name, String word1, String word2, Integer desc1, Integer desc2) { 14 | this.name = name; 15 | this.word1 = word1; 16 | this.word2 = word2; 17 | this.desc1 = desc1; 18 | this.desc2 = desc2; 19 | } 20 | 21 | public String getName() { 22 | return name; 23 | } 24 | 25 | public void setName(String name) { 26 | this.name = name; 27 | } 28 | 29 | public String getWord1() { 30 | return word1; 31 | } 32 | 33 | public void setWord1(String word1) { 34 | this.word1 = word1; 35 | } 36 | 37 | public String getWord2() { 38 | return word2; 39 | } 40 | 41 | public void setWord2(String word2) { 42 | this.word2 = word2; 43 | } 44 | 45 | public Integer getDesc1() { 46 | return desc1; 47 | } 48 | 49 | public void setDesc1(Integer desc1) { 50 | this.desc1 = desc1; 51 | } 52 | 53 | public Integer getDesc2() { 54 | return desc2; 55 | } 56 | 57 | public void setDesc2(Integer desc2) { 58 | this.desc2 = desc2; 59 | } 60 | 61 | 62 | @Override 63 | public String toString() { 64 | return "Student{" + 65 | "name='" + name + '\'' + 66 | ", word1='" + word1 + '\'' + 67 | ", word2='" + word2 + '\'' + 68 | ", desc1=" + desc1 + 69 | ", desc2=" + desc2 + 70 | '}'; 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/World.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | /** 4 | * Created by xu on 2017/6/6. 5 | */ 6 | public class World { 7 | private Integer a; 8 | private Integer b; 9 | private Integer c; 10 | 11 | public World(Integer a, Integer b, Integer c) { 12 | this.a = a; 13 | this.b = b; 14 | this.c = c; 15 | } 16 | 17 | public Integer getA() { 18 | return a; 19 | } 20 | 21 | public void setA(Integer a) { 22 | this.a = a; 23 | } 24 | 25 | public Integer getB() { 26 | return b; 27 | } 28 | 29 | public void setB(Integer b) { 30 | this.b = b; 31 | } 32 | 33 | public Integer getC() { 34 | return c; 35 | } 36 | 37 | public void setC(Integer c) { 38 | this.c = c; 39 | } 40 | 41 | @Override 42 | public String toString() { 43 | return "World{" + 44 | "a=" + a + 45 | ", b=" + b + 46 | ", c=" + c + 47 | '}'; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/bean/XiaoMing.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.bean; 2 | 3 | /** 4 | * Created by xu on 2017/6/5. 5 | * 小明喝水问题中的小明 6 | */ 7 | public class XiaoMing { 8 | 9 | //总共的钱 10 | private int money; 11 | //空瓶子数目 12 | private int bottle; 13 | //已经喝掉的汽水 14 | private int drink; 15 | 16 | public int getMoney() { 17 | return money; 18 | } 19 | 20 | public void setMoney(int money) { 21 | this.money = money; 22 | } 23 | 24 | public int getBottle() { 25 | return bottle; 26 | } 27 | 28 | public void setBottle(int bottle) { 29 | this.bottle = bottle; 30 | } 31 | 32 | public int getDrink() { 33 | return drink; 34 | } 35 | 36 | public void setDrink(int drink) { 37 | this.drink = drink; 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/common/bean/ExceptionType.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.common.bean; 2 | 3 | /** 4 | * Enum 响应类型 5 | * 6 | * @date 16/08/01 7 | * @auther hua xu 8 | */ 9 | public enum ExceptionType { 10 | SUCCESS(200, "success",2), 11 | SYSTEM_ERROR(300001, "系统错误", 5), 12 | RULE_IS_NULL(300002, "系统错误", 2), 13 | RULE_IS_ERROR(300003, "规则语句错误", 2); 14 | 15 | private int code; 16 | private String message; 17 | private int level; 18 | 19 | ExceptionType(int code, String message, int level) { 20 | this.code = code; 21 | this.message = message; 22 | this.level = level; 23 | } 24 | 25 | public int getCode() { 26 | return code; 27 | } 28 | 29 | public String getMessage() { 30 | return message; 31 | } 32 | 33 | public int getLevel() { 34 | return level; 35 | } 36 | } 37 | 38 | 39 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/common/exception/BusinessException.java: -------------------------------------------------------------------------------- 1 | 2 | package com.xu.drools.common.exception; 3 | 4 | 5 | import com.xu.drools.common.bean.ExceptionType; 6 | 7 | /** 8 | * 业务异常 9 | * 10 | * @author xuhua 11 | * @since 1.0.0 12 | */ 13 | public class BusinessException extends RuntimeException { 14 | 15 | private int code; 16 | 17 | private String message; 18 | 19 | private int level; 20 | 21 | public BusinessException(ExceptionType exceptionType) { 22 | this.code = exceptionType.getCode(); 23 | this.message = exceptionType.getMessage(); 24 | this.level = exceptionType.getLevel(); 25 | } 26 | 27 | public BusinessException(int code, String message, int level) { 28 | this.code = code; 29 | this.message = message; 30 | this.level = level; 31 | } 32 | 33 | public int getCode() { 34 | return code; 35 | } 36 | 37 | @Override 38 | public String getMessage() { 39 | return message; 40 | } 41 | 42 | public int getLevel() { 43 | return level; 44 | } 45 | 46 | } 47 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/common/exception/JsonResponse.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.common.exception; 2 | 3 | 4 | 5 | /** 6 | * 业务异常类json 7 | * 8 | * @author xuhua 9 | * @since 1.0.0 10 | */ 11 | public class JsonResponse { 12 | private int code; 13 | private int level; 14 | private String message; 15 | private Object data; 16 | 17 | public JsonResponse(Exception exception) { 18 | if (exception instanceof BusinessException) { 19 | BusinessException businessException = (BusinessException) exception; 20 | this.code = businessException.getCode(); 21 | this.message = businessException.getMessage(); 22 | this.level = businessException.getLevel(); 23 | } else { 24 | this.code = 500; 25 | this.message = "传入数据错误"; 26 | this.level = 5; 27 | } 28 | } 29 | 30 | public JsonResponse(Object data) { 31 | this.code = 200; 32 | this.message = "success"; 33 | this.data = data; 34 | } 35 | 36 | public int getCode() { 37 | return code; 38 | } 39 | 40 | public void setCode(int code) { 41 | this.code = code; 42 | } 43 | 44 | public String getMessage() { 45 | return message; 46 | } 47 | 48 | public void setMessage(String message) { 49 | this.message = message; 50 | } 51 | 52 | public Object getData() { 53 | return data; 54 | } 55 | 56 | public void setData(Object data) { 57 | this.data = data; 58 | } 59 | 60 | public int getLevel() { 61 | return level; 62 | } 63 | 64 | public void setLevel(int level) { 65 | this.level = level; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/common/web/JsonHandlerExceptionResolver.java: -------------------------------------------------------------------------------- 1 | 2 | package com.xu.drools.common.web; 3 | 4 | 5 | import com.xu.drools.common.exception.BusinessException; 6 | import com.xu.drools.common.exception.JsonResponse; 7 | import net.sf.json.JSONObject; 8 | import org.apache.logging.log4j.LogManager; 9 | import org.apache.logging.log4j.Logger; 10 | import org.springframework.stereotype.Component; 11 | import org.springframework.web.bind.annotation.RequestMapping; 12 | import org.springframework.web.bind.annotation.ResponseBody; 13 | import org.springframework.web.method.HandlerMethod; 14 | import org.springframework.web.servlet.HandlerExceptionResolver; 15 | import org.springframework.web.servlet.ModelAndView; 16 | 17 | import javax.servlet.http.HttpServletRequest; 18 | import javax.servlet.http.HttpServletResponse; 19 | import java.io.IOException; 20 | import java.util.Map; 21 | 22 | @Component 23 | public class JsonHandlerExceptionResolver implements HandlerExceptionResolver { 24 | 25 | private static Logger logger = LogManager.getLogger(); 26 | 27 | @ResponseBody 28 | @Override 29 | public ModelAndView resolveException(HttpServletRequest request, HttpServletResponse response, 30 | Object handler, Exception exception) { 31 | ModelAndView mv = new ModelAndView(); 32 | Map parameterMap = request.getParameterMap(); 33 | logException(handler, request, exception, parameterMap); 34 | JsonResponse jsonResponse = new JsonResponse(exception); 35 | JSONObject result = new JSONObject(); 36 | result.put("code", jsonResponse.getCode()); 37 | result.put("message", jsonResponse.getMessage()); 38 | try { 39 | response.setHeader("Content-type", "application/json;charset=UTF-8"); 40 | response.getWriter().write(result.toString()); 41 | } catch (IOException e) { 42 | logger.error("json response error", exception); 43 | logger.error("error", e); 44 | } 45 | return mv; 46 | } 47 | 48 | private void logException(Object handler, HttpServletRequest request, 49 | Exception exception, Map parameterMap) { 50 | if (handler != null && HandlerMethod.class.isAssignableFrom(handler.getClass())) { 51 | try { 52 | HandlerMethod handlerMethod = (HandlerMethod) handler; 53 | Class beanType = handlerMethod.getBeanType(); 54 | String methodName = handlerMethod.getMethod().getName(); 55 | RequestMapping controllerRequestMapping = beanType.getDeclaredAnnotation(RequestMapping.class); 56 | String classMapping = ""; 57 | if (controllerRequestMapping != null) { 58 | classMapping = controllerRequestMapping.value()[0]; 59 | } 60 | RequestMapping methodRequestMapping = handlerMethod.getMethodAnnotation(RequestMapping.class); 61 | String methodMapping = ""; 62 | if (methodRequestMapping != null) { 63 | methodMapping = methodRequestMapping.value()[0]; 64 | } 65 | if (!methodMapping.startsWith("/")) { 66 | methodMapping = "/" + methodMapping; 67 | } 68 | String userInfo; 69 | try { 70 | userInfo = request.getSession().getAttribute("AccountName").toString(); 71 | } catch (Exception e) { 72 | userInfo = "无授权回调"; 73 | } 74 | Logger logger = LogManager.getLogger(beanType); 75 | if (exception instanceof BusinessException) { 76 | int level = ((BusinessException) exception).getLevel(); 77 | if (level > 4) { 78 | logger.error("User is:" + userInfo + 79 | "RequestMapping is:" + classMapping + methodMapping + 80 | " HandlerMethod is:" + beanType.getSimpleName() + "." + methodName + "()" 81 | + " ParameterMap is:" + JSONObject.fromObject(parameterMap).toString()); 82 | logger.error(msg(exception)); 83 | } else { 84 | logger.info("level:" + level); 85 | logger.info("RequestMapping is:" + classMapping + methodMapping); 86 | logger.info("HandlerMethod is:" + beanType.getSimpleName() + "." + methodName + "()"); 87 | logger.info("ParameterMap is:" + JSONObject.fromObject(parameterMap).toString()); 88 | logger.info("exception is:" + exception.getMessage()); 89 | } 90 | } else { 91 | logger.error("User is:" + userInfo 92 | + " RequestMapping is:" + classMapping + methodMapping 93 | + " HandlerMethod is:" + beanType.getSimpleName() + "." + methodName + "()" 94 | + " ParameterMap is:" + JSONObject.fromObject(parameterMap).toString() 95 | + " Exception is:" + exception.toString()); 96 | logger.error(msg(exception)); 97 | } 98 | } catch (Exception e) { 99 | e.printStackTrace(); 100 | logger.error(handler + " execute failed.", exception); 101 | logger.error("error", e); 102 | } 103 | } else { 104 | logger.error(handler + " execute failed.", exception); 105 | } 106 | } 107 | 108 | private String msg(Exception e) { 109 | StringBuilder builder = new StringBuilder(); 110 | StackTraceElement[] elements = e.getStackTrace(); 111 | builder.append(e.getClass()); 112 | builder.append(":"); 113 | builder.append(e.getMessage()); 114 | builder.append("\n"); 115 | 116 | for (StackTraceElement element : elements) { 117 | String className = element.getClassName(); 118 | if (className != null) { 119 | builder.append("\t"); 120 | builder.append(element.getClassName()); 121 | builder.append("#"); 122 | builder.append(element.getMethodName()); 123 | builder.append("("); 124 | builder.append(element.getFileName()); 125 | builder.append(":"); 126 | builder.append(element.getLineNumber()); 127 | builder.append(")\n"); 128 | } 129 | } 130 | 131 | return builder.toString(); 132 | } 133 | 134 | } 135 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/config/DataSourceConfig.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.config; 2 | 3 | import org.apache.ibatis.session.SqlSessionFactory; 4 | import org.mybatis.spring.SqlSessionFactoryBean; 5 | import org.mybatis.spring.annotation.MapperScan; 6 | import org.springframework.beans.factory.annotation.Qualifier; 7 | import org.springframework.boot.autoconfigure.jdbc.DataSourceBuilder; 8 | import org.springframework.boot.context.properties.ConfigurationProperties; 9 | import org.springframework.context.annotation.Bean; 10 | import org.springframework.context.annotation.Configuration; 11 | import org.springframework.context.annotation.Primary; 12 | import org.springframework.jdbc.datasource.DataSourceTransactionManager; 13 | 14 | import javax.sql.DataSource; 15 | 16 | @Configuration 17 | @MapperScan(basePackages = DataSourceConfig.PACKAGE, sqlSessionFactoryRef = "SqlSessionFactory") 18 | public class DataSourceConfig { 19 | static final String PACKAGE = "com.xu.drools.dao"; 20 | 21 | 22 | @Primary 23 | @Bean(name = "DataSource") 24 | @ConfigurationProperties(prefix="spring.datasource") 25 | public DataSource DataSource() { 26 | return DataSourceBuilder.create().build(); 27 | } 28 | 29 | @Bean(name = "TransactionManager") 30 | @Primary 31 | public DataSourceTransactionManager dbTransactionManager() { 32 | return new DataSourceTransactionManager(DataSource()); 33 | } 34 | 35 | @Bean(name = "SqlSessionFactory") 36 | @Primary 37 | public SqlSessionFactory dbSqlSessionFactory(@Qualifier("DataSource") DataSource DataSource) throws Exception { 38 | final SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean(); 39 | sessionFactory.setDataSource(DataSource); 40 | return sessionFactory.getObject(); 41 | } 42 | } -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/dao/RulesDao.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.dao; 2 | 3 | 4 | import com.xu.drools.bean.Rules; 5 | import org.apache.ibatis.annotations.*; 6 | 7 | import java.util.List; 8 | 9 | @Mapper 10 | public interface RulesDao { 11 | 12 | @Select("SELECT * FROM drools_rule where id = #{id}") 13 | Rules getById(@Param("id") Integer id); 14 | 15 | @Insert("INSERT INTO drools_rule(name,rule) VALUE(#{name},#{rule})") 16 | Integer setRule(@Param("name") String name,@Param("rule") String rule); 17 | 18 | @Select("SELECT * FROM drools_rule order by create_time DESC") 19 | List getRuleList(); 20 | 21 | @Update("UPDATE drools_rule SET visible=0 WHERE id = #{id}") 22 | Integer deleteRule(@Param("id") Integer id); 23 | 24 | @Update("UPDATE drools_rule SET rule= #{rule} AND name = #{name} WHERE id = #{id}") 25 | Integer updateRule(@Param("id") Integer id,@Param("name") String name,@Param("rule") String rule); 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/complexProblem/GolferProblem.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.complexProblem; 2 | 3 | import com.xu.drools.bean.Golfer; 4 | import org.kie.api.KieServices; 5 | import org.kie.api.runtime.KieContainer; 6 | import org.kie.api.runtime.KieSession; 7 | 8 | /** 9 | * 使用kmodule的方式调用drools 10 | * /resources/META-INF/kmodule.xml 11 | * 高尔夫球员站位问题 12 | */ 13 | public class GolferProblem { 14 | 15 | /** 16 | * 已知有四个高尔夫球员,他们的名字是Fred,Joe,Bob,Tom; 17 | * 今天他们分别穿着红色,蓝色,橙色,以及格子衣服,并且他们按照从左往右的顺序站成一排。 18 | * 我们将最左边的位置定为1,最右边的位置定为4,中间依次是2,3位置。 19 | * 现在我们了解的情况是: 20 | * 1.高尔夫球员Fred,目前不知道他的位置和衣服颜色 21 | * 2.Fred右边紧挨着的球员穿蓝色衣服 22 | * 3.Joe排在第2个位置 23 | * 4.Bob穿着格子短裤 24 | * 5.Tom没有排在第1位或第4位,也没有穿橙色衣服 25 | * 请问,这四名球员的位置和衣服颜色。 26 | */ 27 | public static void main(final String[] args) { 28 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 29 | System.out.println(kc.verify().getMessages().toString()); 30 | execute(kc); 31 | } 32 | 33 | private static void execute(KieContainer kc) { 34 | KieSession ksession = kc.newKieSession("mingKS"); 35 | String[] names = new String[]{"Fred", "Joe", "Bob", "Tom"}; 36 | String[] colors = new String[]{"red", "blue", "plaid", "orange"}; 37 | int[] positions = new int[]{1, 2, 3, 4}; 38 | 39 | for (String name : names) { 40 | for (String color : colors) { 41 | for (int position : positions) { 42 | ksession.insert(new Golfer(name, color, position)); 43 | } 44 | } 45 | } 46 | ksession.fireAllRules(); 47 | ksession.dispose(); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/complexProblem/MingDrink.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.complexProblem; 2 | 3 | import com.xu.drools.bean.XiaoMing; 4 | import org.kie.api.KieServices; 5 | import org.kie.api.runtime.KieContainer; 6 | import org.kie.api.runtime.KieSession; 7 | 8 | /** 9 | * 使用kmodule的方式调用drools 10 | * /resources/META-INF/kmodule.xml 11 | * 小明喝水问题 12 | */ 13 | public class MingDrink { 14 | 15 | /** 16 | * 小明喝汽水问题 17 | * 18 | * 1元钱一瓶汽水,喝完后两个空瓶换一瓶汽水,问:小明有20元钱,最多可以喝到几瓶汽水? 19 | */ 20 | public static void main(final String[] args) { 21 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 22 | System.out.println(kc.verify().getMessages().toString()); 23 | execute(kc); 24 | } 25 | 26 | private static void execute(KieContainer kc) { 27 | KieSession ksession = kc.newKieSession("mingKS"); 28 | XiaoMing xiaoMing=new XiaoMing(); 29 | xiaoMing.setMoney(50); 30 | ksession.insert(xiaoMing); 31 | ksession.fireAllRules(); 32 | ksession.dispose(); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/complexProblem/WorldProblem.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.complexProblem; 2 | 3 | import com.xu.drools.bean.Student; 4 | import org.kie.api.KieServices; 5 | import org.kie.api.runtime.KieContainer; 6 | import org.kie.api.runtime.KieSession; 7 | 8 | /** 9 | * 使用kmodule的方式调用drools 10 | * /resources/META-INF/kmodule.xml 11 | * 猜对错问题 12 | */ 13 | public class WorldProblem { 14 | 15 | /** 16 | * 在一次数学竞赛中,获得前三名的同学是A,B,C. 老师对他们说:“祝贺你们,请你们猜一猜名次。” 17 | * 甲:“A是第二,C是第三.” 18 | * 乙:“A是第一,B是第三.” 19 | * 丙:“B是第二,A是第三.” 20 | * 感觉有更好的方法,但是写不出规则来0.0 21 | */ 22 | public static void main(final String[] args) { 23 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 24 | System.out.println(kc.verify().getMessages().toString()); 25 | execute(kc); 26 | } 27 | 28 | private static void execute(KieContainer kc) { 29 | KieSession ksession = kc.newKieSession("worldKS"); 30 | String[] names = new String[]{"jia", "yi", "bing"}; 31 | String[] word1 = new String[]{"A", "B", "C"}; 32 | String[] word2 = new String[]{"A", "B", "C"}; 33 | int[] desc1 = new int[]{1, 2, 3}; 34 | int[] desc2 = new int[]{1, 2, 3}; 35 | for (String n : names) { 36 | for (String w1 : word1) { 37 | for (String w2 : word2) { 38 | for (int d1 : desc1) { 39 | for (int d2 : desc2) { 40 | Student student = new Student(n, w1, w2, d1, d2); 41 | ksession.insert(student); 42 | } 43 | } 44 | } 45 | } 46 | } 47 | 48 | ksession.fireAllRules(); 49 | ksession.dispose(); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/honestpolitician/HonestPoliticianExample.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.honestpolitician; 2 | 3 | import com.xu.drools.bean.Politician; 4 | import org.kie.api.KieServices; 5 | import org.kie.api.runtime.KieContainer; 6 | import org.kie.api.runtime.KieSession; 7 | 8 | /** 9 | * 使用kmodule的方式调用drools 10 | * /resources/META-INF/kmodule.xml 11 | */ 12 | public class HonestPoliticianExample { 13 | 14 | public static void main(final String[] args) { 15 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 16 | System.out.println(kc.verify().getMessages().toString()); 17 | execute(kc); 18 | } 19 | 20 | private static void execute(KieContainer kc) { 21 | KieSession ksession = kc.newKieSession("HonestPoliticianKS"); 22 | 23 | final Politician p1 = new Politician("President of Umpa Lumpa", true); 24 | final Politician p2 = new Politician("Prime Minster of Cheeseland", true); 25 | final Politician p3 = new Politician("Tsar of Pringapopaloo", true); 26 | final Politician p4 = new Politician("Omnipotence Om", true); 27 | 28 | ksession.insert(p1); 29 | ksession.insert(p2); 30 | ksession.insert(p3); 31 | ksession.insert(p4); 32 | 33 | ksession.fireAllRules(); 34 | 35 | ksession.dispose(); 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/rule1/rule1.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.rule1; 2 | 3 | import org.kie.api.KieServices; 4 | import org.kie.api.runtime.KieContainer; 5 | import org.kie.api.runtime.KieSession; 6 | 7 | /** 8 | * 使用kmodule的方式调用drools 9 | * /resources/META-INF/kmodule.xml 10 | */ 11 | public class rule1 { 12 | public static void main(final String[] args) { 13 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 14 | System.out.println(kc.verify().getMessages().toString()); 15 | execute(kc); 16 | } 17 | 18 | private static void execute(KieContainer kc) { 19 | KieSession ksession = kc.newKieSession("rule1KS"); 20 | 21 | 22 | ksession.fireAllRules(); 23 | 24 | ksession.dispose(); 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/rule/rule2/rule2.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.rule.rule2; 2 | 3 | import com.xu.drools.bean.Person; 4 | import org.kie.api.KieServices; 5 | import org.kie.api.runtime.KieContainer; 6 | import org.kie.api.runtime.KieSession; 7 | import org.kie.api.runtime.rule.QueryResults; 8 | import org.kie.api.runtime.rule.QueryResultsRow; 9 | 10 | /** 11 | * 使用kmodule的方式调用drools 12 | * /resources/META-INF/kmodule.xml 13 | */ 14 | public class rule2 { 15 | 16 | public static void main(final String[] args) { 17 | KieContainer kc = KieServices.Factory.get().getKieClasspathContainer(); 18 | System.out.println(kc.verify().getMessages().toString()); 19 | execute(kc); 20 | } 21 | 22 | private static void execute(KieContainer kc) { 23 | KieSession ksession = kc.newKieSession("rule2KS"); 24 | 25 | Person p1 = new Person(35, "xu", "handsome"); 26 | Person p2 = new Person(30, "hua", "handsome"); 27 | 28 | ksession.insert(p1); 29 | ksession.insert(p2); 30 | 31 | ksession.fireAllRules(); 32 | 33 | QueryResults results = ksession.getQueryResults("people2"); 34 | System.out.println("we have " + results.size() + " people over the age of 30"); 35 | 36 | System.out.println("These people are are over 30:"); 37 | 38 | for (QueryResultsRow row : results) { 39 | Person person = (Person) row.get("person"); 40 | System.out.println(person.getName() + "\n"); 41 | } 42 | 43 | ksession.dispose(); 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/service/RuleTableService.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.service; 2 | 3 | 4 | import org.apache.logging.log4j.LogManager; 5 | import org.apache.logging.log4j.Logger; 6 | import org.drools.decisiontable.SpreadsheetCompiler; 7 | import org.kie.internal.io.ResourceFactory; 8 | import org.springframework.stereotype.Service; 9 | 10 | import java.io.File; 11 | import java.io.InputStream; 12 | 13 | @Service 14 | public class RuleTableService { 15 | private static Logger logger = LogManager.getLogger(); 16 | /** 17 | * 默认规则文件所在路径 18 | */ 19 | private static final String RULES_PATH = "tables"; 20 | 21 | public String getRuleTable() { 22 | //把excel翻译成drl文件 23 | SpreadsheetCompiler compiler = new SpreadsheetCompiler(); 24 | String rules = compiler.compile(ResourceFactory.newClassPathResource(RULES_PATH + File.separator + "rule.xlsx", "UTF-8"), "rule-table"); 25 | System.out.println(rules); 26 | return rules; 27 | } 28 | 29 | /** 30 | * 通过决策表文件流获取rule 31 | * 32 | * @param inputStream 决策表文件流 33 | * @return rule 34 | */ 35 | public String getRuleTable(InputStream inputStream) { 36 | //把excel翻译成drl文件 37 | SpreadsheetCompiler compiler = new SpreadsheetCompiler(); 38 | String rules = compiler.compile(ResourceFactory.newInputStreamResource(inputStream, "UTF-8"), "rule-table"); 39 | logger.info("get rule from xls:" + rules); 40 | return rules; 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/service/RulesService.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.service; 2 | 3 | 4 | import com.xu.drools.bean.Person; 5 | import com.xu.drools.bean.Rules; 6 | import com.xu.drools.common.bean.ExceptionType; 7 | import com.xu.drools.common.exception.BusinessException; 8 | import com.xu.drools.dao.RulesDao; 9 | import org.kie.api.KieBase; 10 | import org.kie.api.KieServices; 11 | import org.kie.api.builder.KieBuilder; 12 | import org.kie.api.builder.KieFileSystem; 13 | import org.kie.api.builder.Results; 14 | import org.kie.api.runtime.KieContainer; 15 | import org.kie.api.runtime.KieSession; 16 | import org.springframework.beans.factory.annotation.Autowired; 17 | import org.springframework.stereotype.Service; 18 | 19 | @Service 20 | public class RulesService { 21 | 22 | @Autowired 23 | private RulesDao rulesDao; 24 | /** 25 | * 动态获取KieSession 26 | * 27 | * @param rules rule 28 | * @return KieSession 29 | */ 30 | public KieSession getKieSession(String rules) { 31 | KieServices kieServices = KieServices.Factory.get(); 32 | KieFileSystem kfs = kieServices.newKieFileSystem(); 33 | kfs.write("src/main/resources/rules/rules.drl", rules.getBytes()); 34 | KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); 35 | Results results = kieBuilder.getResults(); 36 | if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) { 37 | System.out.println(results.getMessages()); 38 | throw new BusinessException(300003,results.getMessages().toString(),4); 39 | } 40 | KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()); 41 | KieBase kieBase = kieContainer.getKieBase(); 42 | 43 | return kieBase.newKieSession(); 44 | } 45 | 46 | /** 47 | * 动态加载已经部署的rule 48 | * 49 | * @param id rule id 50 | * @param t 对象 51 | * @return 结果对象 52 | */ 53 | public Person getRulesWrite(Integer id, Person t) { 54 | String rules; 55 | Rules ru = rulesDao.getById(id); 56 | if (ru != null && ru.getRule() != null) { 57 | rules = ru.getRule(); 58 | } else throw new BusinessException(ExceptionType.RULE_IS_NULL); 59 | 60 | KieServices kieServices = KieServices.Factory.get(); 61 | KieFileSystem kfs = kieServices.newKieFileSystem(); 62 | kfs.write("src/main/resources/rules/rules.drl", rules.getBytes()); 63 | KieBuilder kieBuilder = kieServices.newKieBuilder(kfs).buildAll(); 64 | Results results = kieBuilder.getResults(); 65 | if (results.hasMessages(org.kie.api.builder.Message.Level.ERROR)) { 66 | System.out.println(results.getMessages()); 67 | throw new IllegalStateException("### errors ###"); 68 | } 69 | KieContainer kieContainer = kieServices.newKieContainer(kieServices.getRepository().getDefaultReleaseId()); 70 | KieBase kieBase = kieContainer.getKieBase(); 71 | KieSession ksession = kieBase.newKieSession(); 72 | 73 | ksession.insert(t); 74 | ksession.fireAllRules(); 75 | return t; 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/web/ComplexProblem.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.web; 2 | 3 | import org.springframework.web.bind.annotation.RequestMapping; 4 | import org.springframework.web.bind.annotation.RestController; 5 | 6 | /** 7 | * 使用drools来解决复杂问题 8 | */ 9 | @RequestMapping(value = "/rules") 10 | @RestController 11 | public class ComplexProblem { 12 | 13 | 14 | } 15 | -------------------------------------------------------------------------------- /src/main/java/com/xu/drools/web/RulesController.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools.web; 2 | 3 | 4 | import com.google.gson.Gson; 5 | import com.xu.drools.bean.Person; 6 | import com.xu.drools.common.exception.JsonResponse; 7 | import com.xu.drools.dao.RulesDao; 8 | import com.xu.drools.service.RuleTableService; 9 | import com.xu.drools.service.RulesService; 10 | import io.swagger.annotations.ApiImplicitParam; 11 | import io.swagger.annotations.ApiImplicitParams; 12 | import io.swagger.annotations.ApiOperation; 13 | import org.kie.api.runtime.KieSession; 14 | import org.springframework.beans.factory.annotation.Autowired; 15 | import org.springframework.web.bind.annotation.RequestMapping; 16 | import org.springframework.web.bind.annotation.RequestMethod; 17 | import org.springframework.web.bind.annotation.RequestParam; 18 | import org.springframework.web.bind.annotation.RestController; 19 | import org.springframework.web.multipart.MultipartFile; 20 | 21 | import java.io.IOException; 22 | import java.io.InputStream; 23 | 24 | /** 25 | * Drools的基本用法,动态规则+决策表 26 | */ 27 | @RequestMapping(value = "/rules") 28 | @RestController 29 | public class RulesController { 30 | 31 | @Autowired 32 | private RulesService rulesService; 33 | @Autowired 34 | private RuleTableService ruleTableService; 35 | @Autowired 36 | private RulesDao rulesDao; 37 | 38 | @ApiOperation(value = "验证规则是否合法",notes = verify) 39 | @RequestMapping(value = "/verify", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 40 | public JsonResponse ruleVerify(@RequestParam(value = "rule") String rule, 41 | @RequestParam(value = "data") String json) { 42 | KieSession kieSession = rulesService.getKieSession(rule); 43 | Gson gson = new Gson(); 44 | Person person = gson.fromJson(json, Person.class); 45 | kieSession.insert(person); 46 | int rules=kieSession.fireAllRules(); 47 | System.out.println(rules); 48 | kieSession.dispose(); 49 | return new JsonResponse(person); 50 | } 51 | 52 | 53 | @ApiOperation(value = "添加规则") 54 | @ApiImplicitParams({ 55 | @ApiImplicitParam(name = "rule", dataType = "String", required = true, value = "规则"), 56 | @ApiImplicitParam(name = "name", dataType = "String", required = true, value = "规则名称")}) 57 | @RequestMapping(value = "/add", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 58 | public JsonResponse ruleAdd(@RequestParam String rule, @RequestParam String name) { 59 | rulesDao.setRule(name, rule); 60 | return new JsonResponse(""); 61 | } 62 | 63 | @ApiOperation(value = "规则列表") 64 | @RequestMapping(value = "/list", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 65 | public JsonResponse getRuleList() { 66 | return new JsonResponse(rulesDao.getRuleList()); 67 | } 68 | 69 | 70 | @ApiOperation(value = "规则结果") 71 | @RequestMapping(value = "/result", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 72 | public JsonResponse getResult(@RequestParam("id") Integer id, @RequestParam("json") String json) { 73 | Gson gson = new Gson(); 74 | Person person = gson.fromJson(json, Person.class); 75 | return new JsonResponse(rulesService.getRulesWrite(id, person)); 76 | } 77 | 78 | @ApiOperation(value = "决策表转换") 79 | @ApiImplicitParam(name = "file", dataType = "MultipartFile", required = true, value = "决策表xls") 80 | @RequestMapping(value = "/getRuleXls", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 81 | public JsonResponse getRuleXls(@RequestParam(value = "file") MultipartFile file) throws IOException { 82 | InputStream inputStream = file.getInputStream(); 83 | String rule = ruleTableService.getRuleTable(inputStream); 84 | try { 85 | KieSession kieSession = rulesService.getKieSession(rule); 86 | kieSession.insert(new Person()); 87 | } catch (Exception e) { 88 | e.printStackTrace(); 89 | return new JsonResponse(e); 90 | } 91 | return new JsonResponse(rule); 92 | } 93 | 94 | @ApiOperation(value = "删除规则") 95 | @ApiImplicitParam(name = "id", dataType = "Integer", required = true, value = "规则编号") 96 | @RequestMapping(value = "/delete", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 97 | public JsonResponse delete(@RequestParam Integer id) { 98 | return new JsonResponse(rulesDao.deleteRule(id)); 99 | } 100 | 101 | @ApiOperation(value = "修改规则") 102 | @ApiImplicitParams({ 103 | @ApiImplicitParam(name = "rule", dataType = "String", required = true, value = "规则"), 104 | @ApiImplicitParam(name = "id", dataType = "Integer", required = true, value = "规则id"), 105 | @ApiImplicitParam(name = "name", dataType = "String", required = true, value = "规则名称")}) 106 | @RequestMapping(value = "/ruleUpdate", method = RequestMethod.POST, produces = "application/json;charset=UTF-8") 107 | public JsonResponse ruleUpdate(@RequestParam String rule, @RequestParam Integer id, @RequestParam String name) { 108 | return new JsonResponse(rulesDao.updateRule(id, name, rule)); 109 | } 110 | 111 | private final static String verify="规则:package com.xu.drools;\n" + 112 | "import com.xu.drools.bean.Person;\n" + 113 | "rule \"2\"\n" + 114 | "\twhen\n" + 115 | " $p : Person(age < 30);\n" + 116 | " then\n" + 117 | "\t\tSystem.out.println(\"hello, young xu2!\");\n" + 118 | "\t\t$p.setDesc(\"young \"+$p.getName());\n" + 119 | "\t\tretract($p)\n" + 120 | "end"+" 数据实体:{\n" + 121 | " \"age\":18,\n" + 122 | " \"name\":\"xu\",\n" + 123 | " \"desc\":\"帅\"\n" + 124 | "}"; 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/main/resources/META-INF/kmodule.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | server: 2 | port: 8081 3 | spring: 4 | datasource: 5 | driver-class-name: com.mysql.jdbc.Driver 6 | url: jdbc:mysql://localhost:3306/xus?useUnicode=true&characterEncoding=utf-8&autoReconnect=true&useSSL=false&noAccessToProcedureBodies=true 7 | username: root 8 | password: 4321 9 | type: com.alibaba.druid.pool.DruidDataSource 10 | initialSize: 5 11 | minIdle: 5 12 | maxActive: 50 13 | maxWait: 1000 14 | filters: stat,wall,log4j -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/complexProblem/golfer.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools 2 | 3 | import com.xu.drools.bean.Golfer; 4 | 5 | rule "find solution" 6 | when 7 | //1.高尔夫球员Fred,目前不知道他的位置和衣服颜色 8 | $fred : Golfer( name == "Fred" ) 9 | 10 | //3.Joe排在第2个位置 11 | $joe : Golfer( name == "Joe", 12 | position == 2, 13 | position != $fred.position, 14 | color != $fred.color ) 15 | 16 | //4.Bob穿着格子短裤 17 | $bob : Golfer( name == "Bob", 18 | position != $fred.position, 19 | position != $joe.position, 20 | color == "plaid", 21 | color != $fred.color, 22 | color != $joe.color ) 23 | 24 | //5.Tom没有排在第1位或第4位,也没有穿橙色衣服 25 | $tom : Golfer( name == "Tom", 26 | position != 1, 27 | position != 4, 28 | position != $fred.position, 29 | position != $joe.position, 30 | position != $bob.position, 31 | color != "orange", 32 | color != $fred.color, 33 | color != $joe.color, 34 | color != $bob.color ) 35 | 36 | //2.Fred右边紧挨着的球员穿蓝色衣服 37 | Golfer( position == ( $fred.position + 1 ), 38 | color == "blue", 39 | this in ( $joe, $bob, $tom ) ) 40 | 41 | then 42 | System.out.println( "Fred " + $fred.getPosition() + " " + $fred.getColor() ); 43 | System.out.println( "Joe " + $joe.getPosition() + " " + $joe.getColor() ); 44 | System.out.println( "Bob " + $bob.getPosition() + " " + $bob.getColor() ); 45 | System.out.println( "Tom " + $tom.getPosition() + " " + $tom.getColor() ); 46 | end -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/complexProblem/ming.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools 2 | 3 | import com.xu.drools.bean.XiaoMing; 4 | 5 | 6 | // 小明喝汽水问题 7 | // 1元钱一瓶汽水,喝完后两个空瓶换一瓶汽水,问:小明有20元钱,最多可以喝到几瓶汽水? 8 | // 规则1:1元钱一瓶汽水 9 | // 规则2:两个空瓶换一瓶汽水 10 | 11 | //规则1:1元钱一瓶汽水。有钱就买水,空瓶+1,钱-1,喝水+1; 12 | rule "rule1" 13 | salience 3 14 | when 15 | $m:XiaoMing(money>0); 16 | then 17 | System.out.println("有钱即可喝水,钱:"+$m.getMoney()); 18 | $m.setBottle($m.getBottle()+1); 19 | $m.setMoney($m.getMoney()-1); 20 | $m.setDrink($m.getDrink()+1); 21 | update($m) 22 | end 23 | 24 | //规则2:两个空瓶换一瓶汽水。有空瓶就换钱,空瓶-2,钱+1; 25 | rule "rule2" 26 | salience 2 27 | when 28 | $m:XiaoMing(bottle>=2); 29 | then 30 | System.out.println("有瓶子就换钱,瓶子:"+$m.getBottle()); 31 | $m.setBottle($m.getBottle()-2); 32 | $m.setMoney($m.getMoney()+1); 33 | update($m) 34 | end 35 | 36 | //规则3,打印已经喝掉的数量 37 | rule "rule3" 38 | salience 1 39 | when 40 | $m:XiaoMing(); 41 | then 42 | System.out.println("总共喝掉:"+$m.getDrink()); 43 | end -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/complexProblem/world.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools 2 | 3 | import com.xu.drools.bean.Student; 4 | import com.xu.drools.bean.World 5 | 6 | rule "find jia1" 7 | salience 2 8 | when 9 | $jia1 : Student(name == "jia",word1=="A",word2=="C",desc1=="2",desc2!="3") 10 | then 11 | insert( new World($jia1.getDesc1(),0,$jia1.getDesc2()) ); 12 | end 13 | 14 | rule "find jia2" 15 | salience 2 16 | when 17 | $jia2 : Student(name == "jia",word1=="A",word2=="C",desc1!="2",desc2=="3") 18 | then 19 | insert( new World($jia2.getDesc1(),0,$jia2.getDesc2()) ); 20 | end 21 | 22 | rule "find yi1" 23 | salience 3 24 | when 25 | $yi1 : Student(name == "yi",word1=="A",word2=="B",desc1=="1",desc2!="3"); 26 | $w : World(a==$yi1.getDesc1()) 27 | then 28 | $w.setB($yi1.getDesc2()); 29 | update($w) 30 | end 31 | 32 | rule "find yi2" 33 | salience 3 34 | when 35 | $yi2 : Student(name == "yi",word1=="A",word2=="B",desc1=="1",desc2!="3") 36 | $w : World(a==$yi2.getDesc1()) 37 | then 38 | $w.setB($yi2.getDesc2()); 39 | update($w) 40 | end 41 | 42 | 43 | rule "find bing1" 44 | salience 4 45 | when 46 | $bing1 : Student(name == "bing",word1=="A",word2=="B",desc1=="3",desc2!="2") 47 | $w : World(a==$bing1.getDesc1(),b==$bing1.getDesc2()) 48 | then 49 | System.out.println("-------"+$w.toString()); 50 | end 51 | 52 | 53 | rule "find bing2" 54 | salience 4 55 | when 56 | $bing2 : Student(name == "bing",word1=="A",word2=="B",desc1!="3",desc2=="2") 57 | $w : World(a==$bing2.getDesc1(),b==$bing2.getDesc2()) 58 | then 59 | System.out.println("-------"+$w.toString()); 60 | end 61 | 62 | 63 | 64 | -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/honestpolitician/HonestPolitician.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools 2 | 3 | import com.xu.drools.bean.Politician; 4 | import com.xu.drools.bean.Hope; 5 | 6 | rule "We have an honest Politician" 7 | salience 10 8 | when 9 | exists( Politician( honest == true ) ) 10 | then 11 | insertLogical( new Hope() ); 12 | end 13 | 14 | rule "Hope Lives" 15 | salience 10 16 | when 17 | exists( Hope() ) 18 | then 19 | System.out.println("Hurrah!!! Democracy Lives"); 20 | end 21 | 22 | rule "Hope is Dead" 23 | when 24 | not( Hope() ) 25 | then 26 | System.out.println( "We are all Doomed!!! Democracy is Dead" ); 27 | end 28 | 29 | rule "Corrupt the Honest" 30 | when 31 | politician : Politician( honest == true ) 32 | exists( Hope() ) 33 | then 34 | System.out.println( "I'm an evil corporation and I have corrupted " + politician.getName() ); 35 | modify( politician ) { 36 | setHonest( false ) 37 | } 38 | end 39 | 40 | -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/rule1/rule1.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools; 2 | import com.xu.drools.bean.Person; 3 | rule "2" 4 | when 5 | $p : Person(age > 30); 6 | then 7 | System.out.println("hello, young xu2!"); 8 | end 9 | 10 | query "people2" 11 | person : Person( age > 30 ) 12 | end -------------------------------------------------------------------------------- /src/main/resources/com/xu/drools/rule/rule2/rule2.drl: -------------------------------------------------------------------------------- 1 | package com.xu.drools; 2 | import com.xu.drools.bean.Person; 3 | rule "2" 4 | when 5 | $p : Person(age > 30); 6 | then 7 | System.out.println("hello, young xu2!"); 8 | end 9 | 10 | query "people2" 11 | person : Person( age > 30 ) 12 | end -------------------------------------------------------------------------------- /src/main/resources/drools_rule.sql: -------------------------------------------------------------------------------- 1 | /* 2 | Navicat MySQL Data Transfer 3 | 4 | Source Server : MyDB 5 | Source Server Version : 50709 6 | Source Host : localhost:3306 7 | Source Database : xus 8 | 9 | Target Server Type : MYSQL 10 | Target Server Version : 50709 11 | File Encoding : 65001 12 | 13 | Date: 2017-08-29 20:17:26 14 | */ 15 | 16 | SET FOREIGN_KEY_CHECKS=0; 17 | 18 | -- ---------------------------- 19 | -- Table structure for drools_rule 20 | -- ---------------------------- 21 | DROP TABLE IF EXISTS `drools_rule`; 22 | CREATE TABLE `drools_rule` ( 23 | `id` int(11) NOT NULL AUTO_INCREMENT, 24 | `name` varchar(64) CHARACTER SET utf8mb4 DEFAULT NULL, 25 | `rule` mediumtext CHARACTER SET utf8mb4, 26 | `create_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP, 27 | `update_time` timestamp NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP, 28 | `visible` int(11) DEFAULT NULL, 29 | PRIMARY KEY (`id`) 30 | ) ENGINE=InnoDB AUTO_INCREMENT=5 DEFAULT CHARSET=latin1; 31 | 32 | -- ---------------------------- 33 | -- Records of drools_rule 34 | -- ---------------------------- 35 | INSERT INTO `drools_rule` VALUES ('3', 'rule_005', 'package com.xu.drools;\r\nimport com.xu.drools.bean.Person;\r\nrule \"2\"\r\n when\r\n $p : Person(age < 30);\r\n then\r\n System.out.println(\"hello, young xu2!\");\r\n $p.setDesc(\"young \"+$p.getName());\r\n retract($p)\r\nend', '2017-01-17 10:43:14', '2017-08-29 20:15:37', '1'); 36 | -------------------------------------------------------------------------------- /src/main/resources/log4j2.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | ???? 5 | %clr{%d{yyyy-MM-dd HH:mm:ss.SSS}}{faint} %clr{%5p} %clr{${sys:PID}}{magenta} %clr{---}{faint} %clr{[%15.15t]}{faint} %clr{%-40.40c{1.}}{cyan} %clr{:}{faint} %m%n%wEx 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | -------------------------------------------------------------------------------- /src/main/resources/tables/rule.xlsx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/MyHerux/drools-springboot/df2f7bda6fd963b882bce0eda458d92d4fb57600/src/main/resources/tables/rule.xlsx -------------------------------------------------------------------------------- /src/test/java/com/xu/drools/DroolsSpringbootApplicationTests.java: -------------------------------------------------------------------------------- 1 | package com.xu.drools; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.boot.test.context.SpringBootTest; 6 | import org.springframework.test.context.junit4.SpringRunner; 7 | 8 | @RunWith(SpringRunner.class) 9 | @SpringBootTest 10 | public class DroolsSpringbootApplicationTests { 11 | 12 | @Test 13 | public void contextLoads() { 14 | } 15 | 16 | } 17 | --------------------------------------------------------------------------------