規則引擎,主要作用,就是將規則與java代碼分離,可通過修改規則實時生效。讓非java程序員,只要熟悉業務,也可以寫規則。
規則引擎主要用在一些,打折、風控前置、后置、結算等模塊地方。
新建一個droolsdemo的maven工程。
pom.xml
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starters</artifactId> <version>2.2.0.RELEASE</version> </parent> <modelVersion>4.0.0</modelVersion> <groupId>com.drools</groupId> <artifactId>DroolsDemo</artifactId> <version>1.0-SNAPSHOT</version> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> </dependency> <dependency> <groupId>commons-lang</groupId> <artifactId>commons-lang</artifactId> <version>2.6</version> </dependency> <!--drools規則引擎--> <dependency> <groupId>org.drools</groupId> <artifactId>drools-core</artifactId> <version>7.6.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-compiler</artifactId> <version>7.6.0.Final</version> </dependency> <dependency> <groupId>org.drools</groupId> <artifactId>drools-templates</artifactId> <version>7.6.0.Final</version> </dependency> <dependency> <groupId>org.kie</groupId> <artifactId>kie-api</artifactId> <version>7.6.0.Final</version> </dependency> <dependency> <groupId>org.kie</groupId> <artifactId>kie-spring</artifactId> <exclusions> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-tx</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-beans</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-core</artifactId> </exclusion> <exclusion> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> </exclusion> </exclusions> <version>7.6.0.Final</version> </dependency> </dependencies> <build> <finalName>${project.artifactId}</finalName> <resources> <resource> <directory>src/main/java</directory> <includes> <include>**/*.xml</include> </includes> <filtering>false</filtering> </resource> <resource> <directory>src/main/resources</directory> <includes> <include>**/*.*</include> </includes> <filtering>false</filtering> </resource> </resources> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> <configuration> <source>1.8</source> <target>1.8</target> </configuration> </plugin> </plugins> </build> </project>
配置文件DroolsConfig.java
package com.drools.config; import org.kie.api.KieBase; import org.kie.api.KieServices; import org.kie.api.builder.KieBuilder; import org.kie.api.builder.KieFileSystem; import org.kie.api.builder.KieRepository; import org.kie.api.runtime.KieContainer; import org.kie.internal.io.ResourceFactory; import org.kie.spring.KModuleBeanFactoryPostProcessor; import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.core.io.support.PathMatchingResourcePatternResolver; import org.springframework.core.io.support.ResourcePatternResolver; import org.springframework.core.io.Resource; import java.io.IOException; /** * 規則引擎配置類 */ @Configuration public class DroolsConfig { //指定規則文件存放的目錄 private static final String RULES_PATH = "rules/"; private final KieServices kieServices = KieServices.Factory.get(); @Bean @ConditionalOnMissingBean public KieFileSystem kieFileSystem() throws IOException { System.setProperty("drools.dateformat","yyyy-MM-dd"); KieFileSystem kieFileSystem = kieServices.newKieFileSystem(); ResourcePatternResolver resourcePatternResolver = new PathMatchingResourcePatternResolver(); Resource[] files = resourcePatternResolver.getResources("classpath*:" + RULES_PATH + "*.*"); String path = null; for (Resource file : files) { path = RULES_PATH + file.getFilename(); kieFileSystem.write(ResourceFactory.newClassPathResource(path, "UTF-8")); } return kieFileSystem; } @Bean @ConditionalOnMissingBean public KieContainer kieContainer() throws IOException { KieRepository kieRepository = kieServices.getRepository(); kieRepository.addKieModule(kieRepository::getDefaultReleaseId); KieBuilder kieBuilder = kieServices.newKieBuilder(kieFileSystem()); kieBuilder.buildAll(); return kieServices.newKieContainer(kieRepository.getDefaultReleaseId()); } @Bean @ConditionalOnMissingBean public KieBase kieBase() throws IOException { return kieContainer().getKieBase(); } @Bean @ConditionalOnMissingBean public KModuleBeanFactoryPostProcessor kiePostProcessor() { return new KModuleBeanFactoryPostProcessor(); } }
入口控制類 RuleController.java
package com.drools.controller; import javax.servlet.http.HttpServletRequest; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import com.drools.entity.Calculation; import com.drools.service.RuleService; @RestController public class RuleController { @Autowired private RuleService ruleService; @RequestMapping("/calculate") public Calculation calculate(HttpServletRequest request){ String wage = request.getParameter("wage"); Calculation calculation = new Calculation(); calculation.setWage(Double.parseDouble(wage)); calculation = ruleService.calculate(calculation); System.out.println(calculation); return calculation; } }
入參實體類 Calculation
package com.drools.entity; public class Calculation { private double wage;//稅前工資 private double wagemore;//應納稅所得額 private double cess;//稅率 private double preminus;//速算扣除數 private double wageminus;//扣稅額 private double actualwage;//稅后工資 @Override public String toString() { return "Calculation{" + "wage=" + wage + ", actualwage=" + actualwage + ", wagemore=" + wagemore + ", cess=" + cess + ", preminus=" + preminus + ", wageminus=" + wageminus + '}'; } public double getWage() { return wage; } public void setWage(double wage) { this.wage = wage; } public double getWagemore() { return wagemore; } public void setWagemore(double wagemore) { this.wagemore = wagemore; } public double getCess() { return cess; } public void setCess(double cess) { this.cess = cess; } public double getPreminus() { return preminus; } public void setPreminus(double preminus) { this.preminus = preminus; } public double getWageminus() { return wageminus; } public void setWageminus(double wageminus) { this.wageminus = wageminus; } public double getActualwage() { return actualwage; } public void setActualwage(double actualwage) { this.actualwage = actualwage; } }
處理服務類RuleService
package com.drools.service; import org.kie.api.KieBase; import org.kie.api.runtime.KieSession; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import com.drools.entity.Calculation; @Service public class RuleService { @Autowired private KieBase kieBase; public void rule(){ KieSession kieSession = kieBase.newKieSession(); kieSession.fireAllRules(); kieSession.dispose(); } /** * @desc 個人所得稅計算 * @date 2020年6月18日 下午4:42:34 * @param calculation * @return */ public Calculation calculate(Calculation calculation){ KieSession kieSession = kieBase.newKieSession(); kieSession.insert(calculation); kieSession.fireAllRules(); kieSession.dispose(); return calculation; } }
程序啟動入口類DsApp
package com.drools; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class DsApp { public static void main(String[] args) { SpringApplication.run(DsApp.class,args); } }
drools 規則文件 calculation.drl
package calculation import com.drools.entity.Calculation /** 當前規則文件中的規則主要分為三類 1、計算應納稅所得額有1個規則 2、設置稅率、速算扣除數有7個規則 3、計算稅后工資有1個規則 **/ //計算應納稅所得額 rule "計算應納稅所得額" salience 100 date-effective "2011-09-01" no-loop true when $cal:Calculation(wage > 0) then double wagemore = $cal.getWage() - 3500; $cal.setWagemore(wagemore); update($cal); end //設置稅率、速算扣除數 rule "設置稅率,應納稅所得額<=1500" salience 90 no-loop true activation-group "SETCess_Group" when $cal:Calculation(wagemore <= 1500) then $cal.setCess(0.03);//稅率 $cal.setPreminus(0);//速算扣除數 update($cal); end rule "設置稅率,應納稅所得額在1500至4500之間" salience 90 no-loop true activation-group "SETCess_Group" when $cal:Calculation(wagemore <= 4500 && wagemore > 1500) then $cal.setCess(0.1);//稅率 $cal.setPreminus(105);//速算扣除數 update($cal); end rule "個人所得稅:設置稅率-->>應納稅所得額在4500志9000之間" salience 90 no-loop true activation-group "SETCess_Group" when $cal : Calculation(wagemore > 4500 && wagemore <= 9000) then $cal.setCess(0.2); $cal.setPreminus(555); update($cal); end rule "個人所得稅:設置稅率-->>應納稅所得額在9000志35000之間" salience 90 no-loop true activation-group "SETCess_Group" when $cal : Calculation(wagemore > 9000 && wagemore <= 35000) then $cal.setCess(0.25); $cal.setPreminus(1005); update($cal); end rule "個人所得稅:設置稅率-->>應納稅所得額在35000至55000之間" salience 90 no-loop true activation-group "SETCess_Group" when $cal : Calculation(wagemore > 35000 && wagemore <= 55000) then $cal.setCess(0.3); $cal.setPreminus(2755); update($cal); end rule "個人所得稅:設置稅率-->>應納稅所得額在55000至80000之間" salience 90 no-loop true activation-group "SETCess_Group" when $cal : Calculation(wagemore > 55000 && wagemore <= 80000) then $cal.setCess(0.35); $cal.setPreminus(5505); update($cal); end rule "個人所得稅:設置稅率-->>應納稅所得額在80000以上" salience 90 no-loop true activation-group "SETCess_Group" when $cal : Calculation(wagemore > 80000) then $cal.setCess(0.45); $cal.setPreminus(13505); update($cal); end rule "個人所得稅:計算稅后工資" salience 80 when $cal : Calculation(wage > 0 && wagemore > 0 && cess > 0) then //扣稅額 double wageminus = $cal.getWagemore() * $cal.getCess() - $cal.getPreminus(); double actualwage = $cal.getWage() - wageminus; $cal.setWageminus(wageminus); $cal.setActualwage(actualwage); System.out.println("-----稅前工資:"+$cal.getWage()); System.out.println("-----應納稅所得額:"+$cal.getWagemore()); System.out.println("-----稅率:" + $cal.getCess()); System.out.println("-----速算扣除數:" + $cal.getPreminus()); System.out.println("-----扣稅額:" + $cal.getWageminus()); System.out.println("-----稅后工資:" + $cal.getActualwage()); end
總的目錄結果如下:

啟動運行。通過postmain訪問。
加入參數wage
http://localhost:8080/calculate

后台打印:

測試成功。
rule "計算應納稅所得額"
salience ----100 優先級
date-effective "2011-09-01" ----規則生效時間
no-loop true ----放死循環
when
----一定的規則條件
then
----這塊純粹的java代碼。。。
end
