当前位置: 首页 > news >正文

Spring Boot项目集成Aviator实现成本计算模块

Spring Boot项目集成Aviator实现表达式动态成本计算功能的完整解决方案


一、Maven依赖配置

<!-- aviator核心库 -->
<dependency><groupId>com.googlecode.aviator</groupId> <artifactId>aviator</artifactId><version>5.3.3</version>
</dependency><!-- 校验框架 -->
<dependency><groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-validation</artifactId>
</dependency>

二、配置类设计

1. Aviator引擎配置
@Configuration 
public class AviatorConfig {@Bean public AviatorEvaluatorInstance aviatorEvaluator() {AviatorEvaluatorInstance instance = AviatorEvaluator.newInstance(); // 配置引擎参数 instance.setOption(Options.USE_USER_ENV_AS_TOP_ENV_DIRECTLY,  true);instance.setOption(Options.MAX_CACHE_SIZE,  1000);  // 表达式缓存数量 instance.setOption(Options.TRACE_EVAL,  false);    // 生产环境关闭调试 return instance;}
}
2. 成本规则加载配置
@Configuration 
@ConfigurationProperties(prefix = "cost.rules") 
public class CostRuleConfig {// 规则文件存储路径 private String location = "classpath:rules/cost";// 规则映射表(示例:{ruleKey: 规则文件名})private Map<String, String> mapping = new HashMap<>();// Getter/Setter 
}

三、领域模型设计

1. 成本计算请求DTO
@Data 
@NoArgsConstructor 
@AllArgsConstructor 
public class CostCalculateRequest {@NotBlank(message = "成本类型不能为空")private String costType;  // 对应规则类型如:hardware/software @NotNull(message = "计算参数不能为空")private Map<String, Object> params;  // 输入参数如数量、单价等 
}
2. 统一响应DTO
@Data 
@AllArgsConstructor 
public class ApiResponse<T> {private int code;private String message;private T data;public static <T> ApiResponse<T> success(T data) {return new ApiResponse<>(200, "Success", data);}
}

四、业务层实现

1. 表达式加载策略接口
public interface ExpressionLoader {/*** 加载指定规则表达式 * @param ruleKey 规则标识 * @return 编译后的表达式 */Expression loadExpression(String ruleKey);
}
2. 文件系统实现(示例)
@Component 
@RequiredArgsConstructor 
public class FileExpressionLoader implements ExpressionLoader {private final CostRuleConfig ruleConfig;private final AviatorEvaluatorInstance evaluator;@Override public Expression loadExpression(String ruleKey) {String fileName = ruleConfig.getMapping().get(ruleKey); try {Resource resource = new ClassPathResource(ruleConfig.getLocation()  + "/" + fileName);return evaluator.compile(resource.getFile().getAbsolutePath(),  true);} catch (IOException e) {throw new BusinessException("规则文件加载失败: " + fileName);}}
}
3. 核心计算服务
@Service 
@RequiredArgsConstructor 
public class CostCalculatorService {private final ExpressionLoader loader;private final AviatorEvaluatorInstance evaluator;/*** 执行成本计算 * @param request 计算请求 * @return 计算结果(包含明细)*/public BigDecimal calculateCost(CostCalculateRequest request) {// 1. 加载表达式 Expression exp = loader.loadExpression(request.getCostType()); // 2. 构建计算环境 Map<String, Object> env = new HashMap<>(request.getParams()); env.put("log",  Math::log);  // 注入数学函数 // 3. 执行计算 Object result = exp.execute(env); // 4. 结果转换 if (result instanceof Number) {return new BigDecimal(result.toString()).setScale(2,  RoundingMode.HALF_UP);}throw new BusinessException("计算结果类型异常");}
}

五、控制层实现

@RestController 
@RequestMapping("/api/cost")
@RequiredArgsConstructor 
public class CostController {private final CostCalculatorService calculator;@PostMapping("/calculate")public ApiResponse<BigDecimal> calculate(@Valid @RequestBody CostCalculateRequest request) {try {BigDecimal result = calculator.calculateCost(request); return ApiResponse.success(result); } catch (BusinessException e) {return new ApiResponse<>(400, e.getMessage(),  null);}}
}

六、规则文件示例

创建 resources/rules/cost/hardware.av

## 硬件成本计算规则 
let {quantity = params.quantity, unit_price = params.unitPrice, discount = params.discount  ?: 1.0  # 默认不打折 
};# 计算逻辑:数量*单价*折扣 + 固定运输成本 
total = quantity * unit_price * discount + 500;# 返回结果 
return total;

七、异常处理增强

@ControllerAdvice 
public class GlobalExceptionHandler {@ExceptionHandler(BusinessException.class) @ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBody public ApiResponse<Void> handleBusinessException(BusinessException ex) {return new ApiResponse<>(400, ex.getMessage(),  null);}@ExceptionHandler({ExpressionSyntaxErrorException.class,  ExpressionRuntimeException.class}) @ResponseStatus(HttpStatus.BAD_REQUEST)@ResponseBody public ApiResponse<Void> handleAviatorException(Exception ex) {return new ApiResponse<>(400, "规则执行错误: " + ex.getMessage(),  null);}
}

八、安全增强配置

application.yml 中添加:

yaml复制aviator:security:max-loop-count: 10000    # 防止死循环 forbidden-classes:       # 禁用危险类 - java.lang.System  - java.lang.Runtime  max-expression-length: 5000  # 限制表达式长度 

九、性能优化建议

