去评论
dz插件网

告别if else!试试这款轻量级流程引擎吧,自带IDEA插件真香!

IT618发布
2026/09/07 14:10:04



mall学习教程官网:macrozheng.com

在我们平时做项目的时候,经常会遇到复杂的业务逻辑,如果使用if else来实现的话,往往会很冗长,维护成本也很高。今天给大家推荐一个轻量级流程引擎LiteFlow,可以优雅地实现复杂的业务逻辑,本文将以电商项目中的订单价格计算为例来聊聊它的使用。

LiteFlow简介


LiteFlow是一个轻量且强大的国产流程引擎框架,可用于复杂的组件化业务的编排工作。通过它我们可以把业务逻辑都定义到不同组件之中,然后使用简洁的规则文件来串联整个流程,从而实现复杂的业务逻辑。

LiteFlow主要特性如下:

下面是使用LiteFlow来实现订单价格计算的展示页面,实现起来确实比较优雅!



这或许是一个对你有用的开源项目,mall项目是一套基于 SpringBoot + Vue + uni-app 实现的电商系统(Github标星60K),采用Docker容器化部署,后端支持多模块和微服务架构。包括前台商城项目和后台管理系统,能支持完整的订单流程!涵盖商品、订单、购物车、权限、优惠券、会员、支付等功能!
  • Boot项目:https://github.com/macrozheng/mall
  • Cloud项目:https://github.com/macrozheng/mall-swarm
  • 视频教程:https://www.macrozheng.com/video/

项目演示:


IDEA插件


LiteFlow还拥有自己的IDEA插件LiteFlowX,通过该插件能支持规则文件的智能提示、语法高亮、组件与规则文件之间的跳转及LiteFlow工具箱等功能,强烈建议大家安装下。








规则表达式


接下来我们学习下规则表达式,也就是规则文件的编写,入门表达式非常简单,但这对使用LiteFlow非常有帮助!

串行编排


当我们想要依次执行a、b、c、d四个组件时,直接使用THEN关键字即可。
<chain name="chain1">
    THEN(a, b, c, d);
</chain>

并行编排


如果想并行执行a、b、c三个组件的话,可以使用WHEN关键字。
<chain name="chain1">
    WHEN(a, b, c);
</chain>

选择编排


如果想实现代码中的switch逻辑的话,例如通过a组件的返回结果进行判断,如果返回的是组件名称b的话则执行b组件,可以使用SWITCH关键字。
<chain name="chain1">
    SWITCH(a).to(b, c, d);
</chain>

条件编排


如果想实现代码中的if逻辑的话,例如当x组件返回为true时执行a,可以使用IF关键字。
<chain name="chain1">
    IF(x, a);
</chain>

如果想实现if的三元运算符逻辑的话,例如x组件返回为true时执行a组件,返回为false时执行b组件,可以编写如下规则文件。
<chain name="chain1">
    IF(x, a, b);
</chain>

如果想实现if else逻辑的话,可以使用ELSE关键字,和上面实现效果等价。
<chain name="chain1">
    IF(x, a).ELSE(b);
</chain>

如果想实现else if逻辑的话,可以使用ELIF关键字。
<chain name="chain1">
    IF(x1, a).ELIF(x2, b).ELSE(c);
</chain>

使用子流程


当某些流程比较复杂时,我们可以定义子流程,然后在主流程中引用,这样逻辑会比较清晰。

例如我们有如下子流程,执行C、D组件。
<chain name="subChain">
   THEN(C, D);
</chain>

然后我们直接在主流程中引用子流程即可。
<chain name="mainChain">
    THEN(
     A, B,
     subChain,
     E
    );
</chain>

使用


学习完规则表达式后,我们发现LiteFlow寥寥几个关键字,就可以实现复杂的流程了。下面我们将以订单价格计算为例,实践下LiteFlow这个流程引擎框架。
<dependency>
    <groupId>com.yomahub</groupId>
    <artifactId>liteflow-spring-boot-starter</artifactId>
    <version>2.8.5</version>
</dependency>
server:
  port: 8580
liteflow:
  #规则文件路径
  rule-source: liteflow/*.el.xml

https://gitee.com/bryan31/liteflow-example




/**
 * 优惠券抵扣计算组件
 */
@Component("couponCmp")
public class CouponCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        PriceContext context = this.getContextBean(PriceContext.class);

        /**这里Mock下根据couponId取到的优惠卷面值为15元**/
        Long couponId = context.getCouponId();
        BigDecimal couponPrice = new BigDecimal(15);

        BigDecimal prePrice = context.getLastestPriceStep().getCurrPrice();
        BigDecimal currPrice = prePrice.subtract(couponPrice);

        context.addPriceStep(new PriceStepVO(PriceTypeEnum.COUPON_DISCOUNT,
                couponId.toString(),
                prePrice,
                currPrice.subtract(prePrice),
                currPrice,
                PriceTypeEnum.COUPON_DISCOUNT.getName()));
    }

    @Override
    public boolean isAccess() {
        PriceContext context = this.getContextBean(PriceContext.class);
        if(context.getCouponId() != null){
            return true;
        }else{
            return false;
        }
    }
}
/**
 * 运费条件组件
 */
