SpringBoot + Aviator + 规则中心:轻量级表达式引擎实现营销优惠动态计算

电商大促活动时,营销规则复杂多变,今天满300减50,明天买2送1,后天又变成阶梯式折扣?每次改规则都得改代码、重新发布,简直是开发人员的噩梦!今天就来聊聊如何用SpringBoot + Aviator表达式引擎,搭建一个灵活的营销规则中心,让运营同学也能轻松配置营销规则,再也不用求着开发改代码了!

一、营销规则的痛点

1.1 传统if-else的困境

在没有规则引擎之前,营销优惠计算通常是这样写的:

// 伪代码:传统的营销优惠计算publicBigDecimalcalculateDiscount(Orderorder){if(order.getUserLevel().equals("VIP")){if(order.getAmount().compareTo(newBigDecimal("1000"))>0){returnorder.getAmount().multiply(newBigDecimal("0.8"));// VIP用户满1000打8折}else{returnorder.getAmount().multiply(newBigDecimal("0.9"));// VIP用户其他情况打9折}}elseif(order.getUserLevel().equals("GOLD")){if(order.getAmount().compareTo(newBigDecimal("500"))>0){returnorder.getAmount().multiply(newBigDecimal("0.85"));// 金牌用户满500打8.5折}else{returnorder.getAmount().multiply(newBigDecimal("0.95"));// 金牌用户其他情况打9.5折}}else{if(order.getAmount().compareTo(newBigDecimal("1000"))>0){returnorder.getAmount().multiply(newBigDecimal("0.9"));// 普通用户满1000打9折}else{returnorder.getAmount();// 普通用户其他情况无折扣}}}

这种写法的问题显而易见:

  • 代码复杂:复杂的if-else嵌套,难以维护
  • 修改困难:每次改规则都要改代码、重新发布
  • 扩展性差:新增规则类型需要修改核心代码
  • 测试困难:各种规则组合需要大量测试用例

1.2 业务规则变化频繁

电商行业的营销活动变化极快:

  • 节日促销:双11、双12、618等
  • 会员权益:不同等级用户享受不同优惠
  • 限时活动:秒杀、拼团、砍价等
  • 渠道差异:APP、小程序、H5不同渠道的差异化策略

面对这些变化,传统的硬编码方式显然跟不上节奏。

二、Aviator表达式引擎的优势

2.1 什么是Aviator

Aviator是一个高性能、轻量级的Java表达式引擎,专门用于动态求值表达式。它的特点:

  • 高性能:通过编译成Java字节码执行,性能优异
  • 轻量级:依赖包仅450K,核心部分仅70K
  • 功能丰富:支持算术运算、逻辑运算、正则表达式等
  • 安全可靠:不支持赋值语句和外部函数调用,防止安全问题

2.2 Aviator vs 其他规则引擎

特性AviatorDroolsQLExpressGroovy
性能⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
体积⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
学习成本⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
功能丰富度⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐⭐
适用场景简单计算复杂业务规则中等复杂度通用脚本

推荐场景

  • Aviator:简单到中等复杂度的计算场景
  • Drools:复杂业务规则,有图形化编辑器需求
  • QLExpress:需要中文语法的业务场景

三、SpringBoot + Aviator 实战

3.1 项目依赖配置

首先在pom.xml中添加Aviator依赖:

<dependency><groupId>com.googlecode.aviator</groupId><artifactId>aviator</artifactId><version>5.3.3</version></dependency>

3.2 核心代码实现

创建Aviator规则引擎服务:

