规则引擎之LiteFlow应用

 

 官网地址:LiteFlow

DEMO 整体结构

1.引入maven依赖

<dependency><groupId>com.yomahub</groupId><artifactId>liteflow-spring-boot-starter</artifactId><version>2.11.4.2</version>
</dependency>

 2. 配置yml

liteflow:#规则文件路径rule-source: config/flow.el.xml

3. 模拟商品订单流程,下单-->计算优惠->计算邮费->总价-> 创建订单

3.0 实体类
package com.example.demo.domain;import lombok.Data;import java.math.BigDecimal;
import java.util.List;/*** @author Jerry* @date 2024-04-10 16:15* 订单*/
@Data
public class Order {private String orderId; // 订单号private List<Product> productList; // 商品列表private BigDecimal amount; // 总价private BigDecimal shippingCost; // 折扣价格
}
package com.example.demo.domain;import lombok.AllArgsConstructor;
import lombok.Data;import java.math.BigDecimal;/*** @author Jerry* @date 2024-04-10 16:13*/
@Data
@AllArgsConstructor
public class Product {private String productType; // 商品类型private String productName; // 商品名称private BigDecimal price; // 商品价格
}

 

 3.1 流程上下文
package com.example.demo.liteflow;import com.example.demo.domain.Order;
import com.example.demo.domain.Product;
import lombok.Data;import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;/*** @author Jerry* @date 2024-04-10 16:19* 订单流程规则上下文*/
@Data
public class OrderProcessFlowContext {private List<Product> productList = new ArrayList<>(); // 商品列表private Order order; // 订单private Map<String, BigDecimal> strategyMap = new HashMap<>(); // 优惠策略
}
3.2 流程启动节点 
package com.example.demo.liteflow.node;import cn.hutool.core.lang.UUID;
import com.example.demo.domain.Order;
import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @author Jerry* @date 2024-04-10 16:08* 优惠券计算组件*/
@Slf4j
@Component
@LiteflowComponent(id = "initOrderNode", name = "流程启动节点") // id - 在流程中的名称
public class InitOrderNode extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);Order order = new Order();order.setOrderId(UUID.fastUUID().toString());order.setProductList(contextBean.getProductList());contextBean.setOrder(order);log.info("流程启动");}
}
3.3 满减策略节点
package com.example.demo.liteflow.node.strategy;import com.example.demo.domain.Product;
import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.List;/*** @author Jerry* @date 2024-04-10 16:30* 满减策略*/
@Slf4j
@Component
@LiteflowComponent(id = "free", name = "满减策略节点")
public class Free extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);List<Product> productList = contextBean.getProductList();BigDecimal amount = new BigDecimal(0);for (Product product : productList) {amount = amount.add(product.getPrice());}// 满200减去30if (amount.intValue() >= 200) {amount = amount.subtract(new BigDecimal(30));}log.info("满减后商品总价:{}", amount.floatValue());contextBean.getStrategyMap().put("FREE", amount);}
}
3.4 折扣策略节点
package com.example.demo.liteflow.node.strategy;import com.example.demo.domain.Product;
import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;/*** @author Jerry* @date 2024-04-10 16:37*/
@Slf4j
@Component
@LiteflowComponent(id = "discount", name = "打折策略节点")
public class Discount extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);List<Product> productList = contextBean.getProductList();BigDecimal amount = new BigDecimal(0);for (Product product : productList) {if ("零食".equals(product.getProductType())) {amount = amount.add(product.getPrice().multiply(new BigDecimal("0.8")));} else if ("电器".equals(product.getProductType())) {amount = amount.add(product.getPrice().multiply(new BigDecimal("0.6")));} else {amount = amount.add(product.getPrice());}amount = amount.setScale(2, RoundingMode.UP);log.info("折扣后商品总价:{}", amount.floatValue());contextBean.getStrategyMap().put("DISCOUNT", amount);}}
}
3.5  确认优惠券策略节点
package com.example.demo.liteflow.node;import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.java.Log;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.math.BigDecimal;
import java.util.Comparator;
import java.util.Map;
import java.util.Optional;/*** @author Jerry* @date 2024-04-10 16:44* 优惠券计算抵扣组件*/
@Slf4j
@Component
@LiteflowComponent(id = "confirmStrategyNode", name = "确认优惠券策略节点")
public class ConfirmStrategyNode extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);Map<String, BigDecimal> strategyMap = contextBean.getStrategyMap();Map.Entry<String, BigDecimal> min = strategyMap.entrySet().stream().min(Map.Entry.comparingByValue()).get();log.info("优惠策略已确认:{}", min.getValue());contextBean.getOrder().setAmount(min.getValue());}
}
3.6 确认邮费节点
package com.example.demo.liteflow.node;import com.example.demo.domain.Order;
import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;import java.math.BigDecimal;/*** @author Jerry* @date 2024-04-10 17:06* 邮费计算*/
@Slf4j
@Component
@LiteflowComponent(id = "confirmShippingCostNode", name = "确认邮费节点")
public class ConfirmShippingCostNode extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);Order order = contextBean.getOrder();if (order.getAmount().intValue() > 68) {order.setShippingCost(new BigDecimal(0));} else {order.setShippingCost(new BigDecimal(10));}log.info("邮费已确认:{}", order.getShippingCost());}
}
3.7 创建订单节点
package com.example.demo.liteflow.node;import com.example.demo.domain.Order;
import com.example.demo.liteflow.OrderProcessFlowContext;
import com.yomahub.liteflow.annotation.LiteflowComponent;
import com.yomahub.liteflow.core.NodeComponent;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;/*** @author Jerry* @date 2024-04-10 17:11*/
@Slf4j
@Component
@LiteflowComponent(id = "createOrderNode", name = "创建订单节点")
public class CreateOrderNode extends NodeComponent {@Overridepublic void process() throws Exception {OrderProcessFlowContext contextBean = this.getContextBean(OrderProcessFlowContext.class);Order order = contextBean.getOrder();log.info("订单创建成功:{}", order);}
}

