突然发现一个非常棒的框架,迫不及待的想要和大家分享一下
规则引擎
规则引擎是一种工具,它使得这种计算模型编程变得更容易。它可能是一个完整的开发环境,或者一个可以在传统平台上工作的框架。生产规则计算模型最适合仅解决一部分计算问题,因此规则引擎可以更好地嵌入到较大的系统中。
实际业务中存在大量的前置条件,以及应用的授权逻辑,都有非常多的规则管理,由于业务的变化大,需求迭代快,需要不断的嵌套规则,硬编码开发。基于业务需要,希望能建立规则引擎,将规则代码从业务中抽离出来,降低规则迭代成本,降低if else等的规则嵌套,增强代码的维护性和复用性。
例如:年龄大于50岁,坐公交 8折
70岁 免费
残疾 免费
退伍军人 免费
学生 半价
。。。。。
往往存在大量的判断 实际写入业务,到后期就会出现维护太麻烦,稍微不注意忘记写注释的话,后期还非常有可能自己写的业务自己也看不懂了。
倘若有一个专门维护这些规则的那就好了
Easy Rules,Drools,Aviator表达式求值引擎,Rule Book、Oracle Rules SDK、Blaze (fico)、IBM Decision Manager,DTRules,DSL规则引擎
规则引擎由三部分
商品搜索----按地址---价格区间--店铺--商品类型--品牌--包装形式
公交刷卡,促销活动等等等等
只要多种条件组合限定什么的都可以采用规则引擎来控制
关系节点为了控制业务流转
AND所有子节点中,有一个返回false 该节点也将是false,全部是true才是true,在执行到false的地方终止执行,类似于Java的&&
ANY所有子节点中,有一个返回true 该节点也将是true,全部false则false,在执行到true的地方终止执行,类似于Java的||
ALL所有子节点都会执行,有任意一个返回true该节点也是true,没有true有一个节点是false则false,没有true也没有false则返回none,所有子节点执行完毕终止
NONE所有子节点都会执行,无论子节点返回什么,都返回none
TRUE所有子节点都会执行,无论子节点返回什么,都返回true,没有子节点也返回true(其他没有子节点返回none)
叶子节点为真正处理的节点
Flow一些条件与规则节点,如例子中的ScoreFlow
Result一些结果性质的节点,如例子中的AmountResult,PointResult
None一些不干预流程的动作,如装配工作等
好了咱们直接来操作一下
源代码:ice: Java规则引擎-ice(用全新的思想编排规则)对于业务中需要设计复杂/灵活变动业务(规则/流程),提供一个全新的抽象编排解决方案新的编排思想,轻量级,高性能,提供可视化操作页面
下载好了之后
可以看到ice里面带了一个调用例子,非常方便我们来学习
然后我们发现例子还是有些不方便我们使用,好了我们改造一下
咱们在ice-test的pom.xml里面,直接拿我的替换就ok,当然要看看版本哈
我写这个博客的时候使用的springboot版本是2.6.8这个版本,可以用swagger3.0.0来就好
4.0.0
com.waitmoon.ice
ice
1.1.0
ice-test
jar
ice-test
1.5.22
3.0.0
1.9.1
1.2.47
com.waitmoon.ice
ice-client-spring-boot-starter
1.1.0
org.springframework.boot
spring-boot-starter-web
com.googlecode.aviator
aviator
5.3.1
io.springfox
springfox-swagger2
${springfox.version}
io.swagger
swagger-annotations
io.swagger
swagger-models
io.swagger
swagger-annotations
${swagger-ui.version}
io.swagger
swagger-models
${swagger-ui.version}
io.springfox
springfox-swagger-ui
${springfox.version}
com.github.xiaoymin
swagger-bootstrap-ui
${swagger-bootstrap-ui.version}
com.alibaba
fastjson
${fastjson.version}
org.springframework.boot
spring-boot-maven-plugin
ice-test
可以看到我较demo多写了两个config的类文件
package com.ice.test.config;
import io.swagger.annotations.ApiOperation;
import io.swagger.models.auth.In;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import springfox.documentation.builders.ApiInfoBuilder;
import springfox.documentation.builders.PathSelectors;
import springfox.documentation.builders.RequestHandlerSelectors;
import springfox.documentation.service.ApiInfo;
import springfox.documentation.service.ApiKey;
import springfox.documentation.service.Contact;
import springfox.documentation.service.SecurityScheme;
import springfox.documentation.spi.DocumentationType;
import springfox.documentation.spring.web.plugins.Docket;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
import java.util.Arrays;
import java.util.List;
@Configuration
@EnableSwagger2
public class SwaggerConfig {
@Bean
public Docket createRestApi1() {
return new Docket(DocumentationType.SWAGGER_2).enable(true).apiInfo(apiInfo()).select()
.apis(RequestHandlerSelectors.withMethodAnnotation(ApiOperation.class))
.apis(RequestHandlerSelectors.basePackage("com.ice.test.controller"))
.paths(PathSelectors.any()).build().securitySchemes(apiKeyList()).groupName("系统接口");
}
private ApiInfo apiInfo() {
return new ApiInfoBuilder()
.title("系统接口文档")
.description("这是系统接口文档说明")
.contact(new Contact("h2", "", ""))
.version("1.0")
.build();
}
private List apiKeyList() {
return Arrays.asList(new ApiKey("登录token", "token", In.HEADER.name()),
new ApiKey("设备类型(android,ios,pc)---必填", "deviceType", In.HEADER.name()));
}
}
package com.ice.test.config;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.servlet.mvc.method.RequestMappingInfoHandlerMapping;
import springfox.documentation.spring.web.plugins.WebFluxRequestHandlerProvider;
import springfox.documentation.spring.web.plugins.WebMvcRequestHandlerProvider;
import java.lang.reflect.Field;
import java.util.List;
import java.util.stream.Collectors;
@Configuration
public class BeanPostProcessorConfig {
@Bean
public static BeanPostProcessor springfoxHandlerProviderBeanPostProcessor() {
return new BeanPostProcessor() {
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean instanceof WebMvcRequestHandlerProvider || bean instanceof WebFluxRequestHandlerProvider) {
customizeSpringfoxHandlerMappings(getHandlerMappings(bean));
}
return bean;
}
private void customizeSpringfoxHandlerMappings(List mappings) {
List copy = mappings.stream()
.filter(mapping -> mapping.getPatternParser() == null)
.collect(Collectors.toList());
mappings.clear();
mappings.addAll(copy);
}
@SuppressWarnings("unchecked")
private List getHandlerMappings(Object bean) {
try {
Field field = ReflectionUtils.findField(bean.getClass(), "handlerMappings");
field.setAccessible(true);
return (List) field.get(bean);
} catch (IllegalArgumentException | IllegalAccessException e) {
throw new IllegalStateException(e);
}
}
};
}
}
server:
port: 8082
spring:
profiles:
active: dev
mvc:
pathmatch:
matching-strategy: ant_path_matcher
ice:
app: 1
# server: zookeeper:localhost:2181,localhost:2182,localhost:2183
server: localhost:18121
scan: com.ice.test
pool:
parallelism: -1
test:
value: 123
environment: dev
然后开启注解
package com.ice.test.controller;
import com.alibaba.fastjson.JSONArray;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.ice.common.utils.JacksonUtils;
import com.ice.core.Ice;
import com.ice.core.context.IceContext;
import com.ice.core.context.IcePack;
import com.ice.core.context.IceRoam;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;
import java.util.List;
import java.util.Map;
/**
* @author waitmoon
*/
@Slf4j
@RestController
public class TestController {
@PostMapping("/test")
@ApiOperation(value = "test")
public List test(@RequestBody Map map) throws JsonProcessingException {
IcePack pack = JacksonUtils.readJson(JacksonUtils.toJsonString(map), IcePack.class);
return Ice.processCtx(pack);
}
@GetMapping( "/recharge")
@ApiOperation(value = "recharge")
public String recharge(@RequestParam Integer cost, @RequestParam Integer uid) {
IcePack pack = new IcePack();
pack.setScene("recharge");
IceRoam roam = new IceRoam();
roam.put("cost", cost);
roam.put("uid", uid);
pack.setRoam(roam);
Ice.syncProcess(pack);
return JacksonUtils.toJsonString(roam.get("result"));
}
@RequestMapping(value = "/consume", method = RequestMethod.GET)
public String consume(@RequestParam Integer cost, @RequestParam Integer uid) {
IcePack pack = new IcePack();
pack.setScene("consume");
IceRoam roam = new IceRoam();
roam.put("cost", cost);
roam.put("uid", uid);
pack.setRoam(roam);
Ice.syncProcess(pack);
return JacksonUtils.toJsonString(roam.get("result"));
}
}
这个位置我也稍微改动了一下
ice-server的数据什么的改一下这个我就不多说了
运行IceServerApplication就可以直接访问
官网demo的规则引擎配置参考以下步骤,到后面视频作者用postman搞事情的时候,我们就可以关掉了,我们实现了swagger,我真是个小聪明
你也可以直接导入我的配置
{
"app": 1,
"base": {
"confId": 1,
"debug": 7,
"id": 1,
"name": "重置活动",
"scenes": "recharge-1,recharge"
},
"confUpdates": [
{
"confField": "{"time":"2022-09-26 00:00:00"}",
"confId": 2,
"confName": "com.ice.test.none.TimeChangeNone",
"iceId": 1,
"id": 10,
"name": "改时间节点",
"type": 7
}
],
"confs": [
{
"confField": "{"time":"2022-09-24 00:00:00"}",
"confName": "com.ice.test.none.TimeChangeNone",
"id": 2,
"name": "改时间节点",
"type": 7
},
{
"confField": "{"key":"uid","value":5}",
"confName": "com.ice.test.result.AmountResult",
"id": 7,
"name": "满100元 发放5元优惠额",
"type": 6
},
{
"id": 5,
"name": "50元10积分",
"sonIds": "8,9",
"start": 1663948800000,
"timeType": 5,
"type": 1
},
{
"confField": "{"key":"cost","score":50}",
"confName": "com.ice.test.flow.ScoreFlow",
"id": 8,
"name": "满50元",
"type": 5
},
{
"confField": "{"score":100,"key":"cost"}",
"confName": "com.ice.test.flow.ScoreFlow",
"id": 6,
"name": "满100元",
"type": 5
},
{
"confField": "{"key":"uid","value":10}",
"confName": "com.ice.test.result.PointResult",
"id": 9,
"name": "满50元发放10积分",
"type": 6
},
{
"id": 1,
"sonIds": "2,3",
"type": 0
},
{
"id": 4,
"name": "100元5余额",
"sonIds": "6,7",
"type": 1
},
{
"end": 1664467200000,
"id": 3,
"name": "9.24-9.30",
"sonIds": "4,5",
"start": 1663948800000,
"timeType": 7,
"type": 4
}
]
}
也可以参考视频设置
规则引擎-ice开发&配置简述_哔哩哔哩_bilibili
好了规则配置好了以后,就可以
我们拿ice-test来试一下
因为我们改造了这个demo,可以直接访问swagger的接口文档
当我们金额超过50了,就出现 "SEND_POINT": true
输入100就返回了 "SEND_AMOUNT": true
当然你也可以参考引入关系节点里面的关键字修改 来设置你要的结果
如果有多个场景一致的情况回出现叠加的结果
本demo可以参考https://download.csdn.net/download/qq_14926283/86695151
也可以参考官方地址首页 | ice