drools 整合springboot 整合 drools 测试例子--个税计算器规则
规则引擎,主要作用,就是将规则与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