官网地址: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 {
@Override
public 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 {
@Override
public 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减去30
if (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 {
@Override
public 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 {
@Override
public 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 {
@Override
public 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 {
@Override
public 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. 测试
@Resource
private 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";
}
}