  1. 表达式缓存:利用Aviator内置的编译缓存(已通过compile方法的第二个参数启用)
  2. 预热加载:在应用启动时预加载高频规则
java复制@EventListener(ApplicationReadyEvent.class) 
public void preloadHotRules() {List<String> hotRules = Arrays.asList("hardware",  "software");hotRules.forEach(rule  -> calculator.calculateCost(new  CostCalculateRequest(rule, new HashMap<>())));
}
  1. 监控埋点:通过Spring Actuator暴露指标
@Bean 
public MeterRegistryCustomizer<MeterRegistry> aviatorMetrics() {return registry -> registry.config().commonTags("module",  "cost-calculation");
}

十、验证测试用例

@SpringBootTest 
public class CostCalculatorTest {@Autowired private CostCalculatorService calculator;@Test void testHardwareCost() {Map<String, Object> params = Map.of( "quantity", 100,"unitPrice", 250.5,"discount", 0.9 );BigDecimal result = calculator.calculateCost( new CostCalculateRequest("hardware", params));assertEquals(new BigDecimal("23045.00"), result);}
}

相关文章:

  • 【阿里云大模型高级工程师ACP习题集】3 总结与展望
  • vscode远程服务器连接----过程尝试写入的管道不存在
  • 修改MySQL枚举类型添加‘location‘值
  • 【AI】Ubuntu 22.04 evalscope 模型评测 Qwen3-4B-FP8
  • Linux——https基础理论
  • 【AI论文】FormalMATH:大型语言模型形式化数学推理能力基准测试
  • C语言内存函数及大小端字节序!
  • Mysql order by 用法
  • Vue + Element UI 表单弹窗输入法卡顿问题解决方案
  • 用 Tailwind CSS 优化你的 Vue 3 项目! ! !
  • 计算机硬件:AMD X670E与B650主板的PCIe通道分配
  • 在 Laravel 12 中实现 WebSocket 通信时进行身份验证
  • 水质监控预警管理平台
  • 构建 Web 浏览 AI Agent:Pydantic + MCP 实现指南
  • C#学习第21天:安全与加密(Security and Cryptography)
  • Linux/AndroidOS中进程间的通信线程间的同步 - 虚拟内存操作
  • 企业级RAG架构设计:从FAISS索引到HyDE优化的全链路拆解,金融/医疗领域RAG落地案例与避坑指南(附架构图)
  • PCIe - ZCU106(RC) + KU5P(EP) + 固化
  • 利用 Kali Linux 进行信息收集和枚举
  • 用python实现鼠标监听与手势交互
  • 4月深圳新房、二手房成交同比均上涨,“5月有望延续积极向好的发展态势”
  • 男子煎服15克山豆根中毒送医,医生:不能盲目相信偏方
  • 是谁提议特朗普向好莱坞征税?
  • 新闻分析:电影关税能“让好莱坞再次伟大”?
  • 杨国荣︱《老子智慧八十一讲》及其他
  • 五一小长假上海“人从众”,全要素旅游交易总额超200亿元