4. flow.el.xml 配置文件

<?xml version="1.0" encoding="UTF-8"?>
<flow><chain name="orderChain">THEN(initOrderNode,WHEN(free,discount),confirmStrategyNode,confirmShippingCostNode,createOrderNode);</chain>
</flow>

5. 测试

   @Resourceprivate FlowExecutor flowExecutor;@GetMapping("liteFlow")public String testLiteFlow() {OrderProcessFlowContext processFlowContext = new OrderProcessFlowContext();processFlowContext.getProductList().add(new Product("零食", "辣条", new BigDecimal(50)));processFlowContext.getProductList().add(new Product("电器", "洗衣机", new BigDecimal(200)));LiteflowResponse response = flowExecutor.execute2Resp("orderChain", null, processFlowContext);OrderProcessFlowContext context = response.getContextBean(OrderProcessFlowContext.class);if (response.isSuccess()) {return "success :" + JSONUtil.toJsonStr(context.getOrder());} else {return "error";}}

6.结果

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/805126.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

蓝桥杯第十三届蓝桥杯大赛软件赛省赛C/C++ 大学 A 组题解

1.裁纸刀 题目链接&#xff1a;0裁纸刀 - 蓝桥云课 (lanqiao.cn) 思路&#xff1a;简单的推导一下公式 #include <iostream> using namespace std; int main() {// 请在此输入您的代码cout<<41921*20<<endl;return 0; } 2.灭鼠先锋 题目链接&#xff1a…

Linux--进程的概念(一)

目录 一、冯诺依曼体系结构二、操作系统2.1 什么是操作系统2.2 操作系统的意义 三、进程3.1 进程的基本概念3.2 描述进程——PCB3.3 进程和程序的区别3.4 task_struct-PCB的一种3.5 task_struct的内容分类 四、如何查看进程4.1 通过系统文件查看进程4.2 通过ps指令查看进程 五、…

uni-app项目创建方式

原生小程序与uni-app的区别 创建uni-app的方式 1.通过HBuilderX创建 2.通过命令行创建 vue3ts版&#xff1a;npx degit dcloudio/uni-preset-vue#vite-ts 项目名称 用vscode开发uni-app项目 安装命令&#xff1a;npm i -D types/wechat-miniprogram uni-helper/uni-app-typ…

蓝桥杯C/C++A组省赛历年真题题解(2020~2023)

刷题整理2020~2023蓝桥A组真题。 2020202120222023门牌制作卡片&#xff08;模拟题&#xff09;裁纸刀幸运数既约分数直线&#xff08;数学枚举&#xff09;灭鼠先锋有奖问答蛇形填数货物摆放(因子暴力枚举&#xff09;求和平方差七段码路径选数异或更小的数平面分割回路计数爬…

大话设计模式——17.状态模式(State Pattern)

简介 对象的行为依赖于它的状态&#xff08;属性&#xff09;&#xff0c;可以根据状态的改变而改变相关行为。 UML图&#xff1a; 应用场景&#xff1a; 对象的行为取决于其状态&#xff0c;并且必须要在运行时刻根据状态而改变行为代码中包含大量与对象状态有关的条件语句 …

4月10日(信息差)

快捷新闻&#xff1a; &#x1f396; 素材来源官方媒体/网络新闻 &#x1f384; 地震预警App被曝收10元年费&#xff0c;回应称仅限苹果系统 &#x1f30d; 2024清明档首日票房破2亿 &#x1f30b; 浙江省杭州市余杭区设立2亿元网络微短剧发展基金 &#x1f381; 抖音拟以超 7…

oracle EXP-00028: 无法打开用于写入的 expdate.dmp

用exp备份带日期格式的文件名,命令如下: exp erpsys/12345678mytestdafilee:\backup\erpsys_mytestda_%date:~0,10%.dmp loge:\backup\erpsys_mytestda_%date:~0,10%.log rowsn buffer65536000 ownererpsys 成功执行后文件名字应如下: dmp文件是erpsys_mytestda_2012-06-13.…