@Component("postageCondCmp")
public class PostageCondCmp extends NodeSwitchComponent {
    @Override
    public String processSwitch() throws Exception {
        PriceContext context = this.getContextBean(PriceContext.class);
        //根据参数oversea来判断是否境外购,转到相应的组件
        boolean oversea = context.isOversea();
        if(oversea){
            return "overseaPostageCmp";
        }else{
            return "postageCmp";
        }
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="promotionChain">
        THEN(fullCutCmp, fullDiscountCmp, rushBuyCmp);
    </chain>
</flow>
<?xml version="1.0" encoding="UTF-8"?>
<flow>
    <chain name="mainChain">
        THEN(
            checkCmp, slotInitCmp, priceStepInitCmp,
            promotionConvertCmp, memberDiscountCmp,
            promotionChain, couponCmp,
            SWITCH(postageCondCmp).to(postageCmp, overseaPostageCmp),
            priceResultCmp, stepPrintCmp
        );
    </chain>
</flow>
@Controller
public class PriceExampleController {

    @Resource
    private FlowExecutor flowExecutor;

    @RequestMapping(value = "/submit", method = RequestMethod.POST)
    @ResponseBody
    public String submit(@Nullable @RequestBody String reqData) {
        try {
            PriceCalcReqVO req = JSON.parseObject(reqData, PriceCalcReqVO.class);
            LiteflowResponse response = flowExecutor.execute2Resp("mainChain", req, PriceContext.class);
            return response.getContextBean(PriceContext.class).getPrintLog();
        } catch (Throwable t) {
            t.printStackTrace();
            return "error";
        }
    }
}
public class PriceContext {

    /**
     * 订单号
     */
    private String orderNo;

    /**
     * 是否境外购
     */
    private boolean oversea;

    /**
     * 商品包
     */
    private List<ProductPackVO> productPackList;

    /**
     * 订单渠道
     */
    private OrderChannelEnum orderChannel;

    /**
     * 会员CODE
     */
    private String memberCode;

    /**
     * 优惠券
     */
    private Long couponId;

    /**
     * 优惠信息
     */
    private List<PromotionPackVO> promotionPackList;

    /**
     * 价格步骤
     */
    private List<PriceStepVO> priceStepList = new ArrayList<>();

    /**
     * 订单原始价格
     */
    private BigDecimal originalOrderPrice;

    /**
     * 订单最终价格
     */
    private BigDecimal finalOrderPrice;

    /**
     * 步骤日志
     */
    private String printLog;
}
/**
 * Slot初始化组件
 */
@Component("slotInitCmp")
public class SlotInitCmp extends NodeComponent {
    @Override
    public void process() throws Exception {
        //把主要参数冗余到slot里
        PriceCalcReqVO req = this.getRequestData();
        PriceContext context = this.getContextBean(PriceContext.class);
        context.setOrderNo(req.getOrderNo());
        context.setOversea(req.isOversea());
        context.setMemberCode(req.getMemberCode());
        context.setOrderChannel(req.getOrderChannel());
        context.setProductPackList(req.getProductPackList());
        context.setCouponId(req.getCouponId());
    }

    @Override
    public boolean isAccess() {
        PriceCalcReqVO req = this.getSlot().getRequestData();
        if(req != null){
            return true;
        }else{
            return false;
        }
    }
}

总结


LiteFlow确实是一款好用的轻量级流程引擎,可以让复杂的业务逻辑变得清晰起来,便于代码维护。它的规则文件比起其他流程引擎来说,编写简单太多了,几分钟就能上手,感兴趣的朋友可以尝试下它!

参考资料


官网文档:https://liteflow.cc/

项目源码地址


https://gitee.com/dromara/liteFlow


Github上标星60K的电商实战项目mall,全套 视频教程(2023最新版) 已更新完毕!全套教程约40小时,共113期,通过这套教程你可以拥有一个涵盖主流Java技术栈的完整项目经验,同时提高自己独立开发一个项目的能力,下面是项目的整体架构图,感兴趣的小伙伴可以点击链接 mall视频教程 加入学习。



整套 视频教程 的内容还是非常完善的,涵盖了mall项目最佳学习路线、整体框架搭建、业务与技术实现全方位解析、线上Docker环境部署、微服务项目学习等内容,具体大纲可以参考下图,你也可以点击链接 mall视频教程 了解更多内容。


推荐阅读