@Component@Slf4jpublicclassAviatorRuleEngine{/** * 缓存编译后的表达式,提高执行效率 */privatefinalMap<String,Expression>expressionCache=newConcurrentHashMap<>();/** * 执行规则表达式 */publicObjectexecuteRule(Stringexpression,Map<String,Object>env){try{// 检查缓存中是否存在编译后的表达式ExpressioncompiledExpression=expressionCache.get(expression);if(compiledExpression==null){// 编译表达式并缓存compiledExpression=AviatorEvaluator.compile(expression,true);expressionCache.put(expression,compiledExpression);log.debug("缓存表达式: {}",expression);}// 执行表达式Objectresult=compiledExpression.execute(env);log.debug("表达式执行结果: {} = {}",expression,result);returnresult;}catch(Exceptione){log.error("执行规则表达式失败: {}",expression,e);thrownewRuntimeException("规则执行失败: "+e.getMessage(),e);}}/** * 验证表达式语法 */publicbooleanvalidateExpression(Stringexpression){try{AviatorEvaluator.compile(expression,true);returntrue;}catch(Exceptione){log.error("表达式语法错误: {}",expression,e);returnfalse;}}}

3.3 营销规则服务实现

@Service@Slf4jpublicclassRuleService{@AutowiredprivateAviatorRuleEngineaviatorRuleEngine;/** * 根据订单金额和用户等级计算折扣 */publicDoublecalculateDiscount(DoubleorderAmount,StringuserLevel,StringproductCategory){Map<String,Object>context=newHashMap<>();context.put("orderAmount",orderAmount);context.put("userLevel",userLevel);context.put("productCategory",productCategory);// 根据不同用户等级和订单金额计算折扣StringruleExpression;if("VIP".equals(userLevel)){// VIP用户:订单金额>1000打8折,否则打9折ruleExpression="orderAmount > 1000 ? 0.8 : 0.9";}elseif("GOLD".equals(userLevel)){// 金牌用户:订单金额>500打8.5折,否则打9.5折ruleExpression="orderAmount > 500 ? 0.85 : 0.95";}else{// 普通用户:订单金额>1000打9折,否则无折扣ruleExpression="orderAmount > 1000 ? 0.9 : 1.0";}Objectresult=aviatorRuleEngine.executeRule(ruleExpression,context);returnDouble.valueOf(result.toString());}/** * 计算满减优惠 */publicDoublecalculateCouponDiscount(DoubleorderAmount,StringcouponType){Map<String,Object>context=newHashMap<>();context.put("orderAmount",orderAmount);context.put("couponType",couponType);StringruleExpression;if("MANYIJIAN".equals(couponType)){// 满减券:满200减20,满500减50ruleExpression="orderAmount >= 500 ? 50 : (orderAmount >= 200 ? 20 : 0)";}elseif("ZHEKOU".equals(couponType)){// 折扣券:满100打9折ruleExpression="orderAmount >= 100 ? orderAmount * 0.1 : 0";}else{ruleExpression="0";}Objectresult=aviatorRuleEngine.executeRule(ruleExpression,context);returnDouble.valueOf(result.toString());}}

3.4 API接口实现

@RestController@RequestMapping("/api/marketing")@Slf4jpublicclassMarketingRuleController{@AutowiredprivateRuleServiceruleService;/** * 计算订单折扣 */@PostMapping("/calculate-discount")publicResponseEntity<Map<String,Object>>calculateDiscount(@RequestBodyMap<String,Object>request){try{DoubleorderAmount=Double.valueOf(request.get("orderAmount").toString());StringuserLevel=request.get("userLevel").toString();StringproductCategory=request.get("productCategory").toString();DoublediscountRate=ruleService.calculateDiscount(orderAmount,userLevel,productCategory);Map<String,Object>result=newHashMap<>();result.put("originalAmount",orderAmount);result.put("discountRate",discountRate);result.put("discountedAmount",orderAmount*discountRate);result.put("savedAmount",orderAmount*(1-discountRate));result.put("userLevel",userLevel);log.info("订单折扣计算完成: {}",result);returnResponseEntity.ok(result);}catch(Exceptione){log.error("计算订单折扣失败",e);Map<String,Object>error=newHashMap<>();error.put("error",e.getMessage());returnResponseEntity.badRequest().body(error);}}}

3.5 常用的营销规则表达式

// 1. 满减规则:满200减20,满500减50StringmanjianRule="orderAmount >= 500 ? 50 : (orderAmount >= 200 ? 20 : 0)";// 2. 折扣规则:VIP用户打8折,金牌用户打8.5折StringzhekouRule="userLevel == 'VIP' ? 0.8 : (userLevel == 'GOLD' ? 0.85 : 1.0)";// 3. 阶梯规则:消费金额越高折扣越大StringjietiRule="orderAmount >= 1000 ? 0.7 : (orderAmount >= 500 ? 0.8 : (orderAmount >= 200 ? 0.9 : 1.0))";// 4. 组合规则:多条件判断StringcomplexRule="(userLevel == 'VIP' and orderAmount >= 1000) ? 0.7 : "+"(userLevel == 'GOLD' and orderAmount >= 500) ? 0.8 : 1.0";// 5. 时间规则:特定时间段内有效StringtimeRule="orderTime >= '2023-11-11 00:00:00' and orderTime <= '2023-11-11 23:59:59' ? 0.5 : 1.0";

四、规则中心架构设计

4.1 整体架构

前端运营系统 ←→ 规则配置API ←→ 规则引擎服务 ←→ 缓存 ←→ 数据库 ↓ 业务服务调用

4.2 规则存储设计

@Entity@Table(name="t_rule")@DatapublicclassRule{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;/** * 规则编码 */@Column(unique=true,nullable=false)privateStringruleCode;/** * 规则名称 */privateStringruleName;/** * 规则表达式 */@LobprivateStringruleExpression;/** * 规则描述 */privateStringdescription;/** * 规则类型 */privateStringruleType;/** * 是否启用 */privateBooleanenabled=true;/** * 版本号 */privateIntegerversion=1;/** * 创建时间 */privateLocalDateTimecreateTime=LocalDateTime.now();/** * 更新时间 */privateLocalDateTimeupdateTime=LocalDateTime.now();}

4.3 规则缓存策略

@ServicepublicclassCachedRuleService{@AutowiredprivateRedisTemplate<String,Object>redisTemplate;@AutowiredprivateRuleRepositoryruleRepository;privatestaticfinalStringRULE_CACHE_PREFIX="rule:expression:";/** * 获取规则表达式(带缓存) */publicStringgetRuleExpression(StringruleCode){StringcacheKey=RULE_CACHE_PREFIX+ruleCode;// 先从缓存获取Stringexpression=(String)redisTemplate.opsForValue().get(cacheKey);if(expression!=null){returnexpression;}// 缓存未命中,从数据库获取Rulerule=ruleRepository.findByRuleCodeAndEnabledTrue(ruleCode);if(rule!=null){expression=rule.getRuleExpression();// 存入缓存,设置过期时间redisTemplate.opsForValue().set(cacheKey,expression,300,TimeUnit.SECONDS);returnexpression;}returnnull;}/** * 更新规则时清除缓存 */publicvoidupdateRule(Rulerule){ruleRepository.save(rule);// 清除缓存StringcacheKey=RULE_CACHE_PREFIX+rule.getRuleCode();redisTemplate.delete(cacheKey);}}

五、最佳实践建议

5.1 规则设计原则

  1. 单一职责:每个规则只负责一个业务逻辑
  2. 可测试性:规则表达式应该易于单元测试
  3. 可读性:复杂的规则应该拆分成多个简单规则
  4. 性能考虑:避免过于复杂的嵌套表达式

5.2 安全性考虑

// 1. 表达式验证publicbooleanvalidateRuleExpression(Stringexpression){try{// 编译表达式验证语法Expressioncompiled=AviatorEvaluator.compile(expression,true);returntrue;}catch(Exceptione){log.error("表达式验证失败: {}",expression,e);returnfalse;}}// 2. 沙箱执行(可选)publicObjectexecuteRuleSafely(Stringexpression,Map<String,Object>env){// 设置执行超时时间,防止死循环Map<String,Object>envWithTimeout=newHashMap<>(env);envWithTimeout.put("max_execution_time",1000);// 1秒超时returnAviatorEvaluator.execute(expression,envWithTimeout);}

5.3 监控和日志

@Service@Slf4jpublicclassMonitoredRuleService{@AutowiredprivateMeterRegistrymeterRegistry;publicObjectexecuteRuleWithMonitor(StringruleCode,Stringexpression,Map<String,Object>env){Timer.Samplesample=Timer.start(meterRegistry);try{Objectresult=aviatorRuleEngine.executeRule(expression,env);// 记录成功指标sample.stop(Timer.builder("rule.execution.time").tag("rule_code",ruleCode).tag("result","success").register(meterRegistry));log.info("规则执行成功: ruleCode={}, result={}",ruleCode,result);returnresult;}catch(Exceptione){// 记录失败指标sample.stop(Timer.builder("rule.execution.time").tag("rule_code",ruleCode).tag("result","error").register(meterRegistry));log.error("规则执行失败: ruleCode={}, expression={}",ruleCode,expression,e);throwe;}}}

5.4 规则版本管理

// 规则版本管理@Entity@Table(name="t_rule_version")@DatapublicclassRuleVersion{@Id@GeneratedValue(strategy=GenerationType.IDENTITY)privateLongid;privateStringruleCode;privateStringruleExpression;privateIntegerversion;privateStringdescription;privateLocalDateTimecreateTime;privateStringcreatedBy;// 是否为当前版本privateBooleancurrent=false;}

六、总结

通过SpringBoot + Aviator的组合,我们可以轻松构建一个灵活的营销规则引擎:

  1. 业务灵活性:运营人员可以动态配置营销规则,无需开发介入
  2. 系统性能:Aviator高性能表达式引擎,满足高并发场景
  3. 维护性:规则与代码分离,降低维护成本
  4. 扩展性:支持复杂的业务规则表达式

这套方案特别适合电商、金融等营销活动频繁变化的业务场景。记住,技术的价值在于解决业务问题,选择合适的工具才能事半功倍!

掌握了这套规则引擎方案,相信你再面对复杂的营销规则时会更加从容不迫,让运营同学也能轻松玩转营销活动!


本文由服务端技术精选原创,转载请注明出处。关注我们,获取更多后端技术干货!

源码下载

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

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

相关文章

Thinkphp的基于协同过滤算法的音乐推荐系统

目录基于协同过滤算法的音乐推荐系统&#xff08;ThinkPHP实现&#xff09;项目开发技术介绍PHP核心代码部分展示系统结论源码获取/同行可拿货,招校园代理基于协同过滤算法的音乐推荐系统&#xff08;ThinkPHP实现&#xff09; 音乐推荐系统通过分析用户行为数据&#xff0c;挖…

前后端分离ONLY在线商城系统系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

&#x1f4a1;实话实说&#xff1a;CSDN上做毕设辅导的都是专业技术服务&#xff0c;大家都要生活&#xff0c;这个很正常。我和其他人不同的是&#xff0c;我有自己的项目库存&#xff0c;不需要找别人拿货再加价&#xff0c;所以能给到超低价格。摘要 随着电子商务的快速发展…

前后端分离“衣依”服装销售平台系统|SpringBoot+Vue+MyBatis+MySQL完整源码+部署教程

摘要 随着电子商务的快速发展&#xff0c;服装销售行业对高效、灵活的管理系统需求日益增长。传统的单机版或前后端耦合的系统架构已难以满足现代企业对快速迭代、高并发访问及跨平台兼容性的需求。服装销售平台需要具备商品管理、订单处理、用户交互等功能&#xff0c;同时还需…

解析HTML表格嵌套问题

在处理HTML表格转换为CSV的过程中,我遇到了一个有趣的问题。让我们来详细探讨一下这个问题,并提供解决方案。 问题背景 假设我们有一个HTML字符串,包含多个表格: <table> <tr><td>A</td>

SpringBoot+Vue 海滨体育馆管理系统平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着体育产业的快速发展&#xff0c;体育馆的管理需求日益复杂化&#xff0c;传统的人工管理模式已无法满足现代化场馆的高效运营需求。海滨体育馆作为一个综合性体育场馆&#xff0c;涉及场地预约、会员管理、设备维护等多方面业务&#xff0c;亟需一套智能化管理系统以提…

探索 qCumber 单元测试框架

在编程领域,单元测试是确保代码质量和可靠性的重要环节。qCumber 是 kdb+/q 语言的一个单元测试框架,专门用于测试 q 脚本。本文将深入探讨如何使用 qCumber 框架进行单元测试,并通过一个具体的实例来展示其应用。 qCumber 简介 qCumber 是一个轻量级的测试框架,适用于 k…

SpringBoot+Vue 墙绘产品展示交易平台平台完整项目源码+SQL脚本+接口文档【Java Web毕设】

摘要 随着城市化进程的加快和艺术文化的普及&#xff0c;墙绘艺术逐渐成为城市美化的重要组成部分&#xff0c;同时也催生了墙绘产品展示与交易的市场需求。传统的墙绘交易模式依赖线下渠道&#xff0c;存在信息不对称、交易效率低等问题。为了解决这些问题&#xff0c;本研究设…

Java Web 网上租赁系统系统源码-SpringBoot2+Vue3+MyBatis-Plus+MySQL8.0【含文档】

摘要 随着互联网技术的快速发展&#xff0c;传统租赁行业正逐步向数字化、智能化转型。网上租赁系统作为一种新型的商业模式&#xff0c;能够有效降低租赁双方的信息不对称问题&#xff0c;提高资源利用率&#xff0c;同时为用户提供便捷的在线租赁服务。该系统通过整合租赁资源…

基于SpringBoot+Vue的Web足球青训俱乐部管理后台系统管理系统设计与实现【Java+MySQL+MyBatis完整源码】

摘要 足球青训俱乐部作为培养青少年足球人才的重要机构&#xff0c;其管理效率直接影响训练质量和学员发展。传统的人工管理方式存在信息记录不准确、数据更新滞后、资源调配效率低等问题&#xff0c;亟需一套信息化管理系统实现规范化运营。随着互联网技术的普及&#xff0c;基…

Java SpringBoot+Vue3+MyBatis 师生健康信息管理系统系统源码|前后端分离+MySQL数据库

摘要 随着信息化技术的快速发展&#xff0c;校园健康管理逐渐成为教育领域的重要课题。传统的师生健康信息管理多依赖纸质记录或分散的电子表格&#xff0c;存在数据易丢失、更新不及时、统计效率低下等问题。尤其是在新冠疫情期间&#xff0c;健康信息的实时监控和高效管理显得…

二叉树高频题目

来自左神讲解&#xff0c;观看b站更精彩。1.二叉树层序遍历解法一#include <iostream> #include <queue> #include <unordered_map>using namespace std;class LevelOrderTraversal { private:struct TreeNode {int val;TreeNode *left, *right;TreeNode() :…

【HarmonyOS NEXT】多线程并发-taskpool

一、背景在鸿蒙开发中提供了两种多线程并发方案&#xff0c;分别是TaskPool与Worker&#xff0c;此篇文章主要总结下TaskPool二、TaskPool概念1、TaskPool是为应用提供多线程运行环境&#xff0c;旨在降低资源消耗并提升系统性能2、开发者无需关心线程的生命周期&#xff0c;由…

大数据领域数据架构的发展趋势洞察

大数据领域数据架构的发展趋势洞察&#xff1a;从传统到新兴的演进之路 摘要/引言 在当今数字化时代&#xff0c;大数据的规模和复杂性呈指数级增长&#xff0c;对数据架构提出了前所未有的挑战。传统的数据架构在应对海量、高维、实时性的数据时逐渐显得力不从心。本文旨在深…

在 Linux 发行版中安装 Times New Roman 字体

在Linux系统中安装Times New Roman字体&#xff0c;可以通过以下几种方法&#xff1a; 方法一&#xff1a;通过字体管理器安装&#xff08;推荐&#xff09;下载字体文件&#xff1a; 从Windows系统复制times.ttf、timesbd.ttf、timesbi.ttf、timesi.ttf等文件或从字体网站下载…

n8n 满分漏洞 Ni8mare 可导致服务器遭劫持

聚焦源代码安全&#xff0c;网罗国内外最新资讯&#xff01;编译&#xff1a;代码卫士n8n 中存在一个CVSS满分、被称为 “Ni8mare” 的严重漏洞CVE-2026-21858&#xff0c;可导致未认证攻击者控制本地部署的工作流自动化平台n8n 实例。网络安全公司 Cyera 表示&#xff0c;目前…

【配电网重构】基于混合整数二阶锥配电网重构研究(Matlab代码实现)

【配电网重构】基于混合整数二阶锥配电网重构研究&#xff08;Matlab代码实现&#xff09;

[特殊字符]_内存管理深度解析:如何避免GC导致的性能陷阱[20260108170807]

作为一名经历过无数性能调优案例的工程师&#xff0c;我深知内存管理对Web应用性能的影响有多大。在最近的一个项目中&#xff0c;我们遇到了一个棘手的性能问题&#xff1a;系统在高并发下会出现周期性的延迟飙升&#xff0c;经过深入分析&#xff0c;发现问题根源竟然是垃圾回…

[特殊字符]_压力测试与性能调优的完整指南[20260108171530]

作为一名经历过无数次压力测试的工程师&#xff0c;我深知压力测试在性能调优中的重要性。压力测试不仅是验证系统性能的必要手段&#xff0c;更是发现性能瓶颈和优化方向的关键工具。今天我要分享的是基于真实项目经验的压力测试与性能调优完整指南。 &#x1f4a1; 压力测试…

今天智谱上市,成为全球大模型第一股!

今天智谱&#xff08;股票代码&#xff1a;2513.HK&#xff09;于2026年1月8日在港交所主板正式挂牌上市&#xff0c;成为"全球大模型第一股"。公司开盘报120港元&#xff0c;较发行价116.2港元上涨3.27%&#xff0c;市值达528亿港元。

今天智谱上市,成为全球大模型第一股!

今天智谱&#xff08;股票代码&#xff1a;2513.HK&#xff09;于2026年1月8日在港交所主板正式挂牌上市&#xff0c;成为"全球大模型第一股"。公司开盘报120港元&#xff0c;较发行价116.2港元上涨3.27%&#xff0c;市值达528亿港元。