小狐狸转账失败,提示gas费过高

做web3开发的时候&#xff0c;明明自己小狐狸里还有2.15的代币&#xff0c;但页面我要转出2.1的时候&#xff0c;明明是够的&#xff0c;而且使用小狐狸提示gas费用是21000&#xff0c;这已经是最小的了&#xff0c;但网页转出到其他账户总是提示失败。而且这个错误非常不好捕获…

Sqlserver格式化日期

使用CONVERT函数格式化日期&#xff1a; CONVERT函数允许你将日期/时间值转换为特定的字符串格式。它接受三个参数&#xff1a;转换的目标数据类型&#xff08;通常是一个字符串类型&#xff09;、要转换的表达式&#xff08;日期或时间值&#xff09;和样式代码。 示例&#x…

软考系规图文领读第1章:还是那碗温白开

第1章信息系统综合知识一共有4部分内容&#xff0c;分别是信息的定义和属性、信息化、信息系统和IT战略。这4部分的主体在第2部分的信息化和第3部分的信息系统。 和中项、高项都大同小异&#xff0c;都是从信息系统知识开始&#xff0c;越来越像一碗没有任何滋味的温白开&#…

使用OMP复原一维信号(MATLAB)

参考文献 https://github.com/aresmiki/CS-Recovery-Algorithms/tree/master MATLAB代码 %% 含有噪声 % minimize ||x||_1 % subject to: (||Ax-y||_2)^2<eps; % minimize : (||Ax-y||_2)^2lambda*||x||_1 % y传输中可能含噪 yyw % %% clc;clearvars; close all; %% 1.构…

【Redis】底层跳表实现

先巩固Redis的数据类型以及底层的数据结构&#xff1a; ZSet&#xff08;有序集合&#xff09;可以使用两种不同的内部数据结构来表示&#xff1a;压缩列表&#xff08;ziplist&#xff09;和跳跃表&#xff08;skiplist&#xff09;。 跳表是redis底层SortedSet(ZSet)的数据…

深入理解nginx realip模块[上]

目录 1. 引言2. Real IP模块的使用2.1 启用Real IP模块2.2 配置Real IP模块2.2.1 配置指令2.2.2 举例 3. 变量的使用 深入理解nginx realip模块[上] 深入理解nginx realip模块[下] 1. 引言 nginx 的 Real IP 模块用于解决代理服务器转发请求到nginx上时可能出现的 IP 地址问题…

python使用leveldb

LevelDB 是由 Google 开发的一个快速的键值存储库&#xff0c;提供了一个持久化的有序映射&#xff0c;非常适合用作简单的高性能数据库。 安装 Plyvel 首先&#xff0c;使用 pip3 来安装 plyvel pip3 install plyvel基本用法 接下来&#xff0c;介绍使用 plyvel 来操作 Le…

C++11 如何优雅地封装线程库以实现多线程编程

在C11标准中&#xff0c;多线程编程被正式纳入语言规范&#xff0c;通过引入 <thread> 头文件&#xff0c;C为开发者提供了一套统一且高效的线程API。std::thread 是 C11 标准库中用于创建和管理线程的核心类。本文将详细介绍C11是如何封装Thread库&#xff0c;以及如何通…

QT:信号与槽

作业&#xff1a; 完善对话框&#xff0c;点击登录对话框&#xff0c;如果账号和密码匹配&#xff0c;则弹出信息对话框&#xff0c;给出提示”登录成功“&#xff0c;提供一个Ok按钮&#xff0c;用户点击Ok后&#xff0c;关闭登录界面&#xff0c;跳转到其他界面 如果账号和…

使用axios进行前后端数据传输

最近在和朋友合作写一个新的项目&#xff0c;前后端进行了分离&#xff0c;既然是分离的&#xff0c;肯定需要交互&#xff0c;今天这篇文章详细介绍一下数据交互的一种常见方式&#xff1a;使用axios,希望对大家有所帮助。 前端&#xff1a;以LoginPage.vue登录页面为例&…

HarmonyOS实战开发-如何实现电话服务中发送短信的功能。

介绍 本示例使用ohos.telephony.sms 接口展示了电话服务中发送短信的功能。 效果预览 使用说明&#xff1a; 首页点击创建联系人&#xff0c;弹框输入联系人姓名和电话&#xff0c;点击确定按钮后&#xff0c;联系人列表中添加该联系人;点击管理&#xff0c;该按钮变成取消&…

同步压缩理论

参考 在频率方向进行能量重新分配&#xff08;分配到中心&#xff09; 时频重排

【Rust】——改进I/O项目

&#x1f4bb;博主现有专栏&#xff1a; C51单片机&#xff08;STC89C516&#xff09;&#xff0c;c语言&#xff0c;c&#xff0c;离散数学&#xff0c;算法设计与分析&#xff0c;数据结构&#xff0c;Python&#xff0c;Java基础&#xff0c;MySQL&#xff0c;linux&#xf…