正如我在之前的文章中所展示的那样, JBoss Drools是一个非常有用的规则引擎 。 唯一的问题是,对于非技术人员而言,以Rule语言创建规则可能会非常复杂。 这就是为什么可以提供一种轻松的方式来创建业务规则的方法-在电子表格中创建决策表!
在以下示例中,我将向您展示一个非常复杂的业务规则示例,该示例已转换为电子表格中的决策表。 作为后端,我们将有Drools,Camel和Spring。首先,让我们看一下我们想象中的业务问题。 让我们假设我们经营一家专注于销售产品(医疗或电子产品)的业务。 我们将产品运送到多个国家(PL,美国,GER,SWE,英国,ESP),并且根据国家/地区,存在不同的法律法规
关于买方的年龄。 在某些国家/地区,您可以比其他国家/地区年轻的时候购买产品。 更重要的是,取决于购买者和产品所来自的国家/地区以及产品的数量,购买者可能会获得折扣。 如您所见,在这种情况下,要实现全域需要大量条件(想象对它进行编程所需的if数量)。
另一个问题是业务方面(与往常一样)。 任何从事项目工作的人都知道需求变化的速度。 如果一个人在代码中输入了所有规则,则每次需求更改时,他都必须重新部署该软件。 因此,将业务逻辑与代码本身分开是一个好习惯。 无论如何,让我们回到我们的示例。 首先,让我们看一下电子表格(在值得一看的JBoss网站上,对决策表的外观进行精确描述之前 ):我们程序的入口是第一个检查电子表格的地方。如果应授予给定用户购买产品的可能性(最好是下载电子表格并从Too Much Coding的Bitbucket仓库中下载电子表格并使用它们: user_table.xls和product_table.xls或Github user_table.xls和product_table.xls ):
user_table.xls(表工作表)
用户获得批准后,他可能会获得折扣:
product_table.xls(表工作表)
product_table.xls(列出工作表)
正如您在图中看到的,业务问题非常复杂。 每行代表一个规则,每列代表一个条件。 您还记得我最近的帖子中的rules语法吗? 因此,您将了解电子表格的隐藏部分,该部分位于第一行可见的上方:
从2到6的行代表一些固定的配置值,例如规则集,导入( 您已经在最近的文章中看到了 )和函数。 在第7行中,您可以找到RuleTable的名称。 然后在第8行中,在我们的场景中,您将具有CONDITION或ACTION –换句话说,分别是LHS或rhe RHS。 行号9既表示条件中表示的类型,又表示对变量的绑定。 在第10行中,我们具有确切的LHS条件。 第11行显示列的标签。 从第12行开始,我们就有一条规则。 您可以在源代码中找到电子表格。
现在让我们看一下代码。 让我们从定义产品和用户的模式开始。
人格
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:include schemaLocation="user.xsd"/><xsd:element name="Product"><xsd:complexType><xsd:sequence><xsd:element name="Name" type="xsd:string"/><xsd:element name="Type" type="ProductType"/><xsd:element name="Price" type="xsd:double"/><xsd:element name="CountryOfOrigin" type="CountryType"/><xsd:element name="AdditionalInfo" type="xsd:string"/><xsd:element name="Quantity" type="xsd:int"/></xsd:sequence></xsd:complexType></xsd:element><xsd:simpleType name="ProductType"><xsd:restriction base="xsd:string"><xsd:enumeration value="MEDICAL"/><xsd:enumeration value="ELECTRONIC"/></xsd:restriction></xsd:simpleType></xsd:schema>
User.xsd
<?xml version="1.0" encoding="UTF-8"?>
<xsd:schema xmlns:xsd="http://www.w3.org/2001/XMLSchema"><xsd:include schemaLocation="product.xsd"/><xsd:element name="User"><xsd:complexType><xsd:sequence><xsd:element name="UserName" type="xsd:string"/><xsd:element name="UserAge" type="xsd:int"/><xsd:element name="UserCountry" type="CountryType"/><xsd:element name="Decision" type="DecisionType"/><xsd:element name="DecisionDescription" type="xsd:string"/></xsd:sequence></xsd:complexType></xsd:element><xsd:simpleType name="CountryType"><xsd:restriction base="xsd:string"><xsd:enumeration value="PL"/><xsd:enumeration value="USA"/><xsd:enumeration value="GER"/><xsd:enumeration value="SWE"/><xsd:enumeration value="UK"/><xsd:enumeration value="ESP"/></xsd:restriction></xsd:simpleType><xsd:simpleType name="DecisionType"><xsd:restriction base="xsd:string"><xsd:enumeration value="ACCEPTED"/><xsd:enumeration value="REJECTED"/></xsd:restriction></xsd:simpleType></xsd:schema>
由于我们正在使用Maven,因此我们可能会使用一个将XSD转换为Java类的插件。
pom.xml的一部分
<build><pluginManagement><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>2.5.1</version></plugin></plugins></pluginManagement><plugins><plugin><groupId>org.codehaus.mojo</groupId><artifactId>jaxb2-maven-plugin</artifactId><version>1.5</version><executions><execution><id>xjc</id><goals><goal>xjc</goal></goals></execution></executions><configuration><packageName>pl.grzejszczak.marcin.drools.decisiontable.model</packageName><schemaDirectory>${project.basedir}/src/main/resources/xsd</schemaDirectory></configuration></plugin></plugins></build>
多亏了这个插件,我们才能在pl.grzejszczczak.marcin.decisiontable.model包中由JAXB类生成。 现在转到drools-context.xml文件,其中我们就Drools定义了所有必需的bean:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:drools="http://drools.org/schema/drools-spring"xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://drools.org/schema/drools-spring http://drools.org/schema/drools-spring.xsd"><!-- Grid Node identifier that is registered in the CamelContext --><drools:grid-node id="node1"/><drools:kbase id="productsKBase" node="node1"><drools:resources><drools:resource type="DTABLE" source="classpath:rules/product_table.xls"/></drools:resources></drools:kbase><drools:ksession id="productsKSession" name="productsKSession" type="stateless" kbase="productsKBase" node="node1"/><drools:kbase id="usersKBase" node="node1"><drools:resources><drools:resource type="DTABLE" source="classpath:rules/user_table.xls"/></drools:resources></drools:kbase><drools:ksession id="usersKSession" name="usersKSession" type="stateless" kbase="usersKBase" node="node1"/></beans>
如您所见,与最近发布的应用程序上下文相比,存在一些差异。 首先,我们没有提供DRL文件作为知识库中的资源,而是提供了决策表(DTABLE)。 我决定传递两个单独的文件,但是您可以为一个文件提供几个工作表并访问这些工作表(通过Decisiontable-conf元素)。 另外还有一个名为node的附加元素。 我们必须选择Node接口的实现(Execution,Grid…),Camel路由才能正常工作,就像您在Spring应用程序上下文文件中看到的那样。
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:camel="http://camel.apache.org/schema/spring"xmlns:context="http://www.springframework.org/schema/context"xsi:schemaLocation="http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsdhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsdhttp://camel.apache.org/schema/spring http://camel.apache.org/schema/spring/camel-spring-2.8.0.xsd"><import resource="classpath:drools-context.xml"/><!-- Show Spring where to search for the beans (in which packages) --><context:component-scan base-package="pl.grzejszczak.marcin.drools.decisiontable" /><camel:camelContext id="camelContext"><camel:route id="acceptanceRoute"><camel:from uri="direct:acceptanceRoute"/><camel:to uri="drools:node1/usersKSession"/></camel:route><camel:route id="discountRoute"><camel:from uri="direct:discountRoute"/><camel:to uri="drools:node1/productsKSession"/></camel:route></camel:camelContext></beans>
如您所见,为了访问Drools Camel组件,我们必须提供一个节点,通过它我们可以访问适当的知识会话 。 我们定义了两条路线-第一条路线终止于Drools组件,该组件访问用户知识会话,而另一条产品知识会话。
我们有一个称为ProductServiceImpl的ProductService接口实现,给定输入User和Product对象,它们将通过Camel的Producer模板传递到两条以Drools组件结尾的Camel路由。 该产品服务的概念是,我们首先处理用户是否可以购买该软件,然后再检查他将获得什么样的折扣。 实际上,从服务的角度来看,我们只是将对象发送出去并等待响应。 最终,我们收到了响应,我们将用户和产品传递给金融服务实施部门,该实施部门将根据用户购买的产品或在需要时拒绝其要约的价格向用户收费。
ProductServiceImpl.java
package pl.grzejszczak.marcin.drools.decisiontable.service;import org.apache.camel.CamelContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import pl.grzejszczak.marcin.drools.decisiontable.model.Product;
import pl.grzejszczak.marcin.drools.decisiontable.model.User;import static com.google.common.collect.Lists.newArrayList;/*** Created with IntelliJ IDEA.* User: mgrzejszczak* Date: 14.01.13*/
@Component("productServiceImpl")
public class ProductServiceImpl implements ProductService {private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImpl.class);@AutowiredCamelContext camelContext;@AutowiredFinancialService financialService;@Overridepublic void runProductLogic(User user, Product product) {LOGGER.debug("Running product logic - first acceptance Route, then discount Route");camelContext.createProducerTemplate().sendBody("direct:acceptanceRoute", newArrayList(user, product));camelContext.createProducerTemplate().sendBody("direct:discountRoute", newArrayList(user, product));financialService.processOrder(user, product);}}
要记住的另一件至关重要的事情是,Camel Drools组件需要Command对象作为输入。 如您所见,在主体中,我们正在发送对象列表(这些不是Command对象)。 我这样做是有目的的,因为我认为最好不要将我们的代码绑定到具体的解决方案。 如果我们发现有比Drools更好的解决方案怎么办? 我们是要更改已创建的所有代码,还是只是更改骆驼路线以指向我们的新解决方案? 这就是骆驼拥有TypeConverters的原因。 我们在这里也有我们自己的。 首先让我们看一下实现。
ProductTypeConverter.java
package pl.grzejszczak.marcin.drools.decisiontable.converter;import org.apache.camel.Converter;
import org.drools.command.Command;
import org.drools.command.CommandFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import pl.grzejszczak.marcin.drools.decisiontable.model.Product;import java.util.List;/*** Created with IntelliJ IDEA.* User: mgrzejszczak* Date: 30.01.13* Time: 21:42*/
@Converter
public class ProductTypeConverter {private static final Logger LOGGER = LoggerFactory.getLogger(ProductTypeConverter.class);@Converterpublic static Command toCommandFromList(List inputList) {LOGGER.debug("Executing ProductTypeConverter's toCommandFromList method");return CommandFactory.newInsertElements(inputList);}@Converterpublic static Command toCommand(Product product) {LOGGER.debug("Executing ProductTypeConverter's toCommand method");return CommandFactory.newInsert(product);}
}
在Camel网站上有一个关于TypeConverters的很好的教程–如果您需要一些更深入的信息。 无论如何,我们都在注释我们的类和用于将不同类型相互转换的函数。 这里重要的是,我们正在向骆驼展示如何将列表和单个产品转换为Commands。 由于类型擦除,不管提供的类型如何,该方法都将起作用,这就是为什么即使我们提供了产品和用户列表,toCommandFromList函数也将被执行。 除此之外,为了使类型转换器正常工作,我们还必须在/ META-INF / services / org / apache / came / TypeConverter文件中提供类的完整名称(FQN)。
类型转换器
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter
为了正确测试我们的功能,应该编写很多测试来验证规则。 相当不错的方法是将输入文件存储在测试资源文件夹中,然后将其传递给规则引擎,然后将结果与经过验证的输出进行比较(不幸的是,使业务部门开发这样的参考集是相当不可能的输出)。 无论如何,让我们看一下仅验证一些规则的单元测试以及运行这些规则所产生的日志:
ProductServiceImplTest.java
package pl.grzejszczak.marcin.drools.decisiontable.service.drools;import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.commons.lang.builder.ToStringStyle;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import pl.grzejszczak.marcin.drools.decisiontable.model.*;
import pl.grzejszczak.marcin.drools.decisiontable.service.ProductService;import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;/*** Created with IntelliJ IDEA.* User: mgrzejszczak* Date: 03.02.13* Time: 16:06*/
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class ProductServiceImplTest {private static final Logger LOGGER = LoggerFactory.getLogger(ProductServiceImplTest.class);@AutowiredProductService objectUnderTest;@Testpublic void testRunProductLogicUserPlUnderageElectronicCountryPL() throws Exception {int initialPrice = 1000;int userAge = 6;int quantity = 10;User user = createUser("Smith", CountryType.PL, userAge);Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice);assertEquals(DecisionType.REJECTED, user.getDecision());}@Testpublic void testRunProductLogicUserPlHighAgeElectronicCountryPLLowQuantity() throws Exception {int initialPrice = 1000;int userAge = 19;int quantity = 1;User user = createUser("Smith", CountryType.PL, userAge);Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice);assertEquals(DecisionType.ACCEPTED, user.getDecision());}@Testpublic void testRunProductLogicUserPlHighAgeElectronicCountryPLHighQuantity() throws Exception {int initialPrice = 1000;int userAge = 19;int quantity = 8;User user = createUser("Smith", CountryType.PL, userAge);Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);double expectedDiscount = 0.1;assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount));assertEquals(DecisionType.ACCEPTED, user.getDecision());}@Testpublic void testRunProductLogicUserUsaLowAgeElectronicCountryPLHighQuantity() throws Exception {int initialPrice = 1000;int userAge = 19;int quantity = 8;User user = createUser("Smith", CountryType.USA, userAge);Product product = createProduct("Electronic", initialPrice, CountryType.PL, ProductType.ELECTRONIC, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice);assertEquals(DecisionType.REJECTED, user.getDecision());}@Testpublic void testRunProductLogicUserUsaHighAgeMedicalCountrySWELowQuantity() throws Exception {int initialPrice = 1000;int userAge = 22;int quantity = 4;User user = createUser("Smith", CountryType.USA, userAge);Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);assertTrue(product.getPrice() == initialPrice);assertEquals(DecisionType.ACCEPTED, user.getDecision());}@Testpublic void testRunProductLogicUserUsaHighAgeMedicalCountrySWEHighQuantity() throws Exception {int initialPrice = 1000;int userAge = 22;int quantity = 8;User user = createUser("Smith", CountryType.USA, userAge);Product product = createProduct("Some name", initialPrice, CountryType.SWE, ProductType.MEDICAL, quantity);printInputs(user, product);objectUnderTest.runProductLogic(user, product);printInputs(user, product);double expectedDiscount = 0.25;assertTrue(product.getPrice() == initialPrice * (1 - expectedDiscount));assertEquals(DecisionType.ACCEPTED, user.getDecision());}private void printInputs(User user, Product product) {LOGGER.debug(ReflectionToStringBuilder.reflectionToString(user, ToStringStyle.MULTI_LINE_STYLE));LOGGER.debug(ReflectionToStringBuilder.reflectionToString(product, ToStringStyle.MULTI_LINE_STYLE));}private User createUser(String name, CountryType countryType, int userAge){User user = new User();user.setUserName(name);user.setUserCountry(countryType);user.setUserAge(userAge);return user;}private Product createProduct(String name, double price, CountryType countryOfOrigin, ProductType productType, int quantity){Product product = new Product();product.setPrice(price);product.setCountryOfOrigin(countryOfOrigin);product.setName(name);product.setType(productType);product.setQuantity(quantity);return product;}}
当然,测试中的log.debugs完全是多余的,但是我希望您能快速看到这些规则是可行的。 很抱歉记录的长度,但是我写了一些测试来显示不同的规则组合(实际上最好有太多的记录而不是相反的记录)
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[userName=SmithuserAge=6userCountry=PLdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=10
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (PL) you can't buy this product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1d48043[userName=SmithuserAge=6userCountry=PLdecision=REJECTEDdecisionDescription=Sorry, according to your age (< 18) and country (PL) you can't buy this product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1e8f2a0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=10
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[userName=SmithuserAge=19userCountry=PLdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=1
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, no discount will be granted.
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@b28f30[userName=SmithuserAge=19userCountry=PLdecision=ACCEPTEDdecisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@d6a0e0[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=Sorry, no discount will be granted.quantity=1
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[userName=SmithuserAge=19userCountry=PLdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations - you've been granted a 10% discount!
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@14510ac[userName=SmithuserAge=19userCountry=PLdecision=ACCEPTEDdecisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1499616[name=Electronictype=ELECTRONICprice=900.0countryOfOrigin=PLadditionalInfo=Congratulations - you've been granted a 10% discount!quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[userName=SmithuserAge=19userCountry=USAdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Sorry, according to your age (< 18) and country (USA) you can't buy this product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:29 Sorry, user has been rejected...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@17667bd[userName=SmithuserAge=19userCountry=USAdecision=REJECTEDdecisionDescription=Sorry, according to your age (< 18) and country (USA) you can't buy this product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@ad9f5d[name=Electronictype=ELECTRONICprice=1000.0countryOfOrigin=PLadditionalInfo=<null>quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[userName=SmithuserAge=22userCountry=USAdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[name=Some nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<null>quantity=4
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@9ff588[userName=SmithuserAge=22userCountry=USAdecision=ACCEPTEDdecisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@1b0d2d0[name=Some nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<null>quantity=4
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[userName=SmithuserAge=22userCountry=USAdecision=<null>decisionDescription=<null>
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[name=Some nametype=MEDICALprice=1000.0countryOfOrigin=SWEadditionalInfo=<null>quantity=8
]
pl.grzejszczak.marcin.drools.decisiontable.service.ProductServiceImpl:31 Running product logic - first acceptance Route, then discount Route
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you have successfully bought the product
pl.grzejszczak.marcin.drools.decisiontable.converter.ProductTypeConverter:25 Executing ProductTypeConverter's toCommandFromList method
pl.grzejszczak.marcin.drools.decisiontable.service.ProductService:8 Congratulations, you are granted a discount
pl.grzejszczak.marcin.drools.decisiontable.service.FinancialServiceImpl:25 User has been approved - processing the order...
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:150 pl.grzejszczak.marcin.drools.decisiontable.model.User@1b27882[userName=SmithuserAge=22userCountry=USAdecision=ACCEPTEDdecisionDescription=Congratulations, you have successfully bought the product
]
pl.grzejszczak.marcin.drools.decisiontable.service.drools.ProductServiceImplTest:151 pl.grzejszczak.marcin.drools.decisiontable.model.Product@5b84b[name=Some nametype=MEDICALprice=750.0countryOfOrigin=SWEadditionalInfo=Congratulations, you are granted a discountquantity=8
]
在这篇文章中,我介绍了如何通过给他一个他可以使用的工具(电子表格中的决策表)来将您的一些开发工作推向BA。 而且,您现在将如何将Drools与Camel集成。 希望您会看到如何简化业务规则的实现(从而将实施和支持的成本降至最低),同时牢记更改的可能性。 我希望这个示例能够比以前关于Drools的文章更好地说明用Java实现所有业务规则将有多么困难。 如果您在决策表,与Spring和Camel的集成方面对Drools有任何经验,请随时发表评论-让我们进行讨论。 所有代码都可以在Bitbucket和GitHub的 Too Much Coding存储库中获得。
翻译自: https://www.javacodegeeks.com/2013/04/drools-decision-tables-with-camel-and-spring.html