文档:AviatorScript 编程指南(5.0) - 1. 介绍 - 《AviatorScript 文档 - 帮助手册 & 教程》 - 极客文档
规则引擎是一个更复杂的系统,它的核心是将业务规则与应用程序代码分离,并基于大量数据和规则进行自动化推理和决策。
市场上有很多规则引擎,比如Drools、EasyRules、QLExpress、Aviator、Groovy等
严格来说,aviator属于表达式计算框架,其语法和JavaScript很像。其具体语法可以参考上述的帮助文档。

本文通过一个具体的例子来学习Aviator使用。
网上看到一个案例“非VIP用户满200减30,VIP用户满150减40,且周二全场额外95折”,针对该需求,使用java的if语法进行硬编码也可以实现,本例使用aviator实现。
导入jar
<dependency>
<groupId>com.googlecode.aviator</groupId>
<artifactId>aviator</artifactId>
<version>5.3.3</version>
</dependency>
测试代码
package com.qfedu.aviatortes;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class DiscountRuleEngine {
// 用户类型
public enum UserType {
VIP, NON_VIP
}
/**
* 计算最终价格
*
* @param userType 用户类型
* @param amount 原始金额
* @param purchaseDate 购买日期(用于判断是否是周二)
* @return 最终价格
*/
public static double calculateFinalPrice(UserType userType, double amount, Date purchaseDate) {
// 设置脚本中的参数的值
Map<String, Object> env = new HashMap<>();
env.put("userType", userType.name());
env.put("amount", amount);
env.put("isTuesday", isTuesday(purchaseDate));
// 定义规则表达式
String ruleExpression =
"let discount = 0; " +
"if (userType == 'VIP') { " +
" if (amount >= 150) { " +
" discount = 40; " +
" } " +
"} else { " +
" if (amount >= 200) { " +
" discount = 30; " +
" } " +
"} " +
"let tempAmount = amount - discount; " +
"if (isTuesday) { " +
" tempAmount * 0.95 " +
"} else { " +
" tempAmount " +
"}";
try {
// 编译表达式
Expression expression = AviatorEvaluator.compile(ruleExpression);
// 执行表达式
Object result = expression.execute(env);
return Double.parseDouble(result.toString());
} catch (Exception e) {
throw new RuntimeException("规则计算失败", e);
}
}
/**
* 判断是否是周二
*/
private static boolean isTuesday(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("u");
String dayOfWeek = sdf.format(date);
return "2".equals(dayOfWeek); // 周一是1,周二是2
}
/**
* 测试方法
*/
public static void main(String[] args) {
// 测试数据
Date tuesday = parseDate("2025-08-19"); // 假设这是周二
Date notTuesday = parseDate("2025-08-20"); // 假设这不是周二
// 测试用例
System.out.println("VIP用户,周二,金额160: " +
calculateFinalPrice(UserType.VIP, 160, tuesday)); // 应输出: (160-40)*0.95=114
System.out.println("VIP用户,非周二,金额160: " +
calculateFinalPrice(UserType.VIP, 160, notTuesday)); // 应输出: 160-40=120
System.out.println("非VIP用户,周二,金额210: " +
calculateFinalPrice(UserType.NON_VIP, 210, tuesday)); // 应输出: (210-30)*0.95=171
System.out.println("非VIP用户,非周二,金额210: " +
calculateFinalPrice(UserType.NON_VIP, 210, notTuesday)); // 应输出: 210-30=180
System.out.println("VIP用户,周二,金额140: " +
calculateFinalPrice(UserType.VIP, 140, tuesday)); // 应输出: 140*0.95=133
}
private static Date parseDate(String dateStr) {
try {
return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
} catch (Exception e) {
return new Date();
}
}
}
注意:let是表达式中定义的变量,用于进行中间运算。userType、amount、isTuesday没有通过let进行定义,这些变量的值需要调用脚本时进行传递
直接通过字符串设置表达式,可读性不好,我们可以定义一个.av后缀的文件,比如在resources目录下新建discount.av

## 定义折扣规则
let discount = 0;
if (userType == 'VIP') {
if (amount >= 150) {
discount = 40;
}
} else {
if (amount >= 200) {
discount = 30;
}
}
let tempAmount = amount - discount;
if (isTuesday) {
tempAmount * 0.95
} else {
tempAmount
}
测试代码修改为:
package com.qfedu.aviatortes;
import com.googlecode.aviator.AviatorEvaluator;
import com.googlecode.aviator.Expression;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
public class DiscountRuleEngine2 {
// 用户类型
public enum UserType {
VIP, NON_VIP
}
/**
* 计算最终价格
*
* @param userType 用户类型
* @param amount 原始金额
* @param purchaseDate 购买日期(用于判断是否是周二)
* @return 最终价格
*/
public static double calculateFinalPrice(UserType userType, double amount, Date purchaseDate) {
Map<String, Object> env = new HashMap<>();
env.put("userType", userType.name());
env.put("amount", amount);
env.put("isTuesday", isTuesday(purchaseDate));
try {
// 获取文件路径
Resource resource = new ClassPathResource("discount.av");
String filePath = resource.getFile().getAbsolutePath();
System.out.println("filePath: " + filePath);
// 通过文件加载表达式规则
Expression expression = AviatorEvaluator.getInstance().compileScript(
filePath);
// 调用规则
Object result = expression.execute(env);
return Double.parseDouble(result.toString());
} catch (Exception e) {
throw new RuntimeException("规则计算失败", e);
}
}
/**
* 判断是否是周二
*/
private static boolean isTuesday(Date date) {
SimpleDateFormat sdf = new SimpleDateFormat("u");
String dayOfWeek = sdf.format(date);
return "2".equals(dayOfWeek); // 周一是1,周二是2
}
/**
* 测试方法
*/
public static void main(String[] args) {
// 测试数据
Date tuesday = parseDate("2025-08-19"); // 周二
Date notTuesday = parseDate("2025-08-20"); // 不是周二
// 测试用例
System.out.println("VIP用户,周二,金额160: " +
calculateFinalPrice(UserType.VIP, 160, tuesday)); // 应输出: (160-40)*0.95=114
System.out.println("VIP用户,非周二,金额160: " +
calculateFinalPrice(UserType.VIP, 160, notTuesday)); // 应输出: 160-40=120
System.out.println("非VIP用户,周二,金额210: " +
calculateFinalPrice(UserType.NON_VIP, 210, tuesday)); // 应输出: (210-30)*0.95=171
System.out.println("非VIP用户,非周二,金额210: " +
calculateFinalPrice(UserType.NON_VIP, 210, notTuesday)); // 应输出: 210-30=180
System.out.println("VIP用户,周二,金额140: " +
calculateFinalPrice(UserType.VIP, 140, tuesday)); // 应输出: 140*0.95=133
}
private static Date parseDate(String dateStr) {
try {
return new SimpleDateFormat("yyyy-MM-dd").parse(dateStr);
} catch (Exception e) {
return new Date();
}
}
}
关于aviator的表达式更多语法,可以参考aviator源码中的examples学习

1万+

被折叠的 条评论
为什么被折